Branch data Line data Source code
1 : : // Copyright (c) 2020-present 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 <test/util/time.h>
14 : : #include <util/fs.h>
15 : : #include <util/readwritefile.h>
16 : :
17 : : #include <cassert>
18 : : #include <cstdint>
19 : : #include <limits>
20 : : #include <string>
21 : : #include <vector>
22 : :
23 : : namespace {
24 : 28774 : int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
25 : : {
26 : : // Avoid signed integer overflow by capping to int32_t max:
27 : : // banman.cpp:137:73: runtime error: signed integer overflow: 1591700817 + 9223372036854775807 cannot be represented in type 'long'
28 : 28774 : return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::max());
29 : : }
30 : : } // namespace
31 : :
32 : 1 : void initialize_banman()
33 : : {
34 [ + - + - : 1 : static const auto testing_setup = MakeNoLogFileContext<>();
+ - ]
35 : 1 : }
36 : :
37 : 6348 : static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs)
38 : : {
39 : 12696 : return lhs.nVersion == rhs.nVersion &&
40 [ + - + - ]: 6348 : lhs.nCreateTime == rhs.nCreateTime &&
41 [ - + ]: 6348 : lhs.nBanUntil == rhs.nBanUntil;
42 : : }
43 : :
44 [ + - ]: 2025 : FUZZ_TARGET(banman, .init = initialize_banman)
45 : : {
46 : 1567 : SeedRandomStateForTest(SeedRand::ZEROS);
47 : 1567 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
48 : 1567 : NodeClockContext clock_ctx{ConsumeTime(fuzzed_data_provider)};
49 [ + - ]: 3134 : fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist";
50 : :
51 : 1567 : const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()};
52 : 1567 : bool force_read_and_write_to_err{false};
53 [ + + ]: 1567 : if (start_with_corrupted_banlist) {
54 [ + - + - : 4228 : assert(WriteBinaryFile(banlist_file + ".json",
+ - + - -
+ ]
55 : : fuzzed_data_provider.ConsumeRandomLengthString()));
56 : : } else {
57 : 510 : force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool();
58 [ + + ]: 510 : if (force_read_and_write_to_err) {
59 [ + - + - : 1240 : banlist_file = fs::path{"path"} / "to" / "inaccessible" / "fuzzed_banlist";
+ - + - ]
60 : : }
61 : : }
62 : :
63 : 1567 : {
64 [ + - + - ]: 1567 : BanMan ban_man{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/ConsumeBanTimeOffset(fuzzed_data_provider)};
65 : : // The complexity is O(N^2), where N is the input size, because each call
66 : : // might call DumpBanlist (or other methods that are at least linear
67 : : // complexity of the input size).
68 : 1567 : bool contains_invalid{false};
69 [ + + + + ]: 55517 : LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
70 : : {
71 [ + - ]: 53950 : CallOneOf(
72 : : fuzzed_data_provider,
73 : 22869 : [&] {
74 : 22869 : CNetAddr net_addr{ConsumeNetAddr(fuzzed_data_provider)};
75 [ + + + - : 22869 : if (!net_addr.IsCJDNS() || !net_addr.IsValid()) {
- + ]
76 [ + - + - : 43692 : const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)};
+ - ]
77 [ + + + - : 21846 : if (addr.has_value() && addr->IsValid()) {
+ + ]
78 : 18482 : net_addr = *addr;
79 : : } else {
80 : 3364 : contains_invalid = true;
81 : : }
82 : : }
83 : 22869 : auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
84 : 22869 : auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
85 [ + - ]: 22869 : ban_man.Ban(net_addr, ban_time_offset, since_unix_epoch);
86 : 22869 : },
87 : 4338 : [&] {
88 : 4338 : CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)};
89 [ + - + - ]: 4338 : subnet = LookupSubNet(subnet.ToString());
90 [ + - + + ]: 4338 : if (!subnet.IsValid()) {
91 : 31 : contains_invalid = true;
92 : : }
93 : 4338 : auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
94 : 4338 : auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
95 [ + - ]: 4338 : ban_man.Ban(subnet, ban_time_offset, since_unix_epoch);
96 : 4338 : },
97 : 3252 : [&] {
98 : 3252 : ban_man.ClearBanned();
99 : 3252 : },
100 : 3724 : [&] {
101 [ + - ]: 3724 : ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
102 : 3724 : },
103 : 2965 : [&] {
104 [ + - ]: 2965 : ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
105 : 2965 : },
106 : 3569 : [&] {
107 [ + - ]: 3569 : ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
108 : 3569 : },
109 : 1581 : [&] {
110 [ + - ]: 1581 : ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
111 : 1581 : },
112 : 1331 : [&] {
113 [ + - ]: 1331 : banmap_t banmap;
114 [ + - ]: 1331 : ban_man.GetBanned(banmap);
115 : 1331 : },
116 : 3661 : [&] {
117 : 3661 : ban_man.DumpBanlist();
118 : 3661 : },
119 : 2504 : [&] {
120 [ + - ]: 2504 : ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
121 : 2504 : },
122 : 4156 : [&] {
123 [ + - ]: 4156 : ban_man.IsDiscouraged(ConsumeNetAddr(fuzzed_data_provider));
124 : 4156 : });
125 : : }
126 [ + + ]: 1567 : if (!force_read_and_write_to_err) {
127 [ + - ]: 1412 : ban_man.DumpBanlist();
128 [ + - ]: 1412 : clock_ctx.set(ConsumeTime(fuzzed_data_provider));
129 [ + - ]: 1412 : banmap_t banmap;
130 [ + - ]: 1412 : ban_man.GetBanned(banmap);
131 [ + - + - ]: 1412 : BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0};
132 [ + - ]: 1412 : banmap_t banmap_read;
133 [ + - ]: 1412 : ban_man_read.GetBanned(banmap_read);
134 [ + + ]: 1412 : if (!contains_invalid) {
135 [ + - - + ]: 1192 : assert(banmap == banmap_read);
136 : : }
137 : 1412 : }
138 : 1567 : }
139 [ + - + - : 9402 : fs::remove(fs::PathToString(banlist_file + ".json"));
- + + - +
- ]
140 : 1567 : }
|