diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include index f259d866c9..5bde793bf2 100644 --- a/tests/qtest/fuzz/Makefile.include +++ b/tests/qtest/fuzz/Makefile.include @@ -5,6 +5,7 @@ fuzz-obj-y += $(libqos-obj-y) fuzz-obj-y += tests/qtest/fuzz/fuzz.o # Fuzzer skeleton fuzz-obj-y += tests/qtest/fuzz/fork_fuzz.o fuzz-obj-y += tests/qtest/fuzz/qos_fuzz.o +fuzz-obj-y += tests/qtest/fuzz/qtest_wrappers.o # Targets fuzz-obj-$(CONFIG_PCI_I440FX) += tests/qtest/fuzz/i440fx_fuzz.o @@ -16,3 +17,23 @@ 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 + +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_inl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_outl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readw +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readl +FUZZ_LDFLAGS += -Wl,-wrap,qtest_readq +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writeb +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writew +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writel +FUZZ_LDFLAGS += -Wl,-wrap,qtest_writeq +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memread +FUZZ_LDFLAGS += -Wl,-wrap,qtest_bufread +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memwrite +FUZZ_LDFLAGS += -Wl,-wrap,qtest_bufwrite +FUZZ_LDFLAGS += -Wl,-wrap,qtest_memset diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 33365c3782..ea630ddb9b 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -91,7 +91,10 @@ static void usage(char *path) printf(" * %s : %s\n", tmp->target->name, tmp->target->description); } - printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n"); + printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n\n" + "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n" + "QTest commands into an ASCII protocol. Useful for building crash\n" + "reproducers, but slows down execution.\n"); exit(0); } @@ -138,6 +141,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) char *target_name; char *dir; + bool serialize = false; /* Initialize qgraph and modules */ qos_graph_init(); @@ -172,6 +176,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) usage(**argv); } + /* Should we always serialize qtest commands? */ + if (getenv("FUZZ_SERIALIZE_QTEST")) { + serialize = true; + } + + fuzz_qtest_set_serialize(serialize); + /* Identify the fuzz target */ fuzz_target = fuzz_get_target(target_name); if (!fuzz_target) { diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index 03901d414e..72d5710f6c 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -82,6 +82,9 @@ typedef struct FuzzTarget { void flush_events(QTestState *); void reboot(QTestState *); +/* Use the QTest ASCII protocol or call address_space API directly?*/ +void fuzz_qtest_set_serialize(bool option); + /* * makes a copy of *target and adds it to the target-list. * i.e. fine to set up target on the caller's stack diff --git a/tests/qtest/fuzz/qtest_wrappers.c b/tests/qtest/fuzz/qtest_wrappers.c new file mode 100644 index 0000000000..713c830cdb --- /dev/null +++ b/tests/qtest/fuzz/qtest_wrappers.c @@ -0,0 +1,252 @@ +/* + * qtest function wrappers + * + * Copyright Red Hat Inc., 2019 + * + * Authors: + * Alexander Bulekov + * + * 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 "cpu.h" +#include "exec/ioport.h" + +#include "fuzz.h" + +static bool serialize = true; + +#define WRAP(RET_TYPE, NAME_AND_ARGS)\ + RET_TYPE __wrap_##NAME_AND_ARGS;\ + RET_TYPE __real_##NAME_AND_ARGS; + +WRAP(uint8_t , qtest_inb(QTestState *s, uint16_t addr)) +WRAP(uint16_t , qtest_inw(QTestState *s, uint16_t addr)) +WRAP(uint32_t , qtest_inl(QTestState *s, uint16_t addr)) +WRAP(void , qtest_outb(QTestState *s, uint16_t addr, uint8_t value)) +WRAP(void , qtest_outw(QTestState *s, uint16_t addr, uint16_t value)) +WRAP(void , qtest_outl(QTestState *s, uint16_t addr, uint32_t value)) +WRAP(uint8_t , qtest_readb(QTestState *s, uint64_t addr)) +WRAP(uint16_t , qtest_readw(QTestState *s, uint64_t addr)) +WRAP(uint32_t , qtest_readl(QTestState *s, uint64_t addr)) +WRAP(uint64_t , qtest_readq(QTestState *s, uint64_t addr)) +WRAP(void , qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)) +WRAP(void , qtest_writew(QTestState *s, uint64_t addr, uint16_t value)) +WRAP(void , qtest_writel(QTestState *s, uint64_t addr, uint32_t value)) +WRAP(void , qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)) +WRAP(void , qtest_memread(QTestState *s, uint64_t addr, + void *data, size_t size)) +WRAP(void , qtest_bufread(QTestState *s, uint64_t addr, void *data, + size_t size)) +WRAP(void , qtest_memwrite(QTestState *s, uint64_t addr, const void *data, + size_t size)) +WRAP(void, qtest_bufwrite(QTestState *s, uint64_t addr, + const void *data, size_t size)) +WRAP(void, qtest_memset(QTestState *s, uint64_t addr, + uint8_t patt, size_t size)) + + +uint8_t __wrap_qtest_inb(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inb(addr); + } else { + return __real_qtest_inb(s, addr); + } +} + +uint16_t __wrap_qtest_inw(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inw(addr); + } else { + return __real_qtest_inw(s, addr); + } +} + +uint32_t __wrap_qtest_inl(QTestState *s, uint16_t addr) +{ + if (!serialize) { + return cpu_inl(addr); + } else { + return __real_qtest_inl(s, addr); + } +} + +void __wrap_qtest_outb(QTestState *s, uint16_t addr, uint8_t value) +{ + if (!serialize) { + cpu_outb(addr, value); + } else { + __real_qtest_outb(s, addr, value); + } +} + +void __wrap_qtest_outw(QTestState *s, uint16_t addr, uint16_t value) +{ + if (!serialize) { + cpu_outw(addr, value); + } else { + __real_qtest_outw(s, addr, value); + } +} + +void __wrap_qtest_outl(QTestState *s, uint16_t addr, uint32_t value) +{ + if (!serialize) { + cpu_outl(addr, value); + } else { + __real_qtest_outl(s, addr, value); + } +} + +uint8_t __wrap_qtest_readb(QTestState *s, uint64_t addr) +{ + uint8_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 1); + return value; + } else { + return __real_qtest_readb(s, addr); + } +} + +uint16_t __wrap_qtest_readw(QTestState *s, uint64_t addr) +{ + uint16_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 2); + return value; + } else { + return __real_qtest_readw(s, addr); + } +} + +uint32_t __wrap_qtest_readl(QTestState *s, uint64_t addr) +{ + uint32_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 4); + return value; + } else { + return __real_qtest_readl(s, addr); + } +} + +uint64_t __wrap_qtest_readq(QTestState *s, uint64_t addr) +{ + uint64_t value; + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 8); + return value; + } else { + return __real_qtest_readq(s, addr); + } +} + +void __wrap_qtest_writeb(QTestState *s, uint64_t addr, uint8_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 1); + } else { + __real_qtest_writeb(s, addr, value); + } +} + +void __wrap_qtest_writew(QTestState *s, uint64_t addr, uint16_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 2); + } else { + __real_qtest_writew(s, addr, value); + } +} + +void __wrap_qtest_writel(QTestState *s, uint64_t addr, uint32_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 4); + } else { + __real_qtest_writel(s, addr, value); + } +} + +void __wrap_qtest_writeq(QTestState *s, uint64_t addr, uint64_t value) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + &value, 8); + } else { + __real_qtest_writeq(s, addr, value); + } +} + +void __wrap_qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) +{ + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data, + size); + } else { + __real_qtest_memread(s, addr, data, size); + } +} + +void __wrap_qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size) +{ + if (!serialize) { + address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, data, + size); + } else { + __real_qtest_bufread(s, addr, data, size); + } +} + +void __wrap_qtest_memwrite(QTestState *s, uint64_t addr, const void *data, + size_t size) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_memwrite(s, addr, data, size); + } +} + +void __wrap_qtest_bufwrite(QTestState *s, uint64_t addr, + const void *data, size_t size) +{ + if (!serialize) { + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_bufwrite(s, addr, data, size); + } +} +void __wrap_qtest_memset(QTestState *s, uint64_t addr, + uint8_t patt, size_t size) +{ + void *data; + if (!serialize) { + data = malloc(size); + memset(data, patt, size); + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + data, size); + } else { + __real_qtest_memset(s, addr, patt, size); + } +} + +void fuzz_qtest_set_serialize(bool option) +{ + serialize = option; +}