96 lines
2.7 KiB
C++
96 lines
2.7 KiB
C++
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <yams/daemon/resource/abi_plugin_loader.h>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace {
|
|
|
|
constexpr size_t kMaxConfigBytes = 2048;
|
|
|
|
std::vector<fs::path> pluginCandidates() {
|
|
std::vector<fs::path> out;
|
|
const fs::path base = "/src/build/fuzzing/tools/fuzzing";
|
|
|
|
const fs::path test1 = base / "libfuzz_abi_test_plugin.so";
|
|
const fs::path test2 = base / "libfuzz_abi_negotiation_plugin.so";
|
|
|
|
if (fs::exists(test1))
|
|
out.push_back(test1);
|
|
if (fs::exists(test2))
|
|
out.push_back(test2);
|
|
return out;
|
|
}
|
|
|
|
std::string configFromBytes(const uint8_t* data, size_t size) {
|
|
if (!data || size == 0)
|
|
return "{}";
|
|
const size_t n = std::min(size, kMaxConfigBytes);
|
|
std::string payload(reinterpret_cast<const char*>(data), n);
|
|
for (char& c : payload) {
|
|
unsigned char uc = static_cast<unsigned char>(c);
|
|
if (uc < 0x20 || uc == '"' || uc == '\\') {
|
|
c = '_';
|
|
}
|
|
}
|
|
return std::string("{\"neg\":\"") + payload + "\"}";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|
if (!data || size == 0)
|
|
return 0;
|
|
|
|
static const bool envInit = [] {
|
|
setenv("YAMS_PLUGIN_TRUST_ALL", "1", 1);
|
|
return true;
|
|
}();
|
|
(void)envInit;
|
|
|
|
auto plugins = pluginCandidates();
|
|
if (plugins.empty()) {
|
|
return 0;
|
|
}
|
|
|
|
const fs::path pluginRoot = plugins.front().parent_path();
|
|
|
|
yams::daemon::AbiPluginLoader loader;
|
|
|
|
loader.setNamePolicy((data[0] & 1) ? yams::daemon::AbiPluginLoader::NamePolicy::Spec
|
|
: yams::daemon::AbiPluginLoader::NamePolicy::Relaxed);
|
|
|
|
(void)loader.scanDirectory(pluginRoot);
|
|
|
|
std::string configJson = configFromBytes(data, size);
|
|
|
|
size_t start = static_cast<size_t>(data[0]) % plugins.size();
|
|
for (size_t i = 0; i < plugins.size(); ++i) {
|
|
const fs::path& p = plugins[(start + i) % plugins.size()];
|
|
auto loaded = loader.load(p, configJson);
|
|
if (!loaded) {
|
|
continue;
|
|
}
|
|
|
|
const auto& info = loaded.value();
|
|
(void)loader.health(info.name);
|
|
|
|
for (const auto& iface : info.interfaces) {
|
|
uint32_t v = 1u + static_cast<uint32_t>(data[(i + iface.size()) % size] % 3u);
|
|
(void)loader.getInterface(info.name, iface, v);
|
|
}
|
|
|
|
std::string dynId = "iface_";
|
|
dynId += static_cast<char>('a' + (data[i % size] % 26));
|
|
(void)loader.getInterface(info.name, dynId, static_cast<uint32_t>(data[(i + 1) % size]));
|
|
|
|
(void)loader.unload(info.name);
|
|
}
|
|
|
|
return 0;
|
|
}
|