Coverage Report

Created: 2025-02-21 14:37

/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
}