[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 24/31] fuzz: support for fork-based fuzzing.
From: |
Stefan Hajnoczi |
Subject: |
[PULL 24/31] fuzz: support for fork-based fuzzing. |
Date: |
Sat, 22 Feb 2020 08:50:23 +0000 |
From: Alexander Bulekov <address@hidden>
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 <address@hidden>
Reviewed-by: Stefan Hajnoczi <address@hidden>
Reviewed-by: Darren Kenny <address@hidden>
Message-id: address@hidden
Signed-off-by: Stefan Hajnoczi <address@hidden>
---
tests/qtest/fuzz/Makefile.include | 5 +++
tests/qtest/fuzz/fork_fuzz.c | 55 +++++++++++++++++++++++++++++++
tests/qtest/fuzz/fork_fuzz.h | 23 +++++++++++++
tests/qtest/fuzz/fork_fuzz.ld | 37 +++++++++++++++++++++
4 files changed, 120 insertions(+)
create mode 100644 tests/qtest/fuzz/fork_fuzz.c
create mode 100644 tests/qtest/fuzz/fork_fuzz.h
create mode 100644 tests/qtest/fuzz/fork_fuzz.ld
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 <address@hidden>
+ *
+ * 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 <address@hidden>
+ *
+ * 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;
--
2.24.1
- [PULL 14/31] qtest: add qtest_server_send abstraction, (continued)
- [PULL 14/31] qtest: add qtest_server_send abstraction, Stefan Hajnoczi, 2020/02/22
- [PULL 15/31] libqtest: add a layer of abstraction to send/recv, Stefan Hajnoczi, 2020/02/22
- [PULL 16/31] libqtest: make bufwrite rely on the TransportOps, Stefan Hajnoczi, 2020/02/22
- [PULL 17/31] qtest: add in-process incoming command handler, Stefan Hajnoczi, 2020/02/22
- [PULL 18/31] libqos: rename i2c_send and i2c_recv, Stefan Hajnoczi, 2020/02/22
- [PULL 19/31] libqos: split qos-test and libqos makefile vars, Stefan Hajnoczi, 2020/02/22
- [PULL 21/31] fuzz: add fuzzer skeleton, Stefan Hajnoczi, 2020/02/22
- [PULL 20/31] libqos: move useful qos-test funcs to qos_external, Stefan Hajnoczi, 2020/02/22
- [PULL 22/31] exec: keep ram block across fork when using qtest, Stefan Hajnoczi, 2020/02/22
- [PULL 23/31] main: keep rcu_atfork callback enabled for qtest, Stefan Hajnoczi, 2020/02/22
- [PULL 24/31] fuzz: support for fork-based fuzzing.,
Stefan Hajnoczi <=
- [PULL 25/31] fuzz: add support for qos-assisted fuzz targets, Stefan Hajnoczi, 2020/02/22
- [PULL 26/31] fuzz: add target/fuzz makefile rules, Stefan Hajnoczi, 2020/02/22
- [PULL 27/31] fuzz: add configure flag --enable-fuzzing, Stefan Hajnoczi, 2020/02/22
- [PULL 28/31] fuzz: add i440fx fuzz targets, Stefan Hajnoczi, 2020/02/22
- [PULL 29/31] fuzz: add virtio-net fuzz target, Stefan Hajnoczi, 2020/02/22
- [PULL 30/31] fuzz: add virtio-scsi fuzz target, Stefan Hajnoczi, 2020/02/22
- [PULL 31/31] fuzz: add documentation to docs/devel/, Stefan Hajnoczi, 2020/02/22