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_ddns_tuning4.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 <log/logger_support.h>
16
#include <util/filesystem.h>
17
18
#include <cstddef>
19
#include <cstdint>
20
#include <vector>
21
#include <list>
22
#include <memory>
23
#include <iostream>
24
#include <filesystem>
25
#include <fstream>
26
#include <string>
27
#include <cstdio>
28
29
#include "helper_func.h"
30
31
using namespace isc::dhcp;
32
using namespace isc::hooks;
33
using namespace isc::util;
34
35
extern "C" int ddns4_update(CalloutHandle& handle);
36
37
namespace isc {
38
    namespace dhcp {
39
        class MyDhcpv4Srv : public ControlledDhcpv4Srv {
40
            public:
41
6.36k
                void fuzz_classifyPacket(const Pkt4Ptr& pkt) {
42
6.36k
                    classifyPacket(pkt);
43
6.36k
                }
44
45
                ConstSubnet4Ptr fuzz_selectSubnet(const Pkt4Ptr& query,
46
                                                  bool& drop,
47
2.43k
                                                  bool allow_answer_park = true) {
48
2.43k
                    return selectSubnet(query, drop, allow_answer_park);
49
2.43k
                }
50
        };
51
    }
52
}
53
54
2.73k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
55
2.73k
    if (size < 236) {
56
        // package size requires at least 236 bytes
57
15
        return 0;
58
15
    }
59
60
    // Disable validatePath checking to allow writing configuration file to /tmp
61
2.71k
    isc::util::file::PathChecker::enableEnforcement(false);
62
63
    // Initialise logging
64
2.71k
    setenv("KEA_LOGGER_DESTINATION", "/dev/null", 0);
65
2.71k
    setenv("KEA_LOCKFILE_DIR", "/tmp", 0);
66
2.71k
    setenv("KEA_PIDFILE_DIR", "/tmp", 0);
67
2.71k
    setenv("KEA_LFC_EXECUTABLE", "/bin/true", 0);
68
2.71k
    try {
69
2.71k
        isc::log::initLogger("fuzzer");
70
2.71k
        isc::process::Daemon::loggerInit("fuzzer", false);
71
2.71k
        isc::process::Daemon::setDefaultLoggerName("fuzzer");
72
2.71k
    } catch (...) {
73
        // Early exit if logging initialisation failed
74
0
        return 0;
75
0
    }
76
77
    // Creating temp config file
78
2.71k
    std::string path = fuzz::writeTempConfig(true);
79
2.71k
    if (path.empty()) {
80
        // Early exit if configuration file creation failed
81
0
        fuzz::deleteTempFile(path);
82
0
        return 0;
83
0
    }
84
85
    // Creating temp lease file
86
2.71k
    std::string lease_path = fuzz::writeTempLease(true);
87
88
2.71k
    Pkt4Ptr pkt;
89
2.71k
    std::unique_ptr<MyDhcpv4Srv> srv;
90
91
    // Package parsing
92
2.71k
    try {
93
        // Add fixed magic cookie and correct hardware address
94
2.71k
        std::vector<uint8_t> buf(data, data + size);
95
2.71k
        if (size >= 240) {
96
            // Max hardware address length is 20
97
2.69k
            buf[2] = 20;
98
99
            // Magic cookie fixed value 0x63825363
100
2.69k
            buf[236] = 0x63;
101
2.69k
            buf[237] = 0x82;
102
2.69k
            buf[238] = 0x53;
103
2.69k
            buf[239] = 0x63;
104
2.69k
        }
105
106
2.71k
        pkt = Pkt4Ptr(new Pkt4(buf.data(), buf.size()));
107
2.71k
        pkt->unpack();
108
2.71k
    } catch (...) {
109
        // Early exit if package parsing failed.
110
1.47k
        return 0;
111
1.47k
    }
112
113
    // Configure random value in packet
114
1.24k
    FuzzedDataProvider fdp(data, size);
115
1.24k
    uint8_t typeChoice = fdp.ConsumeIntegralInRange<uint8_t>(0, 8);
116
1.24k
    pkt->setType(static_cast<DHCPMessageType>(typeChoice));
117
118
    // Server initialisation
119
1.24k
    try {
120
1.24k
        srv.reset(new MyDhcpv4Srv());
121
1.24k
        srv->init(path);
122
1.24k
    } catch (...) {
123
        // Early exit if server initialisation failed.
124
21
        return 0;
125
21
    }
126
127
1.22k
    if (!srv) {
128
        // Early exit if server initialisation failed.
129
0
        return 0;
130
0
    }
131
132
    // Call classifyPacket for packet checking
133
1.22k
    try {
134
1.22k
        srv->fuzz_classifyPacket(pkt);
135
1.22k
    } catch (const isc::Exception& e) {
136
        // Slient exceptions
137
0
    } catch (const boost::exception& e) {
138
        // Slient exceptions
139
0
    }
140
141
    // Prepare client context
142
1.22k
    CalloutHandlePtr handle = getCalloutHandle(pkt);
143
1.22k
    AllocEngine::ClientContext4Ptr ctx(new AllocEngine::ClientContext4());
144
145
    // Call earlyGHRLookup
146
1.22k
    try {
147
1.22k
        srv->earlyGHRLookup(pkt, ctx);
148
1.22k
    } catch (const isc::Exception& e) {
149
        // Slient exceptions
150
0
    } catch (const boost::exception& e) {
151
        // Slient exceptions
152
0
    }
153
154
    // Call select subnet
155
1.22k
    try {
156
1.22k
        bool drop = false;
157
1.22k
        if (!ctx) {
158
0
            ctx.reset(new AllocEngine::ClientContext4());
159
0
        }
160
1.22k
        if (ctx) {
161
1.22k
            ctx->subnet_ = srv->fuzz_selectSubnet(pkt, drop, false);
162
1.22k
        }
163
1.22k
    } catch (const isc::Exception& e) {
164
        // Slient exceptions
165
0
    } catch (const boost::exception& e) {
166
        // Slient exceptions
167
0
    }
168
169
    // Fuzz ddns4_update
170
1.22k
    try {
171
1.22k
        Pkt4Ptr rsp;
172
1.22k
        handle = getCalloutHandle(pkt);
173
1.22k
        handle->setArgument("query4", pkt);
174
1.22k
        handle->setArgument("response4", rsp);
175
1.22k
        handle->setArgument("hostname", fdp.ConsumeRandomLengthString(32));
176
1.22k
        handle->setArgument("fwd-update", fdp.ConsumeBool());
177
1.22k
        handle->setArgument("rev-update", fdp.ConsumeBool());
178
1.22k
        if (!ctx) {
179
0
            ctx.reset(new AllocEngine::ClientContext4());
180
0
        }
181
1.22k
        if (ctx) {
182
1.22k
            handle->setArgument("ddns-params", ctx->getDdnsParams());
183
1.22k
            handle->setArgument("subnet4", ctx->subnet_);
184
1.22k
        }
185
1.22k
        ddns4_update(*handle);
186
1.22k
    } catch (const isc::Exception& e) {
187
        // Slient exceptions
188
1.22k
    } catch (const boost::exception& e) {
189
        // Slient exceptions
190
0
    }
191
192
    // Clean handle to avoid mem leak
193
1.22k
    if (handle) {
194
1.22k
        handle->deleteAllArguments();
195
1.22k
    }
196
197
1.22k
    srv.reset();
198
199
    // Remove temp files
200
1.22k
    fuzz::deleteTempFile(path);
201
1.22k
    fuzz::deleteTempFile(lease_path);
202
1.22k
    return 0;
203
1.22k
}