diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-09-02 14:59:05 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-09-02 14:59:05 +0100 |
commit | 8664d30a30fd676b56b4c29dbcbdd5c5538acfc1 (patch) | |
tree | 571d19bddf7a8b6f16b9143ccfe723fc7554fb7d | |
parent | 9093028dd48c50bc0392791f78aab44afef57ead (diff) | |
parent | 5d32fc3b60ffad175cab27dfaf07e0929a4f5755 (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-- | MAINTAINERS | 2 | ||||
-rwxr-xr-x | configure | 28 | ||||
-rw-r--r-- | scripts/oss-fuzz/instrumentation-filter-template | 15 | ||||
-rw-r--r-- | tests/qtest/fuzz/generic_fuzz.c | 55 |
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 @@ -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"); |