[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH v2 15/17] fuzz: Add general qtest fuzz-target
From: |
Oleinik, Alexander |
Subject: |
[Qemu-devel] [RFC PATCH v2 15/17] fuzz: Add general qtest fuzz-target |
Date: |
Mon, 5 Aug 2019 07:11:15 +0000 |
Signed-off-by: Alexander Oleinik <address@hidden>
---
tests/fuzz/qtest_fuzz.c | 260 ++++++++++++++++++++++++++++++++++++++++
tests/fuzz/qtest_fuzz.h | 37 ++++++
2 files changed, 297 insertions(+)
create mode 100644 tests/fuzz/qtest_fuzz.c
create mode 100644 tests/fuzz/qtest_fuzz.h
diff --git a/tests/fuzz/qtest_fuzz.c b/tests/fuzz/qtest_fuzz.c
new file mode 100644
index 0000000000..a4560535e1
--- /dev/null
+++ b/tests/fuzz/qtest_fuzz.c
@@ -0,0 +1,260 @@
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "qemu/main-loop.h"
+#include <wordexp.h>
+#include "qemu-common.h"
+#include "fuzzer_hooks.h"
+
+
+#include "fuzz.h"
+#include "qtest_fuzz.h"
+#include "tests/libqtest.h"
+#include "fuzz/qos_fuzz.h"
+
+
+/* Make sure that the io_port is mapped to some device */
+static uint16_t normalize_io_port(uint64_t addr)
+{
+ return addr;
+ addr = addr % total_io_mem;
+ fuzz_memory_region *fmr = fuzz_memory_region_head;
+ while (addr != 0) {
+ if (!fmr->io) {
+ fmr = fmr->next;
+ continue;
+ }
+ if (addr <= fmr->length) {
+ addr = fmr->start + addr;
+ break;
+ }
+ addr -= fmr->length + 1;
+ fmr = fmr->next;
+ }
+ /* Stuff that times out or hotplugs.. */
+ if (addr >= 0x5655 && addr <= 0x565b) {
+ return 0;
+ }
+ if (addr >= 0x510 && addr <= 0x518) {
+ return 0;
+ }
+ /* PCI Hotplug */
+ if (addr >= 0xae00 && addr <= 0xae13) {
+ return 0;
+ }
+ /* CPU Hotplug */
+ if (addr >= 0xaf00 && addr <= 0xaf1f) {
+ return 0;
+ }
+ return addr;
+}
+
+/* Make sure that the memory address is mapped to some interesting device */
+static uint16_t normalize_mem_addr(uint64_t addr)
+{
+ return addr;
+ addr = addr % total_ram_mem;
+ fuzz_memory_region *fmr = fuzz_memory_region_head;
+ while (addr != 0) {
+ if (fmr->io) {
+ fmr = fmr->next;
+ continue;
+ }
+ if (addr <= fmr->length) {
+ return fmr->start + addr;
+ }
+ addr -= fmr->length + 1;
+ fmr = fmr->next;
+ }
+ return addr;
+}
+
+static void qtest_fuzz(const unsigned char *Data, size_t Size)
+{
+ const unsigned char *pos = Data;
+ const unsigned char *End = Data + Size;
+
+ qtest_cmd *cmd;
+
+ while (pos < Data + Size) {
+ /* Translate the fuzz input to a qtest command */
+ cmd = &commands[(*pos) % (sizeof(commands) / sizeof(qtest_cmd))];
+ pos++;
+
+ if (strcmp(cmd->name, "clock_step") == 0) {
+ /* TODO: This times out */
+ /* qtest_clock_step_next(s); */
+ } else if (strcmp(cmd->name, "outb") == 0) {
+ if (pos + sizeof(uint16_t) + sizeof(uint8_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ uint8_t val = *(uint16_t *)(pos);
+ pos += sizeof(uint8_t);
+ addr = normalize_io_port(addr);
+ qtest_outb(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "outw") == 0) {
+ if (pos + sizeof(uint16_t) + sizeof(uint16_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ uint16_t val = *(uint16_t *)(pos);
+ pos += sizeof(uint16_t);
+ addr = normalize_io_port(addr);
+ qtest_outw(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "outl") == 0) {
+ if (pos + sizeof(uint16_t) + sizeof(uint32_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ uint32_t val = *(uint32_t *)(pos);
+ pos += sizeof(uint32_t);
+ addr = normalize_io_port(addr);
+ qtest_outl(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "inb") == 0) {
+ if (pos + sizeof(uint16_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ addr = normalize_io_port(addr);
+ qtest_inb(s, addr);
+ }
+ } else if (strcmp(cmd->name, "inw") == 0) {
+ if (pos + sizeof(uint16_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ addr = normalize_io_port(addr);
+ qtest_inw(s, addr);
+ }
+ } else if (strcmp(cmd->name, "inl") == 0) {
+ if (pos + sizeof(uint16_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ addr = normalize_io_port(addr);
+ qtest_inl(s, addr);
+ }
+ } else if (strcmp(cmd->name, "writeb") == 0) {
+ if (pos + sizeof(uint32_t) + sizeof(uint8_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ uint8_t val = *(uint8_t *)(pos);
+ pos += sizeof(uint8_t);
+ addr = normalize_mem_addr(addr);
+ qtest_writeb(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "writew") == 0) {
+ if (pos + sizeof(uint32_t) + sizeof(uint16_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ uint16_t val = *(uint16_t *)(pos);
+ pos += sizeof(uint16_t);
+ addr = normalize_mem_addr(addr);
+ qtest_writew(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "writel") == 0) {
+ if (pos + sizeof(uint32_t) + sizeof(uint32_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ uint32_t val = *(uint32_t *)(pos);
+ pos += sizeof(uint32_t);
+ addr = normalize_mem_addr(addr);
+ qtest_writel(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "readb") == 0) {
+ if (pos + sizeof(uint32_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ addr = normalize_mem_addr(addr);
+ qtest_readb(s, addr);
+ }
+ } else if (strcmp(cmd->name, "readw") == 0) {
+ if (pos + sizeof(uint32_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ addr = normalize_mem_addr(addr);
+ qtest_readw(s, addr); }
+ } else if (strcmp(cmd->name, "readl") == 0) {
+ if (pos + sizeof(uint32_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ addr = normalize_mem_addr(addr);
+ qtest_readl(s, addr);
+ }
+ } else if (strcmp(cmd->name, "write_dma") == 0) {
+ if (pos + sizeof(uint32_t) + sizeof(uint16_t) < End) {
+ uint32_t addr = *(int32_t *)(pos);
+ pos += sizeof(uint32_t);
+ uint32_t val = 0x100000;
+ addr = normalize_mem_addr(addr);
+ qtest_writel(s, addr, val);
+ }
+ } else if (strcmp(cmd->name, "out_dma") == 0) {
+ if (pos + sizeof(uint16_t) + sizeof(uint16_t) < End) {
+ uint16_t addr = *(int16_t *)(pos);
+ pos += sizeof(uint16_t);
+ uint32_t val = 0x100000;
+ addr = normalize_io_port(addr);
+ qtest_outl(s, addr, val);
+ }
+ }
+ /* main_loop_wait(false); */
+ }
+}
+
+static void *net_test_setup_nosocket(GString *cmd_line, void *arg)
+{
+ g_string_append(cmd_line, " -netdev hubport,hubid=0,id=hs0 ");
+ return arg;
+}
+
+static void fuzz_fork(const unsigned char *Data, size_t Size)
+{
+ if (fork() == 0) {
+ qtest_fuzz(Data, Size);
+ counter_shm_store();
+ _Exit(0);
+ } else {
+ wait(NULL);
+ counter_shm_load();
+ }
+}
+
+static void fork_pre_main(void)
+{
+ qos_setup();
+ counter_shm_init();
+}
+
+int qtest_argc;
+char **qtest_argv;
+static void register_qtest_fuzz_targets(void)
+{
+ QOSGraphTestOptions opts = {
+ .before = net_test_setup_nosocket,
+ };
+ FuzzTarget fuzz_opts = {
+ .pre_main = qos_setup,
+ .pre_save_state = qos_init_path,
+ .save_state = &save_vm_state,
+ .reset = &load_vm_state,
+ .pre_fuzz = NULL,
+ .fuzz = &qtest_fuzz,
+ .post_fuzz = NULL,
+ };
+ fuzz_add_qos_target("qtest-fuzz", "fuzz qtest commands and a dma buffer. \
+ Reset device state for each run", "e1000e", &opts, &fuzz_opts);
+
+ fuzz_opts.pre_main = &fork_pre_main;
+ fuzz_opts.pre_fuzz = NULL;
+ fuzz_opts.fuzz = &fuzz_fork;
+ fuzz_opts.reset = NULL;
+ fuzz_add_qos_target("qtest-fork-fuzz", "fuzz qtest commands and a dma \
+ buffer. Use COW/forking to reset state", "e1000e", &opts,
+ &fuzz_opts);
+
+}
+
+fuzz_target_init(register_qtest_fuzz_targets);
diff --git a/tests/fuzz/qtest_fuzz.h b/tests/fuzz/qtest_fuzz.h
new file mode 100644
index 0000000000..c4cf08f5a2
--- /dev/null
+++ b/tests/fuzz/qtest_fuzz.h
@@ -0,0 +1,37 @@
+#ifndef _QTEST_FUZZ_H_
+#define _QTEST_FUZZ_H_
+
+typedef struct qtest_cmd {
+ char name[32];
+ uint8_t size;
+} qtest_cmd;
+
+typedef uint32_t addr_type;
+
+static qtest_cmd commands[] = {
+ {"clock_step", 0},
+ {"clock_step", 0},
+ {"clock_set", 1},
+ {"outb", 2},
+ {"outw", 2},
+ {"outl", 2},
+ {"inb", 1},
+ {"inw", 1},
+ {"inl", 1},
+ {"writeb", 2},
+ {"writew", 2},
+ {"writel", 2},
+ {"writeq", 2},
+ {"readb", 1},
+ {"readw", 1},
+ {"readl", 1},
+ {"readq", 1},
+ {"read", 2},
+ {"write", 3},
+ {"b64read", 2},
+ {"b64write", 10},
+ {"memset", 3},
+ {"write_dma", 2},
+ {"out_dma", 2},
+};
+#endif
--
2.20.1
- Re: [Qemu-devel] [RFC PATCH v2 08/17] fuzz: Export the qemu_savevm_live_state function, (continued)
- [Qemu-devel] [RFC PATCH v2 10/17] fuzz: qtest client directly interacts with server, Oleinik, Alexander, 2019/08/05
- [Qemu-devel] [RFC PATCH v2 11/17] fuzz: Move useful qos functions to separate object, Oleinik, Alexander, 2019/08/05
- [Qemu-devel] [RFC PATCH v2 14/17] fuzz: Add forking support to the fuzzer, Oleinik, Alexander, 2019/08/05
- [Qemu-devel] [RFC PATCH v2 13/17] fuzz: Add libqos support to the fuzzer, Oleinik, Alexander, 2019/08/05
- [Qemu-devel] [RFC PATCH v2 17/17] fuzz: Add fuzz accelerator type, Oleinik, Alexander, 2019/08/05
- [Qemu-devel] [RFC PATCH v2 12/17] fuzz: Add fuzzer skeleton, Oleinik, Alexander, 2019/08/05
- [Qemu-devel] [RFC PATCH v2 15/17] fuzz: Add general qtest fuzz-target,
Oleinik, Alexander <=
- [Qemu-devel] [RFC PATCH v2 16/17] fuzz: Add virtio-net fuzz targets, Oleinik, Alexander, 2019/08/05
- Re: [Qemu-devel] [RFC PATCH v2 00/17] Add virtual device fuzzing support, no-reply, 2019/08/05