tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dav1d_fuzzer.c (5887B)


      1 /*
      2 * Copyright © 2018, VideoLAN and dav1d authors
      3 * Copyright © 2018, Janne Grunau
      4 * All rights reserved.
      5 *
      6 * Redistribution and use in source and binary forms, with or without
      7 * modification, are permitted provided that the following conditions are met:
      8 *
      9 * 1. Redistributions of source code must retain the above copyright notice, this
     10 *    list of conditions and the following disclaimer.
     11 *
     12 * 2. Redistributions in binary form must reproduce the above copyright notice,
     13 *    this list of conditions and the following disclaimer in the documentation
     14 *    and/or other materials provided with the distribution.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27 
     28 #include "config.h"
     29 
     30 #include <errno.h>
     31 #include <stddef.h>
     32 #include <stdint.h>
     33 #include <string.h>
     34 #include <stdlib.h>
     35 
     36 #include <dav1d/dav1d.h>
     37 #include "src/cpu.h"
     38 #include "dav1d_fuzzer.h"
     39 
     40 #ifdef DAV1D_ALLOC_FAIL
     41 
     42 #include "alloc_fail.h"
     43 
     44 static unsigned djb_xor(const uint8_t * c, size_t len) {
     45    unsigned hash = 5381;
     46    for(size_t i = 0; i < len; i++)
     47        hash = hash * 33 ^ c[i];
     48    return hash;
     49 }
     50 #endif
     51 
     52 static unsigned r32le(const uint8_t *const p) {
     53    return ((uint32_t)p[3] << 24U) | (p[2] << 16U) | (p[1] << 8U) | p[0];
     54 }
     55 
     56 #define DAV1D_FUZZ_MAX_SIZE 4096 * 4096
     57 
     58 // search for "--cpumask xxx" in argv and remove both parameters
     59 int LLVMFuzzerInitialize(int *argc, char ***argv) {
     60    int i = 1;
     61    for (; i < *argc; i++) {
     62        if (!strcmp((*argv)[i], "--cpumask")) {
     63            const char * cpumask = (*argv)[i+1];
     64            if (cpumask) {
     65                char *end;
     66                unsigned res;
     67                if (!strncmp(cpumask, "0x", 2)) {
     68                    cpumask += 2;
     69                    res = (unsigned) strtoul(cpumask, &end, 16);
     70                } else {
     71                    res = (unsigned) strtoul(cpumask, &end, 0);
     72                }
     73                if (end != cpumask && !end[0]) {
     74                    dav1d_set_cpu_flags_mask(res);
     75                }
     76            }
     77            break;
     78        }
     79    }
     80 
     81    for (; i < *argc - 2; i++) {
     82        (*argv)[i] = (*argv)[i + 2];
     83    }
     84 
     85    *argc = i;
     86 
     87    return 0;
     88 }
     89 
     90 
     91 // expects ivf input
     92 
     93 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
     94 {
     95    Dav1dSettings settings = { 0 };
     96    Dav1dContext * ctx = NULL;
     97    Dav1dPicture pic;
     98    const uint8_t *ptr = data;
     99    int have_seq_hdr = 0;
    100    int err;
    101 
    102    dav1d_version();
    103 
    104    if (size < 32) goto end;
    105 #ifdef DAV1D_ALLOC_FAIL
    106    unsigned h = djb_xor(ptr, 32);
    107    unsigned seed = h;
    108    unsigned probability = h > (RAND_MAX >> 5) ? RAND_MAX >> 5 : h;
    109    int max_frame_delay = (h & 0xf) + 1;
    110    int n_threads = ((h >> 4) & 0x7) + 1;
    111    if (max_frame_delay > 5) max_frame_delay = 1;
    112    if (n_threads > 3) n_threads = 1;
    113 #endif
    114    ptr += 32; // skip ivf header
    115 
    116    dav1d_default_settings(&settings);
    117 
    118 #ifdef DAV1D_MT_FUZZING
    119    settings.max_frame_delay = settings.n_threads = 4;
    120 #elif defined(DAV1D_ALLOC_FAIL)
    121    settings.max_frame_delay = max_frame_delay;
    122    settings.n_threads = n_threads;
    123    dav1d_setup_alloc_fail(seed, probability);
    124 #else
    125    settings.max_frame_delay = settings.n_threads = 1;
    126 #endif
    127 #if defined(DAV1D_FUZZ_MAX_SIZE)
    128    settings.frame_size_limit = DAV1D_FUZZ_MAX_SIZE;
    129 #endif
    130 
    131    err = dav1d_open(&ctx, &settings);
    132    if (err < 0) goto end;
    133 
    134    while (ptr <= data + size - 12) {
    135        Dav1dData buf;
    136        uint8_t *p;
    137 
    138        size_t frame_size = r32le(ptr);
    139        ptr += 12;
    140 
    141        if (frame_size > size || ptr > data + size - frame_size)
    142            break;
    143 
    144        if (!frame_size) continue;
    145 
    146        if (!have_seq_hdr) {
    147            Dav1dSequenceHeader seq;
    148            int err = dav1d_parse_sequence_header(&seq, ptr, frame_size);
    149            // skip frames until we see a sequence header
    150            if  (err != 0) {
    151                ptr += frame_size;
    152                continue;
    153            }
    154            have_seq_hdr = 1;
    155        }
    156 
    157        // copy frame data to a new buffer to catch reads past the end of input
    158        p = dav1d_data_create(&buf, frame_size);
    159        if (!p) goto cleanup;
    160        memcpy(p, ptr, frame_size);
    161        ptr += frame_size;
    162 
    163        do {
    164            if ((err = dav1d_send_data(ctx, &buf)) < 0) {
    165                if (err != DAV1D_ERR(EAGAIN))
    166                    break;
    167            }
    168            memset(&pic, 0, sizeof(pic));
    169            err = dav1d_get_picture(ctx, &pic);
    170            if (err == 0) {
    171                dav1d_picture_unref(&pic);
    172            } else if (err != DAV1D_ERR(EAGAIN)) {
    173                break;
    174            }
    175        } while (buf.sz > 0);
    176 
    177        if (buf.sz > 0)
    178            dav1d_data_unref(&buf);
    179    }
    180 
    181    memset(&pic, 0, sizeof(pic));
    182    if ((err = dav1d_get_picture(ctx, &pic)) == 0) {
    183        /* Test calling dav1d_picture_unref() after dav1d_close() */
    184        do {
    185            Dav1dPicture pic2 = { 0 };
    186            if ((err = dav1d_get_picture(ctx, &pic2)) == 0)
    187                dav1d_picture_unref(&pic2);
    188        } while (err != DAV1D_ERR(EAGAIN));
    189 
    190        dav1d_close(&ctx);
    191        dav1d_picture_unref(&pic);
    192        return 0;
    193    }
    194 
    195 cleanup:
    196    dav1d_close(&ctx);
    197 end:
    198    return 0;
    199 }