Signed-off-by: Alexander Oleinik <alx...@bu.edu> --- tests/fuzz/qos_fuzz.c | 58 ++++++++++++ tests/fuzz/qos_fuzz.h | 23 +++++ tests/fuzz/qos_helpers.c | 190 +++++++++++++++++++++++++++++++++++++++ tests/fuzz/qos_helpers.h | 17 ++++ 4 files changed, 288 insertions(+) create mode 100644 tests/fuzz/qos_fuzz.c create mode 100644 tests/fuzz/qos_fuzz.h create mode 100644 tests/fuzz/qos_helpers.c create mode 100644 tests/fuzz/qos_helpers.h
diff --git a/tests/fuzz/qos_fuzz.c b/tests/fuzz/qos_fuzz.c new file mode 100644 index 0000000000..80a22793d6 --- /dev/null +++ b/tests/fuzz/qos_fuzz.c @@ -0,0 +1,58 @@ + + +#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 "libqos/malloc.h" +#include "libqos/qgraph.h" +#include "libqos/qgraph_internal.h" + +#include "hw/virtio/virtio-net.h" +#include "hw/virtio/virtio.h" +#include "libqos/virtio-net.h" +#include "fuzz.h" +#include "qos_fuzz.h" +#include "qos_helpers.h" +#include "tests/libqos/qgraph.h" +#include "tests/libqtest.h" + + +fuzz_memory_region *fuzz_memory_region_head; +fuzz_memory_region *fuzz_memory_region_tail; + +uint64_t total_io_mem; +uint64_t total_ram_mem; + + +void fuzz_add_qos_target(const char *name, + const char *description, + const char *interface, + QOSGraphTestOptions *opts, + FuzzTarget *fuzz_opts + ) +{ + qos_add_test(name, interface, NULL, opts); + fuzz_opts->main_argc = &qos_argc; + fuzz_opts->main_argv = &qos_argv; + fuzz_add_target(name, description, fuzz_opts); +} + + +/* Do what is normally done in qos_test.c:main */ +void qos_setup(void){ + qtest_setup(); + qos_set_machines_devices_available(); + qos_graph_foreach_test_path(walk_path); + qos_build_main_args(); +} + +void qos_init_path(void) +{ + qos_obj = qos_allocate_objects(global_qtest, &qos_alloc); +} diff --git a/tests/fuzz/qos_fuzz.h b/tests/fuzz/qos_fuzz.h new file mode 100644 index 0000000000..68d0684a7c --- /dev/null +++ b/tests/fuzz/qos_fuzz.h @@ -0,0 +1,23 @@ +#ifndef _QOS_FUZZ_H_ +#define _QOS_FUZZ_H_ + +#include "tests/libqos/qgraph.h" + +int qos_fuzz(const unsigned char *Data, size_t Size); +void qos_setup(void); + +extern char **fuzz_path_vec; +extern int qos_argc; +extern char **qos_argv; +extern void *qos_obj; +extern QGuestAllocator *qos_alloc; + + +void fuzz_add_qos_target(const char *name, + const char *description, + const char *interface, + QOSGraphTestOptions *opts, + FuzzTarget *fuzz_opts); + +void qos_init_path(void); +#endif diff --git a/tests/fuzz/qos_helpers.c b/tests/fuzz/qos_helpers.c new file mode 100644 index 0000000000..c65f32e78b --- /dev/null +++ b/tests/fuzz/qos_helpers.c @@ -0,0 +1,190 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qos_helpers.h" +#include "fuzz.h" +#include "qapi/qmp/qlist.h" +#include "libqtest.h" +#include "sysemu/qtest.h" +#include "libqos/qgraph.h" +#include "libqos/qgraph_internal.h" +#include "libqos/qos_external.h" +#include "qapi/qapi-commands-machine.h" +#include "qapi/qapi-commands-misc.h" +#include "qapi/qapi-commands-qom.h" +#include <wordexp.h> +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" + + + +/* + * Replaced the qmp commands with direct qmp_marshal calls. + * Probably there is a better way to do this + */ +void qos_set_machines_devices_available(void) +{ + QDict *req = qdict_new(); + QObject *response; + QDict *args = qdict_new(); + QList *lst; + Error *err = NULL; + + qmp_marshal_query_machines(NULL, &response, &err); + assert(!err); + lst = qobject_to(QList, response); + apply_to_qlist(lst, true); + + qobject_unref(response); + + + qdict_put_str(req, "execute", "qom-list-types"); + qdict_put_str(args, "implements", "device"); + qdict_put_bool(args, "abstract", true); + qdict_put_obj(req, "arguments", (QObject *) args); + + qmp_marshal_qom_list_types(args, &response, &err); + assert(!err); + lst = qobject_to(QList, response); + apply_to_qlist(lst, false); + qobject_unref(response); + qobject_unref(req); +} + +static char **current_path; + + +void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc) +{ + return allocate_objects(qts, current_path + 1, p_alloc); +} + + +char **fuzz_path_vec; +void *qos_obj; +QGuestAllocator *qos_alloc; + +int qos_argc; +char **qos_argv; + +void qos_build_main_args() +{ + char **path = fuzz_path_vec; + QOSGraphNode *test_node; + GString *cmd_line = g_string_new(path[0]); + void *test_arg; + + /* Before test */ + current_path = path; + test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]); + test_arg = test_node->u.test.arg; + if (test_node->u.test.before) { + test_arg = test_node->u.test.before(cmd_line, test_arg); + } + + /* Prepend the arguments that we need */ + g_string_prepend(cmd_line, + "qemu-system-i386 -display none -machine accel=fuzz -m 16 "); + wordexp_t result; + wordexp(cmd_line->str, &result, 0); + qos_argc = result.we_wordc; + qos_argv = result.we_wordv; + + g_string_free(cmd_line, true); +} + +/* + * This function is largely a copy of qos-test.c: + * TODO: Possibly add a callback argument to walk_path to use one function + * for both fuzzing and normal testing + */ +void walk_path(QOSGraphNode *orig_path, int len) +{ + QOSGraphNode *path; + QOSGraphEdge *edge; + + /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */ + QOSEdgeType etype = QEDGE_CONSUMED_BY; + + /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */ + char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2)); + int path_vec_size = 0; + + char *after_cmd, *before_cmd, *after_device; + GString *after_device_str = g_string_new(""); + char *node_name = orig_path->name, *path_str; + + GString *cmd_line = g_string_new(""); + GString *cmd_line2 = g_string_new(""); + + path = qos_graph_get_node(node_name); /* root */ + node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */ + + path_vec[path_vec_size++] = node_name; + path_vec[path_vec_size++] = qos_get_machine_type(node_name); + + for (;;) { + path = qos_graph_get_node(node_name); + if (!path->path_edge) { + break; + } + + node_name = qos_graph_edge_get_dest(path->path_edge); + + /* append node command line + previous edge command line */ + if (path->command_line && etype == QEDGE_CONSUMED_BY) { + g_string_append(cmd_line, path->command_line); + g_string_append(cmd_line, after_device_str->str); + g_string_truncate(after_device_str, 0); + } + + path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge); + /* detect if edge has command line args */ + after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge); + after_device = qos_graph_edge_get_extra_device_opts(path->path_edge); + before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge); + edge = qos_graph_get_edge(path->name, node_name); + etype = qos_graph_edge_get_type(edge); + + if (before_cmd) { + g_string_append(cmd_line, before_cmd); + } + if (after_cmd) { + g_string_append(cmd_line2, after_cmd); + } + if (after_device) { + g_string_append(after_device_str, after_device); + } + } + + path_vec[path_vec_size++] = NULL; + g_string_append(cmd_line, after_device_str->str); + g_string_free(after_device_str, true); + + g_string_append(cmd_line, cmd_line2->str); + g_string_free(cmd_line2, true); + + /* + * here position 0 has <arch>/<machine>, position 1 has <machine>. + * The path must not have the <arch>, qtest_add_data_func adds it. + */ + path_str = g_strjoinv("/", path_vec + 1); + + /* Check that this is the test we care about: */ + char *test_name = strrchr(path_str, '/') + 1; + if (strcmp(test_name, fuzz_target->name->str) == 0) { + /* + * put arch/machine in position 1 so run_one_test can do its work + * and add the command line at position 0. + */ + path_vec[1] = path_vec[0]; + path_vec[0] = g_string_free(cmd_line, false); + printf("path_str: %s path_vec[0]: %s [1]: %s\n", path_str, path_vec[0], + path_vec[1]); + + fuzz_path_vec = path_vec; + } else { + g_free(path_vec); + } + + g_free(path_str); +} diff --git a/tests/fuzz/qos_helpers.h b/tests/fuzz/qos_helpers.h new file mode 100644 index 0000000000..baf9b49e9c --- /dev/null +++ b/tests/fuzz/qos_helpers.h @@ -0,0 +1,17 @@ +#ifndef QOS_HELPERS_H +#define QOS_HELPERS_H + +#include "qemu/osdep.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qstring.h" +#include "libqtest.h" +#include "qapi/qmp/qlist.h" +#include "libqos/qgraph_internal.h" + + +void qos_set_machines_devices_available(void); +void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc); +void walk_path(QOSGraphNode *orig_path, int len); +void qos_build_main_args(void); +#endif -- 2.20.1