Coverage Report

Created: 2025-11-16 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea-fuzzer/fuzz_hook_radius4.cc
Line
Count
Source
1
// Copyright (C) 2025 Ada Logcis Ltd.
2
//
3
// This Source Code Form is subject to the terms of the Mozilla Public
4
// License, v. 2.0. If a copy of the MPL was not distributed with this
5
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
////////////////////////////////////////////////////////////////////////////////
7
#include <config.h>
8
#include <fuzzer/FuzzedDataProvider.h>
9
10
#include <dhcp/dhcp4.h>
11
#include <dhcp/pkt4.h>
12
#include <dhcp/libdhcp++.h>
13
#include <dhcp4/ctrl_dhcp4_srv.h>
14
#include <dhcpsrv/callout_handle_store.h>
15
#include <dhcpsrv/cfgmgr.h>
16
#include <dhcpsrv/lease_mgr_factory.h>
17
#include <log/logger_support.h>
18
#include <util/filesystem.h>
19
20
#include <cstddef>
21
#include <cstdint>
22
#include <vector>
23
#include <list>
24
#include <memory>
25
#include <iostream>
26
#include <filesystem>
27
#include <fstream>
28
#include <string>
29
#include <cstdio>
30
31
#include "helper_func.h"
32
33
using namespace isc::dhcp;
34
using namespace isc::hooks;
35
using namespace isc::util;
36
37
extern "C" int subnet4_select(CalloutHandle& handle);
38
extern "C" int lease4_release(CalloutHandle& handle);
39
extern "C" int lease4_decline(CalloutHandle& handle);
40
41
namespace isc {
42
    namespace dhcp {
43
        class MyDhcpv4Srv : public ControlledDhcpv4Srv {
44
            public:
45
6.36k
                void fuzz_classifyPacket(const Pkt4Ptr& pkt) {
46
6.36k
                    classifyPacket(pkt);
47
6.36k
                }
48
        };
49
    }
50
}
51
52
2.71k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
53
2.71k
    if (size < 236) {
54
        // package size requires at least 236 bytes
55
15
        return 0;
56
15
    }
57
58
    // Disable validatePath checking to allow writing configuration file to /tmp
59
2.69k
    isc::util::file::PathChecker::enableEnforcement(false);
60
61
    // Initialise logging
62
2.69k
    setenv("KEA_LOGGER_DESTINATION", "/dev/null", 0);
63
2.69k
    setenv("KEA_LOCKFILE_DIR", "/tmp", 0);
64
2.69k
    setenv("KEA_PIDFILE_DIR", "/tmp", 0);
65
2.69k
    setenv("KEA_LFC_EXECUTABLE", "/bin/true", 0);
66
2.69k
    try {
67
2.69k
        isc::log::initLogger("fuzzer");
68
2.69k
        isc::process::Daemon::loggerInit("fuzzer", false);
69
2.69k
        isc::process::Daemon::setDefaultLoggerName("fuzzer");
70
2.69k
    } catch (...) {
71
        // Early exit if logging initialisation failed
72
0
        return 0;
73
0
    }
74
75
    // Creating temp config file
76
2.69k
    std::string path = fuzz::writeTempConfig(true);
77
2.69k
    if (path.empty()) {
78
        // Early exit if configuration file creation failed
79
0
        fuzz::deleteTempFile(path);
80
0
        return 0;
81
0
    }
82
83
    // Creating temp lease file
84
2.69k
    std::string lease_path = fuzz::writeTempLease(true);
85
86
2.69k
    Pkt4Ptr pkt;
87
2.69k
    std::unique_ptr<MyDhcpv4Srv> srv;
88
89
    // Package parsing
90
2.69k
    try {
91
        // Add fixed magic cookie and correct hardware address
92
2.69k
        std::vector<uint8_t> buf(data, data + size);
93
2.69k
        if (size >= 240) {
94
            // Max hardware address length is 20
95
2.66k
            buf[2] = 20;
96
97
            // Magic cookie fixed value 0x63825363
98
2.66k
            buf[236] = 0x63;
99
2.66k
            buf[237] = 0x82;
100
2.66k
            buf[238] = 0x53;
101
2.66k
            buf[239] = 0x63;
102
2.66k
        }
103
104
2.69k
        pkt = Pkt4Ptr(new Pkt4(buf.data(), buf.size()));
105
2.69k
        pkt->unpack();
106
2.69k
    } catch (...) {
107
        // Early exit if package parsing failed.
108
1.41k
        return 0;
109
1.41k
    }
110
111
    // Configure random value in packet
112
1.27k
    FuzzedDataProvider fdp(data, size);
113
1.27k
    uint8_t typeChoice = fdp.ConsumeIntegralInRange<uint8_t>(0, 8);
114
1.27k
    pkt->setType(static_cast<DHCPMessageType>(typeChoice));
115
116
    // Server initialisation
117
1.27k
    try {
118
1.27k
        srv.reset(new MyDhcpv4Srv());
119
1.27k
        srv->init(path);
120
1.27k
    } catch (...) {
121
        // Early exit if server initialisation failed.
122
3
        return 0;
123
3
    }
124
125
1.27k
    if (!srv) {
126
        // Early exit if server initialisation failed.
127
0
        return 0;
128
0
    }
129
130
    // Call classifyPacket for packet checking
131
1.27k
    try {
132
1.27k
        srv->fuzz_classifyPacket(pkt);
133
1.27k
    } catch (const isc::Exception& e) {
134
        // Slient exceptions
135
0
    } catch (const boost::exception& e) {
136
        // Slient exceptions
137
0
    }
138
139
    // Prepare client context
140
1.27k
    CalloutHandlePtr handle = nullptr;
141
1.27k
    AllocEngine::ClientContext4Ptr ctx(new AllocEngine::ClientContext4());
142
143
    // Call earlyGHRLookup
144
1.27k
    try {
145
1.27k
        srv->earlyGHRLookup(pkt, ctx);
146
1.27k
    } catch (const isc::Exception& e) {
147
        // Slient exceptions
148
0
    } catch (const boost::exception& e) {
149
        // Slient exceptions
150
0
    }
151
152
    // Fuzz subnet4_select
153
1.27k
    try {
154
1.27k
        handle = getCalloutHandle(pkt);
155
1.27k
        Pkt4Ptr rsp;
156
1.27k
        CfgMgr& cfgmgr = CfgMgr::instance();
157
1.27k
        handle = getCalloutHandle(pkt);
158
1.27k
        handle->setArgument("query4", pkt);
159
1.27k
        handle->setArgument("subnet4collection",
160
1.27k
                            cfgmgr.getCurrentCfg()->getCfgSubnets4()->getAll());
161
1.27k
        if (!ctx) {
162
0
            ctx.reset(new AllocEngine::ClientContext4());
163
0
        }
164
1.27k
        if (ctx) {
165
1.27k
            handle->setArgument("subnet4", ctx->subnet_);
166
1.27k
        }
167
1.27k
        subnet4_select(*handle);
168
1.27k
    } catch (const isc::Exception& e) {
169
        // Slient exceptions
170
0
    } catch (const boost::exception& e) {
171
        // Slient exceptions
172
0
    }
173
174
    // Clean handle to avoid mem leak
175
1.27k
    if (handle) {
176
1.27k
        handle->deleteAllArguments();
177
1.27k
    }
178
179
    // Call lease4_release
180
1.27k
    try {
181
1.27k
        handle = getCalloutHandle(pkt);
182
1.27k
        uint8_t mac_addr[6];
183
8.91k
        for (size_t i = 0; i < 6; ++i) {
184
7.64k
            mac_addr[i] = fdp.ConsumeIntegral<uint8_t>();
185
7.64k
        }
186
1.27k
        HWAddr hw(mac_addr, sizeof(mac_addr), HTYPE_ETHER);
187
1.27k
        Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw);
188
1.27k
        handle->setArgument("leases4", leases);
189
1.27k
        handle->setArgument("query4", pkt);
190
191
1.27k
        lease4_release(*handle);
192
1.27k
    } catch (const isc::Exception& e) {
193
        // Slient exceptions
194
1.27k
    } catch (const boost::exception& e) {
195
        // Slient exceptions
196
0
    }
197
198
    // Clean up to avoid mem leak
199
1.27k
    if (handle) {
200
1.27k
        handle->deleteAllArguments();
201
1.27k
    }
202
203
    // Call lease4_decline
204
1.27k
    try {
205
1.27k
        uint8_t mac_addr[6];
206
8.91k
        for (size_t i = 0; i < 6; ++i) {
207
7.64k
            mac_addr[i] = fdp.ConsumeIntegral<uint8_t>();
208
7.64k
        }
209
1.27k
        HWAddr hw(mac_addr, sizeof(mac_addr), HTYPE_ETHER);
210
1.27k
        Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw);
211
1.27k
        handle->setArgument("leases4", leases);
212
1.27k
        handle->setArgument("query4", pkt);
213
214
1.27k
        lease4_decline(*handle);
215
1.27k
    } catch (const isc::Exception& e) {
216
        // Slient exceptions
217
1.27k
    } catch (const boost::exception& e) {
218
        // Slient exceptions
219
0
    }
220
221
    // Clean up to avoid mem leak
222
1.27k
    if (handle) {
223
1.27k
        handle->deleteAllArguments();
224
1.27k
    }
225
226
1.27k
    srv.reset();
227
228
    // Remove temp files
229
1.27k
    fuzz::deleteTempFile(path);
230
1.27k
    fuzz::deleteTempFile(lease_path);
231
1.27k
    return 0;
232
1.27k
}