diff --git a/src/test/fuzz/cmpctblock.cpp b/src/test/fuzz/cmpctblock.cpp index ff5279caed8..0cdc380848e 100644 --- a/src/test/fuzz/cmpctblock.cpp +++ b/src/test/fuzz/cmpctblock.cpp @@ -164,6 +164,7 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); FakeNodeClock clock{1610000000s}; + FakeSteadyClock steady_clock; auto setup = g_setup; auto& mempool = *setup->m_node.mempool; @@ -189,7 +190,7 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) std::vector peers; for (int i = 0; i < 4; ++i) { - peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release()); + peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock, i).release()); CNode& p2p_node = *peers.back(); FillNode(fuzzed_data_provider, connman, p2p_node); connman.AddTestNode(p2p_node); diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index 614bdf4f337..cca9b1371ce 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -42,6 +42,7 @@ FUZZ_TARGET(connman, .init = initialize_connman) SeedRandomStateForTest(SeedRand::ZEROS); FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)}; + FakeSteadyClock steady_clock; auto netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)}; auto addr_man_ptr{std::make_unique(netgroupman, fuzzed_data_provider, GetCheckRatio())}; if (fuzzed_data_provider.ConsumeBool()) { @@ -58,8 +59,8 @@ FUZZ_TARGET(connman, .init = initialize_connman) // Mock CreateSock() to create FuzzedSock. auto CreateSockOrig = CreateSock; - CreateSock = [&fuzzed_data_provider](int, int, int) { - return std::make_unique(fuzzed_data_provider); + CreateSock = [&fuzzed_data_provider, &steady_clock](int, int, int) { + return std::make_unique(fuzzed_data_provider, steady_clock); }; // Mock g_dns_lookup() to return a fuzzed address. @@ -96,13 +97,13 @@ FUZZ_TARGET(connman, .init = initialize_connman) CNetAddr random_netaddr; CAddress random_address; - CNode random_node = ConsumeNode(fuzzed_data_provider); + CNode random_node = ConsumeNode(fuzzed_data_provider, steady_clock); CSubNet random_subnet; std::string random_string; std::vector node_ids; LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) { - CNode& p2p_node{*ConsumeNodeAsUniquePtr(fuzzed_data_provider).release()}; + CNode& p2p_node{*ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock).release()}; // Simulate post-handshake state. p2p_node.fSuccessfullyConnected = true; connman.AddTestNode(p2p_node); diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp index 5c94a19b8d8..1e4be8a9803 100644 --- a/src/test/fuzz/i2p.cpp +++ b/src/test/fuzz/i2p.cpp @@ -28,11 +28,12 @@ FUZZ_TARGET(i2p, .init = initialize_i2p) FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)}; + FakeSteadyClock steady_clock; // Mock CreateSock() to create FuzzedSock. auto CreateSockOrig = CreateSock; - CreateSock = [&fuzzed_data_provider](int, int, int) { - return std::make_unique(fuzzed_data_provider); + CreateSock = [&fuzzed_data_provider, &steady_clock](int, int, int) { + return std::make_unique(fuzzed_data_provider, steady_clock); }; const fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key"; diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index 93ea00cb94c..8ee08ed623d 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -33,7 +33,8 @@ FUZZ_TARGET(net, .init = initialize_net) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)}; - CNode node{ConsumeNode(fuzzed_data_provider)}; + FakeSteadyClock steady_clock; + CNode node{ConsumeNode(fuzzed_data_provider, steady_clock)}; node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral()); if (const auto service_opt = ConsumeDeserializable(fuzzed_data_provider, ConsumeDeserializationParams(fuzzed_data_provider))) @@ -82,8 +83,9 @@ FUZZ_TARGET(local_address, .init = initialize_net) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)}; + FakeSteadyClock steady_clock; CService service{ConsumeService(fuzzed_data_provider)}; - CNode node{ConsumeNode(fuzzed_data_provider)}; + CNode node{ConsumeNode(fuzzed_data_provider, steady_clock)}; { LOCK(g_maplocalhost_mutex); mapLocalHost.clear(); diff --git a/src/test/fuzz/p2p_handshake.cpp b/src/test/fuzz/p2p_handshake.cpp index affc63c9a16..e0c8ac160aa 100644 --- a/src/test/fuzz/p2p_handshake.cpp +++ b/src/test/fuzz/p2p_handshake.cpp @@ -42,6 +42,7 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize) auto& connman{static_cast(*node.connman)}; auto& chainman{static_cast(*node.chainman)}; FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd + FakeSteadyClock steady_clock; chainman.ResetIbd(); node.banman.reset(); @@ -64,7 +65,7 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize) std::vector peers; const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3); for (int i = 0; i < num_peers_to_add; ++i) { - peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release()); + peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock, i).release()); connman.AddTestNode(*peers.back()); node.peerman->InitializeNode( *peers.back(), diff --git a/src/test/fuzz/pcp.cpp b/src/test/fuzz/pcp.cpp index a656d44311f..221d237dfc8 100644 --- a/src/test/fuzz/pcp.cpp +++ b/src/test/fuzz/pcp.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -31,11 +32,12 @@ void port_map_target_init() FUZZ_TARGET(pcp_request_port_map, .init = port_map_target_init) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + FakeSteadyClock steady_clock; // Create a mocked socket between random (and potentially invalid) client and gateway addresses. CreateSock = [&](int domain, int type, int protocol) { if ((domain == AF_INET || domain == AF_INET6) && type == SOCK_DGRAM && protocol == IPPROTO_UDP) { - return std::make_unique(fuzzed_data_provider); + return std::make_unique(fuzzed_data_provider, steady_clock); } return std::unique_ptr(); }; @@ -59,11 +61,12 @@ FUZZ_TARGET(pcp_request_port_map, .init = port_map_target_init) FUZZ_TARGET(natpmp_request_port_map, .init = port_map_target_init) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + FakeSteadyClock steady_clock; // Create a mocked socket between random (and potentially invalid) client and gateway addresses. CreateSock = [&](int domain, int type, int protocol) { if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) { - return std::make_unique(fuzzed_data_provider); + return std::make_unique(fuzzed_data_provider, steady_clock); } return std::unique_ptr(); }; diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index f5d59891f25..7712ea6fcda 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -84,6 +84,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd + FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -111,7 +112,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) node.validation_signals->RegisterValidationInterface(node.peerman.get()); - CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider).release(); + CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock).release(); connman.AddTestNode(p2p_node); FillNode(fuzzed_data_provider, connman, p2p_node); diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 68eb2b8ddb9..fd0c9abf1c8 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -73,6 +73,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd + FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -98,7 +99,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) std::vector peers; const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3); for (int i = 0; i < num_peers_to_add; ++i) { - peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release()); + peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock, i).release()); CNode& p2p_node = *peers.back(); FillNode(fuzzed_data_provider, connman, p2p_node); diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index 0bd1710d2a8..8a4592c87e5 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -32,6 +32,7 @@ FUZZ_TARGET(socks5, .init = initialize_socks5) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)}; + FakeSteadyClock steady_clock; ProxyCredentials proxy_credentials; proxy_credentials.username = fuzzed_data_provider.ConsumeRandomLengthString(512); proxy_credentials.password = fuzzed_data_provider.ConsumeRandomLengthString(512); @@ -41,7 +42,7 @@ FUZZ_TARGET(socks5, .init = initialize_socks5) // Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This // will slow down fuzzing. g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1ms : default_socks5_recv_timeout; - FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider); + FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider, steady_clock); // This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within // a few seconds of fuzzing. auto str_dest = fuzzed_data_provider.ConsumeRandomLengthString(512); diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp index ba17e4e9360..dfd295b3ec4 100644 --- a/src/test/fuzz/util/net.cpp +++ b/src/test/fuzz/util/net.cpp @@ -111,13 +111,12 @@ P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcep template CNetAddr::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept; template CAddress::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept; -FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) +FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider, FakeSteadyClock& clock) : Sock{fuzzed_data_provider.ConsumeIntegralInRange(INVALID_SOCKET - 1, INVALID_SOCKET)}, m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()}, - m_time{MockableSteadyClock::INITIAL_MOCK_TIME} + m_clock{clock} { - ElapseTime(std::chrono::seconds(0)); // start mocking the steady clock. } FuzzedSock::~FuzzedSock() @@ -129,12 +128,6 @@ FuzzedSock::~FuzzedSock() m_socket = INVALID_SOCKET; } -void FuzzedSock::ElapseTime(std::chrono::milliseconds duration) const -{ - m_time += duration; - MockableSteadyClock::SetMockTime(m_time); -} - FuzzedSock& FuzzedSock::operator=(Sock&& other) { assert(false && "Move of Sock into FuzzedSock not allowed."); @@ -340,7 +333,7 @@ std::unique_ptr FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) co } } } - return std::make_unique(m_fuzzed_data_provider); + return std::make_unique(m_fuzzed_data_provider, m_clock); } int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const @@ -428,7 +421,7 @@ bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* // FuzzedDataProvider runs out of data. *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested; } - ElapseTime(timeout); + m_clock += timeout; return true; } @@ -441,7 +434,7 @@ bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& even // FuzzedDataProvider runs out of data. events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested; } - ElapseTime(timeout); + m_clock += timeout; return true; } diff --git a/src/test/fuzz/util/net.h b/src/test/fuzz/util/net.h index 36393811624..520c6732dab 100644 --- a/src/test/fuzz/util/net.h +++ b/src/test/fuzz/util/net.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -178,17 +179,16 @@ class FuzzedSock : public Sock const bool m_selectable; /** - * Used to mock the steady clock in methods waiting for a given duration. + * Externally-provided context used to mock the steady clock in methods + * waiting for a given duration. It is a reference (rather than an owned + * member) so that several FuzzedSock instances sharing a test case (e.g. + * one per peer, or one created from Accept()) advance a single mocked + * clock. */ - mutable std::chrono::milliseconds m_time; - - /** - * Set the value of the mocked steady clock such as that many ms have passed. - */ - void ElapseTime(std::chrono::milliseconds duration) const; + FakeSteadyClock& m_clock; public: - explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider); + explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider, FakeSteadyClock& clock); ~FuzzedSock() override; @@ -228,9 +228,9 @@ public: return FuzzedNetEvents{fdp}; } -[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider) +[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider, FakeSteadyClock& clock) { - return FuzzedSock{fuzzed_data_provider}; + return FuzzedSock{fuzzed_data_provider, clock}; } [[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept @@ -267,10 +267,10 @@ inline std::vector ConsumeServiceVector(FuzzedDataProvider& fuzzed_dat CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept; template -auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional& node_id_in = std::nullopt) noexcept +auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, FakeSteadyClock& clock, const std::optional& node_id_in = std::nullopt) noexcept { const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits::max())); - const auto sock = std::make_shared(fuzzed_data_provider); + const auto sock = std::make_shared(fuzzed_data_provider, clock); const CAddress address = ConsumeAddress(fuzzed_data_provider); const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral(); const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral(); @@ -307,7 +307,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional& node_id_in = std::nullopt) { return ConsumeNode(fdp, node_id_in); } +inline std::unique_ptr ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, FakeSteadyClock& clock, const std::optional& node_id_in = std::nullopt) { return ConsumeNode(fdp, clock, node_id_in); } void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);