Coverage Report

Created: 2026-06-12 16:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/fuzz/banman.cpp
Line
Count
Source
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
int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
25
0
{
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
0
    return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::max());
29
0
}
30
} // namespace
31
32
void initialize_banman()
33
0
{
34
0
    static const auto testing_setup = MakeNoLogFileContext<>();
35
0
}
36
37
static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs)
38
0
{
39
0
    return lhs.nVersion == rhs.nVersion &&
  Branch (39:12): [True: 0, False: 0]
40
0
           lhs.nCreateTime == rhs.nCreateTime &&
  Branch (40:12): [True: 0, False: 0]
41
0
           lhs.nBanUntil == rhs.nBanUntil;
  Branch (41:12): [True: 0, False: 0]
42
0
}
43
44
FUZZ_TARGET(banman, .init = initialize_banman)
45
0
{
46
0
    SeedRandomStateForTest(SeedRand::ZEROS);
47
0
    FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
48
0
    FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)};
49
0
    fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist";
50
51
0
    const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()};
52
0
    bool force_read_and_write_to_err{false};
53
0
    if (start_with_corrupted_banlist) {
  Branch (53:9): [True: 0, False: 0]
54
0
        assert(WriteBinaryFile(banlist_file + ".json",
  Branch (54:9): [True: 0, False: 0]
55
0
                               fuzzed_data_provider.ConsumeRandomLengthString()));
56
0
    } else {
57
0
        force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool();
58
0
        if (force_read_and_write_to_err) {
  Branch (58:13): [True: 0, False: 0]
59
0
            banlist_file = fs::path{"path"} / "to" / "inaccessible" / "fuzzed_banlist";
60
0
        }
61
0
    }
62
63
0
    {
64
0
        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
0
        bool contains_invalid{false};
69
0
        LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
70
0
        {
71
0
            CallOneOf(
72
0
                fuzzed_data_provider,
73
0
                [&] {
74
0
                    CNetAddr net_addr{ConsumeNetAddr(fuzzed_data_provider)};
75
0
                    if (!net_addr.IsCJDNS() || !net_addr.IsValid()) {
  Branch (75:25): [True: 0, False: 0]
  Branch (75:48): [True: 0, False: 0]
76
0
                        const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)};
77
0
                        if (addr.has_value() && addr->IsValid()) {
  Branch (77:29): [True: 0, False: 0]
  Branch (77:49): [True: 0, False: 0]
78
0
                            net_addr = *addr;
79
0
                        } else {
80
0
                            contains_invalid = true;
81
0
                        }
82
0
                    }
83
0
                    auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
84
0
                    auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
85
0
                    ban_man.Ban(net_addr, ban_time_offset, since_unix_epoch);
86
0
                },
87
0
                [&] {
88
0
                    CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)};
89
0
                    subnet = LookupSubNet(subnet.ToString());
90
0
                    if (!subnet.IsValid()) {
  Branch (90:25): [True: 0, False: 0]
91
0
                        contains_invalid = true;
92
0
                    }
93
0
                    auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
94
0
                    auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
95
0
                    ban_man.Ban(subnet, ban_time_offset, since_unix_epoch);
96
0
                },
97
0
                [&] {
98
0
                    ban_man.ClearBanned();
99
0
                },
100
0
                [&] {
101
0
                    ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
102
0
                },
103
0
                [&] {
104
0
                    ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
105
0
                },
106
0
                [&] {
107
0
                    ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
108
0
                },
109
0
                [&] {
110
0
                    ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
111
0
                },
112
0
                [&] {
113
0
                    banmap_t banmap;
114
0
                    ban_man.GetBanned(banmap);
115
0
                },
116
0
                [&] {
117
0
                    ban_man.DumpBanlist();
118
0
                },
119
0
                [&] {
120
0
                    ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
121
0
                },
122
0
                [&] {
123
0
                    ban_man.IsDiscouraged(ConsumeNetAddr(fuzzed_data_provider));
124
0
                });
125
0
        }
126
0
        if (!force_read_and_write_to_err) {
  Branch (126:13): [True: 0, False: 0]
127
0
            ban_man.DumpBanlist();
128
0
            clock.set(ConsumeTime(fuzzed_data_provider));
129
0
            banmap_t banmap;
130
0
            ban_man.GetBanned(banmap);
131
0
            BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0};
132
0
            banmap_t banmap_read;
133
0
            ban_man_read.GetBanned(banmap_read);
134
0
            if (!contains_invalid) {
  Branch (134:17): [True: 0, False: 0]
135
0
                assert(banmap == banmap_read);
  Branch (135:17): [True: 0, False: 0]
136
0
            }
137
0
        }
138
0
    }
139
0
    fs::remove(fs::PathToString(banlist_file + ".json"));
140
0
}