Merge #19222: tests: Add fuzzing harness for BanMan

97846d7f5b tests: Add fuzzing harness for BanMan (practicalswift)
deba199f1c tests: Add ConsumeSubNet(...). Move and increase coverage in ConsumeNetAddr(...). (practicalswift)

Pull request description:

  Add fuzzing harness for `BanMan`.

  See [`doc/fuzzing.md`](https://github.com/bitcoin/bitcoin/blob/master/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](https://github.com/bitcoin-core/qa-assets).

  Happy fuzzing :)

Top commit has no ACKs.

Tree-SHA512: f4126c15bbb77638833367d73f58193c8f05d16bed0b1d6c33b39387d5b610ff34af78cd721adb51778062ce3ac5e79756d1c3895ef54c6c80c61dcf056e94ff
This commit is contained in:
MarcoFalke 2020-07-11 11:41:06 +02:00
commit a42631775a
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
4 changed files with 132 additions and 29 deletions

View file

@ -11,6 +11,7 @@ FUZZ_TARGETS = \
test/fuzz/asmap \
test/fuzz/asmap_direct \
test/fuzz/banentry_deserialize \
test/fuzz/banman \
test/fuzz/base_encode_decode \
test/fuzz/bech32 \
test/fuzz/block \
@ -355,6 +356,12 @@ test_fuzz_banentry_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_banentry_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_banentry_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_banman_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_banman_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_banman_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_banman_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_banman_SOURCES = test/fuzz/banman.cpp
test_fuzz_base_encode_decode_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_base_encode_decode_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_base_encode_decode_LDADD = $(FUZZ_SUITE_LD_COMMON)

88
src/test/fuzz/banman.cpp Normal file
View file

@ -0,0 +1,88 @@
// 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 <fs.h>
#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/system.h>
#include <cstdint>
#include <limits>
#include <string>
#include <vector>
namespace {
int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
// Avoid signed integer overflow by capping to int32_t max:
// banman.cpp:137:73: runtime error: signed integer overflow: 1591700817 + 9223372036854775807 cannot be represented in type 'long'
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::max());
}
} // namespace
void initialize()
{
InitializeFuzzingContext();
}
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
const fs::path banlist_file = GetDataDir() / "fuzzed_banlist.dat";
fs::remove(banlist_file);
{
BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)};
while (fuzzed_data_provider.ConsumeBool()) {
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
case 0: {
ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider),
ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
break;
}
case 1: {
ban_man.Ban(ConsumeSubNet(fuzzed_data_provider),
ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
break;
}
case 2: {
ban_man.ClearBanned();
break;
}
case 4: {
ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
break;
}
case 5: {
ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
break;
}
case 6: {
ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
break;
}
case 7: {
ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
break;
}
case 8: {
banmap_t banmap;
ban_man.GetBanned(banmap);
break;
}
case 9: {
ban_man.DumpBanlist();
break;
}
case 11: {
ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
break;
}
}
}
}
fs::remove(banlist_file);
}

View file

@ -5,41 +5,13 @@
#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cassert>
#include <cstdint>
#include <netinet/in.h>
#include <vector>
namespace {
CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
if (network == Network::NET_IPV4) {
const in_addr v4_addr = {
.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
return CNetAddr{v4_addr};
} else if (network == Network::NET_IPV6) {
if (fuzzed_data_provider.remaining_bytes() < 16) {
return CNetAddr{};
}
in6_addr v6_addr = {};
memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
return CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
} else if (network == Network::NET_INTERNAL) {
CNetAddr net_addr;
net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
return net_addr;
} else if (network == Network::NET_ONION) {
CNetAddr net_addr;
net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
return net_addr;
} else {
assert(false);
}
}
}; // namespace
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());

View file

@ -8,8 +8,11 @@
#include <amount.h>
#include <arith_uint256.h>
#include <attributes.h>
#include <chainparamsbase.h>
#include <coins.h>
#include <consensus/consensus.h>
#include <netaddress.h>
#include <netbase.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/standard.h>
@ -17,6 +20,7 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
#include <uint256.h>
#include <version.h>
@ -228,4 +232,36 @@ NODISCARD inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataPro
return result;
}
CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
CNetAddr net_addr;
if (network == Network::NET_IPV4) {
const in_addr v4_addr = {
.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
net_addr = CNetAddr{v4_addr};
} else if (network == Network::NET_IPV6) {
if (fuzzed_data_provider.remaining_bytes() >= 16) {
in6_addr v6_addr = {};
memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
}
} else if (network == Network::NET_INTERNAL) {
net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
} else if (network == Network::NET_ONION) {
net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
}
return net_addr;
}
CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>()};
}
void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
{
static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
}
#endif // BITCOIN_TEST_FUZZ_UTIL_H