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 "ekt.h"
12 #include "fuzzer.h"
13 #include "mt19937.h"
14 #include "testmem.h"
15
16 /* Global variables */
17 static bool g_no_align = false; /* Can be enabled with --no_align */
18 static bool g_post_init =
19 false; /* Set to true once past initialization phase */
20 static bool g_write_input = false;
21
22 #ifdef FUZZ_32BIT
23 #include <sys/mman.h>
24 static bool g_no_mmap = false; /* Can be enabled with --no_mmap */
25 static void *g_mmap_allocation =
26 NULL; /* Keeps current mmap() allocation address */
27 static size_t g_mmap_allocation_size =
28 0; /* Keeps current mmap() allocation size */
29 #endif
30
31 /* Custom allocator functions */
32
fuzz_alloc(const size_t size,const bool do_zero)33 static void *fuzz_alloc(const size_t size, const bool do_zero)
34 {
35 void *ret = NULL;
36 #ifdef FUZZ_32BIT
37 bool do_malloc = true;
38 #endif
39 bool do_mmap, mmap_high = true;
40
41 if (size == 0) {
42 size_t ret;
43 /* Allocations of size 0 are not illegal, but are a bad practice, since
44 * writing just a single byte to this region constitutes undefined
45 * behavior per the C spec. glibc will return a small, valid memory
46 * region
47 * whereas OpenBSD will crash upon writing to it.
48 * Intentionally return a pointer to an invalid page to detect
49 * unsound code efficiently.
50 * fuzz_free is aware of this pointer range and will not attempt
51 * to free()/munmap() it.
52 */
53 ret = 0x01 + (fuzz_mt19937_get() % 1024);
54 return (void *)ret;
55 }
56
57 /* Don't do mmap()-based allocations during initialization */
58 if (g_post_init == true) {
59 /* Even extract these values if --no_mmap is specified.
60 * This keeps the PRNG output stream consistent across
61 * fuzzer configurations.
62 */
63 do_mmap = (fuzz_mt19937_get() % 64) == 0 ? true : false;
64 if (do_mmap == true) {
65 mmap_high = (fuzz_mt19937_get() % 2) == 0 ? true : false;
66 }
67 } else {
68 do_mmap = false;
69 }
70
71 #ifdef FUZZ_32BIT
72 /* g_mmap_allocation must be NULL because we only support a single
73 * concurrent mmap allocation at a time
74 */
75 if (g_mmap_allocation == NULL && g_no_mmap == false && do_mmap == true) {
76 void *mmap_address;
77 if (mmap_high == true) {
78 mmap_address = (void *)0xFFFF0000;
79 } else {
80 mmap_address = (void *)0x00010000;
81 }
82 g_mmap_allocation_size = size;
83
84 ret = mmap(mmap_address, g_mmap_allocation_size, PROT_READ | PROT_WRITE,
85 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
86
87 if (ret == MAP_FAILED) {
88 /* That's okay -- just return NULL to the caller */
89
90 ret = NULL;
91
92 /* Reset this for the sake of cleanliness */
93 g_mmap_allocation_size = 0;
94 }
95 /* ret not being MAP_FAILED does not mean that ret is the requested
96 * address (mmap_address). That's okay. We're not going to perform
97 * a munmap() on it and call malloc() instead. It won't gain us
98 * anything.
99 */
100
101 g_mmap_allocation = ret;
102 do_malloc = false;
103 }
104
105 if (do_malloc == true)
106 #endif
107 {
108 ret = malloc(size);
109 }
110
111 /* Mimic calloc() if so requested */
112 if (ret != NULL && do_zero) {
113 memset(ret, 0, size);
114 }
115
116 return ret;
117 }
118
119 /* Internal allocations by this fuzzer must on one hand (sometimes)
120 * receive memory from mmap(), but on the other hand these requests for
121 * memory may not fail. By calling this function, the allocation is
122 * guaranteed to succeed; it first tries with fuzz_alloc(), which may
123 * fail if it uses mmap(), and if that is the case, memory is allocated
124 * via the libc allocator (malloc, calloc) which should always succeed */
fuzz_alloc_succeed(const size_t size,const bool do_zero)125 static void *fuzz_alloc_succeed(const size_t size, const bool do_zero)
126 {
127 void *ret = fuzz_alloc(size, do_zero);
128 if (ret == NULL) {
129 if (do_zero == false) {
130 ret = malloc(size);
131 } else {
132 ret = calloc(1, size);
133 }
134 }
135
136 return ret;
137 }
138
fuzz_calloc(const size_t nmemb,const size_t size)139 void *fuzz_calloc(const size_t nmemb, const size_t size)
140 {
141 /* We must be past srtp_init() to prevent that that function fails */
142 if (g_post_init == true) {
143 /* Fail 1 in 64 allocations on average to test whether the library
144 * can deal with this properly.
145 */
146 if ((fuzz_mt19937_get() % 64) == 0) {
147 return NULL;
148 }
149 }
150
151 return fuzz_alloc(nmemb * size, true);
152 }
153
fuzz_is_special_pointer(void * ptr)154 static bool fuzz_is_special_pointer(void *ptr)
155 {
156 /* Special, invalid pointers introduced when code attempted
157 * to do size = 0 allocations.
158 */
159 if ((size_t)ptr >= 0x01 && (size_t)ptr < (0x01 + 1024)) {
160 return true;
161 } else {
162 return false;
163 }
164 }
165
fuzz_free(void * ptr)166 void fuzz_free(void *ptr)
167 {
168 if (fuzz_is_special_pointer(ptr) == true) {
169 return;
170 }
171
172 #ifdef FUZZ_32BIT
173 if (g_post_init == true && ptr != NULL && ptr == g_mmap_allocation) {
174 if (munmap(g_mmap_allocation, g_mmap_allocation_size) == -1) {
175 /* Shouldn't happen */
176 abort();
177 }
178 g_mmap_allocation = NULL;
179 } else
180 #endif
181 {
182 free(ptr);
183 }
184 }
185
fuzz_srtp_protect(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)186 static srtp_err_status_t fuzz_srtp_protect(srtp_t srtp_sender,
187 void *hdr,
188 int *len,
189 uint8_t use_mki,
190 unsigned int mki)
191 {
192 return srtp_protect(srtp_sender, hdr, len);
193 }
194
fuzz_srtp_unprotect(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)195 static srtp_err_status_t fuzz_srtp_unprotect(srtp_t srtp_sender,
196 void *hdr,
197 int *len,
198 uint8_t use_mki,
199 unsigned int mki)
200 {
201 return srtp_unprotect(srtp_sender, hdr, len);
202 }
203
fuzz_srtp_protect_rtcp(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)204 static srtp_err_status_t fuzz_srtp_protect_rtcp(srtp_t srtp_sender,
205 void *hdr,
206 int *len,
207 uint8_t use_mki,
208 unsigned int mki)
209 {
210 return srtp_protect_rtcp(srtp_sender, hdr, len);
211 }
212
fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)213 static srtp_err_status_t fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender,
214 void *hdr,
215 int *len,
216 uint8_t use_mki,
217 unsigned int mki)
218 {
219 return srtp_unprotect_rtcp(srtp_sender, hdr, len);
220 }
221
fuzz_srtp_protect_mki(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)222 static srtp_err_status_t fuzz_srtp_protect_mki(srtp_t srtp_sender,
223 void *hdr,
224 int *len,
225 uint8_t use_mki,
226 unsigned int mki)
227 {
228 return srtp_protect_mki(srtp_sender, hdr, len, use_mki, mki);
229 }
230
fuzz_srtp_protect_rtcp_mki(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)231 static srtp_err_status_t fuzz_srtp_protect_rtcp_mki(srtp_t srtp_sender,
232 void *hdr,
233 int *len,
234 uint8_t use_mki,
235 unsigned int mki)
236 {
237 return srtp_protect_rtcp_mki(srtp_sender, hdr, len, use_mki, mki);
238 }
239
fuzz_srtp_unprotect_mki(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)240 static srtp_err_status_t fuzz_srtp_unprotect_mki(srtp_t srtp_sender,
241 void *hdr,
242 int *len,
243 uint8_t use_mki,
244 unsigned int mki)
245 {
246 return srtp_unprotect_mki(srtp_sender, hdr, len, use_mki);
247 }
248
fuzz_srtp_unprotect_rtcp_mki(srtp_t srtp_sender,void * hdr,int * len,uint8_t use_mki,unsigned int mki)249 static srtp_err_status_t fuzz_srtp_unprotect_rtcp_mki(srtp_t srtp_sender,
250 void *hdr,
251 int *len,
252 uint8_t use_mki,
253 unsigned int mki)
254 {
255 return srtp_unprotect_rtcp_mki(srtp_sender, hdr, len, use_mki);
256 }
257
258 /* Get protect length functions */
259
fuzz_srtp_get_protect_length(const srtp_t srtp_ctx,uint8_t use_mki,unsigned int mki,uint32_t * length)260 static srtp_err_status_t fuzz_srtp_get_protect_length(const srtp_t srtp_ctx,
261 uint8_t use_mki,
262 unsigned int mki,
263 uint32_t *length)
264 {
265 return srtp_get_protect_trailer_length(srtp_ctx, 0, 0, length);
266 }
267
fuzz_srtp_get_protect_rtcp_length(const srtp_t srtp_ctx,uint8_t use_mki,unsigned int mki,uint32_t * length)268 static srtp_err_status_t fuzz_srtp_get_protect_rtcp_length(
269 const srtp_t srtp_ctx,
270 uint8_t use_mki,
271 unsigned int mki,
272 uint32_t *length)
273 {
274 return srtp_get_protect_rtcp_trailer_length(srtp_ctx, 0, 0, length);
275 }
276
fuzz_srtp_get_protect_mki_length(const srtp_t srtp_ctx,uint8_t use_mki,unsigned int mki,uint32_t * length)277 static srtp_err_status_t fuzz_srtp_get_protect_mki_length(const srtp_t srtp_ctx,
278 uint8_t use_mki,
279 unsigned int mki,
280 uint32_t *length)
281 {
282 return srtp_get_protect_trailer_length(srtp_ctx, use_mki, mki, length);
283 }
284
fuzz_srtp_get_protect_rtcp_mki_length(const srtp_t srtp_ctx,uint8_t use_mki,unsigned int mki,uint32_t * length)285 static srtp_err_status_t fuzz_srtp_get_protect_rtcp_mki_length(
286 const srtp_t srtp_ctx,
287 uint8_t use_mki,
288 unsigned int mki,
289 uint32_t *length)
290 {
291 return srtp_get_protect_rtcp_trailer_length(srtp_ctx, use_mki, mki, length);
292 }
293
extract_key(const uint8_t ** data,size_t * size,const size_t key_size)294 static uint8_t *extract_key(const uint8_t **data,
295 size_t *size,
296 const size_t key_size)
297 {
298 uint8_t *ret;
299 if (*size < key_size) {
300 return NULL;
301 }
302
303 ret = fuzz_alloc_succeed(key_size, false);
304 EXTRACT(ret, *data, *size, key_size);
305
306 return ret;
307 }
308
extract_master_key(const uint8_t ** data,size_t * size,const size_t key_size,bool simulate,bool * success)309 static srtp_master_key_t *extract_master_key(const uint8_t **data,
310 size_t *size,
311 const size_t key_size,
312 bool simulate,
313 bool *success)
314 {
315 srtp_master_key_t *ret = NULL;
316 uint16_t mki_id_size;
317
318 if (simulate == true) {
319 *success = false;
320 }
321
322 EXTRACT_IF(&mki_id_size, *data, *size, sizeof(mki_id_size));
323
324 if (*size < key_size + mki_id_size) {
325 goto end;
326 }
327
328 if (simulate == true) {
329 *data += key_size + mki_id_size;
330 *size -= key_size + mki_id_size;
331 *success = true;
332 goto end;
333 }
334
335 ret = fuzz_alloc_succeed(sizeof(srtp_master_key_t), false);
336 ret->key = fuzz_alloc_succeed(key_size, false);
337
338 ret->mki_id = fuzz_alloc_succeed(mki_id_size, false);
339
340 EXTRACT(ret->key, *data, *size, key_size);
341 EXTRACT(ret->mki_id, *data, *size, mki_id_size);
342 ret->mki_size = mki_id_size;
343 end:
344 return ret;
345 }
346
extract_master_keys(const uint8_t ** data,size_t * size,const size_t key_size,unsigned long * num_master_keys)347 static srtp_master_key_t **extract_master_keys(const uint8_t **data,
348 size_t *size,
349 const size_t key_size,
350 unsigned long *num_master_keys)
351 {
352 const uint8_t *data_orig = *data;
353 size_t size_orig = *size;
354 size_t i = 0;
355
356 srtp_master_key_t **ret = NULL;
357
358 *num_master_keys = 0;
359
360 /* First pass -- dry run, determine how many keys we want and can extract */
361 while (1) {
362 uint8_t do_extract_master_key;
363 bool success;
364 if (*size < sizeof(do_extract_master_key)) {
365 goto next;
366 }
367 EXTRACT(&do_extract_master_key, *data, *size,
368 sizeof(do_extract_master_key));
369
370 /* Decide whether to extract another key */
371 if ((do_extract_master_key % 2) == 0) {
372 break;
373 }
374
375 extract_master_key(data, size, key_size, true, &success);
376
377 if (success == false) {
378 break;
379 }
380
381 (*num_master_keys)++;
382 }
383
384 next:
385 *data = data_orig;
386 *size = size_orig;
387
388 /* Allocate array of pointers */
389 ret = fuzz_alloc_succeed(*num_master_keys * sizeof(srtp_master_key_t *),
390 false);
391
392 /* Second pass -- perform the actual extractions */
393 for (i = 0; i < *num_master_keys; i++) {
394 uint8_t do_extract_master_key;
395 EXTRACT_IF(&do_extract_master_key, *data, *size,
396 sizeof(do_extract_master_key));
397
398 if ((do_extract_master_key % 2) == 0) {
399 break;
400 }
401
402 ret[i] = extract_master_key(data, size, key_size, false, NULL);
403
404 if (ret[i] == NULL) {
405 /* Shouldn't happen */
406 abort();
407 }
408 }
409
410 end:
411 return ret;
412 }
413
extract_ekt_policy(const uint8_t ** data,size_t * size)414 static srtp_ekt_policy_t extract_ekt_policy(const uint8_t **data, size_t *size)
415 {
416 srtp_ekt_policy_t ret = NULL;
417 struct {
418 srtp_ekt_spi_t spi;
419 uint8_t key[16];
420
421 } params;
422
423 EXTRACT_IF(¶ms, *data, *size, sizeof(params));
424
425 ret = fuzz_alloc_succeed(sizeof(struct srtp_ekt_policy_ctx_t), false);
426
427 ret->spi = params.spi;
428
429 /* The only supported cipher type */
430 ret->ekt_cipher_type = SRTP_EKT_CIPHER_AES_128_ECB;
431
432 ret->ekt_key = fuzz_alloc_succeed(sizeof(params.key), false);
433 memcpy(ret->ekt_key, params.key, sizeof(params.key));
434
435 ret->next_ekt_policy = NULL;
436
437 end:
438 return ret;
439 }
440
extract_policy(const uint8_t ** data,size_t * size)441 static srtp_policy_t *extract_policy(const uint8_t **data, size_t *size)
442 {
443 srtp_policy_t *policy = NULL;
444 struct {
445 uint8_t srtp_crypto_policy_func;
446 uint64_t window_size;
447 uint8_t allow_repeat_tx;
448 uint8_t ssrc_type;
449 uint32_t ssrc_value;
450 uint8_t num_xtn_hdr;
451 uint8_t with_ekt;
452 srtp_ekt_spi_t ekt_spi;
453 uint8_t do_extract_key;
454 uint8_t do_extract_master_keys;
455 } params;
456
457 EXTRACT_IF(¶ms, *data, *size, sizeof(params));
458
459 params.srtp_crypto_policy_func %= sizeof(fuzz_srtp_crypto_policies) /
460 sizeof(fuzz_srtp_crypto_policies[0]);
461 params.allow_repeat_tx %= 2;
462 params.ssrc_type %=
463 sizeof(fuzz_ssrc_type_map) / sizeof(fuzz_ssrc_type_map[0]);
464 params.with_ekt %= 2;
465
466 policy = fuzz_alloc_succeed(sizeof(*policy), true);
467
468 fuzz_srtp_crypto_policies[params.srtp_crypto_policy_func]
469 .crypto_policy_func(&policy->rtp);
470 fuzz_srtp_crypto_policies[params.srtp_crypto_policy_func]
471 .crypto_policy_func(&policy->rtcp);
472
473 if (policy->rtp.cipher_key_len > MAX_KEY_LEN) {
474 /* Shouldn't happen */
475 abort();
476 }
477
478 policy->ssrc.type = fuzz_ssrc_type_map[params.ssrc_type].srtp_ssrc_type;
479 policy->ssrc.value = params.ssrc_value;
480
481 if ((params.do_extract_key % 2) == 0) {
482 policy->key = extract_key(data, size, policy->rtp.cipher_key_len);
483
484 if (policy->key == NULL) {
485 fuzz_free(policy);
486 return NULL;
487 }
488 }
489
490 if (params.num_xtn_hdr != 0) {
491 const size_t xtn_hdr_size = params.num_xtn_hdr * sizeof(int);
492 if (*size < xtn_hdr_size) {
493 fuzz_free(policy->key);
494 fuzz_free(policy);
495 return NULL;
496 }
497 policy->enc_xtn_hdr = fuzz_alloc_succeed(xtn_hdr_size, false);
498 EXTRACT(policy->enc_xtn_hdr, *data, *size, xtn_hdr_size);
499 policy->enc_xtn_hdr_count = params.num_xtn_hdr;
500 }
501
502 if ((params.do_extract_master_keys % 2) == 0) {
503 policy->keys = extract_master_keys(
504 data, size, policy->rtp.cipher_key_len, &policy->num_master_keys);
505 if (policy->keys == NULL) {
506 fuzz_free(policy->key);
507 fuzz_free(policy->enc_xtn_hdr);
508 fuzz_free(policy);
509 return NULL;
510 }
511 }
512
513 if (params.with_ekt) {
514 policy->ekt = extract_ekt_policy(data, size);
515 }
516
517 policy->window_size = params.window_size;
518 policy->allow_repeat_tx = params.allow_repeat_tx;
519 policy->next = NULL;
520
521 end:
522 return policy;
523 }
524
extract_policies(const uint8_t ** data,size_t * size)525 static srtp_policy_t *extract_policies(const uint8_t **data, size_t *size)
526 {
527 srtp_policy_t *curpolicy = NULL, *policy_chain = NULL;
528
529 curpolicy = extract_policy(data, size);
530 if (curpolicy == NULL) {
531 return NULL;
532 }
533
534 policy_chain = curpolicy;
535
536 while (1) {
537 uint8_t do_extract_policy;
538 EXTRACT_IF(&do_extract_policy, *data, *size, sizeof(do_extract_policy));
539
540 /* Decide whether to extract another policy */
541 if ((do_extract_policy % 2) == 0) {
542 break;
543 }
544
545 curpolicy->next = extract_policy(data, size);
546 if (curpolicy->next == NULL) {
547 break;
548 }
549 curpolicy = curpolicy->next;
550 }
551
552 end:
553 return policy_chain;
554 }
555
extract_remove_stream_ssrc(const uint8_t ** data,size_t * size,uint8_t * num_remove_stream)556 static uint32_t *extract_remove_stream_ssrc(const uint8_t **data,
557 size_t *size,
558 uint8_t *num_remove_stream)
559 {
560 uint32_t *ret = NULL;
561 uint8_t _num_remove_stream;
562 size_t total_size;
563
564 *num_remove_stream = 0;
565
566 EXTRACT_IF(&_num_remove_stream, *data, *size, sizeof(_num_remove_stream));
567
568 if (_num_remove_stream == 0) {
569 goto end;
570 }
571
572 total_size = _num_remove_stream * sizeof(uint32_t);
573
574 if (*size < total_size) {
575 goto end;
576 }
577
578 ret = fuzz_alloc_succeed(total_size, false);
579 EXTRACT(ret, *data, *size, total_size);
580
581 *num_remove_stream = _num_remove_stream;
582
583 end:
584 return ret;
585 }
586
extract_set_roc(const uint8_t ** data,size_t * size,uint8_t * num_set_roc)587 static uint32_t *extract_set_roc(const uint8_t **data,
588 size_t *size,
589 uint8_t *num_set_roc)
590 {
591 uint32_t *ret = NULL;
592 uint8_t _num_set_roc;
593 size_t total_size;
594
595 *num_set_roc = 0;
596 EXTRACT_IF(&_num_set_roc, *data, *size, sizeof(_num_set_roc));
597 if (_num_set_roc == 0) {
598 goto end;
599 }
600
601 /* Tuples of 2 uint32_t's */
602 total_size = _num_set_roc * sizeof(uint32_t) * 2;
603
604 if (*size < total_size) {
605 goto end;
606 }
607
608 ret = fuzz_alloc_succeed(total_size, false);
609 EXTRACT(ret, *data, *size, total_size);
610
611 *num_set_roc = _num_set_roc;
612
613 end:
614 return ret;
615 }
616
free_policies(srtp_policy_t * curpolicy)617 static void free_policies(srtp_policy_t *curpolicy)
618 {
619 size_t i;
620 while (curpolicy) {
621 srtp_policy_t *next = curpolicy->next;
622
623 fuzz_free(curpolicy->key);
624
625 for (i = 0; i < curpolicy->num_master_keys; i++) {
626 fuzz_free(curpolicy->keys[i]->key);
627 fuzz_free(curpolicy->keys[i]->mki_id);
628 fuzz_free(curpolicy->keys[i]);
629 }
630
631 fuzz_free(curpolicy->keys);
632 fuzz_free(curpolicy->enc_xtn_hdr);
633
634 if (curpolicy->ekt) {
635 fuzz_free(curpolicy->ekt->ekt_key);
636 fuzz_free(curpolicy->ekt);
637 }
638
639 fuzz_free(curpolicy);
640
641 curpolicy = next;
642 }
643 }
644
run_srtp_func(const srtp_t srtp_ctx,const uint8_t ** data,size_t * size)645 static uint8_t *run_srtp_func(const srtp_t srtp_ctx,
646 const uint8_t **data,
647 size_t *size)
648 {
649 uint8_t *ret = NULL;
650 uint8_t *copy = NULL, *copy_2 = NULL;
651
652 struct {
653 uint16_t size;
654 uint8_t srtp_func;
655 uint8_t use_mki;
656 uint32_t mki;
657 uint8_t stretch;
658 } params_1;
659
660 struct {
661 uint8_t srtp_func;
662 uint8_t use_mki;
663 uint32_t mki;
664 } params_2;
665 int ret_size;
666
667 EXTRACT_IF(¶ms_1, *data, *size, sizeof(params_1));
668 params_1.srtp_func %= sizeof(srtp_funcs) / sizeof(srtp_funcs[0]);
669 params_1.use_mki %= 2;
670
671 if (*size < params_1.size) {
672 goto end;
673 }
674
675 /* Enforce 4 byte alignment */
676 if (g_no_align == false) {
677 params_1.size -= params_1.size % 4;
678 }
679
680 if (params_1.size == 0) {
681 goto end;
682 }
683
684 ret_size = params_1.size;
685 if (srtp_funcs[params_1.srtp_func].protect == true) {
686 /* Intentionally not initialized to trigger MemorySanitizer, if
687 * applicable */
688 uint32_t alloc_size;
689
690 if (srtp_funcs[params_1.srtp_func].get_length(
691 srtp_ctx, params_1.use_mki, params_1.mki, &alloc_size) !=
692 srtp_err_status_ok) {
693 goto end;
694 }
695
696 copy = fuzz_alloc_succeed(ret_size + alloc_size, false);
697 } else {
698 copy = fuzz_alloc_succeed(ret_size, false);
699 }
700
701 EXTRACT(copy, *data, *size, params_1.size);
702
703 if (srtp_funcs[params_1.srtp_func].srtp_func(
704 srtp_ctx, copy, &ret_size, params_1.use_mki, params_1.mki) !=
705 srtp_err_status_ok) {
706 fuzz_free(copy);
707 goto end;
708 }
709 // fuzz_free(copy);
710
711 fuzz_testmem(copy, ret_size);
712
713 ret = copy;
714
715 EXTRACT_IF(¶ms_2, *data, *size, sizeof(params_2));
716 params_2.srtp_func %= sizeof(srtp_funcs) / sizeof(srtp_funcs[0]);
717 params_2.use_mki %= 2;
718
719 if (ret_size == 0) {
720 goto end;
721 }
722
723 if (srtp_funcs[params_2.srtp_func].protect == true) {
724 /* Intentionally not initialized to trigger MemorySanitizer, if
725 * applicable */
726 uint32_t alloc_size;
727
728 if (srtp_funcs[params_2.srtp_func].get_length(
729 srtp_ctx, params_2.use_mki, params_2.mki, &alloc_size) !=
730 srtp_err_status_ok) {
731 goto end;
732 }
733
734 copy_2 = fuzz_alloc_succeed(ret_size + alloc_size, false);
735 } else {
736 copy_2 = fuzz_alloc_succeed(ret_size, false);
737 }
738
739 memcpy(copy_2, copy, ret_size);
740 fuzz_free(copy);
741 copy = copy_2;
742
743 if (srtp_funcs[params_2.srtp_func].srtp_func(
744 srtp_ctx, copy, &ret_size, params_2.use_mki, params_2.mki) !=
745 srtp_err_status_ok) {
746 fuzz_free(copy);
747 ret = NULL;
748 goto end;
749 }
750
751 fuzz_testmem(copy, ret_size);
752
753 ret = copy;
754
755 end:
756 return ret;
757 }
758
fuzz_srtp_event_handler(srtp_event_data_t * data)759 void fuzz_srtp_event_handler(srtp_event_data_t *data)
760 {
761 fuzz_testmem(data, sizeof(srtp_event_data_t));
762 if (data->session != NULL) {
763 fuzz_testmem(data->session, sizeof(*data->session));
764 }
765 }
766
fuzz_write_input(const uint8_t * data,size_t size)767 static void fuzz_write_input(const uint8_t *data, size_t size)
768 {
769 FILE *fp = fopen("input.bin", "wb");
770
771 if (fp == NULL) {
772 /* Shouldn't happen */
773 abort();
774 }
775
776 if (size != 0 && fwrite(data, size, 1, fp) != 1) {
777 printf("Cannot write\n");
778 /* Shouldn't happen */
779 abort();
780 }
781
782 fclose(fp);
783 }
784
LLVMFuzzerInitialize(int * argc,char *** argv)785 int LLVMFuzzerInitialize(int *argc, char ***argv)
786 {
787 char **_argv = *argv;
788 int i;
789 bool no_custom_event_handler = false;
790
791 if (srtp_init() != srtp_err_status_ok) {
792 /* Shouldn't happen */
793 abort();
794 }
795
796 for (i = 0; i < *argc; i++) {
797 if (strcmp("--no_align", _argv[i]) == 0) {
798 g_no_align = true;
799 } else if (strcmp("--no_custom_event_handler", _argv[i]) == 0) {
800 no_custom_event_handler = true;
801 } else if (strcmp("--write_input", _argv[i]) == 0) {
802 g_write_input = true;
803 }
804 #ifdef FUZZ_32BIT
805 else if (strcmp("--no_mmap", _argv[i]) == 0) {
806 g_no_mmap = true;
807 }
808 #endif
809 else if (strncmp("--", _argv[i], 2) == 0) {
810 printf("Invalid argument: %s\n", _argv[i]);
811 exit(0);
812 }
813 }
814
815 if (no_custom_event_handler == false) {
816 if (srtp_install_event_handler(fuzz_srtp_event_handler) !=
817 srtp_err_status_ok) {
818 /* Shouldn't happen */
819 abort();
820 }
821 }
822
823 /* Fully initialized -- past this point, simulated allocation failures
824 * are allowed to occur */
825 g_post_init = true;
826
827 return 0;
828 }
829
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)830 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
831 {
832 uint8_t num_remove_stream;
833 uint32_t *remove_stream_ssrc = NULL;
834 uint8_t num_set_roc;
835 uint32_t *set_roc = NULL;
836 srtp_t srtp_ctx = NULL;
837 srtp_policy_t *policy_chain = NULL, *policy_chain_2 = NULL;
838 uint32_t randseed;
839 static bool firstrun = true;
840
841 if (firstrun == true) {
842 /* TODO version check etc and send it to MSAN */
843 }
844
845 #ifdef FUZZ_32BIT
846 /* Free the mmap allocation made during the previous iteration, if
847 * applicable */
848 fuzz_free(g_mmap_allocation);
849 #endif
850
851 if (g_write_input == true) {
852 fuzz_write_input(data, size);
853 }
854
855 EXTRACT_IF(&randseed, data, size, sizeof(randseed));
856 fuzz_mt19937_init(randseed);
857 srand(randseed);
858
859 /* policy_chain is used to initialize the srtp context with */
860 if ((policy_chain = extract_policies(&data, &size)) == NULL) {
861 goto end;
862 }
863 /* policy_chain_2 is used as an argument to srtp_update later on */
864 if ((policy_chain_2 = extract_policies(&data, &size)) == NULL) {
865 goto end;
866 }
867
868 /* Create context */
869 if (srtp_create(&srtp_ctx, policy_chain) != srtp_err_status_ok) {
870 goto end;
871 }
872
873 // free_policies(policy_chain);
874 // policy_chain = NULL;
875
876 /* Don't check for NULL result -- no extractions is fine */
877 remove_stream_ssrc =
878 extract_remove_stream_ssrc(&data, &size, &num_remove_stream);
879
880 /* Don't check for NULL result -- no extractions is fine */
881 set_roc = extract_set_roc(&data, &size, &num_set_roc);
882
883 {
884 uint8_t *ret;
885 int i = 0, j = 0;
886
887 while ((ret = run_srtp_func(srtp_ctx, &data, &size)) != NULL) {
888 fuzz_free(ret);
889
890 /* Keep removing streams until the set of SSRCs extracted from the
891 * fuzzer input is exhausted */
892 if (i < num_remove_stream) {
893 if (srtp_remove_stream(srtp_ctx, remove_stream_ssrc[i]) !=
894 srtp_err_status_ok) {
895 goto end;
896 }
897 i++;
898 }
899
900 /* Keep setting and getting ROCs until the set of SSRC/ROC tuples
901 * extracted from the fuzzer input is exhausted */
902 if (j < num_set_roc * 2) {
903 uint32_t roc;
904 if (srtp_set_stream_roc(srtp_ctx, set_roc[j], set_roc[j + 1]) !=
905 srtp_err_status_ok) {
906 goto end;
907 }
908 if (srtp_get_stream_roc(srtp_ctx, set_roc[j + 1], &roc) !=
909 srtp_err_status_ok) {
910 goto end;
911 }
912 j += 2;
913 }
914
915 if (policy_chain_2 != NULL) {
916 /* TODO srtp_update(srtp_ctx, policy_chain_2); */
917
918 /* Discard after using once */
919 free_policies(policy_chain_2);
920 policy_chain_2 = NULL;
921 }
922 }
923 }
924
925 end:
926 free_policies(policy_chain);
927 free_policies(policy_chain_2);
928 fuzz_free(remove_stream_ssrc);
929 fuzz_free(set_roc);
930 if (srtp_ctx != NULL) {
931 srtp_dealloc(srtp_ctx);
932 }
933 fuzz_mt19937_destroy();
934
935 return 0;
936 }
937