|
| 1 | +// Copyright (c) 2020 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 <chainparams.h> |
| 7 | +#include <consensus/consensus.h> |
| 8 | +#include <net.h> |
| 9 | +#include <net_processing.h> |
| 10 | +#include <protocol.h> |
| 11 | +#include <scheduler.h> |
| 12 | +#include <script/script.h> |
| 13 | +#include <streams.h> |
| 14 | +#include <test/fuzz/FuzzedDataProvider.h> |
| 15 | +#include <test/fuzz/fuzz.h> |
| 16 | +#include <test/util/mining.h> |
| 17 | +#include <test/util/setup_common.h> |
| 18 | +#include <util/memory.h> |
| 19 | +#include <validationinterface.h> |
| 20 | +#include <version.h> |
| 21 | + |
| 22 | +#include <algorithm> |
| 23 | +#include <atomic> |
| 24 | +#include <cassert> |
| 25 | +#include <chrono> |
| 26 | +#include <cstdint> |
| 27 | +#include <iosfwd> |
| 28 | +#include <iostream> |
| 29 | +#include <map> |
| 30 | +#include <memory> |
| 31 | +#include <set> |
| 32 | +#include <string> |
| 33 | +#include <vector> |
| 34 | + |
| 35 | +bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc); |
| 36 | + |
| 37 | +namespace { |
| 38 | + |
| 39 | +#ifdef MESSAGE_TYPE |
| 40 | +#define TO_STRING_(s) #s |
| 41 | +#define TO_STRING(s) TO_STRING_(s) |
| 42 | +const std::string LIMIT_TO_MESSAGE_TYPE{TO_STRING(MESSAGE_TYPE)}; |
| 43 | +#else |
| 44 | +const std::string LIMIT_TO_MESSAGE_TYPE; |
| 45 | +#endif |
| 46 | + |
| 47 | +const std::map<std::string, std::set<std::string>> EXPECTED_DESERIALIZATION_EXCEPTIONS = { |
| 48 | + {"CDataStream::read(): end of data: iostream error", {"addr", "block", "blocktxn", "cmpctblock", "feefilter", "filteradd", "filterload", "getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", "notfound", "ping", "sendcmpct", "tx"}}, |
| 49 | + {"CompactSize exceeds limit of type: iostream error", {"cmpctblock"}}, |
| 50 | + {"differential value overflow: iostream error", {"getblocktxn"}}, |
| 51 | + {"index overflowed 16 bits: iostream error", {"getblocktxn"}}, |
| 52 | + {"index overflowed 16-bits: iostream error", {"cmpctblock"}}, |
| 53 | + {"indexes overflowed 16 bits: iostream error", {"getblocktxn"}}, |
| 54 | + {"non-canonical ReadCompactSize(): iostream error", {"addr", "block", "blocktxn", "cmpctblock", "filteradd", "filterload", "getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", "notfound", "tx"}}, |
| 55 | + {"ReadCompactSize(): size too large: iostream error", {"addr", "block", "blocktxn", "cmpctblock", "filteradd", "filterload", "getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", "notfound", "tx"}}, |
| 56 | + {"Superfluous witness record: iostream error", {"block", "blocktxn", "cmpctblock", "tx"}}, |
| 57 | + {"Unknown transaction optional data: iostream error", {"block", "blocktxn", "cmpctblock", "tx"}}, |
| 58 | +}; |
| 59 | + |
| 60 | +const RegTestingSetup* g_setup; |
| 61 | +} // namespace |
| 62 | + |
| 63 | +void initialize() |
| 64 | +{ |
| 65 | + static RegTestingSetup setup{}; |
| 66 | + g_setup = &setup; |
| 67 | + |
| 68 | + for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { |
| 69 | + MineBlock(g_setup->m_node, CScript() << OP_TRUE); |
| 70 | + } |
| 71 | + SyncWithValidationInterfaceQueue(); |
| 72 | +} |
| 73 | + |
| 74 | +void test_one_input(const std::vector<uint8_t>& buffer) |
| 75 | +{ |
| 76 | + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); |
| 77 | + const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()}; |
| 78 | + if (!LIMIT_TO_MESSAGE_TYPE.empty() && random_message_type != LIMIT_TO_MESSAGE_TYPE) { |
| 79 | + return; |
| 80 | + } |
| 81 | + CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION}; |
| 82 | + CNode p2p_node{0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, false}; |
| 83 | + p2p_node.fSuccessfullyConnected = true; |
| 84 | + p2p_node.nVersion = PROTOCOL_VERSION; |
| 85 | + p2p_node.SetSendVersion(PROTOCOL_VERSION); |
| 86 | + g_setup->m_node.peer_logic->InitializeNode(&p2p_node); |
| 87 | + try { |
| 88 | + (void)ProcessMessage(&p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(), Params(), g_setup->m_node.connman.get(), g_setup->m_node.banman.get(), std::atomic<bool>{false}); |
| 89 | + } catch (const std::ios_base::failure& e) { |
| 90 | + const std::string exception_message{e.what()}; |
| 91 | + const auto p = EXPECTED_DESERIALIZATION_EXCEPTIONS.find(exception_message); |
| 92 | + if (p == EXPECTED_DESERIALIZATION_EXCEPTIONS.cend() || p->second.count(random_message_type) == 0) { |
| 93 | + std::cout << "Unexpected exception when processing message type \"" << random_message_type << "\": " << exception_message << std::endl; |
| 94 | + assert(false); |
| 95 | + } |
| 96 | + } |
| 97 | + SyncWithValidationInterfaceQueue(); |
| 98 | +} |
0 commit comments