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