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