Fuzzing Patches for 2021-09-01

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE+tTiv4cTddY0BRfETmYd3lg6lk4FAmEvZwgACgkQTmYd3lg6
 lk6nCw//X5wVWFBHDw+7nQ3lpu/rYTVTdqzdwgcOih5ima4ZeqmRbEMGhKYHcekZ
 YQxAP3r4k11Fp2Jev4CS18c4TVE/jYE7d8RwS5ROGTT8IOhe3Ntgd6d5MNjIdm86
 HwaTmmrxpL2cCWUgCGX8H+BXT0p+sjNpMTXfgu9CYlYEgVQKVRiTBTEsCku12FRM
 kwqHaFzJZoFMd45NhbH2wHt/dmDVuVYp7UuCM/HzNFKLO8E25sBLQip97RRTgInB
 iT9vadTYsgkrdRbIWiQbP8vWKL4D0SS7Sw6DYlxTCYhEEZffiiXPVqEwf+qr9LRX
 sLui6vMyjLB4yhjsg5AEd0IMZSP4H431su6YEuP0XOXG5yh5nSNkGVim0ezt1UBF
 DDvYDumVK0P4seCVhK87fEejW9+GAlTSf65LBcK07JSo5DLyRzfmwBXQM3EKzdCK
 y58Jthkmlhe4zym40WNwM91QFaNuWAD0pdvB9fa9OcidvuLgkhdgN72LJVgZSoq9
 7UuWSV6laTnTAIP1YL4R5fvq1r5gNE1cnzCFf6th87pmvOUhO43Y2dT6Me8UR0v8
 B7tHxtAiZJkfWvOYL4Jy3vaBXuivZCtEYUUDc0Y0Cmzfd9DnvnkxrKirZ6ECoyDs
 RsR6nUO1tbpe0ekdl8EvYG3PRt8iHIahZ25GnKcUSTRFydetPqE=
 =ec6M
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2021-09-02 14:59:05 +01:00
commit 8664d30a30
4 changed files with 83 additions and 17 deletions

View File

@ -2760,6 +2760,8 @@ R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com> R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com> R: Stefan Hajnoczi <stefanha@redhat.com>
R: Thomas Huth <thuth@redhat.com> R: Thomas Huth <thuth@redhat.com>
R: Darren Kenny <darren.kenny@oracle.com>
R: Qiuhao Li <Qiuhao.Li@outlook.com>
S: Maintained S: Maintained
F: tests/qtest/fuzz/ F: tests/qtest/fuzz/
F: tests/qtest/fuzz-*test.c F: tests/qtest/fuzz-*test.c

28
configure vendored
View File

@ -4198,13 +4198,21 @@ fi
########################################## ##########################################
# checks for fuzzer # checks for fuzzer
if test "$fuzzing" = "yes" && test -z "${LIB_FUZZING_ENGINE+xxx}"; then if test "$fuzzing" = "yes" ; then
write_c_fuzzer_skeleton write_c_fuzzer_skeleton
if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer" ""; then if test -z "${LIB_FUZZING_ENGINE+xxx}"; then
have_fuzzer=yes if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer" ""; then
else have_fuzzer=yes
error_exit "Your compiler doesn't support -fsanitize=fuzzer" else
exit 1 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
fi fi
@ -4884,6 +4892,14 @@ if test "$fuzzing" = "yes" ; then
else else
FUZZ_EXE_LDFLAGS="$LIB_FUZZING_ENGINE" FUZZ_EXE_LDFLAGS="$LIB_FUZZING_ENGINE"
fi 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 fi
if test "$plugins" = "yes" ; then if test "$plugins" = "yes" ; then

View File

@ -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:*

View File

@ -240,10 +240,17 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
addr, &addr1, &l, true, addr, &addr1, &l, true,
MEMTXATTRS_UNSPECIFIED); 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); 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 */ /* ROM/RAM case */
if (qtest_log_enabled) { if (qtest_log_enabled) {
/* /*
@ -661,31 +668,41 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
uint8_t op; uint8_t op;
if (fork() == 0) { 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 * Sometimes the fuzzer will find inputs that take quite a long time to
* process. Often times, these inputs do not result in new coverage. * process. Often times, these inputs do not result in new coverage.
* Even if these inputs might be interesting, they can slow down the * 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) { if (timeout) {
struct sigaction sact;
struct itimerval timer;
sigemptyset(&sact.sa_mask); sigemptyset(&sact.sa_mask);
sact.sa_flags = SA_NODEFER; sact.sa_flags = SA_NODEFER;
sact.sa_handler = handle_timeout; sact.sa_handler = handle_timeout;
sigaction(SIGALRM, &sact, NULL); sigaction(SIGALRM, &sact, NULL);
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
memset(&timer, 0, sizeof(timer)); memset(&timer, 0, sizeof(timer));
timer.it_value.tv_sec = timeout / USEC_IN_SEC; timer.it_value.tv_sec = timeout / USEC_IN_SEC;
timer.it_value.tv_usec = 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); op_clear_dma_patterns(s, NULL, 0);
pci_disabled = false; pci_disabled = false;
while (cmd && Size) { 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 */ /* Get the length until the next command or end of input */
nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR)); nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR));
cmd_len = nextcmd ? nextcmd - cmd : Size; 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) static int locate_fuzz_objects(Object *child, void *opaque)
{ {
GString *type_name;
GString *path_name;
char *pattern = opaque; 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 */ /* Find and save ptrs to any child MemoryRegions */
object_child_foreach_recursive(child, locate_fuzz_memory_regions, NULL); 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)); g_ptr_array_add(fuzzable_pci_devices, PCI_DEVICE(child));
} }
} else if (object_dynamic_cast(OBJECT(child), TYPE_MEMORY_REGION)) { } else if (object_dynamic_cast(OBJECT(child), TYPE_MEMORY_REGION)) {
if (g_pattern_match_simple(pattern, path_name = g_string_new(object_get_canonical_path_component(child));
object_get_canonical_path_component(child))) { g_string_ascii_down(path_name);
if (g_pattern_match_simple(pattern, path_name->str)) {
MemoryRegion *mr; MemoryRegion *mr;
mr = MEMORY_REGION(child); mr = MEMORY_REGION(child);
if ((memory_region_is_ram(mr) || 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_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
} }
} }
g_string_free(path_name, true);
} }
g_string_free(type_name, true);
return 0; return 0;
} }
@ -802,6 +827,7 @@ static void generic_pre_fuzz(QTestState *s)
MemoryRegion *mr; MemoryRegion *mr;
QPCIBus *pcibus; QPCIBus *pcibus;
char **result; char **result;
GString *name_pattern;
if (!getenv("QEMU_FUZZ_OBJECTS")) { if (!getenv("QEMU_FUZZ_OBJECTS")) {
usage(); usage();
@ -831,10 +857,17 @@ static void generic_pre_fuzz(QTestState *s)
result = g_strsplit(getenv("QEMU_FUZZ_OBJECTS"), " ", -1); result = g_strsplit(getenv("QEMU_FUZZ_OBJECTS"), " ", -1);
for (int i = 0; result[i] != NULL; i++) { 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]); printf("Matching objects by name %s\n", result[i]);
object_child_foreach_recursive(qdev_get_machine(), object_child_foreach_recursive(qdev_get_machine(),
locate_fuzz_objects, locate_fuzz_objects,
result[i]); name_pattern->str);
g_string_free(name_pattern, true);
} }
g_strfreev(result); g_strfreev(result);
printf("This process will try to fuzz the following MemoryRegions:\n"); printf("This process will try to fuzz the following MemoryRegions:\n");