|
| 1 | +#include "initialisation.h" |
| 2 | +#include "rpc_endpoints.h" |
| 3 | +#include <fuzzer/FuzzedDataProvider.h> |
| 4 | + |
| 5 | +#include <csignal> |
| 6 | +#include <csetjmp> |
| 7 | +#include <iostream> |
| 8 | +#include <vector> |
| 9 | +#include <algorithm> |
| 10 | + |
| 11 | +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| 12 | + // In general an iteration needs a fair amount of data so ensure we have enough |
| 13 | + // to work with, otherwise return 0 to skip this iteration. |
| 14 | + if (size < 512) { |
| 15 | + return 0; |
| 16 | + } |
| 17 | + |
| 18 | + // Determine if this iteration should run in safe mode |
| 19 | +#ifdef SAFE |
| 20 | + constexpr bool is_safe_mode = true; |
| 21 | +#else |
| 22 | + constexpr bool is_safe_mode = false; |
| 23 | +#endif |
| 24 | + |
| 25 | + // Retrieve a list of all fuzz targets |
| 26 | + auto fuzz_targets = get_fuzz_targets(is_safe_mode); |
| 27 | + |
| 28 | + // Disable fatal exits for logging. |
| 29 | + el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog); |
| 30 | + |
| 31 | + // Prepare base FuzzedDataProvider |
| 32 | + FuzzedDataProvider provider(data, size); |
| 33 | + |
| 34 | + // Randomly choose multiple fuzz_targets to fuzz |
| 35 | + int rpc_messages_to_send = provider.ConsumeIntegralInRange<int>(1, 16); |
| 36 | + std::vector<int> selectors; |
| 37 | + if (is_safe_mode) { |
| 38 | + selectors.reserve(rpc_messages_to_send); |
| 39 | + } else { |
| 40 | + selectors.reserve(rpc_messages_to_send + priority_fuzz_targets.size()); |
| 41 | + for (int i = 0; i < priority_fuzz_targets.size(); ++i) { |
| 42 | + selectors.push_back(i); |
| 43 | + } |
| 44 | + |
| 45 | + // Randomly shuffle the selectors for priority fuzz targets |
| 46 | + for (int i = 0; i < priority_fuzz_targets.size(); i++) { |
| 47 | + int target = provider.ConsumeIntegralInRange<int>(0, priority_fuzz_targets.size() - 1); |
| 48 | + std::swap(selectors[i], selectors[target]); |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + // Randomly select rpc functions to call |
| 53 | + for (int i = 0; i < rpc_messages_to_send && provider.remaining_bytes() >= 2; ++i) { |
| 54 | + int selector = provider.ConsumeIntegralInRange<int>(0, fuzz_targets.size() - 1); |
| 55 | + selectors.push_back(selector); |
| 56 | + } |
| 57 | + |
| 58 | + // Initialise core and core_rpc_server |
| 59 | + auto core_env = initialise_rpc_core(); |
| 60 | + auto& dummy_core = core_env->core; |
| 61 | + auto rpc_handler = initialise_rpc_server(*dummy_core, provider, !is_safe_mode); |
| 62 | + |
| 63 | + // Generate random blocks/miners/transactions and push to the core blockchains |
| 64 | + if (!generate_random_blocks(*dummy_core, provider)) { |
| 65 | + // No randomised blocks have been successfully added, skipping this iteration |
| 66 | + dummy_core->get_blockchain_storage().get_db().batch_stop(); |
| 67 | + return 0; |
| 68 | + } |
| 69 | + |
| 70 | + // Disable bootstrap daemon |
| 71 | + disable_bootstrap_daemon(*rpc_handler->rpc); |
| 72 | + |
| 73 | + for (int selector : selectors) { |
| 74 | + try { |
| 75 | + // Fuzz the target function |
| 76 | + fuzz_targets[selector](*rpc_handler->rpc, provider); |
| 77 | + } catch (const std::runtime_error&) { |
| 78 | + // Known runtime_error thrown from monero |
| 79 | + } catch (const cryptonote::DB_ERROR& e) { |
| 80 | + // Known error thrown from monero on internal blockchain DB check |
| 81 | + // when fuzzing with random values |
| 82 | +#ifdef CATCH_ALL_EXCEPTIONS |
| 83 | + } catch (...) { |
| 84 | + // Silent all exceptions |
| 85 | +#endif |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + dummy_core->get_blockchain_storage().get_db().batch_stop(); |
| 90 | + return 0; |
| 91 | +} |
0 commit comments