Branch data 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 : : #include <cstdint>
18 : : #include <limits>
19 : : #include <string>
20 : : #include <vector>
21 : :
22 : : namespace {
23 : 23469 : 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 : 23469 : return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::max());
28 : : }
29 : : } // namespace
30 : :
31 : 1 : void initialize_banman()
32 : : {
33 [ + - + - ]: 2 : static const auto testing_setup = MakeNoLogFileContext<>();
34 [ + - ]: 2 : }
35 : :
36 : 6845 : static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs)
37 : : {
38 : 13690 : return lhs.nVersion == rhs.nVersion &&
39 [ + - + - ]: 6845 : lhs.nCreateTime == rhs.nCreateTime &&
40 [ - + ]: 6845 : lhs.nBanUntil == rhs.nBanUntil;
41 : : }
42 : :
43 [ + - ]: 1856 : FUZZ_TARGET(banman, .init = initialize_banman)
44 : : {
45 : 1444 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
46 : 1444 : SetMockTime(ConsumeTime(fuzzed_data_provider));
47 [ + - ]: 2888 : fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist";
48 : :
49 : 1444 : const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()};
50 : 1444 : bool force_read_and_write_to_err{false};
51 [ + + ]: 1444 : if (start_with_corrupted_banlist) {
52 [ + - + - : 4060 : assert(WriteBinaryFile(banlist_file + ".json",
+ - + - -
+ ]
53 : : fuzzed_data_provider.ConsumeRandomLengthString()));
54 : : } else {
55 : 429 : force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool();
56 [ + + ]: 429 : if (force_read_and_write_to_err) {
57 [ + - + - : 1208 : banlist_file = fs::path{"path"} / "to" / "inaccessible" / "fuzzed_banlist";
+ - + - ]
58 : : }
59 : : }
60 : :
61 : 1444 : {
62 [ + - + - ]: 1444 : 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 : 1444 : bool contains_invalid{false};
67 [ + + + + ]: 60026 : LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
68 : : {
69 [ + - ]: 58582 : CallOneOf(
70 : : fuzzed_data_provider,
71 : 9426 : [&] {
72 : 9426 : CNetAddr net_addr{ConsumeNetAddr(fuzzed_data_provider)};
73 [ + + + - : 9426 : if (!net_addr.IsCJDNS() || !net_addr.IsValid()) {
- + ]
74 [ + - + - : 8721 : const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)};
+ - ]
75 [ + + + - : 8721 : if (addr.has_value() && addr->IsValid()) {
+ + ]
76 : 7273 : net_addr = *addr;
77 : : } else {
78 : 1448 : contains_invalid = true;
79 : : }
80 : 8721 : }
81 : 9426 : auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
82 : 9426 : auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
83 [ + - ]: 9426 : ban_man.Ban(net_addr, ban_time_offset, since_unix_epoch);
84 : 9426 : },
85 : 12599 : [&] {
86 : 12599 : CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)};
87 [ + - + - ]: 12599 : subnet = LookupSubNet(subnet.ToString());
88 [ + - + + ]: 12599 : if (!subnet.IsValid()) {
89 : 41 : contains_invalid = true;
90 : : }
91 : 12599 : auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
92 : 12599 : auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
93 [ + - ]: 12599 : ban_man.Ban(subnet, ban_time_offset, since_unix_epoch);
94 : 12599 : },
95 : 2269 : [&] {
96 : 2269 : ban_man.ClearBanned();
97 : 2269 : },
98 : 6889 : [&] {
99 [ + - ]: 6889 : ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
100 : 6889 : },
101 : 2096 : [&] {
102 [ + - ]: 2096 : ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
103 : 2096 : },
104 : 5093 : [&] {
105 [ + - ]: 5093 : ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
106 : 5093 : },
107 : 623 : [&] {
108 [ + - ]: 623 : ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
109 : 623 : },
110 : 10412 : [&] {
111 [ + - ]: 10412 : banmap_t banmap;
112 [ + - ]: 10412 : ban_man.GetBanned(banmap);
113 : 10412 : },
114 : 4132 : [&] {
115 : 4132 : ban_man.DumpBanlist();
116 : 4132 : },
117 : 5043 : [&] {
118 [ + - ]: 5043 : ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
119 : 5043 : });
120 : : }
121 [ + + ]: 1444 : if (!force_read_and_write_to_err) {
122 [ + - ]: 1293 : ban_man.DumpBanlist();
123 [ + - ]: 1293 : SetMockTime(ConsumeTime(fuzzed_data_provider));
124 [ + - ]: 1293 : banmap_t banmap;
125 [ + - ]: 1293 : ban_man.GetBanned(banmap);
126 [ + - + - ]: 1293 : BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0};
127 [ + - ]: 1293 : banmap_t banmap_read;
128 [ + - ]: 1293 : ban_man_read.GetBanned(banmap_read);
129 [ + + ]: 1293 : if (!contains_invalid) {
130 [ + - - + ]: 1099 : assert(banmap == banmap_read);
131 : : }
132 : 1293 : }
133 : 1444 : }
134 [ + - + - : 8664 : fs::remove(fs::PathToString(banlist_file + ".json"));
+ - + - +
- ]
135 : 1444 : }
|