aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-09-02 14:59:05 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-09-02 14:59:05 +0100
commit8664d30a30fd676b56b4c29dbcbdd5c5538acfc1 (patch)
tree571d19bddf7a8b6f16b9143ccfe723fc7554fb7d
parent9093028dd48c50bc0392791f78aab44afef57ead (diff)
parent5d32fc3b60ffad175cab27dfaf07e0929a4f5755 (diff)
Merge remote-tracking branch 'remotes/a1xndr/tags/fuzz-pull-2021-09-01' into staging
Fuzzing Patches for 2021-09-01 # gpg: Signature made Wed 01 Sep 2021 12:42:00 BST # gpg: using RSA key FAD4E2BF871375D6340517C44E661DDE583A964E # gpg: Good signature from "Alexander Bulekov <alxndr@bu.edu>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: FAD4 E2BF 8713 75D6 3405 17C4 4E66 1DDE 583A 964E * remotes/a1xndr/tags/fuzz-pull-2021-09-01: MAINTAINERS: add fuzzing reviewer MAINTAINERS: Add myself as a reviewer for Device Fuzzing fuzz: unblock SIGALRM so the timeout works fuzz: use ITIMER_REAL for timeouts fuzz: add an instrumentation filter fuzz: make object-name matching case-insensitive fuzz: adjust timeout to allow for longer inputs fuzz: fix sparse memory access in the DMA callback Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS2
-rwxr-xr-xconfigure28
-rw-r--r--scripts/oss-fuzz/instrumentation-filter-template15
-rw-r--r--tests/qtest/fuzz/generic_fuzz.c55
4 files changed, 83 insertions, 17 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e42e2028e5..5d923a6544 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2760,6 +2760,8 @@ R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
R: Thomas Huth <thuth@redhat.com>
+R: Darren Kenny <darren.kenny@oracle.com>
+R: Qiuhao Li <Qiuhao.Li@outlook.com>
S: Maintained
F: tests/qtest/fuzz/
F: tests/qtest/fuzz-*test.c
diff --git a/configure b/configure
index 9a79a004d7..dcdbe3f068 100755
--- a/configure
+++ b/configure
@@ -4198,13 +4198,21 @@ fi
##########################################
# checks for fuzzer
-if test "$fuzzing" = "yes" && test -z "${LIB_FUZZING_ENGINE+xxx}"; then
+if test "$fuzzing" = "yes" ; then
write_c_fuzzer_skeleton
- if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer" ""; then
- have_fuzzer=yes
- else
- error_exit "Your compiler doesn't support -fsanitize=fuzzer"
- exit 1
+ if test -z "${LIB_FUZZING_ENGINE+xxx}"; then
+ if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer" ""; then
+ have_fuzzer=yes
+ else
+ error_exit "Your compiler doesn't support -fsanitize=fuzzer"
+ exit 1
+ fi
+ fi
+
+ have_clang_coverage_filter=no
+ echo > $TMPTXT
+ if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer -fsanitize-coverage-allowlist=$TMPTXT" ""; then
+ have_clang_coverage_filter=yes
fi
fi
@@ -4884,6 +4892,14 @@ if test "$fuzzing" = "yes" ; then
else
FUZZ_EXE_LDFLAGS="$LIB_FUZZING_ENGINE"
fi
+
+ # Specify a filter to only instrument code that is directly related to
+ # virtual-devices.
+ if test "$have_clang_coverage_filter" = "yes" ; then
+ cp "$source_path/scripts/oss-fuzz/instrumentation-filter-template" \
+ instrumentation-filter
+ QEMU_CFLAGS="$QEMU_CFLAGS -fsanitize-coverage-allowlist=instrumentation-filter"
+ fi
fi
if test "$plugins" = "yes" ; then
diff --git a/scripts/oss-fuzz/instrumentation-filter-template b/scripts/oss-fuzz/instrumentation-filter-template
new file mode 100644
index 0000000000..76d2b6139a
--- /dev/null
+++ b/scripts/oss-fuzz/instrumentation-filter-template
@@ -0,0 +1,15 @@
+# Code that we actually want the fuzzer to target
+# See: https://clang.llvm.org/docs/SanitizerCoverage.html#disabling-instrumentation-without-source-modification
+#
+src:*/hw/*
+src:*/include/hw/*
+src:*/slirp/*
+src:*/net/*
+
+# We don't care about coverage over fuzzer-specific code, however we should
+# instrument the fuzzer entry-point so libFuzzer always sees at least some
+# coverage - otherwise it will exit after the first input
+src:*/tests/qtest/fuzz/fuzz.c
+
+# Enable instrumentation for all functions in those files
+fun:*
diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c
index 6c67522717..dd7e25851c 100644
--- a/tests/qtest/fuzz/generic_fuzz.c
+++ b/tests/qtest/fuzz/generic_fuzz.c
@@ -240,10 +240,17 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
addr, &addr1, &l, true,
MEMTXATTRS_UNSPECIFIED);
- if (!(memory_region_is_ram(mr1) ||
- memory_region_is_romd(mr1)) && mr1 != sparse_mem_mr) {
+ /*
+ * If mr1 isn't RAM, address_space_translate doesn't update l. Use
+ * memory_access_size to identify the number of bytes that it is safe
+ * to write without accidentally writing to another MemoryRegion.
+ */
+ if (!memory_region_is_ram(mr1)) {
l = memory_access_size(mr1, l, addr1);
- } else {
+ }
+ if (memory_region_is_ram(mr1) ||
+ memory_region_is_romd(mr1) ||
+ mr1 == sparse_mem_mr) {
/* ROM/RAM case */
if (qtest_log_enabled) {
/*
@@ -661,31 +668,41 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
uint8_t op;
if (fork() == 0) {
+ struct sigaction sact;
+ struct itimerval timer;
+ sigset_t set;
/*
* Sometimes the fuzzer will find inputs that take quite a long time to
* process. Often times, these inputs do not result in new coverage.
* Even if these inputs might be interesting, they can slow down the
- * fuzzer, overall. Set a timeout to avoid hurting performance, too much
+ * fuzzer, overall. Set a timeout for each command to avoid hurting
+ * performance, too much
*/
if (timeout) {
- struct sigaction sact;
- struct itimerval timer;
sigemptyset(&sact.sa_mask);
sact.sa_flags = SA_NODEFER;
sact.sa_handler = handle_timeout;
sigaction(SIGALRM, &sact, NULL);
+ sigemptyset(&set);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
memset(&timer, 0, sizeof(timer));
timer.it_value.tv_sec = timeout / USEC_IN_SEC;
timer.it_value.tv_usec = timeout % USEC_IN_SEC;
- setitimer(ITIMER_VIRTUAL, &timer, NULL);
}
op_clear_dma_patterns(s, NULL, 0);
pci_disabled = false;
while (cmd && Size) {
+ /* Reset the timeout, each time we run a new command */
+ if (timeout) {
+ setitimer(ITIMER_REAL, &timer, NULL);
+ }
+
/* Get the length until the next command or end of input */
nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR));
cmd_len = nextcmd ? nextcmd - cmd : Size;
@@ -746,8 +763,13 @@ static int locate_fuzz_memory_regions(Object *child, void *opaque)
static int locate_fuzz_objects(Object *child, void *opaque)
{
+ GString *type_name;
+ GString *path_name;
char *pattern = opaque;
- if (g_pattern_match_simple(pattern, object_get_typename(child))) {
+
+ type_name = g_string_new(object_get_typename(child));
+ g_string_ascii_down(type_name);
+ if (g_pattern_match_simple(pattern, type_name->str)) {
/* Find and save ptrs to any child MemoryRegions */
object_child_foreach_recursive(child, locate_fuzz_memory_regions, NULL);
@@ -764,8 +786,9 @@ static int locate_fuzz_objects(Object *child, void *opaque)
g_ptr_array_add(fuzzable_pci_devices, PCI_DEVICE(child));
}
} else if (object_dynamic_cast(OBJECT(child), TYPE_MEMORY_REGION)) {
- if (g_pattern_match_simple(pattern,
- object_get_canonical_path_component(child))) {
+ path_name = g_string_new(object_get_canonical_path_component(child));
+ g_string_ascii_down(path_name);
+ if (g_pattern_match_simple(pattern, path_name->str)) {
MemoryRegion *mr;
mr = MEMORY_REGION(child);
if ((memory_region_is_ram(mr) ||
@@ -774,7 +797,9 @@ static int locate_fuzz_objects(Object *child, void *opaque)
g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
}
}
+ g_string_free(path_name, true);
}
+ g_string_free(type_name, true);
return 0;
}
@@ -802,6 +827,7 @@ static void generic_pre_fuzz(QTestState *s)
MemoryRegion *mr;
QPCIBus *pcibus;
char **result;
+ GString *name_pattern;
if (!getenv("QEMU_FUZZ_OBJECTS")) {
usage();
@@ -831,10 +857,17 @@ static void generic_pre_fuzz(QTestState *s)
result = g_strsplit(getenv("QEMU_FUZZ_OBJECTS"), " ", -1);
for (int i = 0; result[i] != NULL; i++) {
+ name_pattern = g_string_new(result[i]);
+ /*
+ * Make the pattern lowercase. We do the same for all the MemoryRegion
+ * and Type names so the configs are case-insensitive.
+ */
+ g_string_ascii_down(name_pattern);
printf("Matching objects by name %s\n", result[i]);
object_child_foreach_recursive(qdev_get_machine(),
locate_fuzz_objects,
- result[i]);
+ name_pattern->str);
+ g_string_free(name_pattern, true);
}
g_strfreev(result);
printf("This process will try to fuzz the following MemoryRegions:\n");