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 : 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 : bool contains_invalid{false};
67 [ # # ][ # # ]: 0 : LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
[ # # ]
68 : : {
69 [ # # ]: 0 : CallOneOf(
70 : : fuzzed_data_provider,
71 : 0 : [&] {
72 : 0 : CNetAddr net_addr{ConsumeNetAddr(fuzzed_data_provider)};
73 [ # # ][ # # ]: 0 : const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)};
[ # # ]
74 [ # # ][ # # ]: 0 : if (addr.has_value() && addr->IsValid()) {
[ # # ]
75 [ # # ]: 0 : net_addr = *addr;
76 : 0 : } else {
77 : 0 : contains_invalid = true;
78 : : }
79 [ # # ][ # # ]: 0 : ban_man.Ban(net_addr, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
80 : 0 : },
81 : 0 : [&] {
82 : 0 : CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)};
83 [ # # ][ # # ]: 0 : subnet = LookupSubNet(subnet.ToString());
84 [ # # ][ # # ]: 0 : if (!subnet.IsValid()) {
85 : 0 : contains_invalid = true;
86 : 0 : }
87 [ # # ][ # # ]: 0 : ban_man.Ban(subnet, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
88 : 0 : },
89 : 0 : [&] {
90 : 0 : ban_man.ClearBanned();
91 : 0 : },
92 : 0 : [&] {
93 [ # # ]: 0 : ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
94 : 0 : },
95 : 0 : [&] {
96 [ # # ]: 0 : ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
97 : 0 : },
98 : 0 : [&] {
99 [ # # ]: 0 : ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
100 : 0 : },
101 : 0 : [&] {
102 [ # # ]: 0 : ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
103 : 0 : },
104 : 0 : [&] {
105 : 0 : banmap_t banmap;
106 [ # # ]: 0 : ban_man.GetBanned(banmap);
107 : 0 : },
108 : 0 : [&] {
109 : 0 : ban_man.DumpBanlist();
110 : 0 : },
111 : 0 : [&] {
112 [ # # ]: 0 : ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
113 : 0 : });
114 : 0 : }
115 [ # # ]: 0 : if (!force_read_and_write_to_err) {
116 [ # # ]: 0 : ban_man.DumpBanlist();
117 [ # # ]: 0 : SetMockTime(ConsumeTime(fuzzed_data_provider));
118 : 0 : banmap_t banmap;
119 [ # # ]: 0 : ban_man.GetBanned(banmap);
120 [ # # ][ # # ]: 0 : BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0};
121 : 0 : banmap_t banmap_read;
122 [ # # ]: 0 : ban_man_read.GetBanned(banmap_read);
123 [ # # ]: 0 : if (!contains_invalid) {
124 [ # # ][ # # ]: 0 : assert(banmap == banmap_read);
125 : 0 : }
126 : 0 : }
127 : 0 : }
128 [ # # ][ # # ]: 0 : fs::remove(fs::PathToString(banlist_file + ".json"));
[ # # ][ # # ]
[ # # ]
129 : 0 : }
|