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