Message ID | 20190725032321.12721-9-alxndr@bu.edu (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add virtual device fuzzing support | expand |
On 25/07/19 05:23, Oleinik, Alexander wrote: > Intercept coverage buffer registration calls and use this information to > copy them to shared memory, if using fork() to avoid resetting device > state. > > Signed-off-by: Alexander Oleinik <alxndr@bu.edu> > --- > tests/fuzz/fuzzer_hooks.c | 106 ++++++++++++++++++++++++++++++++++++++ > tests/fuzz/fuzzer_hooks.h | 9 ++++ > 2 files changed, 115 insertions(+) > create mode 100644 tests/fuzz/fuzzer_hooks.c > create mode 100644 tests/fuzz/fuzzer_hooks.h > > diff --git a/tests/fuzz/fuzzer_hooks.c b/tests/fuzz/fuzzer_hooks.c > new file mode 100644 > index 0000000000..5a0bbec413 > --- /dev/null > +++ b/tests/fuzz/fuzzer_hooks.c > @@ -0,0 +1,106 @@ > +#include "qemu/osdep.h" > +#include "qemu/units.h" > +#include "qapi/error.h" > +#include "qemu-common.h" > +#include "fuzzer_hooks.h" > + > +#include <dlfcn.h> > +#include <elf.h> > + > + > +extern void* _ZN6fuzzer3TPCE; Would it make sense to make this a C++ source, so that you can avoid using the mangled names (in this case, "namespace fuzzer { extern void *TPC; }" and then using fuzzer::TPC)? Even if it's just a single symbol. > +// The libfuzzer handlers > +void __real___sanitizer_cov_8bit_counters_init(uint8_t*, uint8_t*); > +void __real___sanitizer_cov_trace_pc_guard_init(uint8_t*, uint8_t*); > + > +void __wrap___sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop); > +void __wrap___sanitizer_cov_trace_pc_guard_init(uint8_t *Start, uint8_t *Stop); > + > + > +void* counter_shm; > + > +typedef struct CoverageRegion { > + uint8_t* start; > + size_t length; > + bool store; /* Set this if it needs to be copied to the forked process */ > +} CoverageRegion; > + > +CoverageRegion regions[10]; > +int region_index = 0; > + > +void __wrap___sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) > +{ > + regions[region_index].start = Start; > + regions[region_index].length = Stop-Start; > + regions[region_index].store = true; > + region_index++; > + __real___sanitizer_cov_8bit_counters_init(Start, Stop); > +} > + > +void __wrap___sanitizer_cov_trace_pc_guard_init(uint8_t *Start, uint8_t *Stop) > +{ > + regions[region_index].start = Start; > + regions[region_index++].length = Stop-Start; > + regions[region_index].store = true; > + region_index++; > + __real___sanitizer_cov_trace_pc_guard_init(Start, Stop); > +} > + > +static void add_tpc_region(void) > +{ > + /* Got symbol and length from readelf. Horrible way to do this! */ > + regions[region_index].start = (uint8_t*)(&_ZN6fuzzer3TPCE); > + regions[region_index].length = 0x443c00; > + regions[region_index].store = true; > + region_index++; > +} > + > +void counter_shm_init(void) > +{ > + /* > + * Add the internal libfuzzer object that gets modified by cmp, etc > + * callbacks > + */ > + add_tpc_region(); > + > + size_t length = 0; > + for(int i=0; i<region_index; i++){ > + printf("%d %lx\n", i, length); > + length += regions[i].length; > + } > + > + /* > + * Map some shared memory. When we use a fork-server we can copy the > + * libfuzzer-related counters > + * */ > + counter_shm = mmap(NULL, length, PROT_READ | PROT_WRITE, > + MAP_SHARED | MAP_ANONYMOUS, -1, 0); > + if(counter_shm == MAP_FAILED) { > + printf("mmap() failed\n"); > + do { perror("error:"); exit(EXIT_FAILURE); } while (0); > + exit(-1); > + } > +} > + > +void counter_shm_store(void) > +{ > + size_t offset = 0; > + for(int i=0; i<region_index; i++) { > + if(regions[i].store) { > + memcpy(counter_shm + offset, regions[i].start, regions[i].length); > + } > + offset+=regions[i].length; > + } > +} > + > +void counter_shm_load(void) > +{ > + size_t offset = 0; > + for(int i=0; i<region_index; i++) { > + if(regions[i].store) { > + memcpy(regions[i].start, counter_shm + offset, regions[i].length); > + } > + offset+=regions[i].length; > + } > +} > + > diff --git a/tests/fuzz/fuzzer_hooks.h b/tests/fuzz/fuzzer_hooks.h > new file mode 100644 > index 0000000000..90dca254d4 > --- /dev/null > +++ b/tests/fuzz/fuzzer_hooks.h > @@ -0,0 +1,9 @@ > +#ifndef FUZZER_HOOKS_H > +#define FUZZER_HOOKS_H > + > +void counter_shm_init(void); > +void counter_shm_store(void); > +void counter_shm_load(void); > + > +#endif > + >
On Thu, Jul 25, 2019 at 10:21:18AM +0200, Paolo Bonzini wrote: > On 25/07/19 05:23, Oleinik, Alexander wrote: > > Intercept coverage buffer registration calls and use this information to > > copy them to shared memory, if using fork() to avoid resetting device > > state. > > > > Signed-off-by: Alexander Oleinik <alxndr@bu.edu> > > --- > > tests/fuzz/fuzzer_hooks.c | 106 ++++++++++++++++++++++++++++++++++++++ > > tests/fuzz/fuzzer_hooks.h | 9 ++++ > > 2 files changed, 115 insertions(+) > > create mode 100644 tests/fuzz/fuzzer_hooks.c > > create mode 100644 tests/fuzz/fuzzer_hooks.h > > > > diff --git a/tests/fuzz/fuzzer_hooks.c b/tests/fuzz/fuzzer_hooks.c > > new file mode 100644 > > index 0000000000..5a0bbec413 > > --- /dev/null > > +++ b/tests/fuzz/fuzzer_hooks.c > > @@ -0,0 +1,106 @@ > > +#include "qemu/osdep.h" > > +#include "qemu/units.h" > > +#include "qapi/error.h" > > +#include "qemu-common.h" > > +#include "fuzzer_hooks.h" > > + > > +#include <dlfcn.h> > > +#include <elf.h> > > + > > + > > +extern void* _ZN6fuzzer3TPCE; > > Would it make sense to make this a C++ source, so that you can avoid > using the mangled names (in this case, "namespace fuzzer { extern void > *TPC; }" and then using fuzzer::TPC)? Even if it's just a single symbol. A proper libfuzzer API is nicest in the long term. Alexander: Could you send a patch to libfuzzer to see if they are willing to support this via their API? Stefan
diff --git a/tests/fuzz/fuzzer_hooks.c b/tests/fuzz/fuzzer_hooks.c new file mode 100644 index 0000000000..5a0bbec413 --- /dev/null +++ b/tests/fuzz/fuzzer_hooks.c @@ -0,0 +1,106 @@ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "fuzzer_hooks.h" + +#include <dlfcn.h> +#include <elf.h> + + +extern void* _ZN6fuzzer3TPCE; +// The libfuzzer handlers +void __real___sanitizer_cov_8bit_counters_init(uint8_t*, uint8_t*); +void __real___sanitizer_cov_trace_pc_guard_init(uint8_t*, uint8_t*); + +void __wrap___sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop); +void __wrap___sanitizer_cov_trace_pc_guard_init(uint8_t *Start, uint8_t *Stop); + + +void* counter_shm; + +typedef struct CoverageRegion { + uint8_t* start; + size_t length; + bool store; /* Set this if it needs to be copied to the forked process */ +} CoverageRegion; + +CoverageRegion regions[10]; +int region_index = 0; + +void __wrap___sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) +{ + regions[region_index].start = Start; + regions[region_index].length = Stop-Start; + regions[region_index].store = true; + region_index++; + __real___sanitizer_cov_8bit_counters_init(Start, Stop); +} + +void __wrap___sanitizer_cov_trace_pc_guard_init(uint8_t *Start, uint8_t *Stop) +{ + regions[region_index].start = Start; + regions[region_index++].length = Stop-Start; + regions[region_index].store = true; + region_index++; + __real___sanitizer_cov_trace_pc_guard_init(Start, Stop); +} + +static void add_tpc_region(void) +{ + /* Got symbol and length from readelf. Horrible way to do this! */ + regions[region_index].start = (uint8_t*)(&_ZN6fuzzer3TPCE); + regions[region_index].length = 0x443c00; + regions[region_index].store = true; + region_index++; +} + +void counter_shm_init(void) +{ + /* + * Add the internal libfuzzer object that gets modified by cmp, etc + * callbacks + */ + add_tpc_region(); + + size_t length = 0; + for(int i=0; i<region_index; i++){ + printf("%d %lx\n", i, length); + length += regions[i].length; + } + + /* + * Map some shared memory. When we use a fork-server we can copy the + * libfuzzer-related counters + * */ + counter_shm = mmap(NULL, length, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if(counter_shm == MAP_FAILED) { + printf("mmap() failed\n"); + do { perror("error:"); exit(EXIT_FAILURE); } while (0); + exit(-1); + } +} + +void counter_shm_store(void) +{ + size_t offset = 0; + for(int i=0; i<region_index; i++) { + if(regions[i].store) { + memcpy(counter_shm + offset, regions[i].start, regions[i].length); + } + offset+=regions[i].length; + } +} + +void counter_shm_load(void) +{ + size_t offset = 0; + for(int i=0; i<region_index; i++) { + if(regions[i].store) { + memcpy(regions[i].start, counter_shm + offset, regions[i].length); + } + offset+=regions[i].length; + } +} + diff --git a/tests/fuzz/fuzzer_hooks.h b/tests/fuzz/fuzzer_hooks.h new file mode 100644 index 0000000000..90dca254d4 --- /dev/null +++ b/tests/fuzz/fuzzer_hooks.h @@ -0,0 +1,9 @@ +#ifndef FUZZER_HOOKS_H +#define FUZZER_HOOKS_H + +void counter_shm_init(void); +void counter_shm_store(void); +void counter_shm_load(void); + +#endif +
Intercept coverage buffer registration calls and use this information to copy them to shared memory, if using fork() to avoid resetting device state. Signed-off-by: Alexander Oleinik <alxndr@bu.edu> --- tests/fuzz/fuzzer_hooks.c | 106 ++++++++++++++++++++++++++++++++++++++ tests/fuzz/fuzzer_hooks.h | 9 ++++ 2 files changed, 115 insertions(+) create mode 100644 tests/fuzz/fuzzer_hooks.c create mode 100644 tests/fuzz/fuzzer_hooks.h