/root/bitcoin/src/test/fuzz/banman.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include <cstdint> |
18 | | #include <limits> |
19 | | #include <string> |
20 | | #include <vector> |
21 | | |
22 | | namespace { |
23 | | int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept |
24 | 0 | { |
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 | 0 | } |
29 | | } // namespace |
30 | | |
31 | | void initialize_banman() |
32 | 0 | { |
33 | 0 | static const auto testing_setup = MakeNoLogFileContext<>(); |
34 | 0 | } |
35 | | |
36 | | static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs) |
37 | 0 | { |
38 | 0 | return lhs.nVersion == rhs.nVersion && |
39 | 0 | lhs.nCreateTime == rhs.nCreateTime && |
40 | 0 | lhs.nBanUntil == rhs.nBanUntil; |
41 | 0 | } |
42 | | |
43 | | FUZZ_TARGET(banman, .init = initialize_banman) |
44 | 0 | { |
45 | 0 | SeedRandomStateForTest(SeedRand::ZEROS); |
46 | 0 | FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; |
47 | 0 | SetMockTime(ConsumeTime(fuzzed_data_provider)); |
48 | 0 | fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist"; |
49 | |
|
50 | 0 | const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()}; |
51 | 0 | bool force_read_and_write_to_err{false}; |
52 | 0 | if (start_with_corrupted_banlist) { |
53 | 0 | assert(WriteBinaryFile(banlist_file + ".json", |
54 | 0 | fuzzed_data_provider.ConsumeRandomLengthString())); |
55 | 0 | } else { |
56 | 0 | force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool(); |
57 | 0 | if (force_read_and_write_to_err) { |
58 | 0 | banlist_file = fs::path{"path"} / "to" / "inaccessible" / "fuzzed_banlist"; |
59 | 0 | } |
60 | 0 | } |
61 | | |
62 | 0 | { |
63 | 0 | BanMan ban_man{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/ConsumeBanTimeOffset(fuzzed_data_provider)}; |
64 | | // The complexity is O(N^2), where N is the input size, because each call |
65 | | // might call DumpBanlist (or other methods that are at least linear |
66 | | // complexity of the input size). |
67 | 0 | bool contains_invalid{false}; |
68 | 0 | LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300) |
69 | 0 | { |
70 | 0 | CallOneOf( |
71 | 0 | fuzzed_data_provider, |
72 | 0 | [&] { |
73 | 0 | CNetAddr net_addr{ConsumeNetAddr(fuzzed_data_provider)}; |
74 | 0 | if (!net_addr.IsCJDNS() || !net_addr.IsValid()) { |
75 | 0 | const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)}; |
76 | 0 | if (addr.has_value() && addr->IsValid()) { |
77 | 0 | net_addr = *addr; |
78 | 0 | } else { |
79 | 0 | contains_invalid = true; |
80 | 0 | } |
81 | 0 | } |
82 | 0 | auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider); |
83 | 0 | auto since_unix_epoch = fuzzed_data_provider.ConsumeBool(); |
84 | 0 | ban_man.Ban(net_addr, ban_time_offset, since_unix_epoch); |
85 | 0 | }, |
86 | 0 | [&] { |
87 | 0 | CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)}; |
88 | 0 | subnet = LookupSubNet(subnet.ToString()); |
89 | 0 | if (!subnet.IsValid()) { |
90 | 0 | contains_invalid = true; |
91 | 0 | } |
92 | 0 | auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider); |
93 | 0 | auto since_unix_epoch = fuzzed_data_provider.ConsumeBool(); |
94 | 0 | ban_man.Ban(subnet, ban_time_offset, since_unix_epoch); |
95 | 0 | }, |
96 | 0 | [&] { |
97 | 0 | ban_man.ClearBanned(); |
98 | 0 | }, |
99 | 0 | [&] { |
100 | 0 | ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); |
101 | 0 | }, |
102 | 0 | [&] { |
103 | 0 | ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider)); |
104 | 0 | }, |
105 | 0 | [&] { |
106 | 0 | ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider)); |
107 | 0 | }, |
108 | 0 | [&] { |
109 | 0 | ban_man.Unban(ConsumeSubNet(fuzzed_data_provider)); |
110 | 0 | }, |
111 | 0 | [&] { |
112 | 0 | banmap_t banmap; |
113 | 0 | ban_man.GetBanned(banmap); |
114 | 0 | }, |
115 | 0 | [&] { |
116 | 0 | ban_man.DumpBanlist(); |
117 | 0 | }, |
118 | 0 | [&] { |
119 | 0 | ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); |
120 | 0 | }); |
121 | 0 | } |
122 | 0 | if (!force_read_and_write_to_err) { |
123 | 0 | ban_man.DumpBanlist(); |
124 | 0 | SetMockTime(ConsumeTime(fuzzed_data_provider)); |
125 | 0 | banmap_t banmap; |
126 | 0 | ban_man.GetBanned(banmap); |
127 | 0 | BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0}; |
128 | 0 | banmap_t banmap_read; |
129 | 0 | ban_man_read.GetBanned(banmap_read); |
130 | 0 | if (!contains_invalid) { |
131 | 0 | assert(banmap == banmap_read); |
132 | 0 | } |
133 | 0 | } |
134 | 0 | } |
135 | 0 | fs::remove(fs::PathToString(banlist_file + ".json")); |
136 | 0 | } |