All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexander Bulekov <alxndr@bu.edu>
To: qemu-devel@nongnu.org
Cc: Laurent Vivier <lvivier@redhat.com>,
	Thomas Huth <thuth@redhat.com>, Alexander Bulekov <alxndr@bu.edu>,
	f4bug@amsat.org, darren.kenny@oracle.com, bsd@redhat.com,
	stefanha@redhat.com, Paolo Bonzini <pbonzini@redhat.com>
Subject: [RFC PATCH 2/3] fuzz: add support for fuzzing DMA regions
Date: Thu, 11 Jun 2020 01:56:50 -0400	[thread overview]
Message-ID: <20200611055651.13784-3-alxndr@bu.edu> (raw)
In-Reply-To: <20200611055651.13784-1-alxndr@bu.edu>

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/qtest/fuzz/general_fuzz.c | 102 ++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/tests/qtest/fuzz/general_fuzz.c b/tests/qtest/fuzz/general_fuzz.c
index 5c29306bb6..9e981e870f 100644
--- a/tests/qtest/fuzz/general_fuzz.c
+++ b/tests/qtest/fuzz/general_fuzz.c
@@ -32,6 +32,7 @@
  * input
  */
 #define CMD_SEP "\x84\x05\x5C\x5E"
+#define MAX_DMA_FILL_SIZE 0x10000
 
 typedef struct {
     size_t addr;
@@ -57,6 +58,18 @@ typedef struct {
  */
 char **region_whitelist;
 
+/*
+ * List of dma regions populated since the last fuzzing command. Used to ensure
+ * that we only write to each DMA address once, to avoid race conditions when
+ * building reproducers.
+ */
+static GArray *dma_regions;
+
+static GArray *dma_patterns;
+int dma_pattern_index;
+
+void dma_read_cb(size_t addr, size_t len);
+
 /*
  * Allocate a block of memory and populate it with a pattern.
  */
@@ -76,6 +89,62 @@ static void *pattern_alloc(pattern p, size_t len)
     return buf;
 }
 
+/*
+ * Call-back for functions that perform DMA reads from guest memory. Confirm
+ * that the region has not already been populated since the last loop in
+ * general_fuzz(), avoiding potential race-conditions, which we don't have
+ * a good way for reproducing right now.
+ */
+void dma_read_cb(size_t addr, size_t len)
+{
+    int i;
+
+    /* Return immediately if we have no data to fill the dma region */
+    if (dma_patterns->len == 0) {
+        return;
+    }
+
+    /* Return immediately if the address is greater than the RAM size */
+    if (addr > current_machine->ram_size) {
+        return;
+    }
+
+    /* Cap the length of the DMA access to something reasonable */
+    len = MIN(len, MAX_DMA_FILL_SIZE);
+
+    /*
+     * If we overlap with any existing dma_regions, split the range and only
+     * populate the non-overlapping parts.
+     */
+    for (i = 0; i < dma_regions->len; ++i) {
+        address_range *region = &g_array_index(dma_regions, address_range, i);
+        if (addr < region->addr + region->len && addr + len > region->addr) {
+            if (addr < region->addr) {
+                dma_read_cb(addr, region->addr - addr);
+            }
+            if (addr + len > region->addr + region->len) {
+                dma_read_cb(region->addr + region->len,
+                        addr + len - (region->addr + region->len));
+            }
+            return;
+        }
+    }
+
+    /*
+     * Otherwise, populate the region using address_space_write_rom to avoid
+     * writing to any IO MemoryRegions
+     */
+    address_range ar = {addr, len};
+    g_array_append_val(dma_regions, ar);
+    void *buf = pattern_alloc(g_array_index(dma_patterns, pattern,
+                              dma_pattern_index), ar.len);
+    address_space_write_rom(first_cpu->as, ar.addr, MEMTXATTRS_UNSPECIFIED,
+                            buf, ar.len);
+    free(buf);
+
+    /* Increment the index of the pattern for the next DMA access */
+    dma_pattern_index = (dma_pattern_index + 1) % dma_patterns->len;
+}
 
 /*
  * Here we want to convert a fuzzer-provided [io-region-index, offset] to
@@ -269,6 +338,32 @@ static void op_write(QTestState *s, const unsigned char * data, size_t len)
     }
 }
 
+static void op_add_dma_pattern(QTestState *s,
+                               const unsigned char *data, size_t len)
+{
+    struct {
+        /*
+         * index and stride can be used to increment the index-th byte of the
+         * pattern by the value stride, for each loop of the pattern.
+         */
+        uint8_t index;
+        uint8_t stride;
+    } a;
+
+    if (len < sizeof(a) + 1) {
+        return;
+    }
+    memcpy(&a, data, sizeof(a));
+    pattern p = {a.index, a.stride, len - sizeof(a), data + sizeof(a)};
+    g_array_append_val(dma_patterns, p);
+    return;
+}
+
+static void op_clear_dma_patterns(QTestState *s,
+                                  const unsigned char *data, size_t len)
+{
+    g_array_set_size(dma_patterns, 0);
+}
 
 static void op_write_pattern(QTestState *s, const unsigned char * data,
                              size_t len)
@@ -341,6 +436,8 @@ static void general_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
         op_out,
         op_read,
         op_write,
+        op_add_dma_pattern,
+        op_clear_dma_patterns,
         op_write_pattern,
         op_clock_step
     };
@@ -348,9 +445,12 @@ static void general_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
     const unsigned char *nextcmd;
     size_t cmd_len;
     uint8_t op;
+    g_array_set_size(dma_patterns, 0);
+    dma_pattern_index = 0;
 
     if (fork() == 0) {
         while (cmd && Size) {
+            g_array_set_size(dma_regions, 0);
             /* Get the length until the next command or end of input */
             nextcmd = memmem(cmd, Size, CMD_SEP, strlen(CMD_SEP));
             cmd_len = nextcmd ? nextcmd - cmd : Size;
@@ -418,6 +518,8 @@ static void general_pre_qos_fuzz(QTestState *s)
     }
     counter_shm_init();
 
+    dma_regions = g_array_new(false, false, sizeof(address_range));
+    dma_patterns = g_array_new(false, false, sizeof(pattern));
 
     qos_init_path(s);
 
-- 
2.26.2



  parent reply	other threads:[~2020-06-11  5:59 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-11  5:56 [RFC PATCH 0/3] fuzz: add generic fuzzer Alexander Bulekov
2020-06-11  5:56 ` [RFC PATCH 1/3] fuzz: add a general fuzzer for any qemu arguments Alexander Bulekov
2020-06-11  5:56 ` Alexander Bulekov [this message]
2020-06-11  5:56 ` [RFC PATCH 3/3] fuzz: Add callbacks for dma-access functions Alexander Bulekov
2020-06-23 14:14   ` Stefan Hajnoczi
2020-06-23 14:55     ` Alexander Bulekov
2020-06-26 15:44       ` Stefan Hajnoczi
2020-07-09 23:48     ` Alexander Bulekov
2020-07-13 11:41       ` Stefan Hajnoczi
2020-07-13 11:52         ` Alexander Bulekov
2020-06-24  9:46   ` Philippe Mathieu-Daudé
2020-06-11  6:55 ` [RFC PATCH 0/3] fuzz: add generic fuzzer no-reply
2020-06-23 14:16 ` Stefan Hajnoczi
2020-06-25 15:30   ` Dima Stepanov

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=20200611055651.13784-3-alxndr@bu.edu \
    --to=alxndr@bu.edu \
    --cc=bsd@redhat.com \
    --cc=darren.kenny@oracle.com \
    --cc=f4bug@amsat.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.