Files
monero/tests/fuzz/fuzz_rpc/fuzz_rpc.cpp
Arthur Chan 36bdfad073 rpc-fuzz: Add new fuzzers for RPC endpoints
Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Add macro definition for fuzzers

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Fix FuzzedDataProvider header missing problem

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Add README

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Provide static FuzzedDataProvider.h

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Update and enhance fuzzer

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Activate UBSan

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Fix fuzz target retrieval

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Remove bias selector and fix protocol lifespan

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Drop SIGALARM handling and fix bug on selectors

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Fix rpc request changes

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Add a new fuzzer profile that catch all expcetions

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Fix typo

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>

Add warning

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>
2025-09-08 18:35:55 +00:00

92 lines
2.9 KiB
C++

#include "initialisation.h"
#include "rpc_endpoints.h"
#include <fuzzer/FuzzedDataProvider.h>
#include <csignal>
#include <csetjmp>
#include <iostream>
#include <vector>
#include <algorithm>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// In general an iteration needs a fair amount of data so ensure we have enough
// to work with, otherwise return 0 to skip this iteration.
if (size < 512) {
return 0;
}
// Determine if this iteration should run in safe mode
#ifdef SAFE
constexpr bool is_safe_mode = true;
#else
constexpr bool is_safe_mode = false;
#endif
// Retrieve a list of all fuzz targets
auto fuzz_targets = get_fuzz_targets(is_safe_mode);
// Disable fatal exits for logging.
el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
// Prepare base FuzzedDataProvider
FuzzedDataProvider provider(data, size);
// Randomly choose multiple fuzz_targets to fuzz
int rpc_messages_to_send = provider.ConsumeIntegralInRange<int>(1, 16);
std::vector<int> selectors;
if (is_safe_mode) {
selectors.reserve(rpc_messages_to_send);
} else {
selectors.reserve(rpc_messages_to_send + priority_fuzz_targets.size());
for (int i = 0; i < priority_fuzz_targets.size(); ++i) {
selectors.push_back(i);
}
// Randomly shuffle the selectors for priority fuzz targets
for (int i = 0; i < priority_fuzz_targets.size(); i++) {
int target = provider.ConsumeIntegralInRange<int>(0, priority_fuzz_targets.size() - 1);
std::swap(selectors[i], selectors[target]);
}
}
// Randomly select rpc functions to call
for (int i = 0; i < rpc_messages_to_send && provider.remaining_bytes() >= 2; ++i) {
int selector = provider.ConsumeIntegralInRange<int>(0, fuzz_targets.size() - 1);
selectors.push_back(selector);
}
// Initialise core and core_rpc_server
auto core_env = initialise_rpc_core();
auto& dummy_core = core_env->core;
auto rpc_handler = initialise_rpc_server(*dummy_core, provider, !is_safe_mode);
// Generate random blocks/miners/transactions and push to the core blockchains
if (!generate_random_blocks(*dummy_core, provider)) {
// No randomised blocks have been successfully added, skipping this iteration
dummy_core->get_blockchain_storage().get_db().batch_stop();
return 0;
}
// Disable bootstrap daemon
disable_bootstrap_daemon(*rpc_handler->rpc);
for (int selector : selectors) {
try {
// Fuzz the target function
fuzz_targets[selector](*rpc_handler->rpc, provider);
} catch (const std::runtime_error&) {
// Known runtime_error thrown from monero
} catch (const cryptonote::DB_ERROR& e) {
// Known error thrown from monero on internal blockchain DB check
// when fuzzing with random values
#ifdef CATCH_ALL_EXCEPTIONS
} catch (...) {
// Silent all exceptions
#endif
}
}
dummy_core->get_blockchain_storage().get_db().batch_stop();
return 0;
}