/ src / test / fuzz / process_message.cpp
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  }