/src/coturn/fuzzing/FuzzStunClient.c
Line | Count | Source |
1 | | /* |
2 | | * SPDX-License-Identifier: BSD-3-Clause |
3 | | * |
4 | | * https://opensource.org/license/bsd-3-clause |
5 | | * |
6 | | * Multi-harness libFuzzer entry point for client-side STUN parsing, |
7 | | * TCP framing, and address codec. |
8 | | * |
9 | | * Every iteration runs all sub-harnesses in sequence on the same input. |
10 | | * Keeping everything behind a single binary allows the upstream OSS-Fuzz |
11 | | * build recipe (which only copies FuzzStun and FuzzStunClient) to stay |
12 | | * unchanged. |
13 | | */ |
14 | | |
15 | | #include <stdbool.h> |
16 | | #include <stdint.h> |
17 | | #include <string.h> |
18 | | |
19 | | #include "apputils.h" |
20 | | #include "ns_turn_msg.h" |
21 | | #include "ns_turn_msg_addr.h" |
22 | | #include "ns_turn_msg_defs.h" |
23 | | #include "ns_turn_utils.h" |
24 | | #include "stun_buffer.h" |
25 | | |
26 | 133k | static uint8_t fuzz_byte(const uint8_t *Data, size_t Size, size_t idx) { return Size ? Data[idx % Size] : 0; } |
27 | | |
28 | 14.2k | static uint16_t fuzz_u16(const uint8_t *Data, size_t Size, size_t idx) { |
29 | 14.2k | return (uint16_t)(((uint16_t)fuzz_byte(Data, Size, idx) << 8) | (uint16_t)fuzz_byte(Data, Size, idx + 1)); |
30 | 14.2k | } |
31 | | |
32 | 4.68k | static uint32_t fuzz_u32(const uint8_t *Data, size_t Size, size_t idx) { |
33 | 4.68k | return ((uint32_t)fuzz_u16(Data, Size, idx) << 16) | (uint32_t)fuzz_u16(Data, Size, idx + 2); |
34 | 4.68k | } |
35 | | |
36 | 574 | static uint64_t fuzz_u64(const uint8_t *Data, size_t Size, size_t idx) { |
37 | 574 | return ((uint64_t)fuzz_u32(Data, Size, idx) << 32) | (uint64_t)fuzz_u32(Data, Size, idx + 4); |
38 | 574 | } |
39 | | |
40 | 6.59k | static bool fuzz_flag(const uint8_t *Data, size_t Size, size_t idx) { return (fuzz_byte(Data, Size, idx) & 1u) != 0; } |
41 | | |
42 | 1.72k | static void fuzz_string(const uint8_t *Data, size_t Size, size_t idx, char *out, size_t out_size) { |
43 | 1.72k | if (!out || !out_size) { |
44 | 0 | return; |
45 | 0 | } |
46 | | |
47 | 1.72k | const size_t max_len = out_size - 1; |
48 | 1.72k | const size_t len = max_len ? (size_t)(fuzz_byte(Data, Size, idx) % (max_len + 1)) : 0; |
49 | | |
50 | 55.6k | for (size_t i = 0; i < len; ++i) { |
51 | 53.9k | out[i] = (char)('A' + (fuzz_byte(Data, Size, idx + 1 + i) % 26)); |
52 | 53.9k | } |
53 | | |
54 | 1.72k | out[len] = '\0'; |
55 | 1.72k | } |
56 | | |
57 | 861 | static void fuzz_tid(const uint8_t *Data, size_t Size, size_t idx, stun_tid *tid) { |
58 | 861 | if (!tid) { |
59 | 0 | return; |
60 | 0 | } |
61 | | |
62 | 861 | memset(tid, 0, sizeof(*tid)); |
63 | 11.1k | for (size_t i = 0; i < STUN_TID_SIZE; ++i) { |
64 | 10.3k | tid->tsx_id[i] = fuzz_byte(Data, Size, idx + i); |
65 | 10.3k | } |
66 | 861 | } |
67 | | |
68 | 3.72k | static void fuzz_addr(const uint8_t *Data, size_t Size, size_t idx, ioa_addr *addr) { |
69 | 3.72k | if (!addr) { |
70 | 0 | return; |
71 | 0 | } |
72 | | |
73 | 3.72k | memset(addr, 0, sizeof(*addr)); |
74 | | |
75 | 3.72k | if (fuzz_flag(Data, Size, idx)) { |
76 | 1.91k | addr->s6.sin6_family = AF_INET6; |
77 | 1.91k | addr->s6.sin6_port = htons(fuzz_u16(Data, Size, idx + 1)); |
78 | 32.5k | for (size_t i = 0; i < 16; ++i) { |
79 | 30.6k | addr->s6.sin6_addr.s6_addr[i] = fuzz_byte(Data, Size, idx + 3 + i); |
80 | 30.6k | } |
81 | 1.91k | if (!memcmp(addr->s6.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) { |
82 | 3 | addr->s6.sin6_addr.s6_addr[15] = 1; |
83 | 3 | } |
84 | 1.91k | } else { |
85 | 1.81k | addr->s4.sin_family = AF_INET; |
86 | 1.81k | addr->s4.sin_port = htons(fuzz_u16(Data, Size, idx + 1)); |
87 | 1.81k | addr->s4.sin_addr.s_addr = htonl(fuzz_u32(Data, Size, idx + 3) | 1u); |
88 | 1.81k | } |
89 | 3.72k | } |
90 | | |
91 | 7.17k | static void inspect_buffer_message(stun_buffer *msg, uint16_t addr_attr_type, const ioa_addr *default_addr) { |
92 | 7.17k | if (!msg) { |
93 | 0 | return; |
94 | 0 | } |
95 | | |
96 | 7.17k | (void)stun_get_command_message_len(msg); |
97 | 7.17k | (void)stun_is_command_message(msg); |
98 | 7.17k | (void)stun_is_request(msg); |
99 | 7.17k | (void)stun_is_response(msg); |
100 | 7.17k | (void)stun_is_success_response(msg); |
101 | 7.17k | (void)stun_is_binding_response(msg); |
102 | 7.17k | (void)stun_get_method(msg); |
103 | 7.17k | (void)stun_get_msg_type(msg); |
104 | | |
105 | 7.17k | { |
106 | 7.17k | int err_code = 0; |
107 | 7.17k | uint8_t err_msg[256] = {0}; |
108 | 7.17k | (void)stun_is_error_response(msg, &err_code, err_msg, sizeof(err_msg)); |
109 | 7.17k | } |
110 | | |
111 | 7.17k | { |
112 | 7.17k | ioa_addr parsed = {0}; |
113 | 7.17k | (void)stun_attr_get_first_addr(msg, addr_attr_type, &parsed, default_addr); |
114 | 7.17k | } |
115 | | |
116 | 7.17k | { |
117 | 7.17k | stun_attr_ref attr = stun_attr_get_first(msg); |
118 | 19.7k | while (attr) { |
119 | 12.6k | (void)stun_attr_get_type(attr); |
120 | 12.6k | (void)stun_attr_get_len(attr); |
121 | 12.6k | if (stun_attr_is_addr(attr)) { |
122 | 4.11k | ioa_addr parsed = {0}; |
123 | 4.11k | (void)stun_attr_get_addr(msg, attr, &parsed, default_addr); |
124 | 4.11k | } |
125 | 12.6k | attr = stun_attr_get_next(msg, attr); |
126 | 12.6k | } |
127 | 7.17k | } |
128 | | |
129 | 7.17k | (void)stun_attr_get_first_channel_number(msg); |
130 | 7.17k | } |
131 | | |
132 | 6.02k | static void inspect_raw_message(const uint8_t *buf, size_t len, uint16_t addr_attr_type, const ioa_addr *default_addr) { |
133 | 6.02k | if (!buf || !len) { |
134 | 0 | return; |
135 | 0 | } |
136 | | |
137 | 6.02k | (void)stun_is_command_message_str((uint8_t *)buf, len); |
138 | 6.02k | (void)stun_is_request_str(buf, len); |
139 | 6.02k | (void)stun_is_response_str(buf, len); |
140 | 6.02k | (void)stun_is_success_response_str(buf, len); |
141 | 6.02k | (void)stun_is_binding_response_str(buf, len); |
142 | 6.02k | (void)stun_get_method_str(buf, len); |
143 | 6.02k | (void)stun_get_msg_type_str(buf, len); |
144 | | |
145 | 6.02k | { |
146 | 6.02k | int err_code = 0; |
147 | 6.02k | uint8_t err_msg[256] = {0}; |
148 | 6.02k | (void)stun_is_error_response_str(buf, len, &err_code, err_msg, sizeof(err_msg)); |
149 | 6.02k | } |
150 | | |
151 | 6.02k | { |
152 | 6.02k | ioa_addr parsed = {0}; |
153 | 6.02k | (void)stun_attr_get_first_addr_str(buf, len, addr_attr_type, &parsed, default_addr); |
154 | 6.02k | } |
155 | | |
156 | 6.02k | { |
157 | 6.02k | stun_attr_ref attr = stun_attr_get_first_str(buf, len); |
158 | 15.6k | while (attr) { |
159 | 9.66k | (void)stun_attr_get_type(attr); |
160 | 9.66k | (void)stun_attr_get_len(attr); |
161 | 9.66k | if (stun_attr_is_addr(attr)) { |
162 | 4.30k | ioa_addr parsed = {0}; |
163 | 4.30k | (void)stun_attr_get_addr_str(buf, len, attr, &parsed, default_addr); |
164 | 4.30k | } |
165 | 9.66k | attr = stun_attr_get_next_str(buf, len, attr); |
166 | 9.66k | } |
167 | 6.02k | } |
168 | | |
169 | 6.02k | (void)stun_attr_get_first_channel_number_str(buf, len); |
170 | 6.02k | } |
171 | | |
172 | | /* ------------------------------------------------------------------ */ |
173 | | /* Raw-input coverage for stun_attr_get_first_addr. */ |
174 | | /* */ |
175 | | /* The inspect_buffer_message() path only sees messages produced by */ |
176 | | /* the project's own serializers, which are always well-formed. This */ |
177 | | /* harness feeds arbitrary fuzzer input through the stun_buffer */ |
178 | | /* wrapper (not just the _str variant) for every address attribute */ |
179 | | /* type, with both NULL and a fuzzed default_addr fallback. */ |
180 | | /* ------------------------------------------------------------------ */ |
181 | | static const uint16_t kFirstAddrAttrs[] = { |
182 | | STUN_ATTRIBUTE_MAPPED_ADDRESS, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, OLD_STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, |
183 | | STUN_ATTRIBUTE_XOR_PEER_ADDRESS, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, STUN_ATTRIBUTE_ALTERNATE_SERVER, |
184 | | STUN_ATTRIBUTE_RESPONSE_ORIGIN, STUN_ATTRIBUTE_OTHER_ADDRESS, |
185 | | }; |
186 | | |
187 | 318 | static void harness_attr_get_first_addr(const uint8_t *Data, size_t Size) { |
188 | 318 | if (Size < STUN_HEADER_LENGTH || Size > 5120) { |
189 | 34 | return; |
190 | 34 | } |
191 | | |
192 | 284 | stun_buffer msg; |
193 | 284 | msg.len = Size; |
194 | 284 | memcpy(msg.buf, Data, Size); |
195 | | |
196 | 284 | ioa_addr default_addr = {0}; |
197 | 284 | fuzz_addr(Data, Size, 0, &default_addr); |
198 | | |
199 | 284 | const size_t num_attrs = sizeof(kFirstAddrAttrs) / sizeof(kFirstAddrAttrs[0]); |
200 | 2.55k | for (size_t i = 0; i < num_attrs; ++i) { |
201 | 2.27k | ioa_addr parsed = {0}; |
202 | 2.27k | (void)stun_attr_get_first_addr(&msg, kFirstAddrAttrs[i], &parsed, NULL); |
203 | | |
204 | 2.27k | memset(&parsed, 0, sizeof(parsed)); |
205 | 2.27k | (void)stun_attr_get_first_addr(&msg, kFirstAddrAttrs[i], &parsed, &default_addr); |
206 | 2.27k | } |
207 | 284 | } |
208 | | |
209 | | /* ------------------------------------------------------------------ */ |
210 | | /* stun_buffer-based client message parsing (original FuzzStunClient). */ |
211 | | /* ------------------------------------------------------------------ */ |
212 | 318 | static void harness_stun_client(const uint8_t *Data, size_t Size) { |
213 | 318 | if (Size < 10 || Size > 5120) { |
214 | 25 | return; |
215 | 25 | } |
216 | | |
217 | 293 | stun_buffer buf; |
218 | 293 | buf.len = Size; |
219 | 293 | memcpy(buf.buf, Data, buf.len); |
220 | | |
221 | 293 | if (!stun_is_command_message(&buf)) { |
222 | 155 | return; |
223 | 155 | } |
224 | | |
225 | 138 | (void)stun_get_method_str(buf.buf, buf.len); |
226 | 138 | (void)stun_get_msg_type_str(buf.buf, buf.len); |
227 | | |
228 | 138 | if (stun_is_response(&buf) && stun_is_success_response(&buf) && stun_is_binding_response(&buf)) { |
229 | 19 | return; |
230 | 19 | } |
231 | | |
232 | 119 | stun_is_indication_str(buf.buf, buf.len); |
233 | | |
234 | 119 | int err_code = 0; |
235 | 119 | uint8_t err_msg[256] = {0}; |
236 | 119 | stun_is_error_response_str(buf.buf, buf.len, &err_code, err_msg, sizeof(err_msg)); |
237 | 119 | } |
238 | | |
239 | | /* ------------------------------------------------------------------ */ |
240 | | /* ChannelData / TCP framing (FuzzChannelData). */ |
241 | | /* ------------------------------------------------------------------ */ |
242 | 318 | static void harness_channel_data(const uint8_t *Data, size_t Size) { |
243 | 318 | if (Size < 4 || Size > 8192) { |
244 | 20 | return; |
245 | 20 | } |
246 | | |
247 | 298 | uint8_t buf[8192] = {0}; |
248 | 298 | memcpy(buf, Data, Size); |
249 | | |
250 | 298 | size_t app_len_tcp = 0; |
251 | 298 | size_t app_len_udp = 0; |
252 | | |
253 | 298 | int mlen_tcp = stun_get_message_len_str(buf, Size, 1, &app_len_tcp); |
254 | 298 | int mlen_udp = stun_get_message_len_str(buf, Size, 0, &app_len_udp); |
255 | | |
256 | 298 | if (mlen_tcp > 0) { |
257 | 168 | if (app_len_tcp > Size) { |
258 | 0 | __builtin_trap(); |
259 | 0 | } |
260 | 168 | if ((size_t)mlen_tcp > Size) { |
261 | 0 | __builtin_trap(); |
262 | 0 | } |
263 | 168 | if ((size_t)mlen_tcp < app_len_tcp) { |
264 | 0 | __builtin_trap(); |
265 | 0 | } |
266 | 168 | } |
267 | | |
268 | 298 | if (mlen_udp > 0) { |
269 | 168 | if (app_len_udp > Size) { |
270 | 0 | __builtin_trap(); |
271 | 0 | } |
272 | 168 | if ((size_t)mlen_udp > Size) { |
273 | 0 | __builtin_trap(); |
274 | 0 | } |
275 | 168 | } |
276 | | |
277 | 298 | size_t blen_tcp = Size; |
278 | 298 | uint16_t chn_tcp = 0; |
279 | 298 | bool is_chan_tcp = stun_is_channel_message_str(buf, &blen_tcp, &chn_tcp, true); |
280 | | |
281 | 298 | size_t blen_udp = Size; |
282 | 298 | uint16_t chn_udp = 0; |
283 | 298 | bool is_chan_udp = stun_is_channel_message_str(buf, &blen_udp, &chn_udp, false); |
284 | | |
285 | 298 | if (is_chan_tcp && (blen_tcp < 4 || blen_tcp > Size)) { |
286 | 0 | __builtin_trap(); |
287 | 0 | } |
288 | 298 | if (is_chan_udp && (blen_udp < 4 || blen_udp > Size)) { |
289 | 0 | __builtin_trap(); |
290 | 0 | } |
291 | 298 | } |
292 | | |
293 | | /* ------------------------------------------------------------------ */ |
294 | | /* STUN address encode/decode (FuzzStunAddrCodec). */ |
295 | | /* ------------------------------------------------------------------ */ |
296 | 318 | static void harness_addr_codec(const uint8_t *Data, size_t Size) { |
297 | 318 | if (Size < 2 || Size > 64) { |
298 | 107 | return; |
299 | 107 | } |
300 | | |
301 | 211 | uint8_t tid[STUN_TID_SIZE] = {0}; |
302 | 211 | size_t tid_bytes = Size > (STUN_TID_SIZE + 2) ? STUN_TID_SIZE : (Size > 2 ? Size - 2 : 0); |
303 | 211 | memcpy(tid, Data, tid_bytes); |
304 | 211 | const uint8_t *payload = Data + tid_bytes; |
305 | 211 | int payload_len = (int)(Size - tid_bytes); |
306 | | |
307 | 211 | ioa_addr addr = {0}; |
308 | | |
309 | | /* XOR decode + round-trip */ |
310 | 211 | if (stun_addr_decode(&addr, payload, payload_len, 1, STUN_MAGIC_COOKIE, tid) == 0) { |
311 | 1 | uint8_t enc_buf[32] = {0}; |
312 | 1 | int enc_len = 0; |
313 | 1 | if (stun_addr_encode(&addr, enc_buf, &enc_len, 1, STUN_MAGIC_COOKIE, tid) == 0) { |
314 | 1 | ioa_addr addr2 = {0}; |
315 | 1 | stun_addr_decode(&addr2, enc_buf, enc_len, 1, STUN_MAGIC_COOKIE, tid); |
316 | 1 | } |
317 | 1 | } |
318 | | |
319 | | /* Plain decode + round-trip */ |
320 | 211 | memset(&addr, 0, sizeof(addr)); |
321 | 211 | if (stun_addr_decode(&addr, payload, payload_len, 0, 0, tid) == 0) { |
322 | 1 | uint8_t enc_buf[32] = {0}; |
323 | 1 | int enc_len = 0; |
324 | 1 | if (stun_addr_encode(&addr, enc_buf, &enc_len, 0, 0, tid) == 0) { |
325 | 1 | ioa_addr addr2 = {0}; |
326 | 1 | stun_addr_decode(&addr2, enc_buf, enc_len, 0, 0, tid); |
327 | 1 | } |
328 | 1 | } |
329 | | |
330 | | /* Alternate magic cookie (old STUN) */ |
331 | 211 | memset(&addr, 0, sizeof(addr)); |
332 | 211 | uint32_t alt_cookie = 0; |
333 | 211 | if (Size >= 4) { |
334 | 209 | memcpy(&alt_cookie, Data, 4); |
335 | 209 | } |
336 | 211 | (void)stun_addr_decode(&addr, payload, payload_len, 1, alt_cookie, tid); |
337 | 211 | } |
338 | | |
339 | | /* ------------------------------------------------------------------ */ |
340 | | /* Message builders / wrappers / round-trip parsing. */ |
341 | | /* ------------------------------------------------------------------ */ |
342 | 318 | static void harness_message_builders(const uint8_t *Data, size_t Size) { |
343 | 318 | if (!Size || Size > 4096) { |
344 | 31 | return; |
345 | 31 | } |
346 | | |
347 | 287 | static const uint16_t kMethods[] = { |
348 | 287 | STUN_METHOD_ALLOCATE, STUN_METHOD_BINDING, STUN_METHOD_CHANNEL_BIND, STUN_METHOD_REFRESH, STUN_METHOD_CONNECT, |
349 | 287 | }; |
350 | 287 | static const uint16_t kErrorCodes[] = { |
351 | 287 | 300, 400, 401, 403, 420, 437, 438, 440, 441, 442, 443, 446, 447, 486, 487, 500, 508, 699, |
352 | 287 | }; |
353 | | |
354 | 287 | stun_tid tid = {0}; |
355 | 287 | ioa_addr relay1 = {0}; |
356 | 287 | ioa_addr relay2 = {0}; |
357 | 287 | ioa_addr reflexive = {0}; |
358 | 287 | ioa_addr peer = {0}; |
359 | 287 | ioa_addr default_addr = {0}; |
360 | 287 | char reason[96] = {0}; |
361 | 287 | char mobile_id[96] = {0}; |
362 | 287 | uint8_t raw[MAX_STUN_MESSAGE_SIZE] = {0}; |
363 | | |
364 | 287 | fuzz_tid(Data, Size, 0, &tid); |
365 | 287 | fuzz_addr(Data, Size, 16, &relay1); |
366 | 287 | fuzz_addr(Data, Size, 40, &relay2); |
367 | 287 | fuzz_addr(Data, Size, 64, &reflexive); |
368 | 287 | fuzz_addr(Data, Size, 88, &peer); |
369 | 287 | fuzz_addr(Data, Size, 112, &default_addr); |
370 | 287 | fuzz_string(Data, Size, 136, reason, sizeof(reason)); |
371 | 287 | fuzz_string(Data, Size, 232, mobile_id, sizeof(mobile_id)); |
372 | | |
373 | 287 | const uint16_t method = kMethods[fuzz_byte(Data, Size, 328) % (sizeof(kMethods) / sizeof(kMethods[0]))]; |
374 | 287 | const uint16_t error_code = kErrorCodes[fuzz_byte(Data, Size, 329) % (sizeof(kErrorCodes) / sizeof(kErrorCodes[0]))]; |
375 | 287 | const uint32_t lifetime = fuzz_u32(Data, Size, 330); |
376 | 287 | const uint32_t max_lifetime = fuzz_u32(Data, Size, 334); |
377 | 287 | const uint64_t reservation_token = fuzz_u64(Data, Size, 338); |
378 | 287 | const uint16_t channel_number = fuzz_u16(Data, Size, 346); |
379 | 287 | const bool include_reason = fuzz_flag(Data, Size, 348); |
380 | 287 | const bool old_stun = fuzz_flag(Data, Size, 349); |
381 | 287 | const bool stun_backward_compatibility = fuzz_flag(Data, Size, 350); |
382 | 287 | const uint32_t old_cookie = fuzz_u32(Data, Size, 351); |
383 | | |
384 | | /* Direct wrapper coverage for stun_init_error_response(). */ |
385 | 287 | { |
386 | 287 | stun_buffer msg; |
387 | 287 | stun_init_buffer(&msg); |
388 | 287 | stun_init_error_response(method, &msg, error_code, reason[0] ? (const uint8_t *)reason : NULL, &tid, |
389 | 287 | include_reason); |
390 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
391 | 287 | } |
392 | | |
393 | | /* Success allocate response covers addr extraction; error allocate response |
394 | | * forces the shared error builder path. */ |
395 | 287 | { |
396 | 287 | stun_buffer msg; |
397 | 287 | stun_init_buffer(&msg); |
398 | 287 | (void)stun_set_allocate_response(&msg, &tid, &relay1, fuzz_flag(Data, Size, 355) ? &relay2 : NULL, &reflexive, |
399 | 287 | lifetime, max_lifetime, 0, (const uint8_t *)reason, reservation_token, mobile_id, |
400 | 287 | include_reason); |
401 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
402 | | |
403 | 287 | size_t raw_len = sizeof(raw); |
404 | 287 | (void)stun_set_allocate_response_str(raw, &raw_len, &tid, &relay1, &relay2, &reflexive, lifetime, max_lifetime, 0, |
405 | 287 | (const uint8_t *)reason, reservation_token, mobile_id, include_reason); |
406 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
407 | | |
408 | 287 | stun_init_buffer(&msg); |
409 | 287 | (void)stun_set_allocate_response(&msg, &tid, NULL, NULL, NULL, lifetime, max_lifetime, error_code, |
410 | 287 | reason[0] ? (const uint8_t *)reason : NULL, reservation_token, mobile_id, |
411 | 287 | include_reason); |
412 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
413 | | |
414 | 287 | raw_len = sizeof(raw); |
415 | 287 | (void)stun_set_allocate_response_str(raw, &raw_len, &tid, NULL, NULL, NULL, lifetime, max_lifetime, error_code, |
416 | 287 | reason[0] ? (const uint8_t *)reason : NULL, reservation_token, mobile_id, |
417 | 287 | include_reason); |
418 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
419 | 287 | } |
420 | | |
421 | 287 | { |
422 | 287 | stun_buffer msg; |
423 | 287 | stun_init_buffer(&msg); |
424 | 287 | (void)stun_set_binding_response(&msg, &tid, &reflexive, 0, (const uint8_t *)reason, include_reason); |
425 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &default_addr); |
426 | | |
427 | 287 | size_t raw_len = sizeof(raw); |
428 | 287 | (void)stun_set_binding_response_str(raw, &raw_len, &tid, &reflexive, 0, (const uint8_t *)reason, old_cookie, |
429 | 287 | old_stun, stun_backward_compatibility, include_reason); |
430 | 287 | inspect_raw_message(raw, raw_len, old_stun ? STUN_ATTRIBUTE_MAPPED_ADDRESS : STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, |
431 | 287 | &default_addr); |
432 | | |
433 | 287 | stun_init_buffer(&msg); |
434 | 287 | (void)stun_set_binding_response(&msg, &tid, NULL, error_code, reason[0] ? (const uint8_t *)reason : NULL, |
435 | 287 | include_reason); |
436 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
437 | | |
438 | 287 | raw_len = sizeof(raw); |
439 | 287 | (void)stun_set_binding_response_str(raw, &raw_len, &tid, NULL, error_code, |
440 | 287 | reason[0] ? (const uint8_t *)reason : NULL, old_cookie, old_stun, |
441 | 287 | stun_backward_compatibility, include_reason); |
442 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
443 | 287 | } |
444 | | |
445 | 287 | { |
446 | 287 | stun_buffer msg; |
447 | 287 | stun_init_buffer(&msg); |
448 | 287 | (void)stun_set_channel_bind_request(&msg, fuzz_flag(Data, Size, 356) ? &peer : NULL, channel_number); |
449 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
450 | | |
451 | 287 | size_t raw_len = sizeof(raw); |
452 | 287 | (void)stun_set_channel_bind_request_str(raw, &raw_len, fuzz_flag(Data, Size, 357) ? &peer : NULL, channel_number); |
453 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
454 | | |
455 | 287 | stun_init_buffer(&msg); |
456 | 287 | stun_set_channel_bind_response(&msg, &tid, 0, (const uint8_t *)reason, include_reason); |
457 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
458 | | |
459 | 287 | raw_len = sizeof(raw); |
460 | 287 | stun_set_channel_bind_response_str(raw, &raw_len, &tid, error_code, reason[0] ? (const uint8_t *)reason : NULL, |
461 | 287 | include_reason); |
462 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
463 | 287 | } |
464 | 287 | } |
465 | | |
466 | | /* ------------------------------------------------------------------ */ |
467 | | /* Deterministic branch coverage for the response builders. */ |
468 | | /* */ |
469 | | /* harness_message_builders randomizes include_reason/old_stun/NULL- */ |
470 | | /* vs-present selectors from single input bytes, so any one iteration */ |
471 | | /* only visits a fraction of the branches inside these builders. This */ |
472 | | /* harness hits every branch point of each listed builder on every */ |
473 | | /* iteration so coverage is not gated on libFuzzer finding the right */ |
474 | | /* bytes. Inputs (tid / addrs / strings / numeric fields) are still */ |
475 | | /* fuzz-derived to keep each call meaningfully distinct. */ |
476 | | /* ------------------------------------------------------------------ */ |
477 | 318 | static void harness_response_matrix(const uint8_t *Data, size_t Size) { |
478 | 318 | if (!Size || Size > 4096) { |
479 | 31 | return; |
480 | 31 | } |
481 | | |
482 | 287 | stun_tid tid = {0}; |
483 | 287 | ioa_addr relay1 = {0}; |
484 | 287 | ioa_addr relay2 = {0}; |
485 | 287 | ioa_addr reflexive = {0}; |
486 | 287 | ioa_addr peer = {0}; |
487 | 287 | ioa_addr default_addr = {0}; |
488 | 287 | char reason[96] = {0}; |
489 | 287 | char mobile_id[96] = {0}; |
490 | 287 | uint8_t raw[MAX_STUN_MESSAGE_SIZE] = {0}; |
491 | | |
492 | 287 | fuzz_tid(Data, Size, 0, &tid); |
493 | 287 | fuzz_addr(Data, Size, 16, &relay1); |
494 | 287 | fuzz_addr(Data, Size, 40, &relay2); |
495 | 287 | fuzz_addr(Data, Size, 64, &reflexive); |
496 | 287 | fuzz_addr(Data, Size, 88, &peer); |
497 | 287 | fuzz_addr(Data, Size, 112, &default_addr); |
498 | 287 | fuzz_string(Data, Size, 136, reason, sizeof(reason)); |
499 | 287 | fuzz_string(Data, Size, 232, mobile_id, sizeof(mobile_id)); |
500 | | |
501 | 287 | const uint32_t max_lifetime = fuzz_u32(Data, Size, 328) | 1u; |
502 | 287 | const uint64_t reservation_token = fuzz_u64(Data, Size, 332) | 1ull; |
503 | 287 | const uint16_t channel_number_valid = (uint16_t)(0x4000u + (fuzz_u16(Data, Size, 340) % (0x7FFFu - 0x4000u + 1u))); |
504 | 287 | const uint32_t old_cookie = fuzz_u32(Data, Size, 344); |
505 | | |
506 | | /* stun_init_error_response — cover (reason NULL vs set) × (include reason). */ |
507 | 287 | { |
508 | 287 | stun_buffer msg; |
509 | 287 | stun_init_buffer(&msg); |
510 | 287 | stun_init_error_response(STUN_METHOD_ALLOCATE, &msg, 437, NULL, &tid, false); |
511 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
512 | | |
513 | 287 | stun_init_buffer(&msg); |
514 | 287 | stun_init_error_response(STUN_METHOD_BINDING, &msg, 400, (const uint8_t *)reason, &tid, true); |
515 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
516 | 287 | } |
517 | | |
518 | | /* stun_set_allocate_response / _str — cover every optional-field branch and |
519 | | * the error path independently of the fuzzer selectors. */ |
520 | 287 | { |
521 | 287 | stun_buffer msg; |
522 | | |
523 | | /* Minimal success: relay1 only, no reflexive, no reservation, no mobile id, |
524 | | * lifetime 0 (triggers the <1 default branch). */ |
525 | 287 | stun_init_buffer(&msg); |
526 | 287 | (void)stun_set_allocate_response(&msg, &tid, &relay1, NULL, NULL, 0, max_lifetime, 0, NULL, 0, NULL, false); |
527 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
528 | | |
529 | 287 | size_t raw_len = sizeof(raw); |
530 | 287 | (void)stun_set_allocate_response_str(raw, &raw_len, &tid, &relay1, NULL, NULL, 0, max_lifetime, 0, NULL, 0, NULL, |
531 | 287 | false); |
532 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
533 | | |
534 | | /* Full success: both relays + reflexive + reservation + mobile id, |
535 | | * lifetime > max (triggers clamp branch). */ |
536 | 287 | stun_init_buffer(&msg); |
537 | 287 | (void)stun_set_allocate_response(&msg, &tid, &relay1, &relay2, &reflexive, max_lifetime + 1, max_lifetime, 0, |
538 | 287 | (const uint8_t *)reason, reservation_token, mobile_id, true); |
539 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
540 | | |
541 | 287 | raw_len = sizeof(raw); |
542 | 287 | (void)stun_set_allocate_response_str(raw, &raw_len, &tid, &relay1, &relay2, &reflexive, max_lifetime + 1, |
543 | 287 | max_lifetime, 0, (const uint8_t *)reason, reservation_token, mobile_id, true); |
544 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
545 | | |
546 | | /* Error path with and without a reason string. */ |
547 | 287 | stun_init_buffer(&msg); |
548 | 287 | (void)stun_set_allocate_response(&msg, &tid, NULL, NULL, NULL, 0, max_lifetime, 441, NULL, 0, NULL, false); |
549 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
550 | | |
551 | 287 | raw_len = sizeof(raw); |
552 | 287 | (void)stun_set_allocate_response_str(raw, &raw_len, &tid, NULL, NULL, NULL, 0, max_lifetime, 508, |
553 | 287 | (const uint8_t *)reason, 0, NULL, true); |
554 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
555 | 287 | } |
556 | | |
557 | | /* stun_set_binding_response / _str — cover success × error × old_stun. */ |
558 | 287 | { |
559 | 287 | stun_buffer msg; |
560 | | |
561 | 287 | stun_init_buffer(&msg); |
562 | 287 | (void)stun_set_binding_response(&msg, &tid, &reflexive, 0, NULL, false); |
563 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &default_addr); |
564 | | |
565 | 287 | stun_init_buffer(&msg); |
566 | 287 | (void)stun_set_binding_response(&msg, &tid, NULL, 420, (const uint8_t *)reason, true); |
567 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
568 | | |
569 | 287 | const bool matrix_old_stun[] = {false, true}; |
570 | 287 | const bool matrix_backcompat[] = {false, true}; |
571 | 861 | for (size_t o = 0; o < sizeof(matrix_old_stun) / sizeof(matrix_old_stun[0]); ++o) { |
572 | 1.72k | for (size_t b = 0; b < sizeof(matrix_backcompat) / sizeof(matrix_backcompat[0]); ++b) { |
573 | 1.14k | size_t raw_len = sizeof(raw); |
574 | 1.14k | (void)stun_set_binding_response_str(raw, &raw_len, &tid, &reflexive, 0, NULL, old_cookie, matrix_old_stun[o], |
575 | 1.14k | matrix_backcompat[b], false); |
576 | 1.14k | inspect_raw_message(raw, raw_len, |
577 | 1.14k | matrix_old_stun[o] ? STUN_ATTRIBUTE_MAPPED_ADDRESS : STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, |
578 | 1.14k | &default_addr); |
579 | | |
580 | 1.14k | raw_len = sizeof(raw); |
581 | 1.14k | (void)stun_set_binding_response_str(raw, &raw_len, &tid, NULL, 500, (const uint8_t *)reason, old_cookie, |
582 | 1.14k | matrix_old_stun[o], matrix_backcompat[b], true); |
583 | 1.14k | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
584 | 1.14k | } |
585 | 574 | } |
586 | 287 | } |
587 | | |
588 | | /* stun_set_channel_bind_request / _str — cover peer NULL vs set. */ |
589 | 287 | { |
590 | 287 | stun_buffer msg; |
591 | | |
592 | 287 | stun_init_buffer(&msg); |
593 | 287 | (void)stun_set_channel_bind_request(&msg, NULL, channel_number_valid); |
594 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
595 | | |
596 | 287 | stun_init_buffer(&msg); |
597 | 287 | (void)stun_set_channel_bind_request(&msg, &peer, channel_number_valid); |
598 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
599 | | |
600 | 287 | size_t raw_len = sizeof(raw); |
601 | 287 | (void)stun_set_channel_bind_request_str(raw, &raw_len, NULL, channel_number_valid); |
602 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
603 | | |
604 | 287 | raw_len = sizeof(raw); |
605 | 287 | (void)stun_set_channel_bind_request_str(raw, &raw_len, &peer, channel_number_valid); |
606 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
607 | 287 | } |
608 | | |
609 | | /* stun_set_channel_bind_response / _str — cover success vs error. */ |
610 | 287 | { |
611 | 287 | stun_buffer msg; |
612 | | |
613 | 287 | stun_init_buffer(&msg); |
614 | 287 | stun_set_channel_bind_response(&msg, &tid, 0, NULL, false); |
615 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
616 | | |
617 | 287 | stun_init_buffer(&msg); |
618 | 287 | stun_set_channel_bind_response(&msg, &tid, 438, (const uint8_t *)reason, true); |
619 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
620 | | |
621 | 287 | size_t raw_len = sizeof(raw); |
622 | 287 | stun_set_channel_bind_response_str(raw, &raw_len, &tid, 0, NULL, false); |
623 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
624 | | |
625 | 287 | raw_len = sizeof(raw); |
626 | 287 | stun_set_channel_bind_response_str(raw, &raw_len, &tid, 486, (const uint8_t *)reason, true); |
627 | 287 | inspect_raw_message(raw, raw_len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
628 | 287 | } |
629 | 287 | } |
630 | | |
631 | | /* ------------------------------------------------------------------ */ |
632 | | /* stun_buffer.c wrapper coverage. */ |
633 | | /* */ |
634 | | /* Exercises every public wrapper in src/apps/common/stun_buffer.c */ |
635 | | /* that is not already reached by the harnesses above: */ |
636 | | /* - stun_get_size NULL/non-NULL */ |
637 | | /* - stun_init_request / _indication / _success_response */ |
638 | | /* - stun_tid_from_message, stun_tid_generate_in_message */ |
639 | | /* - stun_is_indication wrapper (gates static is_channel_msg) */ |
640 | | /* - stun_attr_add, stun_attr_add_channel_number, stun_attr_add_addr */ |
641 | | /* - stun_attr_add_even_port (zero + non-zero branches) */ |
642 | | /* - stun_attr_get_first_by_type */ |
643 | | /* - stun_set_allocate_request (rt NULL + non-NULL) */ |
644 | | /* - stun_set_binding_request, stun_prepare_binding_request */ |
645 | | /* - stun_init_channel_message + stun_is_channel_message wrappers */ |
646 | | /* */ |
647 | | /* Each call is followed by inspect_buffer_message so the resulting */ |
648 | | /* serialized message is also walked by the parser predicates. */ |
649 | | /* The tail block also pumps raw fuzzer bytes through the predicate */ |
650 | | /* wrappers to hit malformed-input branches the serializers cannot */ |
651 | | /* produce. */ |
652 | | /* ------------------------------------------------------------------ */ |
653 | 318 | static void harness_stun_buffer_api(const uint8_t *Data, size_t Size) { |
654 | 318 | if (!Size || Size > 4096) { |
655 | 31 | return; |
656 | 31 | } |
657 | | |
658 | 287 | static const uint16_t kMethods[] = { |
659 | 287 | STUN_METHOD_ALLOCATE, STUN_METHOD_BINDING, STUN_METHOD_CHANNEL_BIND, STUN_METHOD_REFRESH, STUN_METHOD_CONNECT, |
660 | 287 | }; |
661 | | |
662 | 287 | stun_tid tid = {0}; |
663 | 287 | ioa_addr peer = {0}; |
664 | 287 | ioa_addr default_addr = {0}; |
665 | 287 | char attr_value[64] = {0}; |
666 | 287 | char rt[8] = {0}; |
667 | | |
668 | 287 | fuzz_tid(Data, Size, 0, &tid); |
669 | 287 | fuzz_addr(Data, Size, 16, &peer); |
670 | 287 | fuzz_addr(Data, Size, 40, &default_addr); |
671 | 287 | fuzz_string(Data, Size, 64, attr_value, sizeof(attr_value)); |
672 | 287 | fuzz_string(Data, Size, 128, rt, sizeof(rt)); |
673 | | |
674 | 287 | const uint16_t method = kMethods[fuzz_byte(Data, Size, 200) % (sizeof(kMethods) / sizeof(kMethods[0]))]; |
675 | 287 | const uint32_t lifetime = fuzz_u32(Data, Size, 201); |
676 | 287 | const uint16_t channel_number = (uint16_t)(0x4000u + (fuzz_u16(Data, Size, 205) & 0x3FFFu)); |
677 | 287 | const uint8_t transport = fuzz_byte(Data, Size, 207); |
678 | 287 | const uint8_t even_port_value = fuzz_byte(Data, Size, 208); |
679 | 287 | const bool af4 = fuzz_flag(Data, Size, 209); |
680 | 287 | const bool af6 = fuzz_flag(Data, Size, 210); |
681 | 287 | const bool mobile = fuzz_flag(Data, Size, 211); |
682 | 287 | const bool padding = fuzz_flag(Data, Size, 212); |
683 | 287 | const int chan_payload_len = (int)(fuzz_u16(Data, Size, 213) % 256); |
684 | 287 | const int ep = (int)(int8_t)fuzz_byte(Data, Size, 215); |
685 | | |
686 | | /* NULL-guard branches. */ |
687 | 287 | (void)stun_get_size(NULL); |
688 | 287 | (void)stun_init_buffer(NULL); |
689 | 287 | (void)stun_get_msg_type(NULL); |
690 | 287 | { |
691 | 287 | stun_tid scratch = {0}; |
692 | 287 | stun_tid_generate_in_message(NULL, &scratch); |
693 | 287 | } |
694 | | |
695 | | /* stun_init_request — also covers stun_get_size (non-NULL), the static |
696 | | * stun_init_command helper, and stun_attr_add* / stun_attr_get_first_by_type |
697 | | * over the freshly built message. */ |
698 | 287 | { |
699 | 287 | stun_buffer msg; |
700 | 287 | stun_init_buffer(&msg); |
701 | 287 | stun_init_request(method, &msg); |
702 | | |
703 | 287 | stun_tid extracted = {0}; |
704 | 287 | stun_tid_from_message(&msg, &extracted); |
705 | 287 | stun_tid_generate_in_message(&msg, &extracted); |
706 | | |
707 | 287 | const int alen = (int)strlen(attr_value); |
708 | 287 | (void)stun_attr_add(&msg, STUN_ATTRIBUTE_USERNAME, attr_value, alen); |
709 | 287 | (void)stun_attr_add_channel_number(&msg, channel_number); |
710 | 287 | (void)stun_attr_add_addr(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &peer); |
711 | 287 | (void)stun_attr_add_even_port(&msg, even_port_value); |
712 | 287 | (void)stun_attr_add_even_port(&msg, 0); |
713 | | |
714 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_USERNAME); |
715 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_CHANNEL_NUMBER); |
716 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS); |
717 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_EVEN_PORT); |
718 | | |
719 | 287 | (void)stun_is_indication(&msg); |
720 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
721 | 287 | } |
722 | | |
723 | | /* stun_init_indication — drives the IS_STUN_INDICATION branch of |
724 | | * stun_is_indication. */ |
725 | 287 | { |
726 | 287 | stun_buffer msg; |
727 | 287 | stun_init_buffer(&msg); |
728 | 287 | stun_init_indication(method, &msg); |
729 | 287 | (void)stun_is_indication(&msg); |
730 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &default_addr); |
731 | 287 | } |
732 | | |
733 | | /* stun_init_success_response. */ |
734 | 287 | { |
735 | 287 | stun_buffer msg; |
736 | 287 | stun_init_buffer(&msg); |
737 | 287 | stun_init_success_response(method, &msg, &tid); |
738 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
739 | 287 | } |
740 | | |
741 | | /* stun_set_allocate_request — both rt NULL and rt non-NULL paths. */ |
742 | 287 | { |
743 | 287 | stun_buffer msg; |
744 | 287 | stun_init_buffer(&msg); |
745 | 287 | (void)stun_set_allocate_request(&msg, lifetime, af4, af6, transport, mobile, rt[0] ? rt : NULL, ep); |
746 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
747 | | |
748 | 287 | stun_init_buffer(&msg); |
749 | 287 | (void)stun_set_allocate_request(&msg, lifetime, !af4, !af6, transport, !mobile, NULL, ep); |
750 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, &default_addr); |
751 | 287 | } |
752 | | |
753 | | /* stun_set_binding_request + stun_prepare_binding_request (both currently |
754 | | * delegate to stun_set_binding_request_str but exercise the wrappers). */ |
755 | 287 | { |
756 | 287 | stun_buffer msg; |
757 | 287 | stun_init_buffer(&msg); |
758 | 287 | stun_set_binding_request(&msg); |
759 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
760 | | |
761 | 287 | stun_init_buffer(&msg); |
762 | 287 | stun_prepare_binding_request(&msg); |
763 | 287 | inspect_buffer_message(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, &default_addr); |
764 | 287 | } |
765 | | |
766 | | /* stun_init_channel_message + stun_is_channel_message wrappers. */ |
767 | 287 | { |
768 | 287 | stun_buffer msg; |
769 | 287 | stun_init_buffer(&msg); |
770 | 287 | if (stun_init_channel_message(channel_number, &msg, chan_payload_len, padding)) { |
771 | 287 | uint16_t parsed_chn = 0; |
772 | 287 | (void)stun_is_channel_message(&msg, &parsed_chn, true); |
773 | 287 | (void)stun_is_channel_message(&msg, &parsed_chn, false); |
774 | 287 | } |
775 | 287 | { |
776 | 287 | uint16_t chn = 0; |
777 | 287 | (void)stun_is_channel_message(NULL, &chn, false); |
778 | 287 | } |
779 | 287 | } |
780 | | |
781 | | /* Raw fuzzer bytes through the wrapper-form predicates so they see |
782 | | * malformed inputs the serializer paths above never produce. */ |
783 | 287 | { |
784 | 287 | stun_buffer msg; |
785 | 287 | msg.len = Size > sizeof(msg.buf) ? sizeof(msg.buf) : Size; |
786 | 287 | memcpy(msg.buf, Data, msg.len); |
787 | | |
788 | 287 | (void)stun_is_indication(&msg); |
789 | | |
790 | 287 | stun_tid extracted = {0}; |
791 | 287 | stun_tid_from_message(&msg, &extracted); |
792 | | |
793 | 287 | { |
794 | 287 | uint16_t chn = 0; |
795 | 287 | const size_t saved_len = msg.len; |
796 | 287 | (void)stun_is_channel_message(&msg, &chn, true); |
797 | 287 | msg.len = saved_len; |
798 | 287 | (void)stun_is_channel_message(&msg, &chn, false); |
799 | 287 | } |
800 | | |
801 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_USERNAME); |
802 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS); |
803 | 287 | (void)stun_attr_get_first_by_type(&msg, STUN_ATTRIBUTE_CHANNEL_NUMBER); |
804 | 287 | } |
805 | 287 | } |
806 | | |
807 | | /* ------------------------------------------------------------------ */ |
808 | | /* libFuzzer entry point — run every harness on each input. */ |
809 | | /* */ |
810 | | /* Note: OAuth token sub-harnesses are intentionally omitted here. */ |
811 | | /* decode_oauth_token_gcm in src/client/ns_turn_msg.c leaks the */ |
812 | | /* EVP_CIPHER_CTX on several early-return paths, which trips ASan */ |
813 | | /* under CIFuzz. Those harnesses will be re-added once the library */ |
814 | | /* leak is fixed in a separate PR. */ |
815 | | /* ------------------------------------------------------------------ */ |
816 | 318 | extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { |
817 | 318 | harness_stun_client(Data, Size); |
818 | 318 | harness_channel_data(Data, Size); |
819 | 318 | harness_addr_codec(Data, Size); |
820 | 318 | harness_message_builders(Data, Size); |
821 | 318 | harness_attr_get_first_addr(Data, Size); |
822 | 318 | harness_response_matrix(Data, Size); |
823 | 318 | harness_stun_buffer_api(Data, Size); |
824 | 318 | return 0; |
825 | 318 | } |