Commit 8bc73da3 authored by Janne Grunau's avatar Janne Grunau

fuzzing: add memory allocation fail fuzzer

Depends on posix_memalign and a linker supporting '--wrap' to wrap
arbitrary symbols.
parent 0636633f
Pipeline #3464 passed with stages
in 5 minutes and 2 seconds
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Janne Grunau
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include "alloc_fail.h"
static int fail_probability;
void dav1d_setup_alloc_fail(unsigned seed, unsigned probability) {
srand(seed);
while (probability >= RAND_MAX)
probability >>= 1;
fail_probability = probability;
}
void * __real_malloc(size_t);
void * __wrap_malloc(size_t);
void * __wrap_malloc(size_t sz) {
if (rand() < fail_probability)
return NULL;
return __real_malloc(sz);
}
#if defined(HAVE_POSIX_MEMALIGN)
int __real_posix_memalign(void **memptr, size_t alignment, size_t size);
int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size);
int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size) {
if (rand() < fail_probability)
return ENOMEM;
return __real_posix_memalign(memptr, alignment, size);
}
#else
#error "HAVE_POSIX_MEMALIGN required"
#endif
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Janne Grunau
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H
#define DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H
#include <dav1d/common.h>
DAV1D_API void dav1d_setup_alloc_fail(unsigned seed, unsigned probability);
#endif /* DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H */
......@@ -36,6 +36,20 @@
#include "src/cpu.h"
#include "dav1d_fuzzer.h"
#ifdef DAV1D_ALLOC_FAIL
#include <stdlib.h>
#include "alloc_fail.h"
static unsigned djb_xor(const uint8_t * c, size_t len) {
unsigned hash = 5381;
for(size_t i = 0; i < len; i++)
hash = hash * 33 ^ c[i];
return hash;
}
#endif
static unsigned r32le(const uint8_t *const p) {
return ((uint32_t)p[3] << 24U) | (p[2] << 16U) | (p[1] << 8U) | p[0];
}
......@@ -74,12 +88,25 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
#endif
if (size < 32) goto end;
#ifdef DAV1D_ALLOC_FAIL
unsigned h = djb_xor(ptr, 32);
unsigned seed = h;
unsigned probability = h > (RAND_MAX >> 5) ? RAND_MAX >> 5 : h;
int n_frame_threads = (h & 0xf) + 1;
int n_tile_threads = ((h >> 4) & 0x7) + 1;
if (n_frame_threads > 5) n_frame_threads = 1;
if (n_tile_threads > 3) n_tile_threads = 1;
#endif
ptr += 32; // skip ivf header
dav1d_default_settings(&settings);
#ifdef DAV1D_MT_FUZZING
settings.n_frame_threads = settings.n_tile_threads = 2;
#elif defined(DAV1D_ALLOC_FAIL)
settings.n_frame_threads = n_frame_threads;
settings.n_tile_threads = n_tile_threads;
dav1d_setup_alloc_fail(seed, probability);
#else
settings.n_frame_threads = settings.n_tile_threads = 1;
#endif
......
......@@ -31,6 +31,8 @@ if not get_option('build_tests')
subdir_done()
endif
libdav1d_nasm_objs_if_needed = []
if is_asm_enabled
checkasm_sources = files('checkasm/checkasm.c')
......@@ -67,7 +69,6 @@ if is_asm_enabled
m_lib = cc.find_library('m', required: false)
libdav1d_nasm_objs_if_needed = []
if meson.version().version_compare('< 0.48.999')
libdav1d_nasm_objs_if_needed = libdav1d_nasm_objs
endif
......@@ -123,6 +124,32 @@ dav1d_fuzzer_mt = executable('dav1d_fuzzer_mt',
dependencies : [thread_dependency],
)
if (cc.has_function('posix_memalign', prefix : '#include <stdlib.h>', args : test_args) and
cc.has_link_argument('-Wl,-wrap,malloc'))
alloc_fail = shared_library('alloc_fail',
files('libfuzzer/alloc_fail.c'),
libdav1d_nasm_objs_if_needed,
objects: [
libdav1d.extract_all_objects(recursive: true),
],
include_directories: dav1d_inc_dirs,
c_args : [stackalign_flag],
link_args: ['-Wl,-wrap,malloc', '-Wl,-wrap,posix_memalign'],
dependencies : [thread_dependency],
)
dav1d_fuzzer_mem = executable('dav1d_fuzzer_mem',
dav1d_fuzzer_sources,
include_directories: dav1d_inc_dirs,
c_args: [stackalign_flag, stackrealign_flag, '-DDAV1D_ALLOC_FAIL'],
link_args: fuzzer_ldflags,
link_with : [alloc_fail],
build_by_default: true,
dependencies : [thread_dependency],
)
endif
# Include dav1d test data repository with additional tests
if get_option('testdata_tests')
subdir('dav1d-test-data')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment