qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Darren Kenny <darren.kenny@oracle.com>
To: Alexander Bulekov <alxndr@bu.edu>
Cc: Laurent Vivier <lvivier@redhat.com>,
	Thomas Huth <thuth@redhat.com>,
	qemu-devel@nongnu.org, bsd@redhat.com, stefanha@redhat.com,
	pbonzini@redhat.com
Subject: Re: [PATCH v10 16/22] fuzz: add support for qos-assisted fuzz targets
Date: Thu, 20 Feb 2020 10:35:10 +0000	[thread overview]
Message-ID: <20200220103510.cidqn4qqovpaycvl@starbug-mbp> (raw)
In-Reply-To: <20200220041118.23264-17-alxndr@bu.edu>

On Wed, Feb 19, 2020 at 11:11:12PM -0500, Alexander Bulekov wrote:
>Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
>Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

Reviewed-by: Darren Kenny <darren.kenny@oracle.com>

>---
> tests/qtest/fuzz/Makefile.include |   2 +
> tests/qtest/fuzz/qos_fuzz.c       | 234 ++++++++++++++++++++++++++++++
> tests/qtest/fuzz/qos_fuzz.h       |  33 +++++
> 3 files changed, 269 insertions(+)
> create mode 100644 tests/qtest/fuzz/qos_fuzz.c
> create mode 100644 tests/qtest/fuzz/qos_fuzz.h
>
>diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include
>index a90915d56d..e3bdd33ff4 100644
>--- a/tests/qtest/fuzz/Makefile.include
>+++ b/tests/qtest/fuzz/Makefile.include
>@@ -1,8 +1,10 @@
> QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF)
>
> fuzz-obj-y += tests/qtest/libqtest.o
>+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_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest
>
>diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c
>new file mode 100644
>index 0000000000..bbb17470ff
>--- /dev/null
>+++ b/tests/qtest/fuzz/qos_fuzz.c
>@@ -0,0 +1,234 @@
>+/*
>+ * QOS-assisted fuzzing helpers
>+ *
>+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
>+ *
>+ * This library is free software; you can redistribute it and/or
>+ * modify it under the terms of the GNU Lesser General Public
>+ * License version 2 as published by the Free Software Foundation.
>+ *
>+ * This library is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>+ * Lesser General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
>+ */
>+
>+#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 "tests/qtest/libqtest.h"
>+#include "tests/qtest/libqos/malloc.h"
>+#include "tests/qtest/libqos/qgraph.h"
>+#include "tests/qtest/libqos/qgraph_internal.h"
>+#include "tests/qtest/libqos/qos_external.h"
>+
>+#include "fuzz.h"
>+#include "qos_fuzz.h"
>+
>+#include "qapi/qapi-commands-machine.h"
>+#include "qapi/qapi-commands-qom.h"
>+#include "qapi/qmp/qlist.h"
>+
>+
>+void *fuzz_qos_obj;
>+QGuestAllocator *fuzz_qos_alloc;
>+
>+static const char *fuzz_target_name;
>+static char **fuzz_path_vec;
>+
>+/*
>+ * Replaced the qmp commands with direct qmp_marshal calls.
>+ * Probably there is a better way to do this
>+ */
>+static 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);
>+}
>+
>+static const char *qos_build_main_args(void)
>+{
>+    char **path = fuzz_path_vec;
>+    QOSGraphNode *test_node;
>+    GString *cmd_line = g_string_new(path[0]);
>+    void *test_arg;
>+
>+    if (!path) {
>+        fprintf(stderr, "QOS Path not found\n");
>+        abort();
>+    }
>+
>+    /* 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,
>+            TARGET_NAME " -display none -machine accel=qtest -m 64 ");
>+    return cmd_line->str;
>+}
>+
>+/*
>+ * This function is largely a copy of qos-test.c:walk_path. Since walk_path
>+ * is itself a callback, its a little annoying to add another argument/layer of
>+ * indirection
>+ */
>+static 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) == 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);
>+
>+        fuzz_path_vec = path_vec;
>+    } else {
>+        g_free(path_vec);
>+    }
>+
>+    g_free(path_str);
>+}
>+
>+static const char *qos_get_cmdline(FuzzTarget *t)
>+{
>+    /*
>+     * Set a global variable that we use to identify the qos_path for our
>+     * fuzz_target
>+     */
>+    fuzz_target_name = t->name;
>+    qos_set_machines_devices_available();
>+    qos_graph_foreach_test_path(walk_path);
>+    return qos_build_main_args();
>+}
>+
>+void fuzz_add_qos_target(
>+        FuzzTarget *fuzz_opts,
>+        const char *interface,
>+        QOSGraphTestOptions *opts
>+        )
>+{
>+    qos_add_test(fuzz_opts->name, interface, NULL, opts);
>+    fuzz_opts->get_init_cmdline = qos_get_cmdline;
>+    fuzz_add_target(fuzz_opts);
>+}
>+
>+void qos_init_path(QTestState *s)
>+{
>+    fuzz_qos_obj = qos_allocate_objects(s , &fuzz_qos_alloc);
>+}
>diff --git a/tests/qtest/fuzz/qos_fuzz.h b/tests/qtest/fuzz/qos_fuzz.h
>new file mode 100644
>index 0000000000..477f11b02b
>--- /dev/null
>+++ b/tests/qtest/fuzz/qos_fuzz.h
>@@ -0,0 +1,33 @@
>+/*
>+ * QOS-assisted 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 _QOS_FUZZ_H_
>+#define _QOS_FUZZ_H_
>+
>+#include "tests/qtest/fuzz/fuzz.h"
>+#include "tests/qtest/libqos/qgraph.h"
>+
>+int qos_fuzz(const unsigned char *Data, size_t Size);
>+void qos_setup(void);
>+
>+extern void *fuzz_qos_obj;
>+extern QGuestAllocator *fuzz_qos_alloc;
>+
>+void fuzz_add_qos_target(
>+        FuzzTarget *fuzz_opts,
>+        const char *interface,
>+        QOSGraphTestOptions *opts
>+        );
>+
>+void qos_init_path(QTestState *);
>+
>+#endif
>-- 
>2.25.0
>


  reply	other threads:[~2020-02-20 10:36 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-20  4:10 [PATCH v10 00/22] Add virtual device fuzzing support Alexander Bulekov
2020-02-20  4:10 ` [PATCH v10 01/22] softmmu: move vl.c to softmmu/ Alexander Bulekov
2020-02-20 10:33   ` Darren Kenny
2020-02-21 13:56   ` Stefan Hajnoczi
2020-02-20  4:10 ` [PATCH v10 02/22] softmmu: split off vl.c:main() into main.c Alexander Bulekov
2020-02-20  4:10 ` [PATCH v10 03/22] module: check module wasn't already initialized Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 04/22] fuzz: add FUZZ_TARGET module type Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 05/22] qtest: add qtest_server_send abstraction Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 06/22] libqtest: add a layer of abstraction to send/recv Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 07/22] libqtest: make bufwrite rely on the TransportOps Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 08/22] qtest: add in-process incoming command handler Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 09/22] libqos: rename i2c_send and i2c_recv Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 10/22] libqos: split qos-test and libqos makefile vars Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 11/22] libqos: move useful qos-test funcs to qos_external Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 12/22] fuzz: add fuzzer skeleton Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 13/22] exec: keep ram block across fork when using qtest Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 14/22] main: keep rcu_atfork callback enabled for qtest Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 15/22] fuzz: support for fork-based fuzzing Alexander Bulekov
2020-02-20 10:34   ` Darren Kenny
2020-02-20  4:11 ` [PATCH v10 16/22] fuzz: add support for qos-assisted fuzz targets Alexander Bulekov
2020-02-20 10:35   ` Darren Kenny [this message]
2020-02-20  4:11 ` [PATCH v10 17/22] fuzz: add target/fuzz makefile rules Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 18/22] fuzz: add configure flag --enable-fuzzing Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 19/22] fuzz: add i440fx fuzz targets Alexander Bulekov
2020-02-20  4:11 ` [PATCH v10 20/22] fuzz: add virtio-net fuzz target Alexander Bulekov
2020-02-20 10:35   ` Darren Kenny
2020-02-20  4:11 ` [PATCH v10 21/22] fuzz: add virtio-scsi " Alexander Bulekov
2020-02-20 10:38   ` Darren Kenny
2020-02-21 13:57   ` Stefan Hajnoczi
2020-02-20  4:11 ` [PATCH v10 22/22] fuzz: add documentation to docs/devel/ Alexander Bulekov
2020-02-21 15:17 ` [PATCH v10 00/22] Add virtual device fuzzing support Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200220103510.cidqn4qqovpaycvl@starbug-mbp \
    --to=darren.kenny@oracle.com \
    --cc=alxndr@bu.edu \
    --cc=bsd@redhat.com \
    --cc=lvivier@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).