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
17 #include "dhcp_arp_checker_fuzzer.h"
18 #include "dhcp_arp_checker.h"
19 #include "dhcp_fuzz_common_func.h"
20 #include <cstdint>
21 #include <string>
22 #include <vector>
23 #include <chrono>
24 #include <cstring>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <linux/if_packet.h>
29 #include <poll.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <algorithm>
33 #include "securec.h"
34 #include "dhcp_arp_checker.h"
35
36 using namespace std;
37 namespace OHOS {
38 namespace DHCP {
39
40 constexpr size_t MIN_U32_SIZE = sizeof(uint32_t);
41 constexpr size_t MIN_U16_SIZE = sizeof(uint16_t);
42 constexpr int32_t DEFAULT_TIMEOUT_MILLIS = 1000;
43 constexpr size_t MIN_ETH_ALEN = ETH_ALEN;
44
45 std::shared_ptr<DhcpArpChecker> pDhcpArpChecker = std::make_shared<DhcpArpChecker>();
46
TestStart(const uint8_t * data,size_t size)47 void TestStart(const uint8_t* data, size_t size)
48 {
49 if (size < MIN_U32_SIZE) {
50 return;
51 }
52 size_t pos = 0;
53 uint32_t ifnameLen = U32_AT(data);
54 pos += MIN_U32_SIZE;
55 if (pos + ifnameLen > size) {
56 return;
57 }
58 string ifname(reinterpret_cast<const char*>(data + pos), ifnameLen);
59 pos += ifnameLen;
60
61 if (pos + MIN_U32_SIZE > size) {
62 return;
63 }
64 uint32_t hwAddrLen = U32_AT(data + pos);
65 pos += MIN_U32_SIZE;
66 if (pos + hwAddrLen > size) {
67 return;
68 }
69 string hwAddr(reinterpret_cast<const char*>(data + pos), hwAddrLen);
70 pos += hwAddrLen;
71
72 if (pos + MIN_U32_SIZE > size) {
73 return;
74 }
75 uint32_t senderIpLen = U32_AT(data + pos);
76 pos += MIN_U32_SIZE;
77 if (pos + senderIpLen > size) {
78 return;
79 }
80 string senderIp(reinterpret_cast<const char*>(data + pos), senderIpLen);
81 pos += senderIpLen;
82
83 if (pos + MIN_U32_SIZE > size) {
84 return;
85 }
86 uint32_t targetIpLen = U32_AT(data + pos);
87 pos += MIN_U32_SIZE;
88 if (pos + targetIpLen > size) {
89 return;
90 }
91 string targetIp(reinterpret_cast<const char*>(data + pos), targetIpLen);
92
93 pDhcpArpChecker->Start(ifname, hwAddr, senderIp, targetIp);
94 }
95
TestStop(const uint8_t * data,size_t size)96 void TestStop(const uint8_t* data, size_t size)
97 {
98 (void)data;
99 (void)size;
100 pDhcpArpChecker->Stop();
101 }
102
TestSetArpPacket(const uint8_t * data,size_t size)103 void TestSetArpPacket(const uint8_t* data, size_t size)
104 {
105 ArpPacket arpPacket;
106 bool isFillSenderIp = (size >= 1) ? (data[0] != 0) : false;
107 pDhcpArpChecker->SetArpPacket(arpPacket, isFillSenderIp);
108 }
109
TestDoArpCheck(const uint8_t * data,size_t size)110 void TestDoArpCheck(const uint8_t* data, size_t size)
111 {
112 int32_t timeoutMillis = (size >= MIN_U32_SIZE) ? static_cast<int32_t>(U32_AT(data)) : DEFAULT_TIMEOUT_MILLIS;
113 bool isFillSenderIp = (size >= MIN_U32_SIZE + 1) ? (data[MIN_U32_SIZE] != 0) : false;
114 uint64_t timeCost = 0;
115 pDhcpArpChecker->DoArpCheck(timeoutMillis, isFillSenderIp, timeCost);
116 }
117
TestGetGwMacAddrList(const uint8_t * data,size_t size)118 void TestGetGwMacAddrList(const uint8_t* data, size_t size)
119 {
120 int32_t timeoutMillis = (size >= MIN_U32_SIZE) ? static_cast<int32_t>(U32_AT(data)) : DEFAULT_TIMEOUT_MILLIS;
121 bool isFillSenderIp = (size >= MIN_U32_SIZE + 1) ? (data[MIN_U32_SIZE] != 0) : false;
122 vector<string> gwMacLists;
123 pDhcpArpChecker->GetGwMacAddrList(timeoutMillis, isFillSenderIp, gwMacLists);
124 }
125
TestSaveGwMacAddr(const uint8_t * data,size_t size)126 void TestSaveGwMacAddr(const uint8_t* data, size_t size)
127 {
128 if (size < MIN_U32_SIZE) {
129 return;
130 }
131 size_t pos = 0;
132 uint32_t gwMacAddrLen = U32_AT(data);
133 pos += MIN_U32_SIZE;
134 if (pos + gwMacAddrLen > size) {
135 return;
136 }
137 string gwMacAddr(reinterpret_cast<const char*>(data + pos), gwMacAddrLen);
138 vector<string> gwMacLists;
139 pDhcpArpChecker->SaveGwMacAddr(gwMacAddr, gwMacLists);
140 }
141
TestCreateSocket(const uint8_t * data,size_t size)142 void TestCreateSocket(const uint8_t* data, size_t size)
143 {
144 if (size < MIN_U32_SIZE) {
145 return;
146 }
147 size_t pos = 0;
148 uint32_t ifaceLen = U32_AT(data);
149 pos += MIN_U32_SIZE;
150 if (pos + ifaceLen > size) {
151 return;
152 }
153 string iface(reinterpret_cast<const char*>(data + pos), ifaceLen);
154 uint16_t protocol = (size >= pos + MIN_U16_SIZE) ? static_cast<uint16_t>(U16_AT(data + pos)) : ETH_P_ARP;
155 pDhcpArpChecker->CreateSocket(iface.c_str(), protocol);
156 }
157
TestSendData(const uint8_t * data,size_t size)158 void TestSendData(const uint8_t* data, size_t size)
159 {
160 if (size < MIN_U32_SIZE) {
161 return;
162 }
163 size_t pos = 0;
164 uint32_t count = U32_AT(data);
165 pos += MIN_U32_SIZE;
166 if (pos + count > size) {
167 return;
168 }
169 uint8_t* buff = const_cast<uint8_t*>(data + pos);
170 pos += count;
171 uint8_t destHwaddr[MIN_ETH_ALEN] = {0};
172 if (pos + MIN_ETH_ALEN <= size) {
173 if (memcpy_s(destHwaddr, MIN_ETH_ALEN, data + pos, MIN_ETH_ALEN) != 0) {
174 return;
175 }
176 }
177 pDhcpArpChecker->SendData(buff, count, destHwaddr);
178 }
179
TestRecvData(const uint8_t * data,size_t size)180 void TestRecvData(const uint8_t* data, size_t size)
181 {
182 if (size < MIN_U32_SIZE) {
183 return;
184 }
185 size_t pos = 0;
186 uint32_t count = U32_AT(data);
187 pos += MIN_U32_SIZE;
188 if (pos + count > size) {
189 return;
190 }
191 uint8_t* buff = const_cast<uint8_t*>(data + pos);
192 pos += count;
193 int32_t timeoutMillis = (size >= pos + MIN_U32_SIZE) ?
194 static_cast<int32_t>(U32_AT(data + pos)) : DEFAULT_TIMEOUT_MILLIS;
195 pDhcpArpChecker->RecvData(buff, count, timeoutMillis);
196 }
197
TestCloseSocket(const uint8_t * data,size_t size)198 void TestCloseSocket(const uint8_t* data, size_t size)
199 {
200 (void)data;
201 (void)size;
202 pDhcpArpChecker->CloseSocket();
203 }
204
TestSetNonBlock(const uint8_t * data,size_t size)205 void TestSetNonBlock(const uint8_t* data, size_t size)
206 {
207 int32_t fd = (size >= MIN_U32_SIZE) ? static_cast<int32_t>(U32_AT(data)) : 0;
208 pDhcpArpChecker->SetNonBlock(fd);
209 }
210
211 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)212 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
213 {
214 if ((data == nullptr) || (size <= MIN_U32_SIZE)) {
215 return 0;
216 }
217
218 TestStart(data, size);
219 TestStop(data, size);
220 TestSetArpPacket(data, size);
221 TestDoArpCheck(data, size);
222 TestGetGwMacAddrList(data, size);
223 TestSaveGwMacAddr(data, size);
224 TestCreateSocket(data, size);
225 TestSendData(data, size);
226 TestRecvData(data, size);
227 TestCloseSocket(data, size);
228 TestSetNonBlock(data, size);
229
230 return 0;
231 }
232 } // namespace DHCP
233 } // namespace OHOS