• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params, *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(&params, *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(&params_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(&params_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