diff options
author | MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> | 2024-12-13 14:42:21 +0100 |
---|---|---|
committer | MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> | 2024-12-16 15:23:56 +0100 |
commit | fa18acb457e91cc0fa6b3640b6b55c6bc61572ee (patch) | |
tree | eef517dc4409c4d73c915fb1acb20507235cf2e0 /src/test | |
parent | fa7809aeab838752af94c52977936a8c6555d315 (diff) |
fuzz: Abort when using global PRNG without re-seed
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/fuzz/fuzz.cpp | 9 | ||||
-rw-r--r-- | src/test/fuzz/util/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/test/fuzz/util/check_globals.cpp | 41 | ||||
-rw-r--r-- | src/test/fuzz/util/check_globals.h | 19 | ||||
-rw-r--r-- | src/test/util/random.cpp | 3 | ||||
-rw-r--r-- | src/test/util/random.h | 4 |
6 files changed, 75 insertions, 2 deletions
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 3c81e0f3fe..e4e4723c74 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -6,6 +6,7 @@ #include <netaddress.h> #include <netbase.h> +#include <test/fuzz/util/check_globals.h> #include <test/util/random.h> #include <test/util/setup_common.h> #include <util/check.h> @@ -78,6 +79,12 @@ void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, static std::string_view g_fuzz_target; static const TypeTestOneInput* g_test_one_input{nullptr}; +inline void test_one_input(FuzzBufferType buffer) +{ + CheckGlobals check{}; + (*Assert(g_test_one_input))(buffer); +} + const std::function<std::string()> G_TEST_GET_FULL_NAME{[]{ return std::string{g_fuzz_target}; }}; @@ -210,7 +217,6 @@ void signal_handler(int signal) // This function is used by libFuzzer extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - static const auto& test_one_input = *Assert(g_test_one_input); test_one_input({data, size}); return 0; } @@ -227,7 +233,6 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) int main(int argc, char** argv) { initialize(); - static const auto& test_one_input = *Assert(g_test_one_input); #ifdef __AFL_LOOP // Enable AFL persistent mode. Requires compilation using afl-clang-fast++. // See fuzzing.md for details. diff --git a/src/test/fuzz/util/CMakeLists.txt b/src/test/fuzz/util/CMakeLists.txt index f73a1a83c2..878286b0f4 100644 --- a/src/test/fuzz/util/CMakeLists.txt +++ b/src/test/fuzz/util/CMakeLists.txt @@ -3,6 +3,7 @@ # file COPYING or https://opensource.org/license/mit/. add_library(test_fuzz STATIC EXCLUDE_FROM_ALL + check_globals.cpp descriptor.cpp mempool.cpp net.cpp diff --git a/src/test/fuzz/util/check_globals.cpp b/src/test/fuzz/util/check_globals.cpp new file mode 100644 index 0000000000..4b74ddedd6 --- /dev/null +++ b/src/test/fuzz/util/check_globals.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <test/fuzz/util/check_globals.h> + +#include <test/util/random.h> + +#include <iostream> +#include <memory> +#include <optional> +#include <string> + +struct CheckGlobalsImpl { + CheckGlobalsImpl() + { + g_used_g_prng = false; + g_seeded_g_prng_zero = false; + } + ~CheckGlobalsImpl() + { + if (g_used_g_prng && !g_seeded_g_prng_zero) { + std::cerr << "\n\n" + "The current fuzz target used the global random state.\n\n" + + "This is acceptable, but requires the fuzz target to call \n" + "SeedRandomStateForTest(SeedRand::ZEROS) at the beginning \n" + "of processing the fuzz input.\n\n" + + "An alternative solution would be to avoid any use of globals.\n\n" + + "Without a solution, fuzz stability and determinism can lead \n" + "to non-reproducible bugs or inefficient fuzzing.\n\n" + << std::endl; + std::abort(); // Abort, because AFL may try to recover from a std::exit + } + } +}; + +CheckGlobals::CheckGlobals() : m_impl(std::make_unique<CheckGlobalsImpl>()) {} +CheckGlobals::~CheckGlobals() = default; diff --git a/src/test/fuzz/util/check_globals.h b/src/test/fuzz/util/check_globals.h new file mode 100644 index 0000000000..79f247535a --- /dev/null +++ b/src/test/fuzz/util/check_globals.h @@ -0,0 +1,19 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TEST_FUZZ_UTIL_CHECK_GLOBALS_H +#define BITCOIN_TEST_FUZZ_UTIL_CHECK_GLOBALS_H + +#include <memory> +#include <optional> +#include <string> + +struct CheckGlobalsImpl; +struct CheckGlobals { + CheckGlobals(); + ~CheckGlobals(); + std::unique_ptr<CheckGlobalsImpl> m_impl; +}; + +#endif // BITCOIN_TEST_FUZZ_UTIL_CHECK_GLOBALS_H diff --git a/src/test/util/random.cpp b/src/test/util/random.cpp index 32d785e45d..8757ab36fb 100644 --- a/src/test/util/random.cpp +++ b/src/test/util/random.cpp @@ -12,6 +12,8 @@ #include <cstdlib> #include <iostream> +std::atomic<bool> g_seeded_g_prng_zero{false}; + extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; void SeedRandomStateForTest(SeedRand seedtype) @@ -36,6 +38,7 @@ void SeedRandomStateForTest(SeedRand seedtype) return GetRandHash(); }(); + g_seeded_g_prng_zero = seedtype == SeedRand::ZEROS; const uint256& seed{seedtype == SeedRand::FIXED_SEED ? ctx_seed : uint256::ZERO}; LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex()); MakeRandDeterministicDANGEROUS(seed); diff --git a/src/test/util/random.h b/src/test/util/random.h index 441150e666..47bc7a18f9 100644 --- a/src/test/util/random.h +++ b/src/test/util/random.h @@ -9,6 +9,7 @@ #include <random.h> #include <uint256.h> +#include <atomic> #include <cstdint> enum class SeedRand { @@ -27,6 +28,9 @@ enum class SeedRand { /** Seed the global RNG state for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */ void SeedRandomStateForTest(SeedRand seed); +extern std::atomic<bool> g_seeded_g_prng_zero; +extern std::atomic<bool> g_used_g_prng; + template <RandomNumberGenerator Rng> inline CAmount RandMoney(Rng&& rng) { |