1 /*
2 * Copyright (C) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dhcpfunction2_fuzzer.h"
17
18 #include <cstddef>
19 #include <cstdint>
20 #include <unistd.h>
21 #include <algorithm>
22 #include <vector>
23 #include <string>
24 #include <arpa/inet.h>
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <net/if.h>
28 #include <netinet/in.h>
29 #include "securec.h"
30 #include "dhcp_function.h"
31 #include "dhcp_client_def.h"
32
33 namespace OHOS {
34 namespace DHCP {
35 constexpr size_t DHCP_SLEEP_1 = 2;
36 constexpr int TWO = 2;
37
38 // Network address and buffer size constants
39 constexpr size_t IPV4_ADDR_SIZE = 4;
40 constexpr size_t IPV6_ADDR_SIZE = 16;
41 constexpr size_t MAC_ADDR_SIZE = 6;
42 constexpr size_t INTERFACE_NAME_MAX_LEN = 16;
43 constexpr size_t MAC_STRING_MAX_LEN = 20;
44 constexpr size_t MAC_STRING_LONG_LEN = 50;
45 constexpr size_t MAC_STRING_SHORT_LEN = 10;
46 constexpr size_t LARGE_BUFFER_SIZE = 1024;
47 constexpr size_t VERY_LARGE_BUFFER_SIZE = 2048;
48
49 // IP address range constants
50 constexpr size_t MAX_TEST_SIZE_RANGE = 20;
51 constexpr size_t MAX_MAC_TEST_LENGTH = 12;
52
53 // File permission constants
54 constexpr int DIR_MODE_755 = 0755;
55 constexpr int DIR_MODE_777 = 0777;
56 constexpr int DIR_MODE_644 = 0644;
57 constexpr int DIR_MODE_600 = 0600;
58 constexpr int DIR_MODE_700 = 0700;
59 constexpr int DIR_MODE_444 = 0444;
60 constexpr int DIR_PERMISSION_MASK = 0777;
61
62 // Array size and index constants
63 constexpr size_t PATH_COMPONENT_SIZE = 4;
64 constexpr size_t MIN_INTERFACE_TEST_SIZE = 9;
65 constexpr size_t LOOP_START_INDEX = 0;
66 constexpr int FUNCTION_SUCCESS = 0;
67 constexpr size_t DATA_PARTITION_COUNT = 3; // For dividing input data into parts
68
Ip4StrConToIntTest(const uint8_t * data,size_t size)69 void Ip4StrConToIntTest(const uint8_t* data, size_t size)
70 {
71 if (size == LOOP_START_INDEX) {
72 return;
73 }
74
75 // Create IP string from fuzz data
76 std::string strIp = std::string(reinterpret_cast<const char*>(data), size);
77 uint32_t uIp = LOOP_START_INDEX;
78 bool bHost = (data[LOOP_START_INDEX] % TWO) ? true : false;
79
80 // Test normal case
81 Ip4StrConToInt(strIp.c_str(), &uIp, bHost);
82
83 // Test with null pointer
84 Ip4StrConToInt(nullptr, &uIp, bHost);
85 Ip4StrConToInt(strIp.c_str(), nullptr, bHost);
86
87 // Test with empty string
88 Ip4StrConToInt("", &uIp, bHost);
89
90 // Test with common IP addresses
91 const std::vector<std::string> commonIps = {
92 "127.0.0.1",
93 "192.168.1.1",
94 "10.0.0.1",
95 "172.16.0.1",
96 "0.0.0.0",
97 };
98
99 for (const auto& ip : commonIps) {
100 uint32_t testIp = LOOP_START_INDEX;
101 Ip4StrConToInt(ip.c_str(), &testIp, true);
102 Ip4StrConToInt(ip.c_str(), &testIp, false);
103 }
104
105 // Test with invalid IP addresses
106 const std::vector<std::string> invalidIps = {
107 "256.256.256.256",
108 "999.999.999.999",
109 "192.168.1",
110 "192.168.1.1.1",
111 "abc.def.ghi.jkl",
112 "192.168.1.-1",
113 "192.168.1.300"
114 };
115
116 for (const auto& ip : invalidIps) {
117 uint32_t testIp = LOOP_START_INDEX;
118 Ip4StrConToInt(ip.c_str(), &testIp, bHost);
119 }
120 }
121
Ip6StrConToCharTest(const uint8_t * data,size_t size)122 void Ip6StrConToCharTest(const uint8_t* data, size_t size)
123 {
124 if (size == LOOP_START_INDEX) {
125 return;
126 }
127
128 // Create IPv6 string from fuzz data
129 std::string strIp = std::string(reinterpret_cast<const char*>(data), size);
130 uint8_t chIp[IPV6_ADDR_SIZE] = {LOOP_START_INDEX};
131
132 // Test normal case
133 Ip6StrConToChar(strIp.c_str(), chIp, sizeof(chIp));
134
135 // Test with null pointer
136 Ip6StrConToChar(nullptr, chIp, sizeof(chIp));
137 Ip6StrConToChar(strIp.c_str(), nullptr, sizeof(chIp));
138
139 // Test with empty string
140 Ip6StrConToChar("", chIp, sizeof(chIp));
141
142 // Test with common IPv6 addresses
143 const std::vector<std::string> commonIp6s = {
144 "::1",
145 "::",
146 "2001:db8::1",
147 "fe80::1",
148 "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
149 "2001:db8:85a3::8a2e:370:7334",
150 "::ffff:192.168.1.1"
151 };
152
153 for (const auto& ip6 : commonIp6s) {
154 uint8_t testIp6[IPV6_ADDR_SIZE] = {LOOP_START_INDEX};
155 Ip6StrConToChar(ip6.c_str(), testIp6, sizeof(testIp6));
156 }
157
158 // Test with different buffer sizes
159 if (size > 1) {
160 size_t testSize = (data[LOOP_START_INDEX] % MAX_TEST_SIZE_RANGE) + 1; // 1-20 bytes
161 uint8_t testBuf[MAX_TEST_SIZE_RANGE] = {LOOP_START_INDEX};
162 Ip6StrConToChar(strIp.c_str(), testBuf, testSize);
163 }
164
165 // Test with invalid IPv6 addresses
166 const std::vector<std::string> invalidIp6s = {
167 "gggg::1",
168 "2001:db8::1::2",
169 "2001:db8:85a3:0000:0000:8a2e:0370:7334:extra",
170 "192.168.1.1",
171 "invalid_ipv6"
172 };
173
174 for (const auto& ip6 : invalidIp6s) {
175 uint8_t testIp6[IPV6_ADDR_SIZE] = {LOOP_START_INDEX};
176 Ip6StrConToChar(ip6.c_str(), testIp6, sizeof(testIp6));
177 }
178 }
179
MacChConToMacStrTest(const uint8_t * data,size_t size)180 void MacChConToMacStrTest(const uint8_t* data, size_t size)
181 {
182 if (size < MAC_ADDR_SIZE) {
183 return; // Need at least 6 bytes for MAC address
184 }
185
186 // Use first 6 bytes as MAC address
187 unsigned char macBytes[MAC_ADDR_SIZE];
188 int ret = memcpy_s(macBytes, sizeof(macBytes), data, MAC_ADDR_SIZE);
189 if (ret != EOK) {
190 return; // Memory copy failed, exit the test
191 }
192
193 // Test with different MAC buffer sizes
194 char macStr[MAC_STRING_MAX_LEN] = {LOOP_START_INDEX}; // Standard MAC string format "xx:xx:xx:xx:xx:xx"
195
196 // Normal case - 6 bytes MAC
197 MacChConToMacStr(macBytes, MAC_ADDR_SIZE, macStr, sizeof(macStr));
198
199 // Edge cases
200 MacChConToMacStr(nullptr, MAC_ADDR_SIZE, macStr, sizeof(macStr)); // null MAC
201 MacChConToMacStr(macBytes, LOOP_START_INDEX, macStr, sizeof(macStr)); // zero length
202 MacChConToMacStr(macBytes, MAC_ADDR_SIZE, nullptr, LOOP_START_INDEX); // null output buffer
203
204 // Test with different MAC lengths
205 if (size > MAC_ADDR_SIZE) {
206 size_t testLen = (data[MAC_ADDR_SIZE] % MAX_MAC_TEST_LENGTH) + 1; // 1-12 bytes
207 char longMacStr[MAC_STRING_LONG_LEN] = {LOOP_START_INDEX};
208 MacChConToMacStr(macBytes, testLen, longMacStr, sizeof(longMacStr));
209 }
210
211 // Test with small buffer
212 char smallMacStr[MAC_STRING_SHORT_LEN] = {LOOP_START_INDEX};
213 MacChConToMacStr(macBytes, MAC_ADDR_SIZE, smallMacStr, sizeof(smallMacStr));
214
215 // Test with various MAC patterns
216 unsigned char testMacs[][MAC_ADDR_SIZE] = {
217 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // all zeros
218 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // all ones
219 {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}, // sequential
220 {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF} // pattern
221 };
222
223 for (size_t i = LOOP_START_INDEX; i < sizeof(testMacs) / sizeof(testMacs[LOOP_START_INDEX]); i++) {
224 char testMacStr[MAC_STRING_MAX_LEN] = {LOOP_START_INDEX};
225 MacChConToMacStr(testMacs[i], MAC_ADDR_SIZE, testMacStr, sizeof(testMacStr));
226 }
227 }
228
GetLocalInterfaceTest(const uint8_t * data,size_t size)229 void GetLocalInterfaceTest(const uint8_t* data, size_t size)
230 {
231 if (size < 1) {
232 return;
233 }
234
235 // Create interface name from fuzz data
236 std::string ifname = std::string(reinterpret_cast<const char*>(data),
237 std::min(size, static_cast<size_t>(INTERFACE_NAME_MAX_LEN)));
238 int ifindex = LOOP_START_INDEX;
239 unsigned char hwaddr[MAC_ADDR_SIZE] = {LOOP_START_INDEX};
240 uint32_t ifaddr4 = LOOP_START_INDEX;
241
242 // Test normal case
243 GetLocalInterface(ifname.c_str(), &ifindex, hwaddr, &ifaddr4);
244
245 // Test with common interface names
246 const std::vector<std::string> commonInterfaces = {"eth0", "wlan0", "lo", "enp0s3", "br0", "tun0"};
247 size_t interfaceIndex = data[LOOP_START_INDEX] % commonInterfaces.size();
248 GetLocalInterface(commonInterfaces[interfaceIndex].c_str(), &ifindex, hwaddr, &ifaddr4);
249
250 // Test with null parameters
251 GetLocalInterface(nullptr, &ifindex, hwaddr, &ifaddr4);
252 GetLocalInterface(ifname.c_str(), nullptr, hwaddr, &ifaddr4);
253 GetLocalInterface(ifname.c_str(), &ifindex, nullptr, &ifaddr4);
254 GetLocalInterface(ifname.c_str(), &ifindex, hwaddr, nullptr); // ifaddr4 can be null
255
256 // Test with empty string
257 GetLocalInterface("", &ifindex, hwaddr, &ifaddr4);
258
259 // Test with non-existent interface
260 GetLocalInterface("nonexistent_12345", &ifindex, hwaddr, &ifaddr4);
261
262 // Test with very long interface name
263 std::string longInterface(LARGE_BUFFER_SIZE, 'X');
264 GetLocalInterface(longInterface.c_str(), &ifindex, hwaddr, &ifaddr4);
265
266 // Test with special characters
267 GetLocalInterface("eth\x00test", &ifindex, hwaddr, &ifaddr4);
268 GetLocalInterface("!@#$%^&*()", &ifindex, hwaddr, &ifaddr4);
269 }
270
GetLocalIpTest(const uint8_t * data,size_t size)271 void GetLocalIpTest(const uint8_t* data, size_t size)
272 {
273 if (size < 1) {
274 return;
275 }
276
277 // Create interface name from fuzz data
278 std::string ifname = std::string(reinterpret_cast<const char*>(data),
279 std::min(size, static_cast<size_t>(INTERFACE_NAME_MAX_LEN)));
280 uint32_t ifaddr4 = LOOP_START_INDEX;
281
282 // Test normal case
283 GetLocalIp(ifname.c_str(), &ifaddr4);
284
285 // Test with common interface names
286 const std::vector<std::string> commonInterfaces = {"eth0", "wlan0", "lo", "enp0s3", "br0", "tun0"};
287 size_t interfaceIndex = data[LOOP_START_INDEX] % commonInterfaces.size();
288 GetLocalIp(commonInterfaces[interfaceIndex].c_str(), &ifaddr4);
289
290 // Test with null parameters
291 GetLocalIp(nullptr, &ifaddr4);
292 GetLocalIp(ifname.c_str(), nullptr);
293
294 // Test with empty string
295 GetLocalIp("", &ifaddr4);
296
297 // Test with non-existent interface
298 GetLocalIp("nonexistent_interface_12345", &ifaddr4);
299
300 // Test with very long interface name
301 std::string longInterface(LARGE_BUFFER_SIZE, 'A');
302 GetLocalIp(longInterface.c_str(), &ifaddr4);
303
304 // Test with special characters
305 GetLocalIp("!@#$%^&*()", &ifaddr4);
306 }
307
SetLocalInterfaceTest(const uint8_t * data,size_t size)308 void SetLocalInterfaceTest(const uint8_t* data, size_t size)
309 {
310 if (size < MIN_INTERFACE_TEST_SIZE) {
311 return; // Need at least 9 bytes for interface name + 8 bytes for IPs
312 }
313
314 // Create interface name from first part of data
315 std::string ifname = std::string(reinterpret_cast<const char*>(data),
316 std::min(size / DATA_PARTITION_COUNT, static_cast<size_t>(INTERFACE_NAME_MAX_LEN)));
317
318 // Extract IP address and netmask from remaining data
319 uint32_t ipAddr;
320 uint32_t netMask;
321 int ret = memcpy_s(&ipAddr, sizeof(ipAddr), data + size / DATA_PARTITION_COUNT, sizeof(ipAddr));
322 if (ret != EOK) {
323 return; // Memory copy failed, exit the test
324 }
325 ret = memcpy_s(&netMask, sizeof(netMask), data + size / DATA_PARTITION_COUNT + IPV4_ADDR_SIZE, sizeof(netMask));
326 if (ret != EOK) {
327 return; // Memory copy failed, exit the test
328 }
329
330 // Test normal case (likely to fail due to permissions, but tests the logic)
331 SetLocalInterface(ifname.c_str(), ipAddr, netMask);
332
333 // Test with common interface names and IP ranges
334 const std::vector<std::string> testInterfaces = {"eth0", "lo", "wlan0", "test123"};
335 const std::vector<std::pair<uint32_t, uint32_t>> testIpPairs = {
336 {htonl(0xC0A80101), htonl(0xFFFFFF00)}, // 192.168.1.1/24
337 {htonl(0x0A000001), htonl(0xFF000000)}, // 10.0.0.1/8
338 {htonl(0x7F000001), htonl(0xFF000000)}, // 127.0.0.1/8
339 {0, 0}, // All zeros
340 {0xFFFFFFFF, 0xFFFFFFFF} // All ones
341 };
342
343 for (const auto& interface : testInterfaces) {
344 for (const auto& ipPair : testIpPairs) {
345 SetLocalInterface(interface.c_str(), ipPair.first, ipPair.second);
346 }
347 }
348
349 // Test with null interface name
350 SetLocalInterface(nullptr, ipAddr, netMask);
351
352 // Test with empty interface name
353 SetLocalInterface("", ipAddr, netMask);
354
355 // Test with very long interface name
356 std::string longInterface(LARGE_BUFFER_SIZE, 'Y');
357 SetLocalInterface(longInterface.c_str(), ipAddr, netMask);
358
359 // Test with non-existent interface
360 SetLocalInterface("nonexistent_interface_xyz", ipAddr, netMask);
361 }
362
CreateDirsTest(const uint8_t * data,size_t size)363 void CreateDirsTest(const uint8_t* data, size_t size)
364 {
365 if (size == LOOP_START_INDEX) {
366 return;
367 }
368
369 int mode = DIR_DEFAULT_MODE;
370
371 // Extract mode from data if available
372 if (size >= IPV4_ADDR_SIZE) {
373 int ret = memcpy_s(&mode, sizeof(mode), data, sizeof(mode));
374 if (ret != EOK) {
375 return; // Memory copy failed, exit the test
376 }
377 mode = mode % DIR_PERMISSION_MASK; // Keep it within valid mode range
378 if (mode == LOOP_START_INDEX) mode = DIR_DEFAULT_MODE;
379 }
380
381 // Create directory path from remaining data
382 size_t pathStart = std::min(size, static_cast<size_t>(PATH_COMPONENT_SIZE));
383 std::string dirs = std::string(reinterpret_cast<const char*>(data + pathStart), size - pathStart);
384
385 // Test normal case
386 CreateDirs(dirs.c_str(), mode);
387
388 // Test with null pointer
389 CreateDirs(nullptr, mode);
390
391 // Test with empty string
392 CreateDirs("", mode);
393
394 // Test with common directory patterns
395 const std::vector<std::string> commonDirs = {
396 "/tmp/test",
397 "/tmp/test/nested/deep",
398 "relative/path",
399 "./current/dir",
400 "../parent/dir",
401 "/tmp/single",
402 "/tmp/with spaces/dir",
403 "/tmp/with-dashes/dir",
404 "/tmp/with_underscores/dir"
405 };
406
407 for (const auto& dir : commonDirs) {
408 CreateDirs(dir.c_str(), mode);
409 }
410
411 // Test with different modes
412 const std::vector<int> testModes = {DIR_MODE_755, DIR_MODE_777, DIR_MODE_644,
413 DIR_MODE_600, DIR_MODE_700, DIR_MODE_444};
414 for (int testMode : testModes) {
415 CreateDirs("/tmp/mode_test", testMode);
416 }
417
418 // Test with very long path
419 std::string longPath(VERY_LARGE_BUFFER_SIZE, 'L');
420 CreateDirs(longPath.c_str(), mode);
421
422 // Test with special characters
423 CreateDirs("/tmp/special!@#$%^&*()", mode);
424 CreateDirs("/tmp/with\x00null", mode);
425 CreateDirs("/tmp/with\ttab", mode);
426 CreateDirs("/tmp/with\nnewline", mode);
427 }
428
429 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)430 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
431 {
432 if (data == nullptr) {
433 return FUNCTION_SUCCESS;
434 }
435 sleep(DHCP_SLEEP_1);
436 OHOS::DHCP::Ip4StrConToIntTest(data, size);
437 OHOS::DHCP::Ip6StrConToCharTest(data, size);
438 OHOS::DHCP::MacChConToMacStrTest(data, size);
439 OHOS::DHCP::GetLocalInterfaceTest(data, size);
440 OHOS::DHCP::GetLocalIpTest(data, size);
441 OHOS::DHCP::SetLocalInterfaceTest(data, size);
442 OHOS::DHCP::CreateDirsTest(data, size);
443 return FUNCTION_SUCCESS;
444 }
445 } // namespace DHCP
446 } // namespace OHOS
447