Line data Source code
1 : // Copyright (c) 2020-2022 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 <common/args.h> 7 : #include <netaddress.h> 8 : #include <test/fuzz/FuzzedDataProvider.h> 9 : #include <test/fuzz/fuzz.h> 10 : #include <test/fuzz/util.h> 11 : #include <test/fuzz/util/net.h> 12 : #include <test/util/setup_common.h> 13 : #include <util/fs.h> 14 : #include <util/readwritefile.h> 15 : 16 : #include <cassert> 17 2 : #include <cstdint> 18 2 : #include <limits> 19 : #include <string> 20 : #include <vector> 21 : 22 : namespace { 23 0 : int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept 24 : { 25 : // Avoid signed integer overflow by capping to int32_t max: 26 : // banman.cpp:137:73: runtime error: signed integer overflow: 1591700817 + 9223372036854775807 cannot be represented in type 'long' 27 0 : return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::max()); 28 : } 29 : } // namespace 30 : 31 0 : void initialize_banman() 32 : { 33 0 : static const auto testing_setup = MakeNoLogFileContext<>(); 34 0 : } 35 : 36 0 : static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs) 37 : { 38 0 : return lhs.nVersion == rhs.nVersion && 39 0 : lhs.nCreateTime == rhs.nCreateTime && 40 0 : lhs.nBanUntil == rhs.nBanUntil; 41 : } 42 : 43 4 : FUZZ_TARGET(banman, .init = initialize_banman) 44 : { 45 0 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; 46 0 : SetMockTime(ConsumeTime(fuzzed_data_provider)); 47 0 : fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist"; 48 : 49 0 : const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()}; 50 0 : bool force_read_and_write_to_err{false}; 51 0 : if (start_with_corrupted_banlist) { 52 0 : assert(WriteBinaryFile(banlist_file + ".json", 53 : fuzzed_data_provider.ConsumeRandomLengthString())); 54 0 : } else { 55 0 : force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool(); 56 0 : if (force_read_and_write_to_err) { 57 0 : banlist_file = fs::path{"path"} / "to" / "inaccessible" / "fuzzed_banlist"; 58 0 : } 59 : } 60 : 61 : { 62 0 : BanMan ban_man{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/ConsumeBanTimeOffset(fuzzed_data_provider)}; 63 : // The complexity is O(N^2), where N is the input size, because each call 64 : // might call DumpBanlist (or other methods that are at least linear 65 : // complexity of the input size). 66 0 : LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300) 67 : { 68 0 : CallOneOf( 69 : fuzzed_data_provider, 70 0 : [&] { 71 0 : ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider), 72 0 : ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); 73 0 : }, 74 2 : [&] { 75 0 : ban_man.Ban(ConsumeSubNet(fuzzed_data_provider), 76 0 : ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); 77 0 : }, 78 0 : [&] { 79 0 : ban_man.ClearBanned(); 80 0 : }, 81 0 : [&] { 82 0 : ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); 83 2 : }, 84 0 : [&] { 85 0 : ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider)); 86 0 : }, 87 0 : [&] { 88 0 : ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider)); 89 0 : }, 90 0 : [&] { 91 0 : ban_man.Unban(ConsumeSubNet(fuzzed_data_provider)); 92 0 : }, 93 0 : [&] { 94 0 : banmap_t banmap; 95 0 : ban_man.GetBanned(banmap); 96 0 : }, 97 0 : [&] { 98 0 : ban_man.DumpBanlist(); 99 0 : }, 100 0 : [&] { 101 0 : ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); 102 0 : }); 103 0 : } 104 0 : if (!force_read_and_write_to_err) { 105 0 : ban_man.DumpBanlist(); 106 0 : SetMockTime(ConsumeTime(fuzzed_data_provider)); 107 0 : banmap_t banmap; 108 0 : ban_man.GetBanned(banmap); 109 0 : BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0}; 110 0 : banmap_t banmap_read; 111 0 : ban_man_read.GetBanned(banmap_read); 112 0 : assert(banmap == banmap_read); 113 0 : } 114 0 : } 115 0 : fs::remove(fs::PathToString(banlist_file + ".json")); 116 0 : }