mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-24 18:23:26 -03:00
fuzz: Abort when using global PRNG without re-seed
This commit is contained in:
parent
fa7809aeab
commit
fa18acb457
7 changed files with 77 additions and 2 deletions
|
@ -671,9 +671,11 @@ void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept
|
|||
{
|
||||
GetRNGState().MakeDeterministic(seed);
|
||||
}
|
||||
std::atomic<bool> g_used_g_prng{false}; // Only accessed from tests
|
||||
|
||||
void GetRandBytes(Span<unsigned char> bytes) noexcept
|
||||
{
|
||||
g_used_g_prng = true;
|
||||
ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST, /*always_use_real_rng=*/false);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
41
src/test/fuzz/util/check_globals.cpp
Normal file
41
src/test/fuzz/util/check_globals.cpp
Normal file
|
@ -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;
|
19
src/test/fuzz/util/check_globals.h
Normal file
19
src/test/fuzz/util/check_globals.h
Normal file
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue