Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2025 Google LLC |
2 | | // |
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 <cstring> |
17 | | #include <stddef.h> |
18 | | #include <stdint.h> |
19 | | #include <string.h> |
20 | | #include <stdlib.h> |
21 | | #include <algorithm> |
22 | | #include <vector> |
23 | | |
24 | | #include <fuzzer/FuzzedDataProvider.h> |
25 | | extern "C" { |
26 | | #include "mhd_str.h" |
27 | | #include "microhttpd2.h" |
28 | | } |
29 | | |
30 | 1.26k | static void fuzz_tokens(FuzzedDataProvider& fdp) { |
31 | | // Prepare random string for string comparison |
32 | 1.26k | std::string payload1 = fdp.ConsumeRandomLengthString(1024); |
33 | 1.26k | std::string payload2 = fdp.ConsumeRandomLengthString(1024); |
34 | 1.26k | std::string payload3 = fdp.ConsumeRandomLengthString(1024); |
35 | 1.26k | const char *payload_str1 = payload1.c_str(); |
36 | 1.26k | const char *payload_str2 = payload2.c_str(); |
37 | 1.26k | const char *payload_str3 = payload3.c_str(); |
38 | 1.26k | size_t payload_size1 = payload1.size(); |
39 | 1.26k | size_t payload_size2 = payload2.size(); |
40 | 1.26k | size_t payload_size3 = payload3.size(); |
41 | | |
42 | | // Fuzz mhd_str_equal_caseless |
43 | 1.26k | mhd_str_equal_caseless(payload_str1, payload_str2); |
44 | | |
45 | | // Fuzz mhd_str_equal_caseless_n |
46 | 1.26k | mhd_str_equal_caseless_n(payload_str1, payload_str2, fdp.ConsumeIntegral<size_t>()); |
47 | | |
48 | | // Fuzz mhd_str_equal_caseless_bin_n |
49 | 1.26k | const size_t min_len = std::min(payload_size1, payload_size2); |
50 | 1.26k | if (min_len) { |
51 | 323 | mhd_str_equal_caseless_bin_n(payload_str1, payload_str2, min_len); |
52 | 323 | } |
53 | | |
54 | | // Fuzz mhd_str_has_token_caseless |
55 | 1.26k | mhd_str_has_token_caseless(payload_str1, payload_str2, payload_size1); |
56 | 1.26k | mhd_str_has_token_caseless(payload_str1, payload_str2, payload_size2); |
57 | | |
58 | | // Fuzz mhd_str_remove_token_caseless |
59 | 1.26k | ssize_t out_sz = (ssize_t)fdp.ConsumeIntegralInRange<int>(1, 1024); |
60 | 1.26k | char *out_buf = (char*) malloc((size_t)out_sz); |
61 | 1.26k | mhd_str_remove_token_caseless(payload_str1, payload_size1, payload_str2, payload_size2, |
62 | 1.26k | out_buf, &out_sz); |
63 | 1.26k | free(out_buf); |
64 | | |
65 | | // Fuzz mhd_str_starts_with_token_opt_param |
66 | 1.26k | struct MHD_String mhd_str1 { |
67 | 1.26k | payload_size1, payload_str1 |
68 | 1.26k | }; |
69 | 1.26k | struct MHD_String mhd_str2 { |
70 | 1.26k | payload_size2, payload_str2 |
71 | 1.26k | }; |
72 | 1.26k | mhd_str_starts_with_token_opt_param(&mhd_str1, &mhd_str2); |
73 | | |
74 | | // Fuzz mhd_str_starts_with_token_req_param |
75 | 1.26k | bool needs_uni = fdp.ConsumeBool(); |
76 | 1.26k | struct MHD_String mhd_str3 { |
77 | 1.26k | payload_size3, payload_str3 |
78 | 1.26k | }; |
79 | 1.26k | struct mhd_BufferConst str3_buf { 0, nullptr }; |
80 | 1.26k | mhd_str_starts_with_token_req_param(&mhd_str1, &mhd_str2, &mhd_str3, &str3_buf, &needs_uni); |
81 | 1.26k | } |
82 | | |
83 | 1.19k | static void fuzz_conversion(FuzzedDataProvider& fdp) { |
84 | | // Prepare random string for string/int conversion |
85 | 1.19k | std::string payload = fdp.ConsumeRandomLengthString(1024); |
86 | 1.19k | const char *payload_str = payload.c_str(); |
87 | 1.19k | size_t payload_size = payload.size(); |
88 | | |
89 | 1.19k | uint_fast32_t u32 = 0; |
90 | 1.19k | uint_fast64_t u64 = 0; |
91 | 1.19k | char small[4], big[128]; |
92 | 1.19k | size_t max_len = fdp.ConsumeIntegralInRange<size_t>(0, payload_size); |
93 | | |
94 | | // Fuzz conversion between string and uint64 with random payload |
95 | 1.19k | mhd_str_to_uint64(payload_str, &u64); |
96 | 1.19k | mhd_str_to_uint64_n(payload_str, max_len, &u64); |
97 | 1.19k | mhd_strx_to_uint64(payload_str, &u64); |
98 | 1.19k | mhd_strx_to_uint64_n(payload_str, max_len, &u64); |
99 | 1.19k | mhd_uint64_to_str((uint_fast64_t)fdp.ConsumeIntegral<uint64_t>(), small, sizeof(small)); |
100 | 1.19k | mhd_uint64_to_str((uint_fast64_t)fdp.ConsumeIntegral<uint64_t>(), big, sizeof(big)); |
101 | | |
102 | | // Fuzz string to uint32 conversion with random payload string |
103 | 1.19k | mhd_strx_to_uint32(payload_str, &u32); |
104 | 1.19k | mhd_strx_to_uint32_n(payload_str, max_len, &u32); |
105 | | |
106 | | // Fuzz uint16 to string conversion with random payload |
107 | 1.19k | mhd_uint16_to_str((uint_least16_t)fdp.ConsumeIntegralInRange<unsigned>(0, 65535), small, sizeof(small)); |
108 | 1.19k | mhd_uint16_to_str((uint_least16_t)fdp.ConsumeIntegralInRange<unsigned>(0, 65535), big, sizeof(big)); |
109 | 1.19k | } |
110 | | |
111 | 215 | static void fuzz_decode(FuzzedDataProvider& fdp) { |
112 | | // Prepare random data for string decode |
113 | 215 | bool ignored = false; |
114 | 215 | std::string payload = fdp.ConsumeRandomLengthString(1024); |
115 | 215 | char *payload_str = payload.data(); |
116 | 215 | size_t payload_size = payload.size(); |
117 | | |
118 | | // Fuzz decode functions with random payload |
119 | 215 | char *out1 = (char*) malloc(payload_size); |
120 | 215 | char *out2 = (char*) malloc(payload_size); |
121 | 215 | if (out1) { |
122 | 215 | mhd_str_pct_decode_strict_n(payload_str, payload_size, out1, payload_size); |
123 | 215 | } |
124 | 215 | if (out2) { |
125 | 215 | mhd_str_pct_decode_lenient_n(payload_str, payload_size, out2, payload_size, &ignored); |
126 | 215 | } |
127 | | |
128 | | // Fuzz decode in place functions with random payload |
129 | 215 | mhd_str_pct_decode_in_place_strict(payload_str); |
130 | 215 | mhd_str_pct_decode_in_place_lenient(payload_str, &ignored); |
131 | | |
132 | 215 | free(out1); |
133 | 215 | free(out2); |
134 | 215 | } |
135 | | |
136 | 200 | static void fuzz_quoted(FuzzedDataProvider& fdp) { |
137 | | // Prepare random data for quote and equality check |
138 | 200 | std::string payload1 = fdp.ConsumeRandomLengthString(1024); |
139 | 200 | std::string payload2 = fdp.ConsumeRandomLengthString(1024); |
140 | 200 | const char *payload_str1 = payload1.c_str(); |
141 | 200 | const char *payload_str2 = payload2.c_str(); |
142 | 200 | size_t payload_size1 = payload1.size(); |
143 | 200 | size_t payload_size2 = payload2.size(); |
144 | | |
145 | | // Fuzz mhd_str_equal_quoted_bin_n with random string payload as binary |
146 | 200 | mhd_str_equal_quoted_bin_n(payload_str1, payload_size1, payload_str2, payload_size2); |
147 | | |
148 | | // Fuzz mhd_str_quote and mhd_str_unquote with random string payload |
149 | 200 | size_t max_out = payload_size1 * 2; |
150 | 200 | char *out = (char*) malloc(max_out); |
151 | 200 | if (out) { |
152 | 200 | mhd_str_quote(payload_str1, payload_size1, out, max_out); |
153 | 200 | mhd_str_unquote(payload_str1, payload_size1, out); |
154 | 200 | } |
155 | 200 | free(out); |
156 | | |
157 | 200 | max_out = payload_size2 * 2; |
158 | 200 | out = (char*) malloc(max_out); |
159 | 200 | if (out) { |
160 | 200 | mhd_str_quote(payload_str2, payload_size2, out, max_out); |
161 | 200 | mhd_str_unquote(payload_str2, payload_size2, out); |
162 | 200 | } |
163 | 200 | free(out); |
164 | 200 | } |
165 | | |
166 | 138 | static void fuzz_base64(FuzzedDataProvider& fdp) { |
167 | | // Prepare random data for base64 conversion |
168 | 138 | std::string payload = fdp.ConsumeRandomLengthString(1024); |
169 | 138 | char *payload_str = payload.data(); |
170 | 138 | size_t payload_size = payload.size(); |
171 | | |
172 | | // Prepare a valid base64 string from random payload |
173 | 138 | static const char valid_chars[] = |
174 | 138 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
175 | 21.6k | for (size_t i = 0; i < payload_size; i++) { |
176 | 21.5k | payload_str[i] = valid_chars[((uint8_t)i) % 64]; |
177 | 21.5k | } |
178 | | |
179 | | // Fuzz mhd_base64_to_bin_n with the random base64 string |
180 | 138 | size_t max_out = (payload.size() / 4) * 4; |
181 | 138 | uint8_t* out = (uint8_t*) malloc(payload_size); |
182 | 138 | if (out) { |
183 | 138 | mhd_base64_to_bin_n(payload_str, payload_size, out, max_out); |
184 | 138 | free(out); |
185 | 138 | } |
186 | 138 | } |
187 | | |
188 | 153 | static void fuzz_transformation(FuzzedDataProvider& fdp) { |
189 | | // Fuzz targets in multiple rounds |
190 | 709 | for (int i = 0; i < fdp.ConsumeIntegralInRange<unsigned>(1, 8); i++) { |
191 | | // Generate random integer |
192 | 556 | int value = fdp.ConsumeIntegral<int>(); |
193 | | |
194 | | // Fuzz conversion functions |
195 | 556 | MHD_http_method_to_string(static_cast<MHD_HTTP_Method>(value)); |
196 | 556 | MHD_predef_header_to_string(static_cast<MHD_PredefinedHeader>(value)); |
197 | 556 | MHD_protocol_version_to_string(static_cast<MHD_HTTP_ProtocolVersion>(value)); |
198 | 556 | } |
199 | 153 | } |
200 | | |
201 | 124 | static void fuzz_hex_conversion(FuzzedDataProvider& fdp) { |
202 | | // Prepare random data for hex conversion |
203 | 124 | std::string payload = fdp.ConsumeRandomLengthString(1024); |
204 | 124 | char *payload_str = payload.data(); |
205 | 124 | size_t payload_size = payload.size(); |
206 | | |
207 | | // Fuzz mhd_hex_to_bin with random payload |
208 | 124 | uint8_t *bin_out = (uint8_t*) malloc(payload_size); |
209 | 124 | if (bin_out) { |
210 | 124 | mhd_hex_to_bin(payload_str, payload_size, bin_out); |
211 | 124 | free(bin_out); |
212 | 124 | } |
213 | | |
214 | | // Fuzz mhd_bin_to_hex with random payload |
215 | 124 | char *hex_out = (char *) malloc(payload_size * 2); |
216 | 124 | if (hex_out) { |
217 | 124 | if (!payload.empty()) { |
218 | 111 | mhd_bin_to_hex(payload_str, payload_size, hex_out); |
219 | 111 | } |
220 | 124 | free(hex_out); |
221 | 124 | } |
222 | | |
223 | 124 | char *hexz_out = (char *) malloc(payload_size * 2 + 1); |
224 | 124 | if (hexz_out) { |
225 | 124 | if (!payload.empty()) { |
226 | 111 | mhd_bin_to_hex(payload_str, payload_size, hexz_out); |
227 | 111 | } |
228 | 124 | free(hexz_out); |
229 | 124 | } |
230 | 124 | } |
231 | | |
232 | 2.35k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
233 | 2.35k | FuzzedDataProvider fdp(data, size); |
234 | | |
235 | 5.72k | for (int i = 0; i < fdp.ConsumeIntegralInRange<unsigned>(1, 6); i++) { |
236 | 3.36k | switch (fdp.ConsumeIntegralInRange<int>(0, 7)) { |
237 | 1.26k | case 0: fuzz_tokens(fdp); break; |
238 | 1.19k | case 1: fuzz_conversion(fdp); break; |
239 | 215 | case 2: fuzz_decode(fdp); break; |
240 | 200 | case 3: fuzz_quoted(fdp); break; |
241 | 138 | case 4: fuzz_base64(fdp); break; |
242 | 153 | case 5: fuzz_transformation(fdp); break; |
243 | 124 | case 6: fuzz_hex_conversion(fdp); break; |
244 | 3.36k | } |
245 | 3.36k | } |
246 | 2.35k | return 0; |
247 | 2.35k | } |