Replace fork-based fuzzing with reboots.

Now the fuzzers will reboot the guest between inputs.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE+tTiv4cTddY0BRfETmYd3lg6lk4FAmPu/LoACgkQTmYd3lg6
 lk6RHg/7BRGI5ZPXb1MmTNCC+SroQ6TT++lO4b0hbkN2HO6U+WVvfuA6+0wg+8qC
 4bp+G1Tabpcq1MTYUuim6DBtWswgpqr0AbWNwn1eF7hya+3W9woH2POVYY2wwc7m
 S3EdwXCCKo9gGXlaNrotnbwIk+o8B4BzXOXLIlRtg26wGYhT5fkJA/BQcHKDXz37
 ctyWxlyjIM8pNCgfybMvjC7MYtp8DufPsv/rrKx9t0TM7f1jPVgXLek7t0+ZwjeY
 qz2Om2jiij1INgK9hTieWs4eHwpwre6vH2a+JKRkZ3sS7WYcj1auNKVJb3GvDqmc
 wy+Nz5Lz4+aPP19pkCYjfz5w3CqEEsSlSDn5UVRbfl2fbENSceoNwo9huMXsF1pB
 oO6NK2NxbOygmNpYxp+JEt45KFIXzUcIFQwbn8aCDODIl+0H2yu7/ll6XgELf1Pa
 P83THOaVxIxfcI9VOdt/FwDq1ZzmV5nk/BkIGJeIWNYMbU4Gze6YoaL3U8AHDxKH
 f6f3qDzcVJjqD0wKhvYcQ3kSPq+vHc/ioh6mYwos6VUEVYz/SLOY876MaSB/K4PE
 ofBV7y6HvJ6AMwg1TBg4YtOP08gWK+4sYH+I09oU40U3UcwEpkbkQTF72lPQHxFs
 8UVRJrgWv/xzrwzXTX5ruQ633F8zuhqQTeERqksj1pPHJ3NdHps=
 =F6qI
 -----END PGP SIGNATURE-----

Merge tag 'pr-2023-02-16' of https://gitlab.com/a1xndr/qemu into staging

Replace fork-based fuzzing with reboots.
Now the fuzzers will reboot the guest between inputs.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEE+tTiv4cTddY0BRfETmYd3lg6lk4FAmPu/LoACgkQTmYd3lg6
# lk6RHg/7BRGI5ZPXb1MmTNCC+SroQ6TT++lO4b0hbkN2HO6U+WVvfuA6+0wg+8qC
# 4bp+G1Tabpcq1MTYUuim6DBtWswgpqr0AbWNwn1eF7hya+3W9woH2POVYY2wwc7m
# S3EdwXCCKo9gGXlaNrotnbwIk+o8B4BzXOXLIlRtg26wGYhT5fkJA/BQcHKDXz37
# ctyWxlyjIM8pNCgfybMvjC7MYtp8DufPsv/rrKx9t0TM7f1jPVgXLek7t0+ZwjeY
# qz2Om2jiij1INgK9hTieWs4eHwpwre6vH2a+JKRkZ3sS7WYcj1auNKVJb3GvDqmc
# wy+Nz5Lz4+aPP19pkCYjfz5w3CqEEsSlSDn5UVRbfl2fbENSceoNwo9huMXsF1pB
# oO6NK2NxbOygmNpYxp+JEt45KFIXzUcIFQwbn8aCDODIl+0H2yu7/ll6XgELf1Pa
# P83THOaVxIxfcI9VOdt/FwDq1ZzmV5nk/BkIGJeIWNYMbU4Gze6YoaL3U8AHDxKH
# f6f3qDzcVJjqD0wKhvYcQ3kSPq+vHc/ioh6mYwos6VUEVYz/SLOY876MaSB/K4PE
# ofBV7y6HvJ6AMwg1TBg4YtOP08gWK+4sYH+I09oU40U3UcwEpkbkQTF72lPQHxFs
# 8UVRJrgWv/xzrwzXTX5ruQ633F8zuhqQTeERqksj1pPHJ3NdHps=
# =F6qI
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 17 Feb 2023 04:04:10 GMT
# 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

* tag 'pr-2023-02-16' of https://gitlab.com/a1xndr/qemu:
  docs/fuzz: remove mentions of fork-based fuzzing
  fuzz: remove fork-fuzzing scaffolding
  fuzz/i440fx: remove fork-based fuzzer
  fuzz/virtio-blk: remove fork-based fuzzer
  fuzz/virtio-net: remove fork-based fuzzer
  fuzz/virtio-scsi: remove fork-based fuzzer
  fuzz/generic-fuzz: add a limit on DMA bytes written
  fuzz/generic-fuzz: use reboots instead of forks to reset state
  fuzz: add fuzz_reset API
  hw/sparse-mem: clear memory on reset

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-02-21 11:28:01 +00:00
commit 4919d0c44a
14 changed files with 72 additions and 405 deletions

View File

@ -19,11 +19,6 @@ responsibility to ensure that state is reset between fuzzing-runs.
Building the fuzzers
--------------------
*NOTE*: If possible, build a 32-bit binary. When forking, the 32-bit fuzzer is
much faster, since the page-map has a smaller size. This is due to the fact that
AddressSanitizer maps ~20TB of memory, as part of its detection. This results
in a large page-map, and a much slower ``fork()``.
To build the fuzzers, install a recent version of clang:
Configure with (substitute the clang binaries with the version you installed).
Here, enable-sanitizers, is optional but it allows us to reliably detect bugs
@ -296,10 +291,9 @@ input. It is also responsible for manually calling ``main_loop_wait`` to ensure
that bottom halves are executed and any cleanup required before the next input.
Since the same process is reused for many fuzzing runs, QEMU state needs to
be reset at the end of each run. There are currently two implemented
options for resetting state:
be reset at the end of each run. For example, this can be done by rebooting the
VM, after each run.
- Reboot the guest between runs.
- *Pros*: Straightforward and fast for simple fuzz targets.
- *Cons*: Depending on the device, does not reset all device state. If the
@ -308,15 +302,3 @@ options for resetting state:
reboot.
- *Example target*: ``i440fx-qtest-reboot-fuzz``
- Run each test case in a separate forked process and copy the coverage
information back to the parent. This is fairly similar to AFL's "deferred"
fork-server mode [3]
- *Pros*: Relatively fast. Devices only need to be initialized once. No need to
do slow reboots or vmloads.
- *Cons*: Not officially supported by libfuzzer. Does not work well for
devices that rely on dedicated threads.
- *Example target*: ``virtio-net-fork-fuzz``

View File

@ -77,6 +77,13 @@ static void sparse_mem_write(void *opaque, hwaddr addr, uint64_t v,
}
static void sparse_mem_enter_reset(Object *obj, ResetType type)
{
SparseMemState *s = SPARSE_MEM(obj);
g_hash_table_remove_all(s->mapped);
return;
}
static const MemoryRegionOps sparse_mem_ops = {
.read = sparse_mem_read,
.write = sparse_mem_write,
@ -123,7 +130,8 @@ static void sparse_mem_realize(DeviceState *dev, Error **errp)
assert(s->baseaddr + s->length > s->baseaddr);
s->mapped = g_hash_table_new(NULL, NULL);
s->mapped = g_hash_table_new_full(NULL, NULL, NULL,
(GDestroyNotify)g_free);
memory_region_init_io(&s->mmio, OBJECT(s), &sparse_mem_ops, s,
"sparse-mem", s->length);
sysbus_init_mmio(sbd, &s->mmio);
@ -131,12 +139,15 @@ static void sparse_mem_realize(DeviceState *dev, Error **errp)
static void sparse_mem_class_init(ObjectClass *klass, void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, sparse_mem_properties);
dc->desc = "Sparse Memory Device";
dc->realize = sparse_mem_realize;
rc->phases.enter = sparse_mem_enter_reset;
}
static const TypeInfo sparse_mem_types[] = {

View File

@ -215,10 +215,6 @@ endif
# Specify linker-script with add_project_link_arguments so that it is not placed
# within a linker --start-group/--end-group pair
if get_option('fuzzing')
add_project_link_arguments(['-Wl,-T,',
(meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
native: false, language: all_languages)
# Specify a filter to only instrument code that is directly related to
# virtual-devices.
configure_file(output: 'instrumentation-filter',

View File

@ -1,41 +0,0 @@
/*
* Fork-based fuzzing helpers
*
* Copyright Red Hat Inc., 2019
*
* Authors:
* Alexander Bulekov <alxndr@bu.edu>
*
* 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 "fork_fuzz.h"
void counter_shm_init(void)
{
/* Copy what's in the counter region to a temporary buffer.. */
void *copy = malloc(&__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START);
memcpy(copy,
&__FUZZ_COUNTERS_START,
&__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START);
/* Map a shared region over the counter region */
if (mmap(&__FUZZ_COUNTERS_START,
&__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS,
0, 0) == MAP_FAILED) {
perror("Error: ");
exit(1);
}
/* Copy the original data back to the counter-region */
memcpy(&__FUZZ_COUNTERS_START, copy,
&__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START);
free(copy);
}

View File

@ -1,23 +0,0 @@
/*
* Fork-based fuzzing helpers
*
* Copyright Red Hat Inc., 2019
*
* Authors:
* Alexander Bulekov <alxndr@bu.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef FORK_FUZZ_H
#define FORK_FUZZ_H
extern uint8_t __FUZZ_COUNTERS_START;
extern uint8_t __FUZZ_COUNTERS_END;
void counter_shm_init(void);
#endif

View File

@ -1,56 +0,0 @@
/*
* We adjust linker script modification to place all of the stuff that needs to
* persist across fuzzing runs into a contiguous section of memory. Then, it is
* easy to re-map the counter-related memory as shared.
*/
SECTIONS
{
.data.fuzz_start : ALIGN(4K)
{
__FUZZ_COUNTERS_START = .;
__start___sancov_cntrs = .;
*(_*sancov_cntrs);
__stop___sancov_cntrs = .;
/* Lowest stack counter */
*(__sancov_lowest_stack);
}
}
INSERT AFTER .data;
SECTIONS
{
.data.fuzz_ordered :
{
/*
* Coverage counters. They're not necessary for fuzzing, but are useful
* for analyzing the fuzzing performance
*/
__start___llvm_prf_cnts = .;
*(*llvm_prf_cnts);
__stop___llvm_prf_cnts = .;
/* Internal Libfuzzer TracePC object which contains the ValueProfileMap */
FuzzerTracePC*(.bss*);
/*
* In case the above line fails, explicitly specify the (mangled) name of
* the object we care about
*/
*(.bss._ZN6fuzzer3TPCE);
}
}
INSERT AFTER .data.fuzz_start;
SECTIONS
{
.data.fuzz_end : ALIGN(4K)
{
__FUZZ_COUNTERS_END = .;
}
}
/*
* Don't overwrite the SECTIONS in the default linker script. Instead insert the
* above into the default script
*/
INSERT AFTER .data.fuzz_ordered;

View File

@ -51,6 +51,12 @@ void flush_events(QTestState *s)
}
}
void fuzz_reset(QTestState *s)
{
qemu_system_reset(SHUTDOWN_CAUSE_GUEST_RESET);
main_loop_wait(true);
}
static QTestState *qtest_setup(void)
{
qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts);

View File

@ -103,7 +103,7 @@ typedef struct FuzzTarget {
} FuzzTarget;
void flush_events(QTestState *);
void reboot(QTestState *);
void fuzz_reset(QTestState *);
/* Use the QTest ASCII protocol or call address_space API directly?*/
void fuzz_qtest_set_serialize(bool option);

View File

@ -18,7 +18,6 @@
#include "tests/qtest/libqtest.h"
#include "tests/qtest/libqos/pci-pc.h"
#include "fuzz.h"
#include "fork_fuzz.h"
#include "string.h"
#include "exec/memory.h"
#include "exec/ramblock.h"
@ -29,6 +28,8 @@
#include "generic_fuzz_configs.h"
#include "hw/mem/sparse-mem.h"
static void pci_enum(gpointer pcidev, gpointer bus);
/*
* SEPARATOR is used to separate "operations" in the fuzz input
*/
@ -47,10 +48,10 @@ enum cmds {
OP_CLOCK_STEP,
};
#define DEFAULT_TIMEOUT_US 100000
#define USEC_IN_SEC 1000000000
#define MAX_DMA_FILL_SIZE 0x10000
#define MAX_TOTAL_DMA_SIZE 0x10000000
#define PCI_HOST_BRIDGE_CFG 0xcf8
#define PCI_HOST_BRIDGE_DATA 0xcfc
@ -60,9 +61,8 @@ typedef struct {
ram_addr_t size; /* The number of bytes until the end of the I/O region */
} address_range;
static useconds_t timeout = DEFAULT_TIMEOUT_US;
static bool qtest_log_enabled;
size_t dma_bytes_written;
MemoryRegion *sparse_mem_mr;
@ -196,6 +196,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
*/
if (dma_patterns->len == 0
|| len == 0
|| dma_bytes_written + len > MAX_TOTAL_DMA_SIZE
|| (mr != current_machine->ram && mr != sparse_mem_mr)) {
return;
}
@ -268,6 +269,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
fflush(stderr);
}
qtest_memwrite(qts_global, addr, buf, l);
dma_bytes_written += l;
}
len -= l;
buf += l;
@ -589,30 +591,6 @@ static void op_disable_pci(QTestState *s, const unsigned char *data, size_t len)
pci_disabled = true;
}
static void handle_timeout(int sig)
{
if (qtest_log_enabled) {
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);
}
/*
* Here, we interpret random bytes from the fuzzer, as a sequence of commands.
* Some commands can be variable-width, so we use a separator, SEPARATOR, to
@ -669,64 +647,33 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
size_t cmd_len;
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 for each command to avoid hurting
* performance, too much
*/
if (timeout) {
op_clear_dma_patterns(s, NULL, 0);
pci_disabled = false;
dma_bytes_written = 0;
sigemptyset(&sact.sa_mask);
sact.sa_flags = SA_NODEFER;
sact.sa_handler = handle_timeout;
sigaction(SIGALRM, &sact, NULL);
QPCIBus *pcibus = qpci_new_pc(s, NULL);
g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus);
qpci_free_pc(pcibus);
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
while (cmd && Size) {
/* Get the length until the next command or end of input */
nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR));
cmd_len = nextcmd ? nextcmd - cmd : Size;
memset(&timer, 0, sizeof(timer));
timer.it_value.tv_sec = timeout / USEC_IN_SEC;
timer.it_value.tv_usec = timeout % USEC_IN_SEC;
if (cmd_len > 0) {
/* Interpret the first byte of the command as an opcode */
op = *cmd % (sizeof(ops) / sizeof((ops)[0]));
ops[op](s, cmd + 1, cmd_len - 1);
/* Run the main loop */
flush_events(s);
}
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;
if (cmd_len > 0) {
/* Interpret the first byte of the command as an opcode */
op = *cmd % (sizeof(ops) / sizeof((ops)[0]));
ops[op](s, cmd + 1, cmd_len - 1);
/* Run the main loop */
flush_events(s);
}
/* Advance to the next command */
cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd;
Size = Size - (cmd_len + sizeof(SEPARATOR) - 1);
g_array_set_size(dma_regions, 0);
}
_Exit(0);
} else {
flush_events(s);
wait(0);
/* Advance to the next command */
cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd;
Size = Size - (cmd_len + sizeof(SEPARATOR) - 1);
g_array_set_size(dma_regions, 0);
}
fuzz_reset(s);
}
static void usage(void)
@ -738,8 +685,6 @@ static void usage(void)
printf("Optionally: QEMU_AVOID_DOUBLE_FETCH= "
"Try to avoid racy DMA double fetch bugs? %d by default\n",
avoid_double_fetches);
printf("Optionally: QEMU_FUZZ_TIMEOUT= Specify a custom timeout (us). "
"0 to disable. %d by default\n", timeout);
exit(0);
}
@ -825,7 +770,6 @@ static void generic_pre_fuzz(QTestState *s)
{
GHashTableIter iter;
MemoryRegion *mr;
QPCIBus *pcibus;
char **result;
GString *name_pattern;
@ -838,9 +782,6 @@ static void generic_pre_fuzz(QTestState *s)
if (getenv("QEMU_AVOID_DOUBLE_FETCH")) {
avoid_double_fetches = 1;
}
if (getenv("QEMU_FUZZ_TIMEOUT")) {
timeout = g_ascii_strtoll(getenv("QEMU_FUZZ_TIMEOUT"), NULL, 0);
}
qts_global = s;
/*
@ -883,12 +824,6 @@ static void generic_pre_fuzz(QTestState *s)
printf("No fuzzable memory regions found...\n");
exit(1);
}
pcibus = qpci_new_pc(s, NULL);
g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus);
qpci_free_pc(pcibus);
counter_shm_init();
}
/*

View File

@ -18,7 +18,6 @@
#include "tests/qtest/libqos/pci-pc.h"
#include "fuzz.h"
#include "qos_fuzz.h"
#include "fork_fuzz.h"
#define I440FX_PCI_HOST_BRIDGE_CFG 0xcf8
@ -89,6 +88,7 @@ static void i440fx_fuzz_qtest(QTestState *s,
size_t Size)
{
ioport_fuzz_qtest(s, Data, Size);
fuzz_reset(s);
}
static void pciconfig_fuzz_qos(QTestState *s, QPCIBus *bus,
@ -145,17 +145,6 @@ static void i440fx_fuzz_qos(QTestState *s,
pciconfig_fuzz_qos(s, bus, Data, Size);
}
static void i440fx_fuzz_qos_fork(QTestState *s,
const unsigned char *Data, size_t Size) {
if (fork() == 0) {
i440fx_fuzz_qos(s, Data, Size);
_Exit(0);
} else {
flush_events(s);
wait(NULL);
}
}
static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest"
" -m 0 -display none";
static GString *i440fx_argv(FuzzTarget *t)
@ -163,10 +152,6 @@ static GString *i440fx_argv(FuzzTarget *t)
return g_string_new(i440fx_qtest_argv);
}
static void fork_init(void)
{
counter_shm_init();
}
static void register_pci_fuzz_targets(void)
{
@ -178,16 +163,6 @@ static void register_pci_fuzz_targets(void)
.get_init_cmdline = i440fx_argv,
.fuzz = i440fx_fuzz_qtest});
/* Uses libqos and forks to prevent state leakage */
fuzz_add_qos_target(&(FuzzTarget){
.name = "i440fx-qos-fork-fuzz",
.description = "Fuzz the i440fx using raw qtest commands and "
"rebooting after each run",
.pre_vm_init = &fork_init,
.fuzz = i440fx_fuzz_qos_fork,},
"i440FX-pcihost",
&(QOSGraphTestOptions){}
);
/*
* Uses libqos. Doesn't do anything to reset state. Note that if we were to

View File

@ -2,7 +2,7 @@ if not get_option('fuzzing')
subdir_done()
endif
specific_fuzz_ss.add(files('fuzz.c', 'fork_fuzz.c', 'qos_fuzz.c',
specific_fuzz_ss.add(files('fuzz.c', 'qos_fuzz.c',
'qtest_wrappers.c'), qos)
# Targets
@ -12,7 +12,7 @@ specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio_scsi_fuz
specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio_blk_fuzz.c'))
specific_fuzz_ss.add(files('generic_fuzz.c'))
fork_fuzz = declare_dependency(
fuzz_ld = declare_dependency(
link_args: fuzz_exe_ldflags +
['-Wl,-wrap,qtest_inb',
'-Wl,-wrap,qtest_inw',
@ -35,4 +35,4 @@ fork_fuzz = declare_dependency(
'-Wl,-wrap,qtest_memset']
)
specific_fuzz_ss.add(fork_fuzz)
specific_fuzz_ss.add(fuzz_ld)

View File

@ -19,7 +19,6 @@
#include "standard-headers/linux/virtio_pci.h"
#include "standard-headers/linux/virtio_blk.h"
#include "fuzz.h"
#include "fork_fuzz.h"
#include "qos_fuzz.h"
#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
@ -128,48 +127,24 @@ static void virtio_blk_fuzz(QTestState *s, QVirtioBlkQueues* queues,
}
}
static void virtio_blk_fork_fuzz(QTestState *s,
const unsigned char *Data, size_t Size)
{
QVirtioBlk *blk = fuzz_qos_obj;
static QVirtioBlkQueues *queues;
if (!queues) {
queues = qvirtio_blk_init(blk->vdev, 0);
}
if (fork() == 0) {
virtio_blk_fuzz(s, queues, Data, Size);
flush_events(s);
_Exit(0);
} else {
flush_events(s);
wait(NULL);
}
}
static void virtio_blk_with_flag_fuzz(QTestState *s,
const unsigned char *Data, size_t Size)
{
QVirtioBlk *blk = fuzz_qos_obj;
static QVirtioBlkQueues *queues;
if (fork() == 0) {
if (Size >= sizeof(uint64_t)) {
queues = qvirtio_blk_init(blk->vdev, *(uint64_t *)Data);
virtio_blk_fuzz(s, queues,
Data + sizeof(uint64_t), Size - sizeof(uint64_t));
flush_events(s);
}
_Exit(0);
} else {
if (Size >= sizeof(uint64_t)) {
queues = qvirtio_blk_init(blk->vdev, *(uint64_t *)Data);
virtio_blk_fuzz(s, queues,
Data + sizeof(uint64_t), Size - sizeof(uint64_t));
flush_events(s);
wait(NULL);
}
fuzz_reset(s);
}
static void virtio_blk_pre_fuzz(QTestState *s)
{
qos_init_path(s);
counter_shm_init();
}
static void drive_destroy(void *path)
@ -208,22 +183,10 @@ static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
static void register_virtio_blk_fuzz_targets(void)
{
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-blk-fuzz",
.description = "Fuzz the virtio-blk virtual queues, forking "
"for each fuzz run",
.pre_vm_init = &counter_shm_init,
.pre_fuzz = &virtio_blk_pre_fuzz,
.fuzz = virtio_blk_fork_fuzz,},
"virtio-blk",
&(QOSGraphTestOptions){.before = virtio_blk_test_setup}
);
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-blk-flags-fuzz",
.description = "Fuzz the virtio-blk virtual queues, forking "
"for each fuzz run (also fuzzes the virtio flags)",
.pre_vm_init = &counter_shm_init,
.description = "Fuzz the virtio-blk virtual queues. "
"Also fuzzes the virtio flags)",
.pre_fuzz = &virtio_blk_pre_fuzz,
.fuzz = virtio_blk_with_flag_fuzz,},
"virtio-blk",

View File

@ -16,7 +16,6 @@
#include "tests/qtest/libqtest.h"
#include "tests/qtest/libqos/virtio-net.h"
#include "fuzz.h"
#include "fork_fuzz.h"
#include "qos_fuzz.h"
@ -115,36 +114,18 @@ static void virtio_net_fuzz_multi(QTestState *s,
}
}
static void virtio_net_fork_fuzz(QTestState *s,
const unsigned char *Data, size_t Size)
{
if (fork() == 0) {
virtio_net_fuzz_multi(s, Data, Size, false);
flush_events(s);
_Exit(0);
} else {
flush_events(s);
wait(NULL);
}
}
static void virtio_net_fork_fuzz_check_used(QTestState *s,
static void virtio_net_fuzz_check_used(QTestState *s,
const unsigned char *Data, size_t Size)
{
if (fork() == 0) {
virtio_net_fuzz_multi(s, Data, Size, true);
flush_events(s);
_Exit(0);
} else {
flush_events(s);
wait(NULL);
}
virtio_net_fuzz_multi(s, Data, Size, true);
flush_events(s);
fuzz_reset(s);
}
static void virtio_net_pre_fuzz(QTestState *s)
{
qos_init_path(s);
counter_shm_init();
}
static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg)
@ -158,23 +139,8 @@ static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg)
return arg;
}
static void *virtio_net_test_setup_user(GString *cmd_line, void *arg)
{
g_string_append_printf(cmd_line, " -netdev user,id=hs0 ");
return arg;
}
static void register_virtio_net_fuzz_targets(void)
{
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-net-socket",
.description = "Fuzz the virtio-net virtual queues. Fuzz incoming "
"traffic using the socket backend",
.pre_fuzz = &virtio_net_pre_fuzz,
.fuzz = virtio_net_fork_fuzz,},
"virtio-net",
&(QOSGraphTestOptions){.before = virtio_net_test_setup_socket}
);
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-net-socket-check-used",
@ -182,20 +148,10 @@ static void register_virtio_net_fuzz_targets(void)
"descriptors to be used. Timeout may indicate improperly handled "
"input",
.pre_fuzz = &virtio_net_pre_fuzz,
.fuzz = virtio_net_fork_fuzz_check_used,},
.fuzz = virtio_net_fuzz_check_used,},
"virtio-net",
&(QOSGraphTestOptions){.before = virtio_net_test_setup_socket}
);
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-net-slirp",
.description = "Fuzz the virtio-net virtual queues with the slirp "
" backend. Warning: May result in network traffic emitted from the "
" process. Run in an isolated network environment.",
.pre_fuzz = &virtio_net_pre_fuzz,
.fuzz = virtio_net_fork_fuzz,},
"virtio-net",
&(QOSGraphTestOptions){.before = virtio_net_test_setup_user}
);
}
fuzz_target_init(register_virtio_net_fuzz_targets);

View File

@ -20,7 +20,6 @@
#include "standard-headers/linux/virtio_pci.h"
#include "standard-headers/linux/virtio_scsi.h"
#include "fuzz.h"
#include "fork_fuzz.h"
#include "qos_fuzz.h"
#define PCI_SLOT 0x02
@ -132,48 +131,24 @@ static void virtio_scsi_fuzz(QTestState *s, QVirtioSCSIQueues* queues,
}
}
static void virtio_scsi_fork_fuzz(QTestState *s,
const unsigned char *Data, size_t Size)
{
QVirtioSCSI *scsi = fuzz_qos_obj;
static QVirtioSCSIQueues *queues;
if (!queues) {
queues = qvirtio_scsi_init(scsi->vdev, 0);
}
if (fork() == 0) {
virtio_scsi_fuzz(s, queues, Data, Size);
flush_events(s);
_Exit(0);
} else {
flush_events(s);
wait(NULL);
}
}
static void virtio_scsi_with_flag_fuzz(QTestState *s,
const unsigned char *Data, size_t Size)
{
QVirtioSCSI *scsi = fuzz_qos_obj;
static QVirtioSCSIQueues *queues;
if (fork() == 0) {
if (Size >= sizeof(uint64_t)) {
queues = qvirtio_scsi_init(scsi->vdev, *(uint64_t *)Data);
virtio_scsi_fuzz(s, queues,
Data + sizeof(uint64_t), Size - sizeof(uint64_t));
flush_events(s);
}
_Exit(0);
} else {
if (Size >= sizeof(uint64_t)) {
queues = qvirtio_scsi_init(scsi->vdev, *(uint64_t *)Data);
virtio_scsi_fuzz(s, queues,
Data + sizeof(uint64_t), Size - sizeof(uint64_t));
flush_events(s);
wait(NULL);
}
fuzz_reset(s);
}
static void virtio_scsi_pre_fuzz(QTestState *s)
{
qos_init_path(s);
counter_shm_init();
}
static void *virtio_scsi_test_setup(GString *cmd_line, void *arg)
@ -189,22 +164,10 @@ static void *virtio_scsi_test_setup(GString *cmd_line, void *arg)
static void register_virtio_scsi_fuzz_targets(void)
{
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-scsi-fuzz",
.description = "Fuzz the virtio-scsi virtual queues, forking "
"for each fuzz run",
.pre_vm_init = &counter_shm_init,
.pre_fuzz = &virtio_scsi_pre_fuzz,
.fuzz = virtio_scsi_fork_fuzz,},
"virtio-scsi",
&(QOSGraphTestOptions){.before = virtio_scsi_test_setup}
);
fuzz_add_qos_target(&(FuzzTarget){
.name = "virtio-scsi-flags-fuzz",
.description = "Fuzz the virtio-scsi virtual queues, forking "
"for each fuzz run (also fuzzes the virtio flags)",
.pre_vm_init = &counter_shm_init,
.description = "Fuzz the virtio-scsi virtual queues. "
"Also fuzzes the virtio flags",
.pre_fuzz = &virtio_scsi_pre_fuzz,
.fuzz = virtio_scsi_with_flag_fuzz,},
"virtio-scsi",