-
Notifications
You must be signed in to change notification settings - Fork 793
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: Add fuzzing harness for ProcessMessage(...). Enables high-leve…
…l fuzzing of the P2P layer. Summary: ``` Add fuzzing harness for ProcessMessage(...). Enables high-level fuzzing of the P2P layer. All code paths reachable from this fuzzer can be assumed to be reachable for an untrusted peer. Seeded from thin air (an empty corpus) this fuzzer reaches roughly 20 000 lines of code. To test this PR: $ make distclean $ ./autogen.sh $ CC=clang CXX=clang++ ./configure --enable-fuzz \ --with-sanitizers=address,fuzzer,undefined $ make $ src/test/fuzz/process_message … Worth noting about this fuzzing harness: To achieve a reasonable number of executions per seconds the state of the fuzzer is unfortunately not entirely reset between test_one_input calls. The set-up (FuzzingSetup ctor) and tear-down (~FuzzingSetup) work is simply too costly to be run on every iteration. There is a trade-off to handle here between a.) achieving high executions/second and b.) giving the fuzzer a totally blank slate for each call. Please let me know if you have any suggestion on how to improve this situation while maintaining >1000 executions/second. To achieve optimal results when using coverage-guided fuzzing I've chosen to create one specialised fuzzing binary per message type (process_message_addr, process_message_block, process_message_blocktxn , etc.) and one general fuzzing binary (process_message) which handles all messages types. The latter general fuzzer can be seeded with inputs generated by the former specialised fuzzers. Happy fuzzing friends! ``` Backport od core [[bitcoin/bitcoin#17989 | PR17989]]. Depends on D8004 (test plan only, fixes a fuzz fixture issue). Test Plan: ninja bitcoin-fuzzers ./src/test/fuzz/process_message ./src/test/fuzz/process_message_getheaders # Or any other message Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Subscribers: deadalnix Differential Revision: https://reviews.bitcoinabc.org/D8005
- Loading branch information
1 parent
c146a46
commit 946eb50
Showing
5 changed files
with
185 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// Copyright (c) 2020 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#include <banman.h> | ||
#include <chainparams.h> | ||
#include <config.h> | ||
#include <consensus/consensus.h> | ||
#include <net.h> | ||
#include <net_processing.h> | ||
#include <protocol.h> | ||
#include <scheduler.h> | ||
#include <script/script.h> | ||
#include <streams.h> | ||
#include <validationinterface.h> | ||
#include <version.h> | ||
|
||
#include <test/fuzz/FuzzedDataProvider.h> | ||
#include <test/fuzz/fuzz.h> | ||
#include <test/util/mining.h> | ||
#include <test/util/setup_common.h> | ||
|
||
#include <algorithm> | ||
#include <atomic> | ||
#include <cassert> | ||
#include <chrono> | ||
#include <cstdint> | ||
#include <iosfwd> | ||
#include <iostream> | ||
#include <map> | ||
#include <memory> | ||
#include <set> | ||
#include <string> | ||
#include <vector> | ||
|
||
namespace { | ||
|
||
#ifdef MESSAGE_TYPE | ||
#define TO_STRING_(s) #s | ||
#define TO_STRING(s) TO_STRING_(s) | ||
const std::string LIMIT_TO_MESSAGE_TYPE{TO_STRING(MESSAGE_TYPE)}; | ||
#else | ||
const std::string LIMIT_TO_MESSAGE_TYPE; | ||
#endif | ||
|
||
const std::map<std::string, std::set<std::string>> | ||
EXPECTED_DESERIALIZATION_EXCEPTIONS = { | ||
{"CDataStream::read(): end of data: iostream error", | ||
{"addr", "block", "blocktxn", "cmpctblock", "feefilter", "filteradd", | ||
"filterload", "getblocks", "getblocktxn", "getdata", "getheaders", | ||
"headers", "inv", "notfound", "ping", "sendcmpct", "tx"}}, | ||
{"CompactSize exceeds limit of type: iostream error", {"cmpctblock"}}, | ||
{"differential value overflow: iostream error", {"getblocktxn"}}, | ||
{"index overflowed 16 bits: iostream error", {"getblocktxn"}}, | ||
{"index overflowed 16-bits: iostream error", {"cmpctblock"}}, | ||
{"indexes overflowed 16 bits: iostream error", {"getblocktxn"}}, | ||
{"non-canonical ReadCompactSize(): iostream error", | ||
{"addr", "block", "blocktxn", "cmpctblock", "filteradd", "filterload", | ||
"getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", | ||
"notfound", "tx"}}, | ||
{"ReadCompactSize(): size too large: iostream error", | ||
{"addr", "block", "blocktxn", "cmpctblock", "filteradd", "filterload", | ||
"getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", | ||
"notfound", "tx"}}, | ||
{"Superfluous witness record: iostream error", | ||
{"block", "blocktxn", "cmpctblock", "tx"}}, | ||
{"Unknown transaction optional data: iostream error", | ||
{"block", "blocktxn", "cmpctblock", "tx"}}, | ||
}; | ||
|
||
const RegTestingSetup *g_setup; | ||
} // namespace | ||
|
||
void initialize() { | ||
static RegTestingSetup setup{}; | ||
g_setup = &setup; | ||
|
||
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { | ||
MineBlock(GetConfig(), g_setup->m_node, CScript() << OP_TRUE); | ||
} | ||
SyncWithValidationInterfaceQueue(); | ||
} | ||
|
||
void test_one_input(const std::vector<uint8_t> &buffer) { | ||
const Config &config = GetConfig(); | ||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); | ||
const std::string random_message_type{ | ||
fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE) | ||
.c_str()}; | ||
if (!LIMIT_TO_MESSAGE_TYPE.empty() && | ||
random_message_type != LIMIT_TO_MESSAGE_TYPE) { | ||
return; | ||
} | ||
CDataStream random_bytes_data_stream{ | ||
fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>(), SER_NETWORK, | ||
PROTOCOL_VERSION}; | ||
CNode p2p_node{0, | ||
ServiceFlags(NODE_NETWORK | NODE_BLOOM), | ||
0, | ||
INVALID_SOCKET, | ||
CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, | ||
0, | ||
0, | ||
CAddress{}, | ||
std::string{}, | ||
false}; | ||
p2p_node.fSuccessfullyConnected = true; | ||
p2p_node.nVersion = PROTOCOL_VERSION; | ||
p2p_node.SetSendVersion(PROTOCOL_VERSION); | ||
g_setup->m_node.peer_logic->InitializeNode(config, &p2p_node); | ||
try { | ||
(void)ProcessMessage( | ||
config, &p2p_node, random_message_type, random_bytes_data_stream, | ||
GetTimeMillis(), g_setup->m_node.connman.get(), | ||
g_setup->m_node.banman.get(), std::atomic<bool>{false}); | ||
} catch (const std::ios_base::failure &e) { | ||
const std::string exception_message{e.what()}; | ||
const auto p = | ||
EXPECTED_DESERIALIZATION_EXCEPTIONS.find(exception_message); | ||
if (p == EXPECTED_DESERIALIZATION_EXCEPTIONS.cend() || | ||
p->second.count(random_message_type) == 0) { | ||
std::cout << "Unexpected exception when processing message type \"" | ||
<< random_message_type << "\": " << exception_message | ||
<< std::endl; | ||
assert(false); | ||
} | ||
} | ||
SyncWithValidationInterfaceQueue(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters