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_user_chk4.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 <dhcp/user_chk/user.h>
14
#include <dhcp/user_chk/user_data_source.h>
15
#include <dhcp/user_chk/user_file.h>
16
#include <dhcp/user_chk/user_registry.h>
17
#include <dhcp4/ctrl_dhcp4_srv.h>
18
#include <dhcpsrv/callout_handle_store.h>
19
#include <dhcpsrv/cfgmgr.h>
20
#include <dhcpsrv/lease_mgr_factory.h>
21
#include <log/logger_support.h>
22
#include <util/filesystem.h>
23
24
#include <cstddef>
25
#include <cstdint>
26
#include <vector>
27
#include <list>
28
#include <memory>
29
#include <iostream>
30
#include <filesystem>
31
#include <fstream>
32
#include <string>
33
#include <cstdio>
34
35
#include "helper_func.h"
36
37
using namespace isc::dhcp;
38
using namespace isc::hooks;
39
using namespace isc::util;
40
using namespace user_chk;
41
42
extern "C" UserRegistryPtr user_registry;
43
extern "C" int pkt4_receive(CalloutHandle& handle);
44
extern "C" int subnet4_select(CalloutHandle& handle);
45
46
namespace isc {
47
    namespace dhcp {
48
        class MyDhcpv4Srv : public ControlledDhcpv4Srv {
49
            public:
50
6.36k
                void fuzz_classifyPacket(const Pkt4Ptr& pkt) {
51
6.36k
                    classifyPacket(pkt);
52
6.36k
                }
53
        };
54
    }
55
}
56
57
3.12k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
58
3.12k
    if (size < 236) {
59
        // package size requires at least 236 bytes
60
15
        return 0;
61
15
    }
62
63
3.10k
    FuzzedDataProvider fdp(data, size);
64
65
    // Disable validatePath checking to allow writing configuration file to /tmp
66
3.10k
    isc::util::file::PathChecker::enableEnforcement(false);
67
68
    // Initialise logging
69
3.10k
    setenv("KEA_LOGGER_DESTINATION", "/dev/null", 0);
70
3.10k
    setenv("KEA_LOCKFILE_DIR", "/tmp", 0);
71
3.10k
    setenv("KEA_PIDFILE_DIR", "/tmp", 0);
72
3.10k
    setenv("KEA_LFC_EXECUTABLE", "/bin/true", 0);
73
3.10k
    try {
74
3.10k
        isc::log::initLogger("fuzzer");
75
3.10k
        isc::process::Daemon::loggerInit("fuzzer", false);
76
3.10k
        isc::process::Daemon::setDefaultLoggerName("fuzzer");
77
3.10k
    } catch (...) {
78
        // Early exit if logging initialisation failed
79
0
        return 0;
80
0
    }
81
82
    // Creating temp config file
83
3.10k
    std::string path = fuzz::writeTempConfig(true);
84
3.10k
    if (path.empty()) {
85
        // Early exit if configuration file creation failed
86
0
        fuzz::deleteTempFile(path);
87
0
        return 0;
88
0
    }
89
90
    // Creating temp lease file
91
3.10k
    std::string lease_path = fuzz::writeTempLease(true);
92
93
    // Creating temp user file
94
3.10k
    std::string user_path = fuzz::writeTempUserFile();
95
96
    // Creating user registry
97
3.10k
    try {
98
3.10k
        user_registry.reset(new UserRegistry());
99
3.10k
        UserDataSourcePtr user_file(new UserFile(user_path));
100
3.10k
        user_registry->setSource(user_file);
101
3.10k
        user_registry->refresh();
102
3.10k
    } catch (std::exception& e) {
103
        // Early exit if user registry failed to create.
104
0
        return 0;
105
0
    }
106
107
3.10k
    try {
108
9.81k
        for (int i = 0; i < fdp.ConsumeIntegralInRange<int>(1, 5); i++) {
109
6.70k
            if (fdp.ConsumeBool()) {
110
2.43k
                std::vector<uint8_t> mac = fdp.ConsumeBytes<uint8_t>(6);
111
2.43k
                UserPtr user = UserPtr(new User(UserId::HW_ADDRESS, mac));
112
2.43k
                user_registry->addUser(user);
113
4.27k
            } else {
114
4.27k
                const size_t len = fdp.ConsumeIntegralInRange<size_t>(2, 64);
115
4.27k
                std::vector<uint8_t> duid = fdp.ConsumeBytes<uint8_t>(len);
116
4.27k
                UserPtr user = UserPtr(new User(UserId::DUID, duid));
117
4.27k
                user_registry->addUser(user);
118
4.27k
            }
119
6.70k
        }
120
3.10k
    } catch (...) {
121
        // Slient exceptions
122
184
    }
123
124
3.10k
    Pkt4Ptr pkt;
125
3.10k
    std::unique_ptr<MyDhcpv4Srv> srv;
126
127
    // Package parsing
128
3.10k
    try {
129
        // Add fixed magic cookie and correct hardware address
130
3.10k
        std::vector<uint8_t> buf(data, data + size);
131
3.10k
        if (size >= 240) {
132
            // Max hardware address length is 20
133
3.00k
            buf[2] = 20;
134
135
            // Magic cookie fixed value 0x63825363
136
3.00k
            buf[236] = 0x63;
137
3.00k
            buf[237] = 0x82;
138
3.00k
            buf[238] = 0x53;
139
3.00k
            buf[239] = 0x63;
140
3.00k
        }
141
142
3.10k
        pkt = Pkt4Ptr(new Pkt4(buf.data(), buf.size()));
143
3.10k
        pkt->unpack();
144
3.10k
    } catch (...) {
145
        // Early exit if package parsing failed.
146
1.81k
        return 0;
147
1.81k
    }
148
149
    // Configure random value in packet
150
1.29k
    uint8_t typeChoice = fdp.ConsumeIntegralInRange<uint8_t>(0, 8);
151
1.29k
    pkt->setType(static_cast<DHCPMessageType>(typeChoice));
152
153
    // Server initialisation
154
1.29k
    try {
155
1.29k
        srv.reset(new MyDhcpv4Srv());
156
1.29k
        srv->init(path);
157
1.29k
    } catch (...) {
158
        // Early exit if server initialisation failed.
159
23
        return 0;
160
23
    }
161
162
1.27k
    if (!srv) {
163
        // Early exit if server initialisation failed.
164
0
        return 0;
165
0
    }
166
167
1.27k
    CalloutHandlePtr handle = nullptr;
168
169
    // Fuzz pkt4_receive
170
1.27k
    try {
171
1.27k
        handle = getCalloutHandle(pkt);
172
1.27k
        handle->setArgument("query4", pkt);
173
1.27k
        pkt4_receive(*handle);
174
1.27k
    } catch (const isc::Exception& e) {
175
        // Slient exceptions
176
0
    } catch (const boost::exception& e) {
177
        // Slient exceptions
178
0
    }
179
180
    // Clean handle to avoid mem leak
181
1.27k
    if (handle) {
182
1.27k
        handle->deleteAllArguments();
183
1.27k
    }
184
185
    // Call classifyPacket for packet checking
186
1.27k
    try {
187
1.27k
        srv->fuzz_classifyPacket(pkt);
188
1.27k
    } catch (const isc::Exception& e) {
189
        // Slient exceptions
190
0
    } catch (const boost::exception& e) {
191
        // Slient exceptions
192
0
    }
193
194
    // Prepare client context
195
1.27k
    AllocEngine::ClientContext4Ptr ctx(new AllocEngine::ClientContext4());
196
197
    // Call earlyGHRLookup
198
1.27k
    try {
199
1.27k
        srv->earlyGHRLookup(pkt, ctx);
200
1.27k
    } catch (const isc::Exception& e) {
201
        // Slient exceptions
202
0
    } catch (const boost::exception& e) {
203
        // Slient exceptions
204
0
    }
205
206
    // Fuzz subnet4_select
207
1.27k
    try {
208
1.27k
        handle = getCalloutHandle(pkt);
209
1.27k
        Pkt4Ptr rsp;
210
1.27k
        CfgMgr& cfgmgr = CfgMgr::instance();
211
1.27k
        handle = getCalloutHandle(pkt);
212
1.27k
        handle->setArgument("query4", pkt);
213
1.27k
        handle->setArgument("subnet4collection",
214
1.27k
                            cfgmgr.getCurrentCfg()->getCfgSubnets4()->getAll());
215
1.27k
        if (!ctx) {
216
0
            ctx.reset(new AllocEngine::ClientContext4());
217
0
        }
218
1.27k
        if (ctx) {
219
1.27k
            handle->setArgument("subnet4", ctx->subnet_);
220
1.27k
        }
221
1.27k
        subnet4_select(*handle);
222
1.27k
    } catch (const isc::Exception& e) {
223
        // Slient exceptions
224
0
    } catch (const boost::exception& e) {
225
        // Slient exceptions
226
0
    }
227
228
    // Clean handle to avoid mem leak
229
1.27k
    if (handle) {
230
1.27k
        handle->deleteAllArguments();
231
1.27k
    }
232
233
1.27k
    srv.reset();
234
235
    // Remove temp files
236
1.27k
    fuzz::deleteTempFile(path);
237
1.27k
    fuzz::deleteTempFile(lease_path);
238
1.27k
    fuzz::deleteTempFile(user_path);
239
1.27k
    return 0;
240
1.27k
}