mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-26 03:03:22 -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);
|
GetRNGState().MakeDeterministic(seed);
|
||||||
}
|
}
|
||||||
|
std::atomic<bool> g_used_g_prng{false}; // Only accessed from tests
|
||||||
|
|
||||||
void GetRandBytes(Span<unsigned char> bytes) noexcept
|
void GetRandBytes(Span<unsigned char> bytes) noexcept
|
||||||
{
|
{
|
||||||
|
g_used_g_prng = true;
|
||||||
ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST, /*always_use_real_rng=*/false);
|
ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST, /*always_use_real_rng=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <netaddress.h>
|
#include <netaddress.h>
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
|
#include <test/fuzz/util/check_globals.h>
|
||||||
#include <test/util/random.h>
|
#include <test/util/random.h>
|
||||||
#include <test/util/setup_common.h>
|
#include <test/util/setup_common.h>
|
||||||
#include <util/check.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 std::string_view g_fuzz_target;
|
||||||
static const TypeTestOneInput* g_test_one_input{nullptr};
|
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{[]{
|
const std::function<std::string()> G_TEST_GET_FULL_NAME{[]{
|
||||||
return std::string{g_fuzz_target};
|
return std::string{g_fuzz_target};
|
||||||
}};
|
}};
|
||||||
|
@ -210,7 +217,6 @@ void signal_handler(int signal)
|
||||||
// This function is used by libFuzzer
|
// This function is used by libFuzzer
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
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});
|
test_one_input({data, size});
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +233,6 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
static const auto& test_one_input = *Assert(g_test_one_input);
|
|
||||||
#ifdef __AFL_LOOP
|
#ifdef __AFL_LOOP
|
||||||
// Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
|
// Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
|
||||||
// See fuzzing.md for details.
|
// See fuzzing.md for details.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# file COPYING or https://opensource.org/license/mit/.
|
# file COPYING or https://opensource.org/license/mit/.
|
||||||
|
|
||||||
add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
|
add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
|
||||||
|
check_globals.cpp
|
||||||
descriptor.cpp
|
descriptor.cpp
|
||||||
mempool.cpp
|
mempool.cpp
|
||||||
net.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 <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
std::atomic<bool> g_seeded_g_prng_zero{false};
|
||||||
|
|
||||||
extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
|
extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
|
||||||
|
|
||||||
void SeedRandomStateForTest(SeedRand seedtype)
|
void SeedRandomStateForTest(SeedRand seedtype)
|
||||||
|
@ -36,6 +38,7 @@ void SeedRandomStateForTest(SeedRand seedtype)
|
||||||
return GetRandHash();
|
return GetRandHash();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
g_seeded_g_prng_zero = seedtype == SeedRand::ZEROS;
|
||||||
const uint256& seed{seedtype == SeedRand::FIXED_SEED ? ctx_seed : uint256::ZERO};
|
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());
|
LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex());
|
||||||
MakeRandDeterministicDANGEROUS(seed);
|
MakeRandDeterministicDANGEROUS(seed);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <random.h>
|
#include <random.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
enum class SeedRand {
|
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(). */
|
/** Seed the global RNG state for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */
|
||||||
void SeedRandomStateForTest(SeedRand seed);
|
void SeedRandomStateForTest(SeedRand seed);
|
||||||
|
|
||||||
|
extern std::atomic<bool> g_seeded_g_prng_zero;
|
||||||
|
extern std::atomic<bool> g_used_g_prng;
|
||||||
|
|
||||||
template <RandomNumberGenerator Rng>
|
template <RandomNumberGenerator Rng>
|
||||||
inline CAmount RandMoney(Rng&& rng)
|
inline CAmount RandMoney(Rng&& rng)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue