From 0a47ee2c9472ac3c3e3e57affef67bd77d828b91 Mon Sep 17 00:00:00 2001 From: selsta Date: Fri, 26 Jun 2026 00:02:50 +0200 Subject: [PATCH] tests: harden RPC fuzz harness setup Initialize RPC server state used by direct handler calls, let fuzz input choose restricted or unrestricted mode, and skip iterations when the dummy core fails to initialize. Also update the RPC fuzz harness documentation after removal of the old RPC payment setup. --- src/rpc/core_rpc_server.cpp | 2 ++ src/rpc/core_rpc_server.h | 1 + tests/fuzz/fuzz_rpc/README.md | 9 ++++----- tests/fuzz/fuzz_rpc/fuzz_rpc.cpp | 5 ++++- tests/fuzz/fuzz_rpc/initialisation.cpp | 23 ++++++++++++++++------- tests/fuzz/fuzz_rpc/initialisation.h | 4 ++-- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 104be85bd..801e67d2e 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -120,9 +120,11 @@ namespace cryptonote core_rpc_server::core_rpc_server( core& cr , nodetool::node_server >& p2p + , bool restricted ) : m_core(cr) , m_p2p(p2p) + , m_restricted(restricted) , disable_rpc_ban(false) {} //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 02b1c1552..31efccc36 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -73,6 +73,7 @@ namespace cryptonote core_rpc_server( core& cr , nodetool::node_server >& p2p + , bool restricted = false ); ~core_rpc_server(); diff --git a/tests/fuzz/fuzz_rpc/README.md b/tests/fuzz/fuzz_rpc/README.md index 05831c18e..7366b64fc 100644 --- a/tests/fuzz/fuzz_rpc/README.md +++ b/tests/fuzz/fuzz_rpc/README.md @@ -9,14 +9,14 @@ These are the main fuzzing entry points, containing `LLVMFuzzerTestOneInput`, wh ## `initialisation.cpp` / `initialisation.h` -This set of source files provides initialisation helper functions to configure the `core_rpc_server` class with dummy protocols, P2P, payment modules, and other components. It also includes functions to generate fake random blocks, miners, and transactions for use in fuzzing. +This set of source files provides initialisation helper functions to configure the `core_rpc_server` class with dummy protocols, P2P, and other components. It also includes functions to generate fake random blocks, miners, and transactions for use in fuzzing. ## `rpc_endpoints.cpp` / `rpc_endpoints.h` / `zmq_endpoints.cpp` / `zmq_endpoints.h` These source files handle the creation of the necessary request and response objects and the invocation of specific endpoint functions. These simulate real RPC requests / ZMQ requests for the purpose of fuzzing. There are three categories of RPC endpoint functions and only one for ZMQ endpoint functions: * **Safe**: Considered stable and unlikely to fail. -* **Risky**: More prone to failure and early exits, especially if no valid blockchain is generated or no payment modules are configured. +* **Risky**: More prone to failure and early exits, especially if no valid blockchain is generated. * **Priority**: Most critical RPC endpoint functions that will at least run once per iteration. # Building the Fuzzing Harnesses @@ -24,7 +24,7 @@ These source files handle the creation of the necessary request and response obj The same `fuzz_rpc.cpp` is compiled into two versions of the fuzzer, one with the `SAFE` macro defined and one without. Meanwhile, `fuzz_zmq` is compiled into a single version. * With `SAFE` defined: Only safe endpoint functions are fuzzed. -* Without `SAFE`: Both safe and risky functions are included in the fuzzing process, and payment modules are configured. +* Without `SAFE`: Both safe and risky functions are included in the fuzzing process. # Fuzzing Harness Flow @@ -35,8 +35,7 @@ Random data is used to generate selectors that choose an RPC endpoint function / ## `initialise_rpc_core` / `initialise_rpc_server` -At the start of each fuzzing iteration, a `core_rpc_server` object is created and initialised with dummy protocols, P2P, payment modules, and more. -If the `SAFE` macro is not defined, the payment module will also be initialised. +At the start of each fuzzing iteration, a `core_rpc_server` object is created and initialised with dummy protocols and P2P. The fuzz input selects whether the server runs in restricted or unrestricted RPC mode. This step is skipped for `fuzz_zmq`. ## `generate_random_blocks` diff --git a/tests/fuzz/fuzz_rpc/fuzz_rpc.cpp b/tests/fuzz/fuzz_rpc/fuzz_rpc.cpp index 1f38da381..365bd9aac 100644 --- a/tests/fuzz/fuzz_rpc/fuzz_rpc.cpp +++ b/tests/fuzz/fuzz_rpc/fuzz_rpc.cpp @@ -57,8 +57,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Initialise core and core_rpc_server auto core_env = initialise_rpc_core(); + if (!core_env) { + return 0; + } auto& dummy_core = core_env->core; - auto rpc_handler = initialise_rpc_server(*dummy_core, provider, !is_safe_mode); + auto rpc_handler = initialise_rpc_server(*dummy_core, provider.ConsumeBool()); // Generate random blocks/miners/transactions and push to the core blockchains if (!generate_random_blocks(*dummy_core, provider)) { diff --git a/tests/fuzz/fuzz_rpc/initialisation.cpp b/tests/fuzz/fuzz_rpc/initialisation.cpp index 9d9a8aeaf..7cac0320a 100644 --- a/tests/fuzz/fuzz_rpc/initialisation.cpp +++ b/tests/fuzz/fuzz_rpc/initialisation.cpp @@ -16,6 +16,7 @@ #include "serialization/binary_utils.h" #include "serialization/variant.h" +#include #include #include #include @@ -51,21 +52,29 @@ std::unique_ptr initialise_rpc_core() { cryptonote::core::init_options(desc); boost::program_options::variables_map vm; - // Add command line argument to configure the rpc core object to use regression testing mode (FAKECHAIN) - // Enabling FAKECHAIN mode allows skipping validation logic of the authors signature and transactions ID - // on valid blocks and transactions while keeping other logic - std::vector argv = {"fuzz", "--regtest"}; + // Add command line arguments to configure the rpc core object to use regression testing mode (FAKECHAIN) + // and a throwaway data directory. Enabling FAKECHAIN mode allows skipping validation logic of the authors + // signature and transactions ID on valid blocks and transactions while keeping other logic. + const boost::filesystem::path data_dir = boost::filesystem::temp_directory_path() / "monero-fuzz-rpc"; + std::vector args = {"fuzz", "--regtest", "--offline", "--data-dir", data_dir.string()}; + std::vector argv; + argv.reserve(args.size()); + for (const auto& arg : args) { + argv.push_back(arg.c_str()); + } boost::program_options::store(boost::program_options::parse_command_line(argv.size(), argv.data(), desc), vm); boost::program_options::notify(vm); // Initialise the dummy core with all the above settings - env->core->init(vm); + if (!env->core->init(vm)) { + return nullptr; + } return env; } // Build the core_rpc_server handler object with the configured dummy core object -std::unique_ptr initialise_rpc_server(cryptonote::core& dummy_core, FuzzedDataProvider& provider, bool need_payment) { +std::unique_ptr initialise_rpc_server(cryptonote::core& dummy_core, bool restricted) { // Create rpc server bundle object auto bundle = std::make_unique(); @@ -73,7 +82,7 @@ std::unique_ptr initialise_rpc_server(cryptonote::core& dummy_c bundle->proto_handler = std::make_unique>(dummy_core, nullptr, true); bundle->proto_handler->set_no_sync(false); bundle->dummy_p2p = std::make_unique>>(*bundle->proto_handler); - bundle->rpc = std::make_unique(dummy_core, *bundle->dummy_p2p); + bundle->rpc = std::make_unique(dummy_core, *bundle->dummy_p2p, restricted); return bundle; } diff --git a/tests/fuzz/fuzz_rpc/initialisation.h b/tests/fuzz/fuzz_rpc/initialisation.h index e892c410e..f3783a6d0 100644 --- a/tests/fuzz/fuzz_rpc/initialisation.h +++ b/tests/fuzz/fuzz_rpc/initialisation.h @@ -6,7 +6,7 @@ // Define templates for dummy protocol object template class nodetool::node_server>; -struct DummyProtocol : public cryptonote::i_cryptonote_protocol { +struct DummyProtocol final : public cryptonote::i_cryptonote_protocol { public: bool is_synchronized() const; bool relay_transactions(cryptonote::NOTIFY_NEW_TRANSACTIONS::request&, const boost::uuids::uuid&, epee::net_utils::zone, cryptonote::relay_method); @@ -25,7 +25,7 @@ struct CoreEnv { }; std::unique_ptr initialise_rpc_core(); -std::unique_ptr initialise_rpc_server(cryptonote::core&, FuzzedDataProvider&, bool); +std::unique_ptr initialise_rpc_server(cryptonote::core&, bool); bool generate_random_blocks(cryptonote::core&, FuzzedDataProvider&); extern std::vector cached_tx_hashes;