/src/libsrtp/fuzzer/fuzzer.c
Line | Count | Source |
1 | | /* By Guido Vranken <guidovranken@gmail.com> -- |
2 | | * https://guidovranken.wordpress.com/ */ |
3 | | |
4 | | #include <stdio.h> |
5 | | #include <string.h> |
6 | | #include <stdlib.h> |
7 | | #include <stdbool.h> |
8 | | #include <limits.h> |
9 | | #include "srtp.h" |
10 | | #include "srtp_priv.h" |
11 | | #include "fuzzer.h" |
12 | | #include "mt19937.h" |
13 | | #include "testmem.h" |
14 | | |
15 | | /* Global variables */ |
16 | | static bool g_no_align = false; /* Can be enabled with --no_align */ |
17 | | static bool g_post_init = |
18 | | false; /* Set to true once past initialization phase */ |
19 | | static bool g_write_input = false; |
20 | | |
21 | | #ifdef FUZZ_32BIT |
22 | | #include <sys/mman.h> |
23 | | static bool g_no_mmap = false; /* Can be enabled with --no_mmap */ |
24 | | static void *g_mmap_allocation = |
25 | | NULL; /* Keeps current mmap() allocation address */ |
26 | | static size_t g_mmap_allocation_size = |
27 | | 0; /* Keeps current mmap() allocation size */ |
28 | | #endif |
29 | | |
30 | | /* Custom allocator functions */ |
31 | | |
32 | | static void *fuzz_alloc(const size_t size, const bool do_zero) |
33 | 60.1k | { |
34 | 60.1k | void *ret = NULL; |
35 | | #ifdef FUZZ_32BIT |
36 | | bool do_malloc = true; |
37 | | #endif |
38 | 60.1k | bool do_mmap, mmap_high = true; |
39 | | |
40 | 60.1k | if (size == 0) { |
41 | 0 | size_t ret; |
42 | | /* Allocations of size 0 are not illegal, but are a bad practice, since |
43 | | * writing just a single byte to this region constitutes undefined |
44 | | * behavior per the C spec. glibc will return a small, valid memory |
45 | | * region |
46 | | * whereas OpenBSD will crash upon writing to it. |
47 | | * Intentionally return a pointer to an invalid page to detect |
48 | | * unsound code efficiently. |
49 | | * fuzz_free is aware of this pointer range and will not attempt |
50 | | * to free()/munmap() it. |
51 | | */ |
52 | 0 | ret = 0x01 + (fuzz_mt19937_get() % 1024); |
53 | 0 | return (void *)ret; |
54 | 0 | } |
55 | | |
56 | | /* Don't do mmap()-based allocations during initialization */ |
57 | 60.1k | if (g_post_init == true) { |
58 | | /* Even extract these values if --no_mmap is specified. |
59 | | * This keeps the PRNG output stream consistent across |
60 | | * fuzzer configurations. |
61 | | */ |
62 | 60.1k | do_mmap = (fuzz_mt19937_get() % 64) == 0 ? true : false; |
63 | 60.1k | if (do_mmap == true) { |
64 | 1.40k | mmap_high = (fuzz_mt19937_get() % 2) == 0 ? true : false; |
65 | 1.40k | } |
66 | 60.1k | } else { |
67 | 0 | do_mmap = false; |
68 | 0 | } |
69 | | |
70 | | #ifdef FUZZ_32BIT |
71 | | /* g_mmap_allocation must be NULL because we only support a single |
72 | | * concurrent mmap allocation at a time |
73 | | */ |
74 | | if (g_mmap_allocation == NULL && g_no_mmap == false && do_mmap == true) { |
75 | | void *mmap_address; |
76 | | if (mmap_high == true) { |
77 | | mmap_address = (void *)0xFFFF0000; |
78 | | } else { |
79 | | mmap_address = (void *)0x00010000; |
80 | | } |
81 | | g_mmap_allocation_size = size; |
82 | | |
83 | | ret = mmap(mmap_address, g_mmap_allocation_size, PROT_READ | PROT_WRITE, |
84 | | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
85 | | |
86 | | if (ret == MAP_FAILED) { |
87 | | /* That's okay -- just return NULL to the caller */ |
88 | | |
89 | | ret = NULL; |
90 | | |
91 | | /* Reset this for the sake of cleanliness */ |
92 | | g_mmap_allocation_size = 0; |
93 | | } |
94 | | /* ret not being MAP_FAILED does not mean that ret is the requested |
95 | | * address (mmap_address). That's okay. We're not going to perform |
96 | | * a munmap() on it and call malloc() instead. It won't gain us |
97 | | * anything. |
98 | | */ |
99 | | |
100 | | g_mmap_allocation = ret; |
101 | | do_malloc = false; |
102 | | } |
103 | | |
104 | | if (do_malloc == true) |
105 | | #endif |
106 | 60.1k | { |
107 | 60.1k | ret = malloc(size); |
108 | 60.1k | } |
109 | | |
110 | | /* Mimic calloc() if so requested */ |
111 | 60.1k | if (ret != NULL && do_zero) { |
112 | 0 | memset(ret, 0, size); |
113 | 0 | } |
114 | | |
115 | 60.1k | return ret; |
116 | 60.1k | } |
117 | | |
118 | | /* Internal allocations by this fuzzer must on one hand (sometimes) |
119 | | * receive memory from mmap(), but on the other hand these requests for |
120 | | * memory may not fail. By calling this function, the allocation is |
121 | | * guaranteed to succeed; it first tries with fuzz_alloc(), which may |
122 | | * fail if it uses mmap(), and if that is the case, memory is allocated |
123 | | * via the libc allocator (malloc, calloc) which should always succeed */ |
124 | | static void *fuzz_alloc_succeed(const size_t size, const bool do_zero) |
125 | 60.1k | { |
126 | 60.1k | void *ret = fuzz_alloc(size, do_zero); |
127 | 60.1k | if (ret == NULL) { |
128 | 0 | if (do_zero == false) { |
129 | 0 | ret = malloc(size); |
130 | 0 | } else { |
131 | 0 | ret = calloc(1, size); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | 60.1k | return ret; |
136 | 60.1k | } |
137 | | |
138 | | void *fuzz_calloc(const size_t nmemb, const size_t size) |
139 | 0 | { |
140 | | /* We must be past srtp_init() to prevent that that function fails */ |
141 | 0 | if (g_post_init == true) { |
142 | | /* Fail 1 in 64 allocations on average to test whether the library |
143 | | * can deal with this properly. |
144 | | */ |
145 | 0 | if ((fuzz_mt19937_get() % 64) == 0) { |
146 | 0 | return NULL; |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | 0 | return fuzz_alloc(nmemb * size, true); |
151 | 0 | } |
152 | | |
153 | | static bool fuzz_is_special_pointer(void *ptr) |
154 | 68.0k | { |
155 | | /* Special, invalid pointers introduced when code attempted |
156 | | * to do size = 0 allocations. |
157 | | */ |
158 | 68.0k | if ((size_t)ptr >= 0x01 && (size_t)ptr < (0x01 + 1024)) { |
159 | 0 | return true; |
160 | 68.0k | } else { |
161 | 68.0k | return false; |
162 | 68.0k | } |
163 | 68.0k | } |
164 | | |
165 | | void fuzz_free(void *ptr) |
166 | 68.0k | { |
167 | 68.0k | if (fuzz_is_special_pointer(ptr) == true) { |
168 | 0 | return; |
169 | 0 | } |
170 | | |
171 | | #ifdef FUZZ_32BIT |
172 | | if (g_post_init == true && ptr != NULL && ptr == g_mmap_allocation) { |
173 | | if (munmap(g_mmap_allocation, g_mmap_allocation_size) == -1) { |
174 | | /* Shouldn't happen */ |
175 | | abort(); |
176 | | } |
177 | | g_mmap_allocation = NULL; |
178 | | } else |
179 | | #endif |
180 | 68.0k | { |
181 | 68.0k | free(ptr); |
182 | 68.0k | } |
183 | 68.0k | } |
184 | | |
185 | | static srtp_err_status_t fuzz_srtp_protect(srtp_t srtp_sender, |
186 | | void *hdr, |
187 | | size_t *len, |
188 | | size_t mki) |
189 | 6.31k | { |
190 | 6.31k | size_t out_len = *len + SRTP_MAX_TRAILER_LEN; |
191 | 6.31k | srtp_err_status_t s = |
192 | 6.31k | srtp_protect(srtp_sender, hdr, *len, hdr, &out_len, mki); |
193 | 6.31k | *len = out_len; |
194 | 6.31k | return s; |
195 | 6.31k | } |
196 | | |
197 | | static srtp_err_status_t fuzz_srtp_unprotect(srtp_t srtp_sender, |
198 | | void *hdr, |
199 | | size_t *len, |
200 | | size_t mki) |
201 | 1.12k | { |
202 | 1.12k | return srtp_unprotect(srtp_sender, hdr, *len, hdr, len); |
203 | 1.12k | } |
204 | | |
205 | | static srtp_err_status_t fuzz_srtp_protect_rtcp(srtp_t srtp_sender, |
206 | | void *hdr, |
207 | | size_t *len, |
208 | | size_t mki) |
209 | 13.1k | { |
210 | 13.1k | size_t out_len = *len + SRTP_MAX_SRTCP_TRAILER_LEN; |
211 | 13.1k | srtp_err_status_t s = |
212 | 13.1k | srtp_protect_rtcp(srtp_sender, hdr, *len, hdr, &out_len, mki); |
213 | 13.1k | *len = out_len; |
214 | 13.1k | return s; |
215 | 13.1k | } |
216 | | |
217 | | static srtp_err_status_t fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender, |
218 | | void *hdr, |
219 | | size_t *len, |
220 | | size_t mki) |
221 | 722 | { |
222 | 722 | return srtp_unprotect_rtcp(srtp_sender, hdr, *len, hdr, len); |
223 | 722 | } |
224 | | |
225 | | /* Get protect length functions */ |
226 | | |
227 | | static srtp_err_status_t fuzz_srtp_get_protect_length(const srtp_t srtp_ctx, |
228 | | size_t mki, |
229 | | size_t *length) |
230 | 6.38k | { |
231 | 6.38k | return srtp_get_protect_trailer_length(srtp_ctx, mki, length); |
232 | 6.38k | } |
233 | | |
234 | | static srtp_err_status_t fuzz_srtp_get_protect_rtcp_length( |
235 | | const srtp_t srtp_ctx, |
236 | | size_t mki, |
237 | | size_t *length) |
238 | 13.3k | { |
239 | 13.3k | return srtp_get_protect_rtcp_trailer_length(srtp_ctx, mki, length); |
240 | 13.3k | } |
241 | | |
242 | | static uint8_t *extract_key(const uint8_t **data, |
243 | | size_t *size, |
244 | | const size_t key_size) |
245 | 37.9k | { |
246 | 37.9k | uint8_t *ret; |
247 | 37.9k | if (*size < key_size) { |
248 | 54 | return NULL; |
249 | 54 | } |
250 | | |
251 | 37.8k | ret = fuzz_alloc_succeed(key_size, false); |
252 | 37.8k | EXTRACT(ret, *data, *size, key_size); |
253 | | |
254 | 37.8k | return ret; |
255 | 37.9k | } |
256 | | |
257 | | static bool extract_and_add_key(srtp_policy_t policy, |
258 | | const uint8_t **data, |
259 | | size_t *size, |
260 | | size_t key_size, |
261 | | size_t salt_size) |
262 | 7.27k | { |
263 | 7.27k | bool added = false; |
264 | 7.27k | uint8_t *salt = NULL; |
265 | 7.27k | uint8_t *key = extract_key(data, size, key_size); |
266 | 7.27k | if (key == NULL) { |
267 | 25 | return false; |
268 | 25 | } |
269 | | |
270 | 7.24k | salt = extract_key(data, size, salt_size); |
271 | 7.24k | if (salt == NULL) { |
272 | 29 | goto end; |
273 | 29 | } |
274 | | |
275 | 7.21k | if (srtp_policy_add_key(policy, key, key_size, salt, salt_size, NULL, 0) == |
276 | 7.21k | srtp_err_status_ok) { |
277 | 7.21k | added = true; |
278 | 7.21k | } |
279 | | |
280 | 7.24k | end: |
281 | 7.24k | fuzz_free(salt); |
282 | 7.24k | fuzz_free(key); |
283 | 7.24k | return added; |
284 | 7.21k | } |
285 | | |
286 | | static bool extract_and_add_master_key(srtp_policy_t policy, |
287 | | const uint8_t **data, |
288 | | size_t *size, |
289 | | size_t key_size, |
290 | | size_t salt_size) |
291 | 13.3k | { |
292 | 13.3k | bool added = false; |
293 | 13.3k | uint8_t *key = NULL; |
294 | 13.3k | uint8_t *salt = NULL; |
295 | 13.3k | uint16_t mki_id_size = 0; |
296 | 13.3k | const uint8_t *mki = NULL; |
297 | 13.3k | srtp_err_status_t status; |
298 | | |
299 | 13.3k | EXTRACT_IF(&mki_id_size, *data, *size, sizeof(mki_id_size)); |
300 | | |
301 | 13.3k | if (*size < key_size + salt_size + mki_id_size) { |
302 | 1.42k | return false; |
303 | 1.42k | } |
304 | | |
305 | 11.9k | if (mki_id_size > SRTP_MAX_MKI_LEN) { |
306 | 248 | *data += key_size + salt_size + mki_id_size; |
307 | 248 | *size -= key_size + salt_size + mki_id_size; |
308 | 248 | return false; |
309 | 248 | } |
310 | | |
311 | 11.7k | key = extract_key(data, size, key_size); |
312 | 11.7k | if (key == NULL) { |
313 | 0 | return false; |
314 | 0 | } |
315 | 11.7k | salt = extract_key(data, size, salt_size); |
316 | 11.7k | if (salt == NULL) { |
317 | 0 | goto end; |
318 | 0 | } |
319 | 11.7k | mki = *data; |
320 | 11.7k | *data += mki_id_size; |
321 | 11.7k | *size -= mki_id_size; |
322 | | |
323 | 11.7k | if (mki_id_size > 0) { |
324 | 10.3k | status = srtp_policy_use_mki(policy, mki_id_size); |
325 | 10.3k | if (status != srtp_err_status_ok) { |
326 | 0 | goto end; |
327 | 0 | } |
328 | 10.3k | } |
329 | | |
330 | 11.7k | status = srtp_policy_add_key(policy, key, key_size, salt, salt_size, mki, |
331 | 11.7k | mki_id_size); |
332 | 11.7k | if (status != srtp_err_status_ok) { |
333 | 1.09k | goto end; |
334 | 1.09k | } |
335 | | |
336 | 10.6k | added = true; |
337 | | |
338 | 11.7k | end: |
339 | 11.7k | fuzz_free(salt); |
340 | 11.7k | fuzz_free(key); |
341 | 11.7k | return added; |
342 | 10.6k | } |
343 | | |
344 | | static srtp_policy_t extract_policy(const uint8_t **data, size_t *size) |
345 | 27.5k | { |
346 | 27.5k | srtp_policy_t policy = NULL; |
347 | 27.5k | srtp_profile_t profile; |
348 | 27.5k | size_t key_size; |
349 | 27.5k | size_t salt_size; |
350 | 27.5k | srtp_err_status_t status; |
351 | 27.5k | struct { |
352 | 27.5k | uint8_t srtp_profile; |
353 | 27.5k | size_t window_size; |
354 | 27.5k | uint8_t allow_repeat_tx; |
355 | 27.5k | uint8_t ssrc_type; |
356 | 27.5k | uint32_t ssrc_value; |
357 | 27.5k | uint8_t num_xtn_hdr; |
358 | 27.5k | uint8_t do_extract_key; |
359 | 27.5k | uint8_t do_extract_master_keys; |
360 | 27.5k | } params; |
361 | | |
362 | 27.5k | EXTRACT_IF(¶ms, *data, *size, sizeof(params)); |
363 | | |
364 | 27.0k | params.srtp_profile %= |
365 | 27.0k | sizeof(fuzz_srtp_profiles) / sizeof(fuzz_srtp_profiles[0]); |
366 | 27.0k | params.allow_repeat_tx %= 2; |
367 | 27.0k | params.ssrc_type %= |
368 | 27.0k | sizeof(fuzz_ssrc_type_map) / sizeof(fuzz_ssrc_type_map[0]); |
369 | 27.0k | profile = fuzz_srtp_profiles[params.srtp_profile].profile; |
370 | | |
371 | 27.0k | status = srtp_policy_create(&policy); |
372 | 27.0k | if (status != srtp_err_status_ok || policy == NULL) { |
373 | 0 | return NULL; |
374 | 0 | } |
375 | | |
376 | 27.0k | status = srtp_policy_set_profile(policy, profile); |
377 | 27.0k | if (status != srtp_err_status_ok) { |
378 | 54 | srtp_policy_destroy(policy); |
379 | 54 | return NULL; |
380 | 54 | } |
381 | | |
382 | 26.9k | key_size = srtp_profile_get_master_key_length(profile); |
383 | 26.9k | salt_size = srtp_profile_get_master_salt_length(profile); |
384 | 26.9k | if (key_size + salt_size > SRTP_MAX_KEY_LEN) { |
385 | | /* Shouldn't happen for a public profile. */ |
386 | 0 | abort(); |
387 | 0 | } |
388 | | |
389 | 26.9k | status = srtp_policy_set_ssrc( |
390 | 26.9k | policy, (srtp_ssrc_t){ |
391 | 26.9k | .type = fuzz_ssrc_type_map[params.ssrc_type].srtp_ssrc_type, |
392 | 26.9k | .value = params.ssrc_value, |
393 | 26.9k | }); |
394 | 26.9k | if (status != srtp_err_status_ok) { |
395 | 159 | srtp_policy_destroy(policy); |
396 | 159 | return NULL; |
397 | 159 | } |
398 | | |
399 | 26.8k | if (profile != srtp_profile_null_null && (params.do_extract_key % 2) == 0) { |
400 | 7.27k | if (!extract_and_add_key(policy, data, size, key_size, salt_size)) { |
401 | 54 | srtp_policy_destroy(policy); |
402 | 54 | return NULL; |
403 | 54 | } |
404 | 7.27k | } |
405 | | |
406 | 26.7k | if (params.num_xtn_hdr != 0) { |
407 | 8.70k | const size_t xtn_hdr_size = params.num_xtn_hdr; |
408 | 8.70k | size_t copy_size = xtn_hdr_size; |
409 | 8.70k | if (*size < xtn_hdr_size) { |
410 | 67 | srtp_policy_destroy(policy); |
411 | 67 | return NULL; |
412 | 67 | } |
413 | 8.63k | if (copy_size > SRTP_MAX_NUM_ENC_HDR_XTND_IDS) { |
414 | 2.37k | copy_size = SRTP_MAX_NUM_ENC_HDR_XTND_IDS; |
415 | 2.37k | } |
416 | 66.0k | for (size_t i = 0; i < copy_size; i++) { |
417 | 57.3k | (void)srtp_policy_add_enc_hdr_xtnd_id(policy, (*data)[i]); |
418 | 57.3k | } |
419 | 8.63k | *data += xtn_hdr_size; |
420 | 8.63k | *size -= xtn_hdr_size; |
421 | 8.63k | } |
422 | | |
423 | 26.7k | if (profile != srtp_profile_null_null && |
424 | 14.2k | (params.do_extract_master_keys % 2) == 0) { |
425 | 20.4k | while (1) { |
426 | 20.4k | uint8_t do_extract_master_key; |
427 | 20.4k | EXTRACT_IF(&do_extract_master_key, *data, *size, |
428 | 20.4k | sizeof(do_extract_master_key)); |
429 | | |
430 | 20.2k | if ((do_extract_master_key % 2) == 0) { |
431 | 6.87k | break; |
432 | 6.87k | } |
433 | | |
434 | 13.3k | if (!extract_and_add_master_key(policy, data, size, key_size, |
435 | 13.3k | salt_size)) { |
436 | 2.77k | break; |
437 | 2.77k | } |
438 | 13.3k | } |
439 | 9.84k | } |
440 | | |
441 | 26.5k | status = srtp_policy_set_window_size(policy, params.window_size); |
442 | 26.5k | if (status != srtp_err_status_ok) { |
443 | 401 | srtp_policy_destroy(policy); |
444 | 401 | return NULL; |
445 | 401 | } |
446 | 26.1k | status = srtp_policy_set_allow_repeat_tx(policy, params.allow_repeat_tx); |
447 | 26.1k | if (status != srtp_err_status_ok) { |
448 | 0 | srtp_policy_destroy(policy); |
449 | 0 | return NULL; |
450 | 0 | } |
451 | | |
452 | 26.8k | end: |
453 | 26.8k | return policy; |
454 | 26.1k | } |
455 | | |
456 | | static void extract_more_policies_to_session(const uint8_t **data, |
457 | | size_t *size, |
458 | | srtp_t srtp_ctx) |
459 | 7.68k | { |
460 | 26.2k | while (1) { |
461 | 26.2k | uint8_t do_extract_policy; |
462 | 26.2k | srtp_policy_t policy = NULL; |
463 | 26.2k | EXTRACT_IF(&do_extract_policy, *data, *size, sizeof(do_extract_policy)); |
464 | | |
465 | | /* Decide whether to extract another policy */ |
466 | 25.9k | if ((do_extract_policy % 2) == 0) { |
467 | 6.88k | break; |
468 | 6.88k | } |
469 | | |
470 | 19.0k | policy = extract_policy(data, size); |
471 | 19.0k | if (policy == NULL) { |
472 | 473 | break; |
473 | 473 | } |
474 | | |
475 | 18.5k | if (srtp_ctx != NULL) { |
476 | 15.3k | (void)srtp_stream_add(srtp_ctx, policy); |
477 | 15.3k | } |
478 | 18.5k | srtp_policy_destroy(policy); |
479 | 18.5k | } |
480 | | |
481 | 7.68k | end: |
482 | 7.68k | return; |
483 | 7.68k | } |
484 | | |
485 | | static uint32_t *extract_remove_stream_ssrc(const uint8_t **data, |
486 | | size_t *size, |
487 | | uint8_t *num_remove_stream) |
488 | 3.58k | { |
489 | 3.58k | uint32_t *ret = NULL; |
490 | 3.58k | uint8_t _num_remove_stream; |
491 | 3.58k | size_t total_size; |
492 | | |
493 | 3.58k | *num_remove_stream = 0; |
494 | | |
495 | 3.58k | EXTRACT_IF(&_num_remove_stream, *data, *size, sizeof(_num_remove_stream)); |
496 | | |
497 | 3.51k | if (_num_remove_stream == 0) { |
498 | 2.70k | goto end; |
499 | 2.70k | } |
500 | | |
501 | 815 | total_size = _num_remove_stream * sizeof(uint32_t); |
502 | | |
503 | 815 | if (*size < total_size) { |
504 | 573 | goto end; |
505 | 573 | } |
506 | | |
507 | 242 | ret = fuzz_alloc_succeed(total_size, false); |
508 | 242 | EXTRACT(ret, *data, *size, total_size); |
509 | | |
510 | 242 | *num_remove_stream = _num_remove_stream; |
511 | | |
512 | 3.58k | end: |
513 | 3.58k | return ret; |
514 | 242 | } |
515 | | |
516 | | static uint32_t *extract_set_roc(const uint8_t **data, |
517 | | size_t *size, |
518 | | uint8_t *num_set_roc) |
519 | 3.58k | { |
520 | 3.58k | uint32_t *ret = NULL; |
521 | 3.58k | uint8_t _num_set_roc; |
522 | 3.58k | size_t total_size; |
523 | | |
524 | 3.58k | *num_set_roc = 0; |
525 | 3.58k | EXTRACT_IF(&_num_set_roc, *data, *size, sizeof(_num_set_roc)); |
526 | 3.49k | if (_num_set_roc == 0) { |
527 | 2.13k | goto end; |
528 | 2.13k | } |
529 | | |
530 | | /* Tuples of 2 uint32_t's */ |
531 | 1.36k | total_size = _num_set_roc * sizeof(uint32_t) * 2; |
532 | | |
533 | 1.36k | if (*size < total_size) { |
534 | 565 | goto end; |
535 | 565 | } |
536 | | |
537 | 800 | ret = fuzz_alloc_succeed(total_size, false); |
538 | 800 | EXTRACT(ret, *data, *size, total_size); |
539 | | |
540 | 800 | *num_set_roc = _num_set_roc; |
541 | | |
542 | 3.58k | end: |
543 | 3.58k | return ret; |
544 | 800 | } |
545 | | |
546 | | static uint8_t *run_srtp_func(const srtp_t srtp_ctx, |
547 | | const uint8_t **data, |
548 | | size_t *size) |
549 | 12.7k | { |
550 | 12.7k | uint8_t *ret = NULL; |
551 | 12.7k | uint8_t *copy = NULL, *copy_2 = NULL; |
552 | | |
553 | 12.7k | struct { |
554 | 12.7k | uint16_t size; |
555 | 12.7k | uint8_t srtp_func; |
556 | 12.7k | uint32_t mki; |
557 | 12.7k | uint8_t stretch; |
558 | 12.7k | } params_1; |
559 | | |
560 | 12.7k | struct { |
561 | 12.7k | uint8_t srtp_func; |
562 | 12.7k | uint32_t mki; |
563 | 12.7k | } params_2; |
564 | 12.7k | size_t ret_size; |
565 | | |
566 | 12.7k | EXTRACT_IF(¶ms_1, *data, *size, sizeof(params_1)); |
567 | 11.8k | params_1.srtp_func %= sizeof(srtp_funcs) / sizeof(srtp_funcs[0]); |
568 | | |
569 | 11.8k | if (*size < params_1.size) { |
570 | 56 | goto end; |
571 | 56 | } |
572 | | |
573 | | /* Enforce 4 byte alignment */ |
574 | 11.8k | if (g_no_align == false) { |
575 | 11.8k | params_1.size -= params_1.size % 4; |
576 | 11.8k | } |
577 | | |
578 | 11.8k | if (params_1.size == 0) { |
579 | 33 | goto end; |
580 | 33 | } |
581 | | |
582 | 11.7k | ret_size = params_1.size; |
583 | 11.7k | if (srtp_funcs[params_1.srtp_func].protect == true) { |
584 | | /* Intentionally not initialized to trigger MemorySanitizer, if |
585 | | * applicable */ |
586 | 10.7k | size_t alloc_size; |
587 | | |
588 | 10.7k | if (srtp_funcs[params_1.srtp_func].get_length( |
589 | 10.7k | srtp_ctx, params_1.mki, &alloc_size) != srtp_err_status_ok) { |
590 | 41 | goto end; |
591 | 41 | } |
592 | | |
593 | 10.7k | copy = fuzz_alloc_succeed(ret_size + alloc_size, false); |
594 | 10.7k | } else { |
595 | 997 | copy = fuzz_alloc_succeed(ret_size, false); |
596 | 997 | } |
597 | | |
598 | 11.7k | EXTRACT(copy, *data, *size, params_1.size); |
599 | | |
600 | 11.7k | if (srtp_funcs[params_1.srtp_func].srtp_func( |
601 | 11.7k | srtp_ctx, copy, &ret_size, params_1.mki) != srtp_err_status_ok) { |
602 | 1.52k | fuzz_free(copy); |
603 | 1.52k | goto end; |
604 | 1.52k | } |
605 | | // fuzz_free(copy); |
606 | | |
607 | 10.2k | fuzz_testmem(copy, ret_size); |
608 | | |
609 | 10.2k | ret = copy; |
610 | | |
611 | 10.2k | EXTRACT_IF(¶ms_2, *data, *size, sizeof(params_2)); |
612 | 9.75k | params_2.srtp_func %= sizeof(srtp_funcs) / sizeof(srtp_funcs[0]); |
613 | | |
614 | 9.75k | if (ret_size == 0) { |
615 | 0 | goto end; |
616 | 0 | } |
617 | | |
618 | 9.75k | if (srtp_funcs[params_2.srtp_func].protect == true) { |
619 | | /* Intentionally not initialized to trigger MemorySanitizer, if |
620 | | * applicable */ |
621 | 8.90k | size_t alloc_size; |
622 | | |
623 | 8.90k | if (srtp_funcs[params_2.srtp_func].get_length( |
624 | 8.90k | srtp_ctx, params_2.mki, &alloc_size) != srtp_err_status_ok) { |
625 | 212 | goto end; |
626 | 212 | } |
627 | | |
628 | 8.69k | copy_2 = fuzz_alloc_succeed(ret_size + alloc_size, false); |
629 | 8.69k | } else { |
630 | 849 | copy_2 = fuzz_alloc_succeed(ret_size, false); |
631 | 849 | } |
632 | | |
633 | 9.54k | memcpy(copy_2, copy, ret_size); |
634 | 9.54k | fuzz_free(copy); |
635 | 9.54k | copy = copy_2; |
636 | | |
637 | 9.54k | if (srtp_funcs[params_2.srtp_func].srtp_func( |
638 | 9.54k | srtp_ctx, copy, &ret_size, params_2.mki) != srtp_err_status_ok) { |
639 | 947 | fuzz_free(copy); |
640 | 947 | ret = NULL; |
641 | 947 | goto end; |
642 | 947 | } |
643 | | |
644 | 8.59k | fuzz_testmem(copy, ret_size); |
645 | | |
646 | 8.59k | ret = copy; |
647 | | |
648 | 12.7k | end: |
649 | 12.7k | return ret; |
650 | 8.59k | } |
651 | | |
652 | | void fuzz_srtp_event_handler(srtp_event_data_t *data) |
653 | 325 | { |
654 | 325 | fuzz_testmem(data, sizeof(srtp_event_data_t)); |
655 | 325 | if (data->session != NULL) { |
656 | 325 | fuzz_testmem(data->session, sizeof(*data->session)); |
657 | 325 | } |
658 | 325 | } |
659 | | |
660 | | static void fuzz_write_input(const uint8_t *data, size_t size) |
661 | 0 | { |
662 | 0 | FILE *fp = fopen("input.bin", "wb"); |
663 | |
|
664 | 0 | if (fp == NULL) { |
665 | | /* Shouldn't happen */ |
666 | 0 | abort(); |
667 | 0 | } |
668 | | |
669 | 0 | if (size != 0 && fwrite(data, size, 1, fp) != 1) { |
670 | 0 | printf("Cannot write\n"); |
671 | | /* Shouldn't happen */ |
672 | 0 | abort(); |
673 | 0 | } |
674 | | |
675 | 0 | fclose(fp); |
676 | 0 | } |
677 | | |
678 | | int LLVMFuzzerInitialize(int *argc, char ***argv) |
679 | 2 | { |
680 | 2 | char **_argv = *argv; |
681 | 2 | int i; |
682 | 2 | bool no_custom_event_handler = false; |
683 | | |
684 | 2 | if (srtp_init() != srtp_err_status_ok) { |
685 | | /* Shouldn't happen */ |
686 | 0 | abort(); |
687 | 0 | } |
688 | | |
689 | 13 | for (i = 0; i < *argc; i++) { |
690 | 11 | if (strcmp("--no_align", _argv[i]) == 0) { |
691 | 0 | g_no_align = true; |
692 | 11 | } else if (strcmp("--no_custom_event_handler", _argv[i]) == 0) { |
693 | 0 | no_custom_event_handler = true; |
694 | 11 | } else if (strcmp("--write_input", _argv[i]) == 0) { |
695 | 0 | g_write_input = true; |
696 | 0 | } |
697 | | #ifdef FUZZ_32BIT |
698 | | else if (strcmp("--no_mmap", _argv[i]) == 0) { |
699 | | g_no_mmap = true; |
700 | | } |
701 | | #endif |
702 | 11 | } |
703 | | |
704 | 2 | if (no_custom_event_handler == false) { |
705 | 2 | if (srtp_install_event_handler(fuzz_srtp_event_handler) != |
706 | 2 | srtp_err_status_ok) { |
707 | | /* Shouldn't happen */ |
708 | 0 | abort(); |
709 | 0 | } |
710 | 2 | } |
711 | | |
712 | | /* Fully initialized -- past this point, simulated allocation failures |
713 | | * are allowed to occur */ |
714 | 2 | g_post_init = true; |
715 | | |
716 | 2 | return 0; |
717 | 2 | } |
718 | | |
719 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
720 | 4.42k | { |
721 | 4.42k | uint8_t num_remove_stream; |
722 | 4.42k | uint32_t *remove_stream_ssrc = NULL; |
723 | 4.42k | uint8_t num_set_roc; |
724 | 4.42k | uint32_t *set_roc = NULL; |
725 | 4.42k | srtp_t srtp_ctx = NULL; |
726 | 4.42k | srtp_policy_t policy = NULL; |
727 | 4.42k | srtp_policy_t policy_2 = NULL; |
728 | 4.42k | uint32_t randseed; |
729 | 4.42k | static bool firstrun = true; |
730 | | |
731 | 4.42k | if (firstrun == true) { |
732 | | /* TODO version check etc and send it to MSAN */ |
733 | 4.42k | } |
734 | | |
735 | | #ifdef FUZZ_32BIT |
736 | | /* Free the mmap allocation made during the previous iteration, if |
737 | | * applicable */ |
738 | | fuzz_free(g_mmap_allocation); |
739 | | #endif |
740 | | |
741 | 4.42k | if (g_write_input == true) { |
742 | 0 | fuzz_write_input(data, size); |
743 | 0 | } |
744 | | |
745 | 4.42k | EXTRACT_IF(&randseed, data, size, sizeof(randseed)); |
746 | 4.42k | fuzz_mt19937_init(randseed); |
747 | 4.42k | srand(randseed); |
748 | | |
749 | | /* policy is used to initialize the srtp context with */ |
750 | 4.42k | if ((policy = extract_policy(&data, &size)) == NULL) { |
751 | 261 | goto end; |
752 | 261 | } |
753 | | |
754 | | /* Create context */ |
755 | 4.16k | if (srtp_create(&srtp_ctx, policy) != srtp_err_status_ok) { |
756 | 67 | goto end; |
757 | 67 | } |
758 | | |
759 | | /* Add additional policies extracted for initial stream setup */ |
760 | 4.09k | extract_more_policies_to_session(&data, &size, srtp_ctx); |
761 | | |
762 | | /* policy_2 is used as an argument for post-create stream additions */ |
763 | 4.09k | if ((policy_2 = extract_policy(&data, &size)) == NULL) { |
764 | 513 | goto end; |
765 | 513 | } |
766 | | |
767 | | /* Consume any additional policies from this second extraction phase */ |
768 | 3.58k | extract_more_policies_to_session(&data, &size, NULL); |
769 | | |
770 | | /* Don't check for NULL result -- no extractions is fine */ |
771 | 3.58k | remove_stream_ssrc = |
772 | 3.58k | extract_remove_stream_ssrc(&data, &size, &num_remove_stream); |
773 | | |
774 | | /* Don't check for NULL result -- no extractions is fine */ |
775 | 3.58k | set_roc = extract_set_roc(&data, &size, &num_set_roc); |
776 | | |
777 | 3.58k | { |
778 | 3.58k | uint8_t *ret; |
779 | 3.58k | int i = 0, j = 0; |
780 | | |
781 | 12.7k | while ((ret = run_srtp_func(srtp_ctx, &data, &size)) != NULL) { |
782 | 9.26k | fuzz_free(ret); |
783 | | |
784 | | /* Keep removing streams until the set of SSRCs extracted from the |
785 | | * fuzzer input is exhausted */ |
786 | 9.26k | if (i < num_remove_stream) { |
787 | 482 | if (srtp_stream_remove(srtp_ctx, remove_stream_ssrc[i]) != |
788 | 482 | srtp_err_status_ok) { |
789 | 60 | goto end; |
790 | 60 | } |
791 | 422 | i++; |
792 | 422 | } |
793 | | |
794 | | /* Keep setting and getting ROCs until the set of SSRC/ROC tuples |
795 | | * extracted from the fuzzer input is exhausted */ |
796 | 9.20k | if (j < num_set_roc * 2) { |
797 | 402 | uint32_t roc; |
798 | 402 | if (srtp_stream_set_roc(srtp_ctx, set_roc[j], set_roc[j + 1]) != |
799 | 402 | srtp_err_status_ok) { |
800 | 51 | goto end; |
801 | 51 | } |
802 | 351 | if (srtp_stream_get_roc(srtp_ctx, set_roc[j + 1], &roc) != |
803 | 351 | srtp_err_status_ok) { |
804 | 37 | goto end; |
805 | 37 | } |
806 | 314 | j += 2; |
807 | 314 | } |
808 | | |
809 | 9.11k | if (policy_2 != NULL) { |
810 | 1.01k | (void)srtp_stream_add(srtp_ctx, policy_2); |
811 | | |
812 | | /* Discard after using once */ |
813 | 1.01k | srtp_policy_destroy(policy_2); |
814 | 1.01k | policy_2 = NULL; |
815 | 1.01k | } |
816 | 9.11k | } |
817 | 3.58k | } |
818 | | |
819 | 4.42k | end: |
820 | 4.42k | srtp_policy_destroy(policy); |
821 | 4.42k | srtp_policy_destroy(policy_2); |
822 | 4.42k | fuzz_free(remove_stream_ssrc); |
823 | 4.42k | fuzz_free(set_roc); |
824 | 4.42k | if (srtp_ctx != NULL) { |
825 | 4.09k | srtp_dealloc(srtp_ctx); |
826 | 4.09k | } |
827 | 4.42k | fuzz_mt19937_destroy(); |
828 | | |
829 | 4.42k | return 0; |
830 | 3.58k | } |