process_message.cpp raw
1 // Copyright (c) 2020-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <addrman.h>
6 #include <banman.h>
7 #include <consensus/consensus.h>
8 #include <kernel/chainparams.h>
9 #include <net.h>
10 #include <net_processing.h>
11 #include <node/mining_types.h>
12 #include <primitives/block.h>
13 #include <primitives/transaction.h>
14 #include <protocol.h>
15 #include <sync.h>
16 #include <test/fuzz/FuzzedDataProvider.h>
17 #include <test/fuzz/fuzz.h>
18 #include <test/fuzz/util.h>
19 #include <test/fuzz/util/net.h>
20 #include <test/util/mining.h>
21 #include <test/util/net.h>
22 #include <test/util/random.h>
23 #include <test/util/setup_common.h>
24 #include <test/util/time.h>
25 #include <test/util/validation.h>
26 #include <util/check.h>
27 #include <util/time.h>
28 #include <validation.h>
29 #include <validationinterface.h>
30
31 #include <algorithm>
32 #include <array>
33 #include <cstdlib>
34 #include <functional>
35 #include <iostream>
36 #include <memory>
37 #include <optional>
38 #include <string>
39 #include <string_view>
40 #include <utility>
41 #include <vector>
42
43 namespace {
44 TestingSetup* g_setup;
45 std::string_view LIMIT_TO_MESSAGE_TYPE{};
46
47 void ResetChainman(TestingSetup& setup)
48 {
49 SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time());
50 setup.m_node.chainman.reset();
51 setup.m_make_chainman();
52 setup.LoadVerifyActivateChainstate();
53 for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
54 node::BlockCreateOptions options;
55 MineBlock(setup.m_node, options);
56 }
57 }
58 } // namespace
59
60 void initialize_process_message()
61 {
62 if (const auto val{std::getenv("LIMIT_TO_MESSAGE_TYPE")}) {
63 LIMIT_TO_MESSAGE_TYPE = val;
64 Assert(std::count(ALL_NET_MESSAGE_TYPES.begin(), ALL_NET_MESSAGE_TYPES.end(), LIMIT_TO_MESSAGE_TYPE)); // Unknown message type passed
65 }
66
67 static const auto testing_setup{
68 MakeNoLogFileContext<TestingSetup>(
69 /*chain_type=*/ChainType::REGTEST,
70 {}),
71 };
72 g_setup = testing_setup.get();
73 ResetChainman(*g_setup);
74 }
75
76 FUZZ_TARGET(process_message, .init = initialize_process_message)
77 {
78 SeedRandomStateForTest(SeedRand::ZEROS);
79 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
80
81 auto& node{g_setup->m_node};
82 auto& connman{static_cast<ConnmanTestMsg&>(*node.connman)};
83 connman.Reset();
84 auto& chainman{static_cast<TestChainstateManager&>(*node.chainman)};
85 const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())};
86 FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd
87 FakeSteadyClock steady_clock;
88 chainman.ResetIbd();
89 chainman.DisableNextWrite();
90
91 // Reset, so that dangling pointers can be detected by sanitizers.
92 node.banman.reset();
93 node.addrman.reset();
94 node.peerman.reset();
95 node.addrman = std::make_unique<AddrMan>(*node.netgroupman, /*deterministic=*/true, /*consistency_check_ratio=*/0);
96 node.peerman = PeerManager::make(connman, *node.addrman,
97 /*banman=*/nullptr, chainman,
98 *node.mempool, *node.warnings,
99 PeerManager::Options{
100 .reconcile_txs = true,
101 .deterministic_rng = true,
102 });
103
104 connman.SetMsgProc(node.peerman.get());
105 connman.SetAddrman(*node.addrman);
106 LOCK(NetEventsInterface::g_msgproc_mutex);
107
108 const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::MESSAGE_TYPE_SIZE).c_str()};
109 if (!LIMIT_TO_MESSAGE_TYPE.empty() && random_message_type != LIMIT_TO_MESSAGE_TYPE) {
110 return;
111 }
112
113 node.validation_signals->RegisterValidationInterface(node.peerman.get());
114
115 CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock).release();
116
117 connman.AddTestNode(p2p_node);
118 FillNode(fuzzed_data_provider, connman, p2p_node);
119
120 clock.set(ConsumeTime(fuzzed_data_provider));
121
122 CSerializedNetMsg net_msg;
123 net_msg.m_type = random_message_type;
124 net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider, MAX_PROTOCOL_MESSAGE_LENGTH);
125
126 connman.FlushSendBuffer(p2p_node);
127 (void)connman.ReceiveMsgFrom(p2p_node, std::move(net_msg));
128
129 bool more_work{true};
130 while (more_work) {
131 p2p_node.fPauseSend = false;
132 try {
133 more_work = connman.ProcessMessagesOnce(p2p_node);
134 } catch (const std::ios_base::failure&) {
135 }
136 node.peerman->SendMessages(p2p_node);
137 }
138 node.validation_signals->SyncWithValidationInterfaceQueue();
139 node.validation_signals->UnregisterValidationInterface(node.peerman.get());
140 node.connman->StopNodes();
141 if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())) {
142 // Reuse the global chainman, but reset it when it is dirty
143 ResetChainman(*g_setup);
144 }
145 }
146