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 21/22] fuzz: add virtio-scsi fuzz target
Date: Thu, 20 Feb 2020 10:38:54 +0000	[thread overview]
Message-ID: <20200220103854.rfhudwoovajac5w5@starbug-mbp> (raw)
In-Reply-To: <20200220041118.23264-22-alxndr@bu.edu>

On Wed, Feb 19, 2020 at 11:11:17PM -0500, Alexander Bulekov wrote:
>The virtio-scsi fuzz target sets up and fuzzes the available virtio-scsi
>queues. After an element is placed on a queue, the fuzzer can select
>whether to perform a kick, or continue adding elements.
>
>Signed-off-by: Alexander Bulekov <alxndr@bu.edu>

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

>---
> tests/qtest/fuzz/Makefile.include   |   1 +
> tests/qtest/fuzz/virtio_scsi_fuzz.c | 213 ++++++++++++++++++++++++++++
> 2 files changed, 214 insertions(+)
> create mode 100644 tests/qtest/fuzz/virtio_scsi_fuzz.c
>
>diff --git a/tests/qtest/fuzz/Makefile.include b/tests/qtest/fuzz/Makefile.include
>index 77385777ef..cde3e9636c 100644
>--- a/tests/qtest/fuzz/Makefile.include
>+++ b/tests/qtest/fuzz/Makefile.include
>@@ -9,6 +9,7 @@ fuzz-obj-y += tests/qtest/fuzz/qos_fuzz.o
> # Targets
> fuzz-obj-y += tests/qtest/fuzz/i440fx_fuzz.o
> fuzz-obj-y += tests/qtest/fuzz/virtio_net_fuzz.o
>+fuzz-obj-y += tests/qtest/fuzz/virtio_scsi_fuzz.o
>
> FUZZ_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest
>
>diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c
>new file mode 100644
>index 0000000000..3b95247f12
>--- /dev/null
>+++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c
>@@ -0,0 +1,213 @@
>+/*
>+ * virtio-serial Fuzzing Target
>+ *
>+ * 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 "tests/qtest/libqtest.h"
>+#include "libqos/virtio-scsi.h"
>+#include "libqos/virtio.h"
>+#include "libqos/virtio-pci.h"
>+#include "standard-headers/linux/virtio_ids.h"
>+#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
>+#define PCI_FN                  0x00
>+#define QVIRTIO_SCSI_TIMEOUT_US (1 * 1000 * 1000)
>+
>+#define MAX_NUM_QUEUES 64
>+
>+/* Based on tests/virtio-scsi-test.c */
>+typedef struct {
>+    int num_queues;
>+    QVirtQueue *vq[MAX_NUM_QUEUES + 2];
>+} QVirtioSCSIQueues;
>+
>+static QVirtioSCSIQueues *qvirtio_scsi_init(QVirtioDevice *dev, uint64_t mask)
>+{
>+    QVirtioSCSIQueues *vs;
>+    uint64_t feat;
>+    int i;
>+
>+    vs = g_new0(QVirtioSCSIQueues, 1);
>+
>+    feat = qvirtio_get_features(dev);
>+    if (mask) {
>+        feat &= ~QVIRTIO_F_BAD_FEATURE | mask;
>+    } else {
>+        feat &= ~(QVIRTIO_F_BAD_FEATURE | (1ull << VIRTIO_RING_F_EVENT_IDX));
>+    }
>+    qvirtio_set_features(dev, feat);
>+
>+    vs->num_queues = qvirtio_config_readl(dev, 0);
>+
>+    for (i = 0; i < vs->num_queues + 2; i++) {
>+        vs->vq[i] = qvirtqueue_setup(dev, fuzz_qos_alloc, i);
>+    }
>+
>+    qvirtio_set_driver_ok(dev);
>+
>+    return vs;
>+}
>+
>+static void virtio_scsi_fuzz(QTestState *s, QVirtioSCSIQueues* queues,
>+        const unsigned char *Data, size_t Size)
>+{
>+    /*
>+     * Data is a sequence of random bytes. We split them up into "actions",
>+     * followed by data:
>+     * [vqa][dddddddd][vqa][dddd][vqa][dddddddddddd] ...
>+     * The length of the data is specified by the preceding vqa.length
>+     */
>+    typedef struct vq_action {
>+        uint8_t queue;
>+        uint8_t length;
>+        uint8_t write;
>+        uint8_t next;
>+        uint8_t kick;
>+    } vq_action;
>+
>+    /* Keep track of the free head for each queue we interact with */
>+    bool vq_touched[MAX_NUM_QUEUES + 2] = {0};
>+    uint32_t free_head[MAX_NUM_QUEUES + 2];
>+
>+    QGuestAllocator *t_alloc = fuzz_qos_alloc;
>+
>+    QVirtioSCSI *scsi = fuzz_qos_obj;
>+    QVirtioDevice *dev = scsi->vdev;
>+    QVirtQueue *q;
>+    vq_action vqa;
>+    while (Size >= sizeof(vqa)) {
>+        /* Copy the action, so we can normalize length, queue and flags */
>+        memcpy(&vqa, Data, sizeof(vqa));
>+
>+        Data += sizeof(vqa);
>+        Size -= sizeof(vqa);
>+
>+        vqa.queue = vqa.queue % queues->num_queues;
>+        /* Cap length at the number of remaining bytes in data */
>+        vqa.length = vqa.length >= Size ? Size : vqa.length;
>+        vqa.write = vqa.write & 1;
>+        vqa.next = vqa.next & 1;
>+        vqa.kick = vqa.kick & 1;
>+
>+
>+        q = queues->vq[vqa.queue];
>+
>+        /* Copy the data into ram, and place it on the virtqueue */
>+        uint64_t req_addr = guest_alloc(t_alloc, vqa.length);
>+        qtest_memwrite(s, req_addr, Data, vqa.length);
>+        if (vq_touched[vqa.queue] == 0) {
>+            vq_touched[vqa.queue] = 1;
>+            free_head[vqa.queue] = qvirtqueue_add(s, q, req_addr, vqa.length,
>+                    vqa.write, vqa.next);
>+        } else {
>+            qvirtqueue_add(s, q, req_addr, vqa.length, vqa.write , vqa.next);
>+        }
>+
>+        if (vqa.kick) {
>+            qvirtqueue_kick(s, dev, q, free_head[vqa.queue]);
>+            free_head[vqa.queue] = 0;
>+        }
>+        Data += vqa.length;
>+        Size -= vqa.length;
>+    }
>+    /* In the end, kick each queue we interacted with */
>+    for (int i = 0; i < MAX_NUM_QUEUES + 2; i++) {
>+        if (vq_touched[i]) {
>+            qvirtqueue_kick(s, dev, queues->vq[i], free_head[i]);
>+        }
>+    }
>+}
>+
>+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 {
>+        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 {
>+        wait(NULL);
>+    }
>+}
>+
>+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)
>+{
>+    g_string_append(cmd_line,
>+                    " -drive file=blkdebug::null-co://,"
>+                    "file.image.read-zeroes=on,"
>+                    "if=none,id=dr1,format=raw,file.align=4k "
>+                    "-device scsi-hd,drive=dr1,lun=0,scsi-id=1");
>+    return 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,
>+                .pre_fuzz = &virtio_scsi_pre_fuzz,
>+                .fuzz = virtio_scsi_with_flag_fuzz,},
>+                "virtio-scsi",
>+                &(QOSGraphTestOptions){.before = virtio_scsi_test_setup}
>+                );
>+}
>+
>+fuzz_target_init(register_virtio_scsi_fuzz_targets);
>-- 
>2.25.0
>


  reply	other threads:[~2020-02-20 10:40 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
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 [this message]
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=20200220103854.rfhudwoovajac5w5@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).