diff options
Diffstat (limited to 'tests/qtest')
-rw-r--r-- | tests/qtest/fuzz-megasas-test.c | 49 | ||||
-rw-r--r-- | tests/qtest/fuzz-test.c | 76 | ||||
-rw-r--r-- | tests/qtest/fuzz-virtio-scsi-test.c | 75 | ||||
-rw-r--r-- | tests/qtest/fuzz/generic_fuzz.c | 29 | ||||
-rw-r--r-- | tests/qtest/fuzz/generic_fuzz_configs.h | 8 | ||||
-rw-r--r-- | tests/qtest/meson.build | 5 |
6 files changed, 161 insertions, 81 deletions
diff --git a/tests/qtest/fuzz-megasas-test.c b/tests/qtest/fuzz-megasas-test.c new file mode 100644 index 0000000000..940a76bf25 --- /dev/null +++ b/tests/qtest/fuzz-megasas-test.c @@ -0,0 +1,49 @@ +/* + * QTest fuzzer-generated testcase for megasas device + * + * Copyright (c) 2020 Li Qiang <liq3ea@gmail.com> + * + * 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 "libqos/libqtest.h" + +/* + * This used to trigger the assert in scsi_dma_complete + * https://bugs.launchpad.net/qemu/+bug/1878263 + */ +static void test_lp1878263_megasas_zero_iov_cnt(void) +{ + QTestState *s; + + s = qtest_init("-nographic -monitor none -serial none " + "-M q35 -device megasas -device scsi-cd,drive=null0 " + "-blockdev driver=null-co,read-zeroes=on,node-name=null0"); + qtest_outl(s, 0xcf8, 0x80001818); + qtest_outl(s, 0xcfc, 0xc101); + qtest_outl(s, 0xcf8, 0x8000181c); + qtest_outl(s, 0xcf8, 0x80001804); + qtest_outw(s, 0xcfc, 0x7); + qtest_outl(s, 0xcf8, 0x8000186a); + qtest_writeb(s, 0x14, 0xfe); + qtest_writeb(s, 0x0, 0x02); + qtest_outb(s, 0xc1c0, 0x17); + qtest_quit(s); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qtest_add_func("fuzz/test_lp1878263_megasas_zero_iov_cnt", + test_lp1878263_megasas_zero_iov_cnt); + } + + return g_test_run(); +} diff --git a/tests/qtest/fuzz-test.c b/tests/qtest/fuzz-test.c index 6f161c93be..00149abec7 100644 --- a/tests/qtest/fuzz-test.c +++ b/tests/qtest/fuzz-test.c @@ -11,29 +11,6 @@ #include "libqos/libqtest.h" -/* - * This used to trigger the assert in scsi_dma_complete - * https://bugs.launchpad.net/qemu/+bug/1878263 - */ -static void test_lp1878263_megasas_zero_iov_cnt(void) -{ - QTestState *s; - - s = qtest_init("-nographic -monitor none -serial none " - "-M q35 -device megasas -device scsi-cd,drive=null0 " - "-blockdev driver=null-co,read-zeroes=on,node-name=null0"); - qtest_outl(s, 0xcf8, 0x80001818); - qtest_outl(s, 0xcfc, 0xc101); - qtest_outl(s, 0xcf8, 0x8000181c); - qtest_outl(s, 0xcf8, 0x80001804); - qtest_outw(s, 0xcfc, 0x7); - qtest_outl(s, 0xcf8, 0x8000186a); - qtest_writeb(s, 0x14, 0xfe); - qtest_writeb(s, 0x0, 0x02); - qtest_outb(s, 0xc1c0, 0x17); - qtest_quit(s); -} - static void test_lp1878642_pci_bus_get_irq_level_assert(void) { QTestState *s; @@ -47,55 +24,6 @@ static void test_lp1878642_pci_bus_get_irq_level_assert(void) qtest_quit(s); } -/* - * Here a MemoryRegionCache pointed to an MMIO region but had a - * larger size than the underlying region. - */ -static void test_mmio_oob_from_memory_region_cache(void) -{ - QTestState *s; - - s = qtest_init("-M pc-q35-5.2 -display none -m 512M " - "-device virtio-scsi,num_queues=8,addr=03.0 "); - - qtest_outl(s, 0xcf8, 0x80001811); - qtest_outb(s, 0xcfc, 0x6e); - qtest_outl(s, 0xcf8, 0x80001824); - qtest_outl(s, 0xcf8, 0x80001813); - qtest_outl(s, 0xcfc, 0xa080000); - qtest_outl(s, 0xcf8, 0x80001802); - qtest_outl(s, 0xcfc, 0x5a175a63); - qtest_outb(s, 0x6e08, 0x9e); - qtest_writeb(s, 0x9f003, 0xff); - qtest_writeb(s, 0x9f004, 0x01); - qtest_writeb(s, 0x9e012, 0x0e); - qtest_writeb(s, 0x9e01b, 0x0e); - qtest_writeb(s, 0x9f006, 0x01); - qtest_writeb(s, 0x9f008, 0x01); - qtest_writeb(s, 0x9f00a, 0x01); - qtest_writeb(s, 0x9f00c, 0x01); - qtest_writeb(s, 0x9f00e, 0x01); - qtest_writeb(s, 0x9f010, 0x01); - qtest_writeb(s, 0x9f012, 0x01); - qtest_writeb(s, 0x9f014, 0x01); - qtest_writeb(s, 0x9f016, 0x01); - qtest_writeb(s, 0x9f018, 0x01); - qtest_writeb(s, 0x9f01a, 0x01); - qtest_writeb(s, 0x9f01c, 0x01); - qtest_writeb(s, 0x9f01e, 0x01); - qtest_writeb(s, 0x9f020, 0x01); - qtest_writeb(s, 0x9f022, 0x01); - qtest_writeb(s, 0x9f024, 0x01); - qtest_writeb(s, 0x9f026, 0x01); - qtest_writeb(s, 0x9f028, 0x01); - qtest_writeb(s, 0x9f02a, 0x01); - qtest_writeb(s, 0x9f02c, 0x01); - qtest_writeb(s, 0x9f02e, 0x01); - qtest_writeb(s, 0x9f030, 0x01); - qtest_outb(s, 0x6e10, 0x00); - qtest_quit(s); -} - int main(int argc, char **argv) { const char *arch = qtest_get_arch(); @@ -103,12 +31,8 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("fuzz/test_lp1878263_megasas_zero_iov_cnt", - test_lp1878263_megasas_zero_iov_cnt); qtest_add_func("fuzz/test_lp1878642_pci_bus_get_irq_level_assert", test_lp1878642_pci_bus_get_irq_level_assert); - qtest_add_func("fuzz/test_mmio_oob_from_memory_region_cache", - test_mmio_oob_from_memory_region_cache); } return g_test_run(); diff --git a/tests/qtest/fuzz-virtio-scsi-test.c b/tests/qtest/fuzz-virtio-scsi-test.c new file mode 100644 index 0000000000..aaf6d10e18 --- /dev/null +++ b/tests/qtest/fuzz-virtio-scsi-test.c @@ -0,0 +1,75 @@ +/* + * QTest fuzzer-generated testcase for virtio-scsi device + * + * Copyright (c) 2020 Li Qiang <liq3ea@gmail.com> + * + * 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 "libqos/libqtest.h" + +/* + * Here a MemoryRegionCache pointed to an MMIO region but had a + * larger size than the underlying region. + */ +static void test_mmio_oob_from_memory_region_cache(void) +{ + QTestState *s; + + s = qtest_init("-M pc-q35-5.2 -display none -m 512M " + "-device virtio-scsi,num_queues=8,addr=03.0 "); + + qtest_outl(s, 0xcf8, 0x80001811); + qtest_outb(s, 0xcfc, 0x6e); + qtest_outl(s, 0xcf8, 0x80001824); + qtest_outl(s, 0xcf8, 0x80001813); + qtest_outl(s, 0xcfc, 0xa080000); + qtest_outl(s, 0xcf8, 0x80001802); + qtest_outl(s, 0xcfc, 0x5a175a63); + qtest_outb(s, 0x6e08, 0x9e); + qtest_writeb(s, 0x9f003, 0xff); + qtest_writeb(s, 0x9f004, 0x01); + qtest_writeb(s, 0x9e012, 0x0e); + qtest_writeb(s, 0x9e01b, 0x0e); + qtest_writeb(s, 0x9f006, 0x01); + qtest_writeb(s, 0x9f008, 0x01); + qtest_writeb(s, 0x9f00a, 0x01); + qtest_writeb(s, 0x9f00c, 0x01); + qtest_writeb(s, 0x9f00e, 0x01); + qtest_writeb(s, 0x9f010, 0x01); + qtest_writeb(s, 0x9f012, 0x01); + qtest_writeb(s, 0x9f014, 0x01); + qtest_writeb(s, 0x9f016, 0x01); + qtest_writeb(s, 0x9f018, 0x01); + qtest_writeb(s, 0x9f01a, 0x01); + qtest_writeb(s, 0x9f01c, 0x01); + qtest_writeb(s, 0x9f01e, 0x01); + qtest_writeb(s, 0x9f020, 0x01); + qtest_writeb(s, 0x9f022, 0x01); + qtest_writeb(s, 0x9f024, 0x01); + qtest_writeb(s, 0x9f026, 0x01); + qtest_writeb(s, 0x9f028, 0x01); + qtest_writeb(s, 0x9f02a, 0x01); + qtest_writeb(s, 0x9f02c, 0x01); + qtest_writeb(s, 0x9f02e, 0x01); + qtest_writeb(s, 0x9f030, 0x01); + qtest_outb(s, 0x6e10, 0x00); + qtest_quit(s); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qtest_add_func("fuzz/test_mmio_oob_from_memory_region_cache", + test_mmio_oob_from_memory_region_cache); + } + + return g_test_run(); +} diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index ee8c17a04c..b5fe27aae1 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -28,6 +28,7 @@ #include "hw/pci/pci.h" #include "hw/boards.h" #include "generic_fuzz_configs.h" +#include "hw/mem/sparse-mem.h" /* * SEPARATOR is used to separate "operations" in the fuzz input @@ -64,6 +65,8 @@ static useconds_t timeout = DEFAULT_TIMEOUT_US; static bool qtest_log_enabled; +MemoryRegion *sparse_mem_mr; + /* * A pattern used to populate a DMA region or perform a memwrite. This is * useful for e.g. populating tables of unique addresses. @@ -191,8 +194,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr) */ if (dma_patterns->len == 0 || len == 0 - || mr != current_machine->ram - || addr > current_machine->ram_size) { + || (mr != current_machine->ram && mr != sparse_mem_mr)) { return; } @@ -238,7 +240,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr) MEMTXATTRS_UNSPECIFIED); if (!(memory_region_is_ram(mr1) || - memory_region_is_romd(mr1))) { + memory_region_is_romd(mr1)) && mr1 != sparse_mem_mr) { l = memory_access_size(mr1, l, addr1); } else { /* ROM/RAM case */ @@ -583,6 +585,21 @@ static void handle_timeout(int sig) fprintf(stderr, "[Timeout]\n"); fflush(stderr); } + + /* + * If there is a crash, libfuzzer/ASAN forks a child to run an + * "llvm-symbolizer" process for printing out a pretty stacktrace. It + * communicates with this child using a pipe. If we timeout+Exit, while + * libfuzzer is still communicating with the llvm-symbolizer child, we will + * be left with an orphan llvm-symbolizer process. Sometimes, this appears + * to lead to a deadlock in the forkserver. Use waitpid to check if there + * are any waitable children. If so, exit out of the signal-handler, and + * let libfuzzer finish communicating with the child, and exit, on its own. + */ + if (waitpid(-1, NULL, WNOHANG) == 0) { + return; + } + _Exit(0); } @@ -799,6 +816,12 @@ static void generic_pre_fuzz(QTestState *s) } qts_global = s; + /* + * Create a special device that we can use to back DMA buffers at very + * high memory addresses + */ + sparse_mem_mr = sparse_mem_init(0, UINT64_MAX); + dma_regions = g_array_new(false, false, sizeof(address_range)); dma_patterns = g_array_new(false, false, sizeof(pattern)); diff --git a/tests/qtest/fuzz/generic_fuzz_configs.h b/tests/qtest/fuzz/generic_fuzz_configs.h index 5d599765c4..8b8c7ac553 100644 --- a/tests/qtest/fuzz/generic_fuzz_configs.h +++ b/tests/qtest/fuzz/generic_fuzz_configs.h @@ -177,7 +177,7 @@ const generic_fuzz_config predefined_configs[] = { .name = "i82550", .args = "-machine q35 -nodefaults " "-device i82550,netdev=net0 -netdev user,id=net0", - .objects = "eepro*" + .objects = "i8255*" },{ .name = "sdhci-v3", .args = "-nodefaults -device sdhci-pci,sd-spec-version=3 " @@ -209,6 +209,12 @@ const generic_fuzz_config predefined_configs[] = { "-blockdev driver=null-co,read-zeroes=on,node-name=null0", .objects = "megasas*", },{ + .name = "am53c974", + .args = "-device am53c974,id=scsi -device scsi-hd,drive=disk0 " + "-drive id=disk0,if=none,file=null-co://,format=raw " + "-nodefaults", + .objects = "*esp* *scsi* *am53c974*", + },{ .name = "ac97", .args = "-machine q35 -nodefaults " "-device ac97,audiodev=snd0 -audiodev none,id=snd0 -nodefaults", diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 66ee9fbf45..6e871077c1 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -17,7 +17,10 @@ slow_qtests = { 'test-hmp' : 120, } -qtests_generic = [ +qtests_generic = \ + (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ + (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ + [ 'cdrom-test', 'device-introspect-test', 'machine-none-test', |