Message ID | 20200222085030.1760640-25-stefanha@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [PULL,01/31] virtio: increase virtqueue size for virtio-scsi and virtio-blk | expand |
On 2/22/20 2:50 AM, Stefan Hajnoczi wrote: > From: Alexander Bulekov <alxndr@bu.edu> > > fork() is a simple way to ensure that state does not leak in between > fuzzing runs. Unfortunately, the fuzzer mutation engine relies on > bitmaps which contain coverage information for each fuzzing run, and > these bitmaps should be copied from the child to the parent(where the > mutation occurs). These bitmaps are created through compile-time > instrumentation and they are not shared with fork()-ed processes, by > default. To address this, we create a shared memory region, adjust its > size and map it _over_ the counter region. Furthermore, libfuzzer > doesn't generally expose the globals that specify the location of the > counters/coverage bitmap. As a workaround, we rely on a custom linker > script which forces all of the bitmaps we care about to be placed in a > contiguous region, which is easy to locate and mmap over. > > Signed-off-by: Alexander Bulekov <alxndr@bu.edu> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> > Reviewed-by: Darren Kenny <darren.kenny@oracle.com> > Message-id: 20200220041118.23264-16-alxndr@bu.edu > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> > --- Random drive-by observation: > +++ b/tests/qtest/fuzz/fork_fuzz.ld > @@ -0,0 +1,37 @@ > +/* We adjust linker script modification to place all of the stuff that needs to > + * persist across fuzzing runs into a contiguous seciton of memory. Then, it is section
On Sat, Feb 22, 2020 at 05:34:29AM -0600, Eric Blake wrote: > On 2/22/20 2:50 AM, Stefan Hajnoczi wrote: > > From: Alexander Bulekov <alxndr@bu.edu> > > > > fork() is a simple way to ensure that state does not leak in between > > fuzzing runs. Unfortunately, the fuzzer mutation engine relies on > > bitmaps which contain coverage information for each fuzzing run, and > > these bitmaps should be copied from the child to the parent(where the > > mutation occurs). These bitmaps are created through compile-time > > instrumentation and they are not shared with fork()-ed processes, by > > default. To address this, we create a shared memory region, adjust its > > size and map it _over_ the counter region. Furthermore, libfuzzer > > doesn't generally expose the globals that specify the location of the > > counters/coverage bitmap. As a workaround, we rely on a custom linker > > script which forces all of the bitmaps we care about to be placed in a > > contiguous region, which is easy to locate and mmap over. > > > > Signed-off-by: Alexander Bulekov <alxndr@bu.edu> > > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> > > Reviewed-by: Darren Kenny <darren.kenny@oracle.com> > > Message-id: 20200220041118.23264-16-alxndr@bu.edu > > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> > > --- > > Random drive-by observation: > > > +++ b/tests/qtest/fuzz/fork_fuzz.ld > > @@ -0,0 +1,37 @@ > > +/* We adjust linker script modification to place all of the stuff that needs to > > + * persist across fuzzing runs into a contiguous seciton of memory. Then, it is > > section Thanks, Eric! Alex, please send follow-up patches to fix this typo and the 80 character line limit issues identified by patchew (see patch email reply to this email thread). Stefan
On 200224 1135, Stefan Hajnoczi wrote: > On Sat, Feb 22, 2020 at 05:34:29AM -0600, Eric Blake wrote: > > On 2/22/20 2:50 AM, Stefan Hajnoczi wrote: > > > From: Alexander Bulekov <alxndr@bu.edu> > > > > > > fork() is a simple way to ensure that state does not leak in between > > > fuzzing runs. Unfortunately, the fuzzer mutation engine relies on > > > bitmaps which contain coverage information for each fuzzing run, and > > > these bitmaps should be copied from the child to the parent(where the > > > mutation occurs). These bitmaps are created through compile-time > > > instrumentation and they are not shared with fork()-ed processes, by > > > default. To address this, we create a shared memory region, adjust its > > > size and map it _over_ the counter region. Furthermore, libfuzzer > > > doesn't generally expose the globals that specify the location of the > > > counters/coverage bitmap. As a workaround, we rely on a custom linker > > > script which forces all of the bitmaps we care about to be placed in a > > > contiguous region, which is easy to locate and mmap over. > > > > > > Signed-off-by: Alexander Bulekov <alxndr@bu.edu> > > > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> > > > Reviewed-by: Darren Kenny <darren.kenny@oracle.com> > > > Message-id: 20200220041118.23264-16-alxndr@bu.edu > > > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> > > > --- > > > > Random drive-by observation: > > > > > +++ b/tests/qtest/fuzz/fork_fuzz.ld > > > @@ -0,0 +1,37 @@ > > > +/* We adjust linker script modification to place all of the stuff that needs to > > > + * persist across fuzzing runs into a contiguous seciton of memory. Then, it is > > > > section > > Thanks, Eric! > > Alex, please send follow-up patches to fix this typo and the 80 > character line limit issues identified by patchew (see patch email reply > to this email thread). Thank you Eric, Stefan! Just sent out some fixes. > Stefan
diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include index 8632bb89f4..a90915d56d 100644 --- a/tests/qtest/fuzz/Makefile.include +++ b/tests/qtest/fuzz/Makefile.include @@ -2,5 +2,10 @@ QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF) fuzz-obj-y += tests/qtest/libqtest.o fuzz-obj-y += tests/qtest/fuzz/fuzz.o # Fuzzer skeleton +fuzz-obj-y += tests/qtest/fuzz/fork_fuzz.o FUZZ_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest + +# Linker Script to force coverage-counters into known regions which we can mark +# shared +FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/qtest/fuzz/fork_fuzz.ld diff --git a/tests/qtest/fuzz/fork_fuzz.c b/tests/qtest/fuzz/fork_fuzz.c new file mode 100644 index 0000000000..2bd0851903 --- /dev/null +++ b/tests/qtest/fuzz/fork_fuzz.c @@ -0,0 +1,55 @@ +/* + * Fork-based fuzzing helpers + * + * Copyright Red Hat Inc., 2019 + * + * Authors: + * Alexander Bulekov <alxndr@bu.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "fork_fuzz.h" + + +void counter_shm_init(void) +{ + char *shm_path = g_strdup_printf("/qemu-fuzz-cntrs.%d", getpid()); + int fd = shm_open(shm_path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + g_free(shm_path); + + if (fd == -1) { + perror("Error: "); + exit(1); + } + if (ftruncate(fd, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START) == -1) { + perror("Error: "); + exit(1); + } + /* Copy what's in the counter region to the shm.. */ + void *rptr = mmap(NULL , + &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + memcpy(rptr, + &__FUZZ_COUNTERS_START, + &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); + + munmap(rptr, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); + + /* And map the shm over the counter region */ + rptr = mmap(&__FUZZ_COUNTERS_START, + &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0); + + close(fd); + + if (!rptr) { + perror("Error: "); + exit(1); + } +} + + diff --git a/tests/qtest/fuzz/fork_fuzz.h b/tests/qtest/fuzz/fork_fuzz.h new file mode 100644 index 0000000000..9ecb8b58ef --- /dev/null +++ b/tests/qtest/fuzz/fork_fuzz.h @@ -0,0 +1,23 @@ +/* + * Fork-based fuzzing helpers + * + * Copyright Red Hat Inc., 2019 + * + * Authors: + * Alexander Bulekov <alxndr@bu.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef FORK_FUZZ_H +#define FORK_FUZZ_H + +extern uint8_t __FUZZ_COUNTERS_START; +extern uint8_t __FUZZ_COUNTERS_END; + +void counter_shm_init(void); + +#endif + diff --git a/tests/qtest/fuzz/fork_fuzz.ld b/tests/qtest/fuzz/fork_fuzz.ld new file mode 100644 index 0000000000..b23a59f194 --- /dev/null +++ b/tests/qtest/fuzz/fork_fuzz.ld @@ -0,0 +1,37 @@ +/* We adjust linker script modification to place all of the stuff that needs to + * persist across fuzzing runs into a contiguous seciton of memory. Then, it is + * easy to re-map the counter-related memory as shared. +*/ + +SECTIONS +{ + .data.fuzz_start : ALIGN(4K) + { + __FUZZ_COUNTERS_START = .; + __start___sancov_cntrs = .; + *(_*sancov_cntrs); + __stop___sancov_cntrs = .; + + /* Lowest stack counter */ + *(__sancov_lowest_stack); + } + .data.fuzz_ordered : + { + /* Coverage counters. They're not necessary for fuzzing, but are useful + * for analyzing the fuzzing performance + */ + __start___llvm_prf_cnts = .; + *(*llvm_prf_cnts); + __stop___llvm_prf_cnts = .; + + /* Internal Libfuzzer TracePC object which contains the ValueProfileMap */ + FuzzerTracePC*(.bss*); + } + .data.fuzz_end : ALIGN(4K) + { + __FUZZ_COUNTERS_END = .; + } +} +/* Dont overwrite the SECTIONS in the default linker script. Instead insert the + * above into the default script */ +INSERT AFTER .data;