Add fuzzing harness for CNode
.
See doc/fuzzing.md
for information on how to fuzz Bitcoin Core. Don’t forget to contribute any coverage increasing inputs you find to the Bitcoin Core fuzzing corpus repo.
Happy fuzzing :)
Add fuzzing harness for CNode
.
See doc/fuzzing.md
for information on how to fuzz Bitcoin Core. Don’t forget to contribute any coverage increasing inputs you find to the Bitcoin Core fuzzing corpus repo.
Happy fuzzing :)
19+#include <string>
20+#include <vector>
21+
22+void initialize()
23+{
24+ static TestingSetup no_log_regtest_setup{CBaseChainParams::REGTEST, {"-nodebuglogfile"}};
TestingSetup
introduces non-determinism and is way too heavy to use just to disable logging. Consider switching to something more lightweight which does exactly what we want and nothing more :)
147+ const int ref_count = node.GetRefCount();
148+ assert(ref_count >= 0);
149+ (void)node.GetSendVersion();
150+ (void)node.IsAddrRelayPeer();
151+
152+ const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({
0 const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ?
1 fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({
Couldn’t this start a new line after the ?
Seems overly wasteful to fill the screen with 8 * 90 pure whitespace
Sure! Now fixed: clang-format
:ed version replaced with another clang-format
:ed version after manual re-arrangement.
When it comes to formatting I really don’t have any personal preferences: I’m happy as long as clang-format
is happy :)
src/test/fuzz/
and should hopefully be trivial to review.
110+ case 10: {
111+ const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
112+ if (!inv_opt) {
113+ break;
114+ }
115+ node.PushInventory(*inv_opt);
0test/fuzz/net.cpp:115:18: error: no member named 'PushInventory' in 'CNode'
1
2 node.PushInventory(*inv_opt);
3
4 ~~~~ ^
5
6test/fuzz/net.cpp:119:18: error: no member named 'PushBlockHash' in 'CNode'
7
8 node.PushBlockHash(ConsumeUInt256(fuzzed_data_provider));
9
10 ~~~~ ^
11
122 errors generated.
35+ const std::optional<CAddress> address_bind = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
36+ if (!address_bind) {
37+ return;
38+ }
39+
40+ CNode node{fuzzed_data_provider.ConsumeIntegral<NodeId>(), static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()), fuzzed_data_provider.ConsumeIntegral<int>(), INVALID_SOCKET, *address, fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), *address_bind, fuzzed_data_provider.ConsumeRandomLengthString(32), fuzzed_data_provider.ConsumeBool(), fuzzed_data_provider.ConsumeBool()};
If the fuzzer didn’t always pass in INVALID_SOCKET
, every line would be covered by the fuzzer in CNode::CloseSocketDisconnect()
.
Maybe instead of doing this CNode node {...}
, you could make a function ConsumeCNode
that can also be used in the process_message.cpp
& process_messages.cpp
fuzzing harnesses. I think this would improve coverage of those fuzzing harnesses too :).
CNode::CloseSocketDisconnect
is okay: INVALID_SOCKET
basically guarantees that all CNode
operations are safe (that’s how it is done in the unit tests). We can look at expanding the coverage safely in a future PR :)
INVALID_SOCKET
. What about void AdvertiseLocal(CNode *pnode)
?
IsPeerAddrLocalGood
and AdvertiseLocal
depend on global state (fDiscover
and fListen
), and in the case of AdvertiseLocal
a FastRandomContext
is deciding which execution path to take. I think they’re sufficiently different to do them in another PR taking those things into account to achieve maximum possible determinism. Makes sense? :)
0 CNode node{fuzzed_data_provider.ConsumeIntegral<NodeId>(), static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()), fuzzed_data_provider.ConsumeIntegral<int>(), INVALID_SOCKET, *address, fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), *address_bind, fuzzed_data_provider.ConsumeRandomLengthString(32), fuzzed_data_provider.ConsumeBool(), fuzzed_data_provider.ConsumeBool(),};
Could add a trailing comma and then clang format to avoid an excessively long line?
43+ case 0: {
44+ node.CloseSocketDisconnect();
45+ break;
46+ }
47+ case 1: {
48+ node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
MaybeSetAddrName
.
ConsumeRandomLengthString(32)
will return a string up to 32 characters long :)
30 hour fuzzing coverage for this harness (libfuzzer --with-sanitizers=address,fuzzer,undefined
): https://crypt-iq.github.io/cnode_cov/src/index.html
Just minor comments from me. Two more functions could be fuzzed:
bool IsPeerAddrLocalGood(CNode *pnode)
void AdvertiseLocal(CNode *pnode)
practicalswift
jb55
MarcoFalke
Crypt-iQ
Labels
Tests