• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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