Coverage Report

Created: 2025-11-16 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea-fuzzer/fuzz_dhcp_pkt_process6.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 <dhcp6/ctrl_dhcp6_srv.h>
14
#include <dhcpsrv/callout_handle_store.h>
15
#include <dhcpsrv/lease_mgr_factory.h>
16
#include <log/logger_support.h>
17
#include <util/filesystem.h>
18
19
#include <cstddef>
20
#include <cstdint>
21
#include <vector>
22
#include <list>
23
#include <memory>
24
#include <iostream>
25
#include <filesystem>
26
#include <fstream>
27
#include <string>
28
#include <cstdio>
29
#include <cstdlib>
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 leases6_committed(CalloutHandle& handle);
38
39
namespace isc {
40
    namespace dhcp {
41
        class MyDhcpv6Srv : public ControlledDhcpv6Srv {
42
            public:
43
1.00k
                void fuzz_sanityCheck(const Pkt6Ptr& query) {
44
1.00k
                    sanityCheck(query);
45
1.00k
                }
46
47
5.71k
                void fuzz_classifyPacket(const Pkt6Ptr& pkt) {
48
5.71k
                    classifyPacket(pkt);
49
5.71k
                }
50
51
2.10k
                ConstSubnet6Ptr fuzz_selectSubnet(const Pkt6Ptr& question, bool& drop) {
52
2.10k
                    return selectSubnet(question, drop);
53
2.10k
                }
54
        };
55
    }
56
}
57
58
1.79k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
59
1.79k
    if (size < 236) {
60
        // package size requires at least 236 bytes
61
15
        return 0;
62
15
    }
63
64
    // Disable validatePath checking to allow writing configuration file to /tmp
65
1.78k
    isc::util::file::PathChecker::enableEnforcement(false);
66
67
    // Force DUID file to /tmp
68
1.78k
    setenv("KEA_DHCP_DATA_DIR", "/tmp", 1);
69
70
    // Initialise logging
71
1.78k
    setenv("KEA_LOGGER_DESTINATION", "/dev/null", 0);
72
1.78k
    setenv("KEA_LOCKFILE_DIR", "/tmp", 0);
73
1.78k
    setenv("KEA_PIDFILE_DIR", "/tmp", 0);
74
1.78k
    setenv("KEA_LFC_EXECUTABLE", "/bin/true", 0);
75
1.78k
    try {
76
1.78k
        isc::log::initLogger("fuzzer");
77
1.78k
        isc::process::Daemon::loggerInit("fuzzer", false);
78
1.78k
        isc::process::Daemon::setDefaultLoggerName("fuzzer");
79
1.78k
    } catch (...) {
80
        // Early exit if logging initialisation failed
81
0
        return 0;
82
0
    }
83
84
    // Creating temp config file
85
1.78k
    std::string path = fuzz::writeTempConfig(false);
86
1.78k
    if (path.empty()) {
87
        // Early exit if configuration file creation failed
88
0
        fuzz::deleteTempFile(path);
89
0
        return 0;
90
0
    }
91
92
    // Creating temp lease file
93
1.78k
    std::string lease_path = fuzz::writeTempLease(false);
94
95
1.78k
    Pkt6Ptr pkt;
96
1.78k
    std::unique_ptr<MyDhcpv6Srv> srv;
97
98
    // Package parsing
99
1.78k
    try {
100
1.78k
        pkt = Pkt6Ptr(new Pkt6(data, size));
101
1.78k
        pkt->unpack();
102
1.78k
    } catch (...) {
103
        // Early exit if package parsing failed.
104
766
        return 0;
105
766
    }
106
107
    // Configure random value in packet
108
1.01k
    FuzzedDataProvider fdp(data, size);
109
1.01k
    uint8_t typeChoice = fdp.ConsumeIntegralInRange<uint8_t>(0, 37);
110
1.01k
    pkt->setType(static_cast<DHCPv6MessageType>(typeChoice));
111
112
    // Server initialisation
113
1.01k
    try {
114
1.01k
        srv.reset(new MyDhcpv6Srv());
115
1.01k
        srv->init(path);
116
1.01k
    } catch (...) {
117
        // Early exit if server initialisation failed.
118
16
        return 0;
119
16
    }
120
121
1.00k
    if (!srv) {
122
        // Early exit if server initialisation failed.
123
0
        return 0;
124
0
    }
125
126
    // Call classifyPacket for packet checking
127
1.00k
    try {
128
1.00k
        srv->fuzz_classifyPacket(pkt);
129
1.00k
    } catch (const isc::Exception& e) {
130
        // Slient exceptions
131
0
    } catch (const boost::exception& e) {
132
        // Slient exceptions
133
0
    }
134
135
    // Call sanityCheck for packet checking
136
1.00k
    try {
137
1.00k
        srv->fuzz_sanityCheck(pkt);
138
1.00k
    } catch (const isc::Exception& e) {
139
        // Slient exceptions
140
0
    } catch (const boost::exception& e) {
141
        // Slient exceptions
142
0
    }
143
144
    // Call process functions after the accept and check
145
1.00k
    try {
146
1.00k
        srv->processDhcp6Query(pkt);
147
1.00k
    } catch (const isc::Exception& e) {
148
        // Slient exceptions
149
2
    } catch (const boost::exception& e) {
150
        // Slient exceptions
151
0
    }
152
153
    // Prepare client context
154
1.00k
    AllocEngine::ClientContext6 ctx;
155
156
    // Call earlyGHRLookup
157
1.00k
    try {
158
1.00k
        srv->earlyGHRLookup(pkt, ctx);
159
1.00k
    } catch (const isc::Exception& e) {
160
        // Slient exceptions
161
2
    } catch (const boost::exception& e) {
162
        // Slient exceptions
163
0
    }
164
165
    // Call select subnet
166
1.00k
    try {
167
1.00k
        bool drop = false;
168
1.00k
        ctx.subnet_ = srv->fuzz_selectSubnet(pkt, drop);
169
1.00k
    } catch (const isc::Exception& e) {
170
       // Slient exceptions
171
0
    } catch (const boost::exception& e) {
172
        // Slient exceptions
173
0
    }
174
175
    // Call processLocalizedQuery6
176
1.00k
    try {
177
1.00k
        srv->processLocalizedQuery6(ctx);
178
1.00k
    } catch (const isc::Exception& e) {
179
        // Slient exceptions
180
0
    } catch (const boost::exception& e) {
181
        // Slient exceptions
182
0
    }
183
184
    // Prepare callout handle
185
1.00k
    CalloutHandlePtr handle = getCalloutHandle(pkt);
186
1.00k
    Pkt6Ptr rsp;
187
188
    // Call lease4_committed
189
1.00k
    try {
190
1.00k
        uint8_t mac_addr[6];
191
7.00k
        for (size_t i = 0; i < 6; ++i) {
192
6.00k
            mac_addr[i] = fdp.ConsumeIntegral<uint8_t>();
193
6.00k
        }
194
1.00k
        HWAddr hw(mac_addr, sizeof(mac_addr), HTYPE_ETHER);
195
1.00k
        Lease6Collection leases = LeaseMgrFactory::instance().getLease6(hw);
196
1.00k
        handle->setArgument("leases6", leases);
197
1.00k
        handle->setArgument("query6", pkt);
198
1.00k
        handle->setArgument("response6", rsp);
199
200
1.00k
        leases6_committed(*handle);
201
1.00k
    } catch (const isc::Exception& e) {
202
        // Slient exceptions
203
0
    } catch (const boost::exception& e) {
204
        // Slient exceptions
205
0
    }
206
207
    // Clean up to avoid mem leak
208
1.00k
    if (handle) {
209
1.00k
        handle->deleteAllArguments();
210
1.00k
    }
211
212
1.00k
    srv.reset();
213
214
    // Remove temp files
215
1.00k
    fuzz::deleteTempFile(path);
216
1.00k
    fuzz::deleteTempFile(lease_path);
217
218
1.00k
    return 0;
219
1.00k
}