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"}};
Note to self: 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 :)
Concept ACK
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>({
const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ?
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 :)
Anything left to do here? :) The changes are limited to 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);
test/fuzz/net.cpp:115:18: error: no member named 'PushInventory' in 'CNode'
node.PushInventory(*inv_opt);
~~~~ ^
test/fuzz/net.cpp:119:18: error: no member named 'PushBlockHash' in 'CNode'
node.PushBlockHash(ConsumeUInt256(fuzzed_data_provider));
~~~~ ^
2 errors generated.
Oh, thanks for letting me know! Now fixed!
@Crypt-iQ Thanks for reporting. Should be fixed now. Would you mind retrying? :)
@practicalswift Fuzzing with clang-10 libfuzzer. afl-gcc/g++ can also build on a22b42e.
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 :).
I think that lack of coverage in 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 :)
Ok that makes sense to me about INVALID_SOCKET. What about void AdvertiseLocal(CNode *pnode)?
@Crypt-iQ Both 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? :)
Yes that makes sense 👍
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?
Good point. Fixed!
43 | + case 0: { 44 | + node.CloseSocketDisconnect(); 45 | + break; 46 | + } 47 | + case 1: { 48 | + node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
Since this always has length of 32, not every line is covered by the fuzzer in MaybeSetAddrName.
ConsumeRandomLengthString(32) will return a string up to 32 characters long :)
Nvm. 👍
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)Tested ACK a22b42e
Ready for merge?
needs rebase
@jb55 @Crypt-iQ @MarcoFalke Thanks a lot for reviewing. Now rebased. Please re-review :)