All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/21] Add virtual device fuzzing support
@ 2019-11-29 21:34 Oleinik, Alexander
  2019-11-29 21:34 ` [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c Oleinik, Alexander
                   ` (22 more replies)
  0 siblings, 23 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

This series adds a framework for coverage-guided fuzzing of
virtual-devices. Fuzzing targets are based on qtest and can make use of
the libqos abstractions.

In this version, I added a virtio-scsi fuzzer. The actual fuzzing code
is very similar to the the virtio-net fuzzer. I experimented with using
a single fuzzer with device-specific initialization for each virtio
device, but it did not come out as cleanly as I hoped, since I could not
find an easy way to override the qos drivers for devices that have
more-complete qos support (such as virtio-net), so these changes have
not made it into v6.

V5/V6: (V5 did not have review tags)
 * added virtio-scsi fuzzer
 * add support for using fork-based fuzzers with multiple libfuzzer
   workers
 * misc fixes addressing V4 comments
 * cleanup in-process handlers/globals in libqtest.c
 * small fixes to fork-based fuzzing and support for multiple workers
 * changes to the virtio-net fuzzer to kick after each vq add

V4:
 * add/transfer license headers to new files
 * restructure the added QTestClientTransportOps struct
 * restructure the FuzzTarget struct and fuzzer skeleton
 * fork-based fuzzer now directly mmaps shm over the coverage bitmaps
 * fixes to i440 and virtio-net fuzz targets
 * undo the changes to qtest_memwrite
 * possible to build /fuzz and /all in the same build-dir
 * misc fixes to address V3 comments

V3:
 * rebased onto v4.1.0+
 * add the fuzzer as a new build-target type in the build-system
 * add indirection to qtest client/server communication functions
 * remove ramfile and snapshot-based fuzzing support
 * add i440fx fuzz-target as a reference for developers.
 * add linker-script to assist with fork-based fuzzer

V2:
 * split off changes to qos virtio-net and qtest server to other patches
 * move vl:main initialization into new func: qemu_init
 * moved useful functions from qos-test.c to a separate object
 * use struct of function pointers for add_fuzz_target(), instead of
   arguments
 * move ramfile to migration/qemu-file
 * rewrite fork-based fuzzer pending patch to libfuzzer
 * pass check-patch

Alexander Bulekov (21):
  softmmu: split off vl.c:main() into main.c
  libqos: Rename i2c_send and i2c_recv
  fuzz: Add FUZZ_TARGET module type
  qtest: add qtest_server_send abstraction
  libqtest: Add a layer of abstraciton to send/recv
  module: check module wasn't already initialized
  qtest: add in-process incoming command handler
  tests: provide test variables to other targets
  libqos: split qos-test and libqos makefile vars
  libqos: move useful qos-test funcs to qos_external
  libqtest: make bufwrite rely on the TransportOps
  libqtest: add in-process qtest.c tx/rx handlers
  fuzz: add configure flag --enable-fuzzing
  fuzz: Add target/fuzz makefile rules
  fuzz: add fuzzer skeleton
  fuzz: add support for fork-based fuzzing.
  fuzz: add support for qos-assisted fuzz targets
  fuzz: add i440fx fuzz targets
  fuzz: add virtio-net fuzz target
  fuzz: add virtio-scsi fuzz target
  fuzz: add documentation to docs/devel/

 Makefile                      |  16 ++-
 Makefile.objs                 |   4 +
 Makefile.target               |  18 ++-
 configure                     |  39 ++++++
 docs/devel/fuzzing.txt        | 119 +++++++++++++++++
 exec.c                        |  12 +-
 include/qemu/module.h         |   4 +-
 include/sysemu/qtest.h        |   4 +
 include/sysemu/sysemu.h       |   4 +
 main.c                        |  53 ++++++++
 qtest.c                       |  31 ++++-
 tests/Makefile.include        |  75 +++++------
 tests/fuzz/Makefile.include   |  12 ++
 tests/fuzz/fork_fuzz.c        |  55 ++++++++
 tests/fuzz/fork_fuzz.h        |  23 ++++
 tests/fuzz/fork_fuzz.ld       |  37 ++++++
 tests/fuzz/fuzz.c             | 179 ++++++++++++++++++++++++++
 tests/fuzz/fuzz.h             |  94 ++++++++++++++
 tests/fuzz/i440fx_fuzz.c      | 176 ++++++++++++++++++++++++++
 tests/fuzz/qos_fuzz.c         | 232 ++++++++++++++++++++++++++++++++++
 tests/fuzz/qos_fuzz.h         |  33 +++++
 tests/fuzz/virtio_net_fuzz.c  | 105 +++++++++++++++
 tests/fuzz/virtio_scsi_fuzz.c | 200 +++++++++++++++++++++++++++++
 tests/libqos/i2c.c            |  10 +-
 tests/libqos/i2c.h            |   4 +-
 tests/libqos/qos_external.c   | 168 ++++++++++++++++++++++++
 tests/libqos/qos_external.h   |  28 ++++
 tests/libqtest.c              | 108 ++++++++++++++--
 tests/libqtest.h              |   4 +
 tests/pca9552-test.c          |  10 +-
 tests/qos-test.c              | 140 +-------------------
 util/module.c                 |   7 +
 vl.c                          |  38 ++----
 33 files changed, 1813 insertions(+), 229 deletions(-)
 create mode 100644 docs/devel/fuzzing.txt
 create mode 100644 main.c
 create mode 100644 tests/fuzz/Makefile.include
 create mode 100644 tests/fuzz/fork_fuzz.c
 create mode 100644 tests/fuzz/fork_fuzz.h
 create mode 100644 tests/fuzz/fork_fuzz.ld
 create mode 100644 tests/fuzz/fuzz.c
 create mode 100644 tests/fuzz/fuzz.h
 create mode 100644 tests/fuzz/i440fx_fuzz.c
 create mode 100644 tests/fuzz/qos_fuzz.c
 create mode 100644 tests/fuzz/qos_fuzz.h
 create mode 100644 tests/fuzz/virtio_net_fuzz.c
 create mode 100644 tests/fuzz/virtio_scsi_fuzz.c
 create mode 100644 tests/libqos/qos_external.c
 create mode 100644 tests/libqos/qos_external.h

-- 
2.23.0



^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03  9:58   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv Oleinik, Alexander
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

A program might rely on functions implemented in vl.c, but implement its
own main(). By placing main into a separate source file, there are no
complaints about duplicate main()s when linking against vl.o. For
example, the virtual-device fuzzer uses a main() provided by libfuzzer,
and needs to perform some initialization before running the softmmu
initialization. Now, main simply calls three vl.c functions which
handle the guest initialization, main loop and cleanup.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 Makefile                |  1 +
 Makefile.objs           |  2 ++
 include/sysemu/sysemu.h |  4 ++++
 main.c                  | 53 +++++++++++++++++++++++++++++++++++++++++
 vl.c                    | 38 ++++++++---------------------
 5 files changed, 70 insertions(+), 28 deletions(-)
 create mode 100644 main.c

diff --git a/Makefile b/Makefile
index b437a346d7..aeca63a2b1 100644
--- a/Makefile
+++ b/Makefile
@@ -480,6 +480,7 @@ $(SOFTMMU_ALL_RULES): $(chardev-obj-y)
 $(SOFTMMU_ALL_RULES): $(crypto-obj-y)
 $(SOFTMMU_ALL_RULES): $(io-obj-y)
 $(SOFTMMU_ALL_RULES): config-all-devices.mak
+$(SOFTMMU_ALL_RULES): $(softmmu-main-y)
 ifdef DECOMPRESS_EDK2_BLOBS
 $(SOFTMMU_ALL_RULES): $(edk2-decompressed)
 endif
diff --git a/Makefile.objs b/Makefile.objs
index 11ba1a36bd..9ff9b0c6f9 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -86,6 +86,8 @@ common-obj-$(CONFIG_FDT) += device_tree.o
 # qapi
 
 common-obj-y += qapi/
+
+softmmu-main-y = main.o
 endif
 
 #######################################################################
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 80c57fdc4e..270df5fa34 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -118,6 +118,10 @@ QemuOpts *qemu_get_machine_opts(void);
 
 bool defaults_enabled(void);
 
+void qemu_init(int argc, char **argv, char **envp);
+void qemu_main_loop(void);
+void qemu_cleanup(void);
+
 extern QemuOptsList qemu_legacy_drive_opts;
 extern QemuOptsList qemu_common_drive_opts;
 extern QemuOptsList qemu_drive_opts;
diff --git a/main.c b/main.c
new file mode 100644
index 0000000000..f10ceda541
--- /dev/null
+++ b/main.c
@@ -0,0 +1,53 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+
+#ifdef CONFIG_SDL
+#if defined(__APPLE__) || defined(main)
+#include <SDL.h>
+int main(int argc, char **argv)
+{
+    return qemu_main(argc, argv, NULL);
+}
+#undef main
+#define main qemu_main
+#endif
+#endif /* CONFIG_SDL */
+
+#ifdef CONFIG_COCOA
+#undef main
+#define main qemu_main
+#endif /* CONFIG_COCOA */
+
+int main(int argc, char **argv, char **envp)
+{
+    qemu_init(argc, argv, envp);
+    qemu_main_loop();
+    qemu_cleanup();
+
+    return 0;
+}
diff --git a/vl.c b/vl.c
index 6a65a64bfd..d294f94ab4 100644
--- a/vl.c
+++ b/vl.c
@@ -36,25 +36,6 @@
 #include "sysemu/seccomp.h"
 #include "sysemu/tcg.h"
 
-#ifdef CONFIG_SDL
-#if defined(__APPLE__) || defined(main)
-#include <SDL.h>
-int qemu_main(int argc, char **argv, char **envp);
-int main(int argc, char **argv)
-{
-    return qemu_main(argc, argv, NULL);
-}
-#undef main
-#define main qemu_main
-#endif
-#endif /* CONFIG_SDL */
-
-#ifdef CONFIG_COCOA
-#undef main
-#define main qemu_main
-#endif /* CONFIG_COCOA */
-
-
 #include "qemu/error-report.h"
 #include "qemu/sockets.h"
 #include "sysemu/accel.h"
@@ -1798,7 +1779,7 @@ static bool main_loop_should_exit(void)
     return false;
 }
 
-static void main_loop(void)
+void qemu_main_loop(void)
 {
 #ifdef CONFIG_PROFILER
     int64_t ti;
@@ -2825,7 +2806,7 @@ static void user_register_global_props(void)
                       global_init_func, NULL, NULL);
 }
 
-int main(int argc, char **argv, char **envp)
+void qemu_init(int argc, char **argv, char **envp)
 {
     int i;
     int snapshot, linux_boot;
@@ -3407,7 +3388,7 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_watchdog:
                 if (watchdog) {
                     error_report("only one watchdog option may be given");
-                    return 1;
+                    exit(1);
                 }
                 watchdog = optarg;
                 break;
@@ -3853,7 +3834,7 @@ int main(int argc, char **argv, char **envp)
     set_memory_options(&ram_slots, &maxram_size, machine_class);
 
     os_daemonize();
-    rcu_disable_atfork();
+    /* rcu_disable_atfork(); */
 
     if (pid_file && !qemu_write_pidfile(pid_file, &err)) {
         error_reportf_err(err, "cannot create PID file: ");
@@ -4338,7 +4319,7 @@ int main(int argc, char **argv, char **envp)
     parse_numa_opts(current_machine);
 
     /* do monitor/qmp handling at preconfig state if requested */
-    main_loop();
+    qemu_main_loop();
 
     audio_init_audiodevs();
 
@@ -4451,7 +4432,7 @@ int main(int argc, char **argv, char **envp)
     if (vmstate_dump_file) {
         /* dump and exit */
         dump_vmstate_json_to_file(vmstate_dump_file);
-        return 0;
+        exit(0);
     }
 
     if (incoming) {
@@ -4468,8 +4449,11 @@ int main(int argc, char **argv, char **envp)
     accel_setup_post(current_machine);
     os_setup_post();
 
-    main_loop();
+    return;
+}
 
+void qemu_cleanup(void)
+{
     gdbserver_cleanup();
 
     /*
@@ -4506,6 +4490,4 @@ int main(int argc, char **argv, char **envp)
     qemu_chr_cleanup();
     user_creatable_cleanup();
     /* TODO: unref root container, check all devices are ok */
-
-    return 0;
 }
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
  2019-11-29 21:34 ` [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2019-12-09 12:02   ` Thomas Huth
  2020-01-03  9:58   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 03/21] fuzz: Add FUZZ_TARGET module type Oleinik, Alexander
                   ` (20 subsequent siblings)
  22 siblings, 2 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

The names i2c_send and i2c_recv collide with functions defined in
hw/i2c/core.c. This causes an error when linking against libqos and
softmmu simultaneously (for example when using qtest inproc). Rename the
libqos functions to avoid this.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/libqos/i2c.c   | 10 +++++-----
 tests/libqos/i2c.h   |  4 ++--
 tests/pca9552-test.c | 10 +++++-----
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c
index 156114e745..38f800dbab 100644
--- a/tests/libqos/i2c.c
+++ b/tests/libqos/i2c.c
@@ -10,12 +10,12 @@
 #include "libqos/i2c.h"
 #include "libqtest.h"
 
-void i2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
+void qi2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
 {
     i2cdev->bus->send(i2cdev->bus, i2cdev->addr, buf, len);
 }
 
-void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
+void qi2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
 {
     i2cdev->bus->recv(i2cdev->bus, i2cdev->addr, buf, len);
 }
@@ -23,8 +23,8 @@ void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
 void i2c_read_block(QI2CDevice *i2cdev, uint8_t reg,
                     uint8_t *buf, uint16_t len)
 {
-    i2c_send(i2cdev, &reg, 1);
-    i2c_recv(i2cdev, buf, len);
+    qi2c_send(i2cdev, &reg, 1);
+    qi2c_recv(i2cdev, buf, len);
 }
 
 void i2c_write_block(QI2CDevice *i2cdev, uint8_t reg,
@@ -33,7 +33,7 @@ void i2c_write_block(QI2CDevice *i2cdev, uint8_t reg,
     uint8_t *cmd = g_malloc(len + 1);
     cmd[0] = reg;
     memcpy(&cmd[1], buf, len);
-    i2c_send(i2cdev, cmd, len + 1);
+    qi2c_send(i2cdev, cmd, len + 1);
     g_free(cmd);
 }
 
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 945b65b34c..c65f087834 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -47,8 +47,8 @@ struct QI2CDevice {
 void *i2c_device_create(void *i2c_bus, QGuestAllocator *alloc, void *addr);
 void add_qi2c_address(QOSGraphEdgeOptions *opts, QI2CAddress *addr);
 
-void i2c_send(QI2CDevice *dev, const uint8_t *buf, uint16_t len);
-void i2c_recv(QI2CDevice *dev, uint8_t *buf, uint16_t len);
+void qi2c_send(QI2CDevice *dev, const uint8_t *buf, uint16_t len);
+void qi2c_recv(QI2CDevice *dev, uint8_t *buf, uint16_t len);
 
 void i2c_read_block(QI2CDevice *dev, uint8_t reg,
                     uint8_t *buf, uint16_t len);
diff --git a/tests/pca9552-test.c b/tests/pca9552-test.c
index 4b800d3c3e..d80ed93cd3 100644
--- a/tests/pca9552-test.c
+++ b/tests/pca9552-test.c
@@ -32,22 +32,22 @@ static void receive_autoinc(void *obj, void *data, QGuestAllocator *alloc)
 
     pca9552_init(i2cdev);
 
-    i2c_send(i2cdev, &reg, 1);
+    qi2c_send(i2cdev, &reg, 1);
 
     /* PCA9552_LS0 */
-    i2c_recv(i2cdev, &resp, 1);
+    qi2c_recv(i2cdev, &resp, 1);
     g_assert_cmphex(resp, ==, 0x54);
 
     /* PCA9552_LS1 */
-    i2c_recv(i2cdev, &resp, 1);
+    qi2c_recv(i2cdev, &resp, 1);
     g_assert_cmphex(resp, ==, 0x55);
 
     /* PCA9552_LS2 */
-    i2c_recv(i2cdev, &resp, 1);
+    qi2c_recv(i2cdev, &resp, 1);
     g_assert_cmphex(resp, ==, 0x55);
 
     /* PCA9552_LS3 */
-    i2c_recv(i2cdev, &resp, 1);
+    qi2c_recv(i2cdev, &resp, 1);
     g_assert_cmphex(resp, ==, 0x54);
 }
 
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 03/21] fuzz: Add FUZZ_TARGET module type
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
  2019-11-29 21:34 ` [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c Oleinik, Alexander
  2019-11-29 21:34 ` [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2019-11-29 21:34 ` [PATCH v6 04/21] qtest: add qtest_server_send abstraction Oleinik, Alexander
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/qemu/module.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/qemu/module.h b/include/qemu/module.h
index 65ba596e46..684753d808 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -46,6 +46,7 @@ typedef enum {
     MODULE_INIT_TRACE,
     MODULE_INIT_XEN_BACKEND,
     MODULE_INIT_LIBQOS,
+    MODULE_INIT_FUZZ_TARGET,
     MODULE_INIT_MAX
 } module_init_type;
 
@@ -56,7 +57,8 @@ typedef enum {
 #define xen_backend_init(function) module_init(function, \
                                                MODULE_INIT_XEN_BACKEND)
 #define libqos_init(function) module_init(function, MODULE_INIT_LIBQOS)
-
+#define fuzz_target_init(function) module_init(function, \
+                                               MODULE_INIT_FUZZ_TARGET)
 #define block_module_load_one(lib) module_load_one("block-", lib)
 #define ui_module_load_one(lib) module_load_one("ui-", lib)
 #define audio_module_load_one(lib) module_load_one("audio-", lib)
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 04/21] qtest: add qtest_server_send abstraction
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (2 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 03/21] fuzz: Add FUZZ_TARGET module type Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2019-12-09 14:37   ` Thomas Huth
  2019-11-29 21:34 ` [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv Oleinik, Alexander
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

qtest_server_send is a function pointer specifying the handler used to
transmit data to the qtest client. In the standard configuration, this
calls the CharBackend handler, but now it is possible for other types of
handlers, e.g direct-function calls if the qtest client and server
exist within the same process (inproc)

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/sysemu/qtest.h |  3 +++
 qtest.c                | 18 ++++++++++++++++--
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index 5ed09c80b1..e2f1047fd7 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -26,4 +26,7 @@ bool qtest_driver(void);
 
 void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **errp);
 
+void qtest_server_set_send_handler(void (*send)(void *, const char *),
+                                 void *opaque);
+
 #endif
diff --git a/qtest.c b/qtest.c
index 8b50e2783e..58d7e2a6fb 100644
--- a/qtest.c
+++ b/qtest.c
@@ -42,6 +42,8 @@ static GString *inbuf;
 static int irq_levels[MAX_IRQ];
 static qemu_timeval start_time;
 static bool qtest_opened;
+static void (*qtest_server_send)(void*, const char*);
+static void *qtest_server_send_opaque;
 
 #define FMT_timeval "%ld.%06ld"
 
@@ -228,8 +230,10 @@ static void GCC_FMT_ATTR(1, 2) qtest_log_send(const char *fmt, ...)
     va_end(ap);
 }
 
-static void do_qtest_send(CharBackend *chr, const char *str, size_t len)
+static void qtest_server_char_be_send(void *opaque, const char *str)
 {
+    size_t len = strlen(str);
+    CharBackend* chr = (CharBackend *)opaque;
     qemu_chr_fe_write_all(chr, (uint8_t *)str, len);
     if (qtest_log_fp && qtest_opened) {
         fprintf(qtest_log_fp, "%s", str);
@@ -238,7 +242,7 @@ static void do_qtest_send(CharBackend *chr, const char *str, size_t len)
 
 static void qtest_send(CharBackend *chr, const char *str)
 {
-    do_qtest_send(chr, str, strlen(str));
+    qtest_server_send(qtest_server_send_opaque, str);
 }
 
 static void GCC_FMT_ATTR(2, 3) qtest_sendf(CharBackend *chr,
@@ -783,6 +787,16 @@ void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **
     qemu_chr_fe_set_echo(&qtest_chr, true);
 
     inbuf = g_string_new("");
+
+    if (!qtest_server_send) {
+        qtest_server_set_send_handler(qtest_server_char_be_send, &qtest_chr);
+    }
+}
+
+void qtest_server_set_send_handler(void (*send)(void*, const char*), void *opaque)
+{
+    qtest_server_send = send;
+    qtest_server_send_opaque = opaque;
 }
 
 bool qtest_driver(void)
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (3 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 04/21] qtest: add qtest_server_send abstraction Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:19   ` Stefan Hajnoczi
  2020-01-03 16:29   ` Philippe Mathieu-Daudé
  2019-11-29 21:34 ` [PATCH v6 06/21] module: check module wasn't already initialized Oleinik, Alexander
                   ` (17 subsequent siblings)
  22 siblings, 2 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

This makes it simple to swap the transport functions for qtest commands
to and from the qtest client. For example, now it is possible to
directly pass qtest commands to a server handler that exists within the
same process, without the standard way of writing to a file descriptor.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/libqtest.c | 50 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 41 insertions(+), 9 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index 91e9cb220c..ac4b6ab5f0 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -35,6 +35,17 @@
 #define SOCKET_TIMEOUT 50
 #define SOCKET_MAX_FDS 16
 
+
+typedef void (*QTestSendFn)(QTestState *s, const char *buf);
+typedef void (*ExternalSendFn)(void *s, const char *buf);
+typedef GString* (*QTestRecvFn)(QTestState *);
+
+typedef struct QTestClientTransportOps {
+    QTestSendFn     send;
+    ExternalSendFn  external_send;
+    QTestRecvFn     recv_line;
+} QTestTransportOps;
+
 struct QTestState
 {
     int fd;
@@ -45,6 +56,7 @@ struct QTestState
     bool big_endian;
     bool irq_level[MAX_IRQ];
     GString *rx;
+    QTestTransportOps ops;
 };
 
 static GHookList abrt_hooks;
@@ -52,6 +64,14 @@ static struct sigaction sigact_old;
 
 static int qtest_query_target_endianness(QTestState *s);
 
+static void qtest_client_socket_send(QTestState*, const char *buf);
+static void socket_send(int fd, const char *buf, size_t size);
+
+static GString *qtest_client_socket_recv_line(QTestState *);
+
+static void qtest_client_set_tx_handler(QTestState *s, QTestSendFn send);
+static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv);
+
 static int init_socket(const char *socket_path)
 {
     struct sockaddr_un addr;
@@ -234,6 +254,9 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
     sock = init_socket(socket_path);
     qmpsock = init_socket(qmp_socket_path);
 
+    qtest_client_set_rx_handler(s, qtest_client_socket_recv_line);
+    qtest_client_set_tx_handler(s, qtest_client_socket_send);
+
     qtest_add_abrt_handler(kill_qemu_hook_func, s);
 
     command = g_strdup_printf("exec %s "
@@ -379,13 +402,9 @@ static void socket_send(int fd, const char *buf, size_t size)
     }
 }
 
-static void socket_sendf(int fd, const char *fmt, va_list ap)
+static void qtest_client_socket_send(QTestState *s, const char *buf)
 {
-    gchar *str = g_strdup_vprintf(fmt, ap);
-    size_t size = strlen(str);
-
-    socket_send(fd, str, size);
-    g_free(str);
+    socket_send(s->fd, buf, strlen(buf));
 }
 
 static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
@@ -393,8 +412,11 @@ static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
     va_list ap;
 
     va_start(ap, fmt);
-    socket_sendf(s->fd, fmt, ap);
+    gchar *str = g_strdup_vprintf(fmt, ap);
     va_end(ap);
+
+    s->ops.send(s, str);
+    g_free(str);
 }
 
 /* Sends a message and file descriptors to the socket.
@@ -431,7 +453,7 @@ static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
     g_assert_cmpint(ret, >, 0);
 }
 
-static GString *qtest_recv_line(QTestState *s)
+static GString *qtest_client_socket_recv_line(QTestState *s)
 {
     GString *line;
     size_t offset;
@@ -468,7 +490,7 @@ static gchar **qtest_rsp(QTestState *s, int expected_args)
     int i;
 
 redo:
-    line = qtest_recv_line(s);
+    line = s->ops.recv_line(s);
     words = g_strsplit(line->str, " ", 0);
     g_string_free(line, TRUE);
 
@@ -1337,3 +1359,13 @@ void qmp_assert_error_class(QDict *rsp, const char *class)
 
     qobject_unref(rsp);
 }
+
+static void qtest_client_set_tx_handler(QTestState *s,
+                    QTestSendFn send)
+{
+    s->ops.send = send;
+}
+static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv)
+{
+    s->ops.recv_line = recv;
+}
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 06/21] module: check module wasn't already initialized
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (4 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 16:30   ` Philippe Mathieu-Daudé
  2019-11-29 21:34 ` [PATCH v6 07/21] qtest: add in-process incoming command handler Oleinik, Alexander
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, Darren Kenny, stefanha, Oleinik,  Alexander

The virtual-device fuzzer must initialize QOM, prior to running
vl:qemu_init, so that it can use the qos_graph to identify the arguments
required to initialize a guest for libqos-assisted fuzzing. This change
prevents errors when vl:qemu_init tries to (re)initialize the previously
initialized QOM module.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
---
 util/module.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/util/module.c b/util/module.c
index e9fe3e5422..841e490e06 100644
--- a/util/module.c
+++ b/util/module.c
@@ -30,6 +30,7 @@ typedef struct ModuleEntry
 typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
 
 static ModuleTypeList init_type_list[MODULE_INIT_MAX];
+static bool modules_init_done[MODULE_INIT_MAX];
 
 static ModuleTypeList dso_init_list;
 
@@ -91,11 +92,17 @@ void module_call_init(module_init_type type)
     ModuleTypeList *l;
     ModuleEntry *e;
 
+    if (modules_init_done[type]) {
+        return;
+    }
+
     l = find_type(type);
 
     QTAILQ_FOREACH(e, l, node) {
         e->init();
     }
+
+    modules_init_done[type] = true;
 }
 
 #ifdef CONFIG_MODULES
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 07/21] qtest: add in-process incoming command handler
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (5 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 06/21] module: check module wasn't already initialized Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:19   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 08/21] tests: provide test variables to other targets Oleinik, Alexander
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

The handler allows a qtest client to send commands to the server by
directly calling a function, rather than using a file/CharBackend

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 include/sysemu/qtest.h |  1 +
 qtest.c                | 13 +++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index e2f1047fd7..eedd3664f0 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -28,5 +28,6 @@ void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **
 
 void qtest_server_set_send_handler(void (*send)(void *, const char *),
                                  void *opaque);
+void qtest_server_inproc_recv(void *opaque, const char *buf);
 
 #endif
diff --git a/qtest.c b/qtest.c
index 58d7e2a6fb..1db712d302 100644
--- a/qtest.c
+++ b/qtest.c
@@ -803,3 +803,16 @@ bool qtest_driver(void)
 {
     return qtest_chr.chr != NULL;
 }
+
+void qtest_server_inproc_recv(void *dummy, const char *buf)
+{
+    static GString *gstr;
+    if (!gstr) {
+        gstr = g_string_new(NULL);
+    }
+    g_string_append(gstr, buf);
+    if (gstr->str[gstr->len - 1] == '\n') {
+        qtest_process_inbuf(NULL, gstr);
+        g_string_truncate(gstr, 0);
+    }
+}
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (7 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 08/21] tests: provide test variables to other targets Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 10:52   ` Stefan Hajnoczi
  2020-01-03 16:32   ` Philippe Mathieu-Daudé
  2019-11-29 21:34 ` [PATCH v6 10/21] libqos: move useful qos-test funcs to qos_external Oleinik, Alexander
                   ` (13 subsequent siblings)
  22 siblings, 2 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, Darren Kenny, stefanha, Oleinik,  Alexander

Most qos-related objects were specified in the qos-test-obj-y variable.
qos-test-obj-y also included qos-test.o which defines a main().
This made it difficult to repurpose qos-test-obj-y to link anything
beside tests/qos-test against libqos. This change separates objects that
are libqos-specific and ones that are qos-test specific into different
variables.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
---
 tests/Makefile.include | 71 +++++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 35 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3669fd1dc3..031240df4b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -703,52 +703,53 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y)
 
 libqgraph-obj-y = tests/libqos/qgraph.o
 
-libqos-obj-y = $(libqgraph-obj-y) tests/libqos/pci.o tests/libqos/fw_cfg.o
-libqos-obj-y += tests/libqos/malloc.o
-libqos-obj-y += tests/libqos/libqos.o
-libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
+libqos-core-obj-y = $(libqgraph-obj-y) tests/libqos/pci.o tests/libqos/fw_cfg.o
+libqos-core-obj-y += tests/libqos/malloc.o
+libqos-core-obj-y += tests/libqos/libqos.o
+libqos-spapr-obj-y = $(libqos-core-obj-y) tests/libqos/malloc-spapr.o
 libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
 libqos-spapr-obj-y += tests/libqos/rtas.o
 libqos-spapr-obj-y += tests/libqos/pci-spapr.o
-libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
+libqos-pc-obj-y = $(libqos-core-obj-y) tests/libqos/pci-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 
 # Devices
-qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
-qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
-qos-test-obj-y += tests/libqos/e1000e.o
-qos-test-obj-y += tests/libqos/i2c.o
-qos-test-obj-y += tests/libqos/i2c-imx.o
-qos-test-obj-y += tests/libqos/i2c-omap.o
-qos-test-obj-y += tests/libqos/sdhci.o
-qos-test-obj-y += tests/libqos/tpci200.o
-qos-test-obj-y += tests/libqos/virtio.o
-qos-test-obj-$(CONFIG_VIRTFS) += tests/libqos/virtio-9p.o
-qos-test-obj-y += tests/libqos/virtio-balloon.o
-qos-test-obj-y += tests/libqos/virtio-blk.o
-qos-test-obj-y += tests/libqos/virtio-mmio.o
-qos-test-obj-y += tests/libqos/virtio-net.o
-qos-test-obj-y += tests/libqos/virtio-pci.o
-qos-test-obj-y += tests/libqos/virtio-pci-modern.o
-qos-test-obj-y += tests/libqos/virtio-rng.o
-qos-test-obj-y += tests/libqos/virtio-scsi.o
-qos-test-obj-y += tests/libqos/virtio-serial.o
+libqos-obj-y = $(libqgraph-obj-y)
+libqos-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+libqos-obj-y += tests/libqos/e1000e.o
+libqos-obj-y += tests/libqos/i2c.o
+libqos-obj-y += tests/libqos/i2c-imx.o
+libqos-obj-y += tests/libqos/i2c-omap.o
+libqos-obj-y += tests/libqos/sdhci.o
+libqos-obj-y += tests/libqos/tpci200.o
+libqos-obj-y += tests/libqos/virtio.o
+libqos-obj-$(CONFIG_VIRTFS) += tests/libqos/virtio-9p.o
+libqos-obj-y += tests/libqos/virtio-balloon.o
+libqos-obj-y += tests/libqos/virtio-blk.o
+libqos-obj-y += tests/libqos/virtio-mmio.o
+libqos-obj-y += tests/libqos/virtio-net.o
+libqos-obj-y += tests/libqos/virtio-pci.o
+libqos-obj-y += tests/libqos/virtio-pci-modern.o
+libqos-obj-y += tests/libqos/virtio-rng.o
+libqos-obj-y += tests/libqos/virtio-scsi.o
+libqos-obj-y += tests/libqos/virtio-serial.o
 
 # Machines
-qos-test-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
-qos-test-obj-y += tests/libqos/arm-imx25-pdk-machine.o
-qos-test-obj-y += tests/libqos/arm-n800-machine.o
-qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
-qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
-qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
-qos-test-obj-y += tests/libqos/arm-virt-machine.o
-qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
-qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
-qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
+libqos-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
+libqos-obj-y += tests/libqos/arm-imx25-pdk-machine.o
+libqos-obj-y += tests/libqos/arm-n800-machine.o
+libqos-obj-y += tests/libqos/arm-raspi2-machine.o
+libqos-obj-y += tests/libqos/arm-sabrelite-machine.o
+libqos-obj-y += tests/libqos/arm-smdkc210-machine.o
+libqos-obj-y += tests/libqos/arm-virt-machine.o
+libqos-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
+libqos-obj-y += tests/libqos/ppc64_pseries-machine.o
+libqos-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
+qos-test-obj-y = tests/qos-test.o
 qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/ds1338-test.o
 qos-test-obj-y += tests/e1000-test.o
@@ -780,7 +781,7 @@ check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
 check-qtest-generic-y += tests/qos-test$(EXESUF)
-tests/qos-test$(EXESUF): $(qos-test-obj-y)
+tests/qos-test$(EXESUF): $(qos-test-obj-y) $(libqos-obj-y)
 
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/qmp-cmd-test$(EXESUF): tests/qmp-cmd-test.o
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 08/21] tests: provide test variables to other targets
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (6 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 07/21] qtest: add in-process incoming command handler Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 10:51   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars Oleinik, Alexander
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, Darren Kenny, stefanha, Oleinik,  Alexander

Before, when tests/Makefile.include was included, the contents would be
ignored if config-host.mak was defined. Moving the ifneq responsible for
this allows a target to depend on both testing-related and host-related
objects. For example the virtual-device fuzzer relies on both
libqtest/libqos objects and softmmu objects.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
---
 tests/Makefile.include | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8566f5f119..3669fd1dc3 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -27,7 +27,6 @@ check-help:
 	@echo "Default options are -k and (for $(MAKE) V=1) --verbose; they can be"
 	@echo "changed with variable GTESTER_OPTIONS."
 
-ifneq ($(wildcard config-host.mak),)
 export SRC_PATH
 
 # TODO don't duplicate $(SRC_PATH)/Makefile's qapi-py here
@@ -878,6 +877,8 @@ tests/test-qga$(EXESUF): tests/test-qga.o $(qtest-obj-y)
 
 SPEED = quick
 
+ifneq ($(wildcard config-host.mak),)
+
 # gtester tests, possibly with verbose output
 # do_test_tap runs all tests, even if some of them fail, while do_test_human
 # stops at the first failure unless -k is given on the command line
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 10/21] libqos: move useful qos-test funcs to qos_external
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (8 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 16:36   ` Philippe Mathieu-Daudé
  2019-11-29 21:34 ` [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps Oleinik, Alexander
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

The moved functions are not specific to qos-test and might be useful
elsewhere. For example the virtual-device fuzzer makes use of them for
qos-assisted fuzz-targets.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/Makefile.include      |   1 +
 tests/libqos/qos_external.c | 168 ++++++++++++++++++++++++++++++++++++
 tests/libqos/qos_external.h |  28 ++++++
 tests/qos-test.c            | 140 ++----------------------------
 4 files changed, 202 insertions(+), 135 deletions(-)
 create mode 100644 tests/libqos/qos_external.c
 create mode 100644 tests/libqos/qos_external.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 031240df4b..79534e9b85 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -718,6 +718,7 @@ libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 # Devices
 libqos-obj-y = $(libqgraph-obj-y)
 libqos-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+libqos-obj-y += tests/libqos/qos_external.o
 libqos-obj-y += tests/libqos/e1000e.o
 libqos-obj-y += tests/libqos/i2c.o
 libqos-obj-y += tests/libqos/i2c-imx.o
diff --git a/tests/libqos/qos_external.c b/tests/libqos/qos_external.c
new file mode 100644
index 0000000000..398556dde0
--- /dev/null
+++ b/tests/libqos/qos_external.c
@@ -0,0 +1,168 @@
+/*
+ * libqos driver framework
+ *
+ * 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 <getopt.h>
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/module.h"
+#include "qapi/qmp/qlist.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "libqos/qgraph_internal.h"
+#include "libqos/qos_external.h"
+
+
+
+void apply_to_node(const char *name, bool is_machine, bool is_abstract)
+{
+    char *machine_name = NULL;
+    if (is_machine) {
+        const char *arch = qtest_get_arch();
+        machine_name = g_strconcat(arch, "/", name, NULL);
+        name = machine_name;
+    }
+    qos_graph_node_set_availability(name, true);
+    if (is_abstract) {
+        qos_delete_cmd_line(name);
+    }
+    g_free(machine_name);
+}
+
+/**
+ * apply_to_qlist(): using QMP queries QEMU for a list of
+ * machines and devices available, and sets the respective node
+ * as true. If a node is found, also all its produced and contained
+ * child are marked available.
+ *
+ * See qos_graph_node_set_availability() for more info
+ */
+void apply_to_qlist(QList *list, bool is_machine)
+{
+    const QListEntry *p;
+    const char *name;
+    bool abstract;
+    QDict *minfo;
+    QObject *qobj;
+    QString *qstr;
+    QBool *qbool;
+
+    for (p = qlist_first(list); p; p = qlist_next(p)) {
+        minfo = qobject_to(QDict, qlist_entry_obj(p));
+        qobj = qdict_get(minfo, "name");
+        qstr = qobject_to(QString, qobj);
+        name = qstring_get_str(qstr);
+
+        qobj = qdict_get(minfo, "abstract");
+        if (qobj) {
+            qbool = qobject_to(QBool, qobj);
+            abstract = qbool_get_bool(qbool);
+        } else {
+            abstract = false;
+        }
+
+        apply_to_node(name, is_machine, abstract);
+        qobj = qdict_get(minfo, "alias");
+        if (qobj) {
+            qstr = qobject_to(QString, qobj);
+            name = qstring_get_str(qstr);
+            apply_to_node(name, is_machine, abstract);
+        }
+    }
+}
+
+QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
+{
+    return obj->get_driver(obj, "memory");
+}
+
+/**
+ * allocate_objects(): given an array of nodes @arg,
+ * walks the path invoking all constructors and
+ * passing the corresponding parameter in order to
+ * continue the objects allocation.
+ * Once the test is reached, return the object it consumes.
+ *
+ * Since the machine and QEDGE_CONSUMED_BY nodes allocate
+ * memory in the constructor, g_test_queue_destroy is used so
+ * that after execution they can be safely free'd.  (The test's
+ * ->before callback is also welcome to use g_test_queue_destroy).
+ *
+ * Note: as specified in walk_path() too, @arg is an array of
+ * char *, where arg[0] is a pointer to the command line
+ * string that will be used to properly start QEMU when executing
+ * the test, and the remaining elements represent the actual objects
+ * that will be allocated.
+ */
+void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
+{
+    int current = 0;
+    QGuestAllocator *alloc;
+    QOSGraphObject *parent = NULL;
+    QOSGraphEdge *edge;
+    QOSGraphNode *node;
+    void *edge_arg;
+    void *obj;
+
+    node = qos_graph_get_node(path[current]);
+    g_assert(node->type == QNODE_MACHINE);
+
+    obj = qos_machine_new(node, qts);
+    qos_object_queue_destroy(obj);
+
+    alloc = get_machine_allocator(obj);
+    if (p_alloc) {
+        *p_alloc = alloc;
+    }
+
+    for (;;) {
+        if (node->type != QNODE_INTERFACE) {
+            qos_object_start_hw(obj);
+            parent = obj;
+        }
+
+        /* follow edge and get object for next node constructor */
+        current++;
+        edge = qos_graph_get_edge(path[current - 1], path[current]);
+        node = qos_graph_get_node(path[current]);
+
+        if (node->type == QNODE_TEST) {
+            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
+            return obj;
+        }
+
+        switch (qos_graph_edge_get_type(edge)) {
+        case QEDGE_PRODUCES:
+            obj = parent->get_driver(parent, path[current]);
+            break;
+
+        case QEDGE_CONSUMED_BY:
+            edge_arg = qos_graph_edge_get_arg(edge);
+            obj = qos_driver_new(node, obj, alloc, edge_arg);
+            qos_object_queue_destroy(obj);
+            break;
+
+        case QEDGE_CONTAINS:
+            obj = parent->get_device(parent, path[current]);
+            break;
+        }
+    }
+}
+
diff --git a/tests/libqos/qos_external.h b/tests/libqos/qos_external.h
new file mode 100644
index 0000000000..7b44930c55
--- /dev/null
+++ b/tests/libqos/qos_external.h
@@ -0,0 +1,28 @@
+/*
+ * libqos driver framework
+ *
+ * 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/>
+ */
+
+#ifndef QOS_EXTERNAL_H
+#define QOS_EXTERNAL_H
+#include "libqos/qgraph.h"
+
+void apply_to_node(const char *name, bool is_machine, bool is_abstract);
+void apply_to_qlist(QList *list, bool is_machine);
+QGuestAllocator *get_machine_allocator(QOSGraphObject *obj);
+void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc);
+
+#endif
diff --git a/tests/qos-test.c b/tests/qos-test.c
index fd70d73ea5..9d02b83e24 100644
--- a/tests/qos-test.c
+++ b/tests/qos-test.c
@@ -27,65 +27,11 @@
 #include "libqos/malloc.h"
 #include "libqos/qgraph.h"
 #include "libqos/qgraph_internal.h"
+#include "libqos/qos_external.h"
 
 static char *old_path;
 
-static void apply_to_node(const char *name, bool is_machine, bool is_abstract)
-{
-    char *machine_name = NULL;
-    if (is_machine) {
-        const char *arch = qtest_get_arch();
-        machine_name = g_strconcat(arch, "/", name, NULL);
-        name = machine_name;
-    }
-    qos_graph_node_set_availability(name, true);
-    if (is_abstract) {
-        qos_delete_cmd_line(name);
-    }
-    g_free(machine_name);
-}
 
-/**
- * apply_to_qlist(): using QMP queries QEMU for a list of
- * machines and devices available, and sets the respective node
- * as true. If a node is found, also all its produced and contained
- * child are marked available.
- *
- * See qos_graph_node_set_availability() for more info
- */
-static void apply_to_qlist(QList *list, bool is_machine)
-{
-    const QListEntry *p;
-    const char *name;
-    bool abstract;
-    QDict *minfo;
-    QObject *qobj;
-    QString *qstr;
-    QBool *qbool;
-
-    for (p = qlist_first(list); p; p = qlist_next(p)) {
-        minfo = qobject_to(QDict, qlist_entry_obj(p));
-        qobj = qdict_get(minfo, "name");
-        qstr = qobject_to(QString, qobj);
-        name = qstring_get_str(qstr);
-
-        qobj = qdict_get(minfo, "abstract");
-        if (qobj) {
-            qbool = qobject_to(QBool, qobj);
-            abstract = qbool_get_bool(qbool);
-        } else {
-            abstract = false;
-        }
-
-        apply_to_node(name, is_machine, abstract);
-        qobj = qdict_get(minfo, "alias");
-        if (qobj) {
-            qstr = qobject_to(QString, qobj);
-            name = qstring_get_str(qstr);
-            apply_to_node(name, is_machine, abstract);
-        }
-    }
-}
 
 /**
  * qos_set_machines_devices_available(): sets availability of qgraph
@@ -129,10 +75,6 @@ static void qos_set_machines_devices_available(void)
     qobject_unref(response);
 }
 
-static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
-{
-    return obj->get_driver(obj, "memory");
-}
 
 static void restart_qemu_or_continue(char *path)
 {
@@ -159,78 +101,6 @@ void qos_invalidate_command_line(void)
     old_path = NULL;
 }
 
-/**
- * allocate_objects(): given an array of nodes @arg,
- * walks the path invoking all constructors and
- * passing the corresponding parameter in order to
- * continue the objects allocation.
- * Once the test is reached, return the object it consumes.
- *
- * Since the machine and QEDGE_CONSUMED_BY nodes allocate
- * memory in the constructor, g_test_queue_destroy is used so
- * that after execution they can be safely free'd.  (The test's
- * ->before callback is also welcome to use g_test_queue_destroy).
- *
- * Note: as specified in walk_path() too, @arg is an array of
- * char *, where arg[0] is a pointer to the command line
- * string that will be used to properly start QEMU when executing
- * the test, and the remaining elements represent the actual objects
- * that will be allocated.
- */
-static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
-{
-    int current = 0;
-    QGuestAllocator *alloc;
-    QOSGraphObject *parent = NULL;
-    QOSGraphEdge *edge;
-    QOSGraphNode *node;
-    void *edge_arg;
-    void *obj;
-
-    node = qos_graph_get_node(path[current]);
-    g_assert(node->type == QNODE_MACHINE);
-
-    obj = qos_machine_new(node, qts);
-    qos_object_queue_destroy(obj);
-
-    alloc = get_machine_allocator(obj);
-    if (p_alloc) {
-        *p_alloc = alloc;
-    }
-
-    for (;;) {
-        if (node->type != QNODE_INTERFACE) {
-            qos_object_start_hw(obj);
-            parent = obj;
-        }
-
-        /* follow edge and get object for next node constructor */
-        current++;
-        edge = qos_graph_get_edge(path[current - 1], path[current]);
-        node = qos_graph_get_node(path[current]);
-
-        if (node->type == QNODE_TEST) {
-            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
-            return obj;
-        }
-
-        switch (qos_graph_edge_get_type(edge)) {
-        case QEDGE_PRODUCES:
-            obj = parent->get_driver(parent, path[current]);
-            break;
-
-        case QEDGE_CONSUMED_BY:
-            edge_arg = qos_graph_edge_get_arg(edge);
-            obj = qos_driver_new(node, obj, alloc, edge_arg);
-            qos_object_queue_destroy(obj);
-            break;
-
-        case QEDGE_CONTAINS:
-            obj = parent->get_device(parent, path[current]);
-            break;
-        }
-    }
-}
 
 /* The argument to run_one_test, which is the test function that is registered
  * with GTest, is a vector of strings.  The first item is the initial command
@@ -239,14 +109,14 @@ static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_
  */
 static char **current_path;
 
-const char *qos_get_current_command_line(void)
+void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
 {
-    return current_path[0];
+    return allocate_objects(qts, current_path + 1, p_alloc);
 }
 
-void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
+const char *qos_get_current_command_line(void)
 {
-    return allocate_objects(qts, current_path + 1, p_alloc);
+    return current_path[0];
 }
 
 /**
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (9 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 10/21] libqos: move useful qos-test funcs to qos_external Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:10   ` Stefan Hajnoczi
  2020-01-03 16:45   ` Philippe Mathieu-Daudé
  2019-11-29 21:34 ` [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers Oleinik, Alexander
                   ` (11 subsequent siblings)
  22 siblings, 2 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

When using qtest "in-process" communication, qtest_sendf directly calls
a function in the server (qtest.c). Previously, bufwrite used
socket_send, which bypasses the TransportOps enabling the call into
qtest.c. This change replaces the socket_send calls with ops->send,
maintaining the benefits of the direct socket_send call, while adding
support for in-process qtest calls.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/libqtest.c | 4 ++--
 tests/libqtest.h | 3 +++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index ac4b6ab5f0..a7df92319a 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1080,8 +1080,8 @@ void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
 
     bdata = g_base64_encode(data, size);
     qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
-    socket_send(s->fd, bdata, strlen(bdata));
-    socket_send(s->fd, "\n", 1);
+    s->ops.send(s, bdata);
+    s->ops.send(s, "\n");
     qtest_rsp(s, 0);
     g_free(bdata);
 }
diff --git a/tests/libqtest.h b/tests/libqtest.h
index c9e21e05b3..0e9b8908ef 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -729,4 +729,7 @@ bool qtest_probe_child(QTestState *s);
  */
 void qtest_set_expected_status(QTestState *s, int status);
 
+QTestState *qtest_inproc_init(bool log, const char* arch,
+                    void (*send)(void*, const char*));
+void qtest_client_inproc_recv(void *opaque, const char *str);
 #endif
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (10 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:15   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 14/21] fuzz: Add target/fuzz makefile rules Oleinik, Alexander
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Thomas Huth, Oleinik, Alexander, bsd, stefanha, pbonzini

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/libqtest.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqtest.h |  3 ++-
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index a7df92319a..e0bc5bbe0b 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1369,3 +1369,57 @@ static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv)
 {
     s->ops.recv_line = recv;
 }
+/* A type-safe wrapper for s->send() */
+static void send_wrapper(QTestState *s, const char *buf)
+{
+    s->ops.external_send(s, buf);
+}
+
+static GString *qtest_client_inproc_recv_line(QTestState *s)
+{
+    GString *line;
+    size_t offset;
+    char *eol;
+
+    eol = strchr(s->rx->str, '\n');
+    offset = eol - s->rx->str;
+    line = g_string_new_len(s->rx->str, offset);
+    g_string_erase(s->rx, 0, offset + 1);
+    return line;
+}
+
+QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
+                    void (*send)(void*, const char*))
+{
+    QTestState *qts;
+    qts = g_new0(QTestState, 1);
+    *s = qts; /* Expose qts early on, since the query endianness relies on it */
+    qts->wstatus = 0;
+    for (int i = 0; i < MAX_IRQ; i++) {
+        qts->irq_level[i] = false;
+    }
+
+    qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line);
+
+    /* send() may not have a matching protoype, so use a type-safe wrapper */
+    qts->ops.external_send = send;
+    qtest_client_set_tx_handler(qts, send_wrapper);
+
+    qts->big_endian = qtest_query_target_endianness(qts);
+    gchar *bin_path = g_strconcat("/qemu-system-", arch, NULL);
+    setenv("QTEST_QEMU_BINARY", bin_path, 0);
+    g_free(bin_path);
+
+    return qts;
+}
+
+void qtest_client_inproc_recv(void *opaque, const char *str)
+{
+    QTestState *qts = *(QTestState **)opaque;
+
+    if (!qts->rx) {
+        qts->rx = g_string_new(NULL);
+    }
+    g_string_append(qts->rx, str);
+    return;
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 0e9b8908ef..f5cf93c386 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -729,7 +729,8 @@ bool qtest_probe_child(QTestState *s);
  */
 void qtest_set_expected_status(QTestState *s, int status);
 
-QTestState *qtest_inproc_init(bool log, const char* arch,
+QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
                     void (*send)(void*, const char*));
+
 void qtest_client_inproc_recv(void *opaque, const char *str);
 #endif
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 14/21] fuzz: Add target/fuzz makefile rules
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (11 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:18   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 13/21] fuzz: add configure flag --enable-fuzzing Oleinik, Alexander
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, Darren Kenny, stefanha, Oleinik,  Alexander

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
---
 Makefile                    | 15 ++++++++++++++-
 Makefile.objs               |  4 +++-
 Makefile.target             | 18 +++++++++++++++++-
 tests/fuzz/Makefile.include |  4 ++++
 4 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 tests/fuzz/Makefile.include

diff --git a/Makefile b/Makefile
index aeca63a2b1..267385917c 100644
--- a/Makefile
+++ b/Makefile
@@ -471,7 +471,7 @@ config-host.h-timestamp: config-host.mak
 qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
 
-TARGET_DIRS_RULES := $(foreach t, all clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
+TARGET_DIRS_RULES := $(foreach t, all fuzz clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
 
 SOFTMMU_ALL_RULES=$(filter %-softmmu/all, $(TARGET_DIRS_RULES))
 $(SOFTMMU_ALL_RULES): $(authz-obj-y)
@@ -485,6 +485,15 @@ ifdef DECOMPRESS_EDK2_BLOBS
 $(SOFTMMU_ALL_RULES): $(edk2-decompressed)
 endif
 
+SOFTMMU_FUZZ_RULES=$(filter %-softmmu/fuzz, $(TARGET_DIRS_RULES))
+$(SOFTMMU_FUZZ_RULES): $(authz-obj-y)
+$(SOFTMMU_FUZZ_RULES): $(block-obj-y)
+$(SOFTMMU_FUZZ_RULES): $(chardev-obj-y)
+$(SOFTMMU_FUZZ_RULES): $(crypto-obj-y)
+$(SOFTMMU_FUZZ_RULES): $(io-obj-y)
+$(SOFTMMU_FUZZ_RULES): config-all-devices.mak
+$(SOFTMMU_FUZZ_RULES): $(edk2-decompressed)
+
 .PHONY: $(TARGET_DIRS_RULES)
 # The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that
 # $(dir $@) yields the sub-directory, and $(notdir $@) yields the sub-goal
@@ -535,6 +544,9 @@ subdir-slirp: slirp/all
 $(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
 	$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
 
+$(filter %/fuzz, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
+	$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
+
 ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
 ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
 # Only keep -O and -g cflags
@@ -544,6 +556,7 @@ $(ROM_DIRS_RULES):
 
 .PHONY: recurse-all recurse-clean recurse-install
 recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
+recurse-fuzz: $(addsuffix /fuzz, $(TARGET_DIRS) $(ROM_DIRS))
 recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS))
 recurse-install: $(addsuffix /install, $(TARGET_DIRS))
 $(addsuffix /install, $(TARGET_DIRS)): all
diff --git a/Makefile.objs b/Makefile.objs
index 9ff9b0c6f9..5478a554f6 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -86,10 +86,12 @@ common-obj-$(CONFIG_FDT) += device_tree.o
 # qapi
 
 common-obj-y += qapi/
+softmmu-obj-y = main.o
 
-softmmu-main-y = main.o
 endif
 
+
+
 #######################################################################
 # Target-independent parts used in system and user emulation
 common-obj-y += cpus-common.o
diff --git a/Makefile.target b/Makefile.target
index 24d79d26eb..217391cae5 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -204,7 +204,7 @@ endif
 COMMON_LDADDS = ../libqemuutil.a
 
 # build either PROG or PROGW
-$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
+$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) $(softmmu-obj-y)
 	$(call LINK, $(filter-out %.mak, $^))
 ifdef CONFIG_DARWIN
 	$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
@@ -229,6 +229,22 @@ ifdef CONFIG_TRACE_SYSTEMTAP
 	rm -f *.stp
 endif
 
+ifdef CONFIG_FUZZ
+include $(SRC_PATH)/tests/fuzz/Makefile.include
+include $(SRC_PATH)/tests/Makefile.include
+
+fuzz: fuzz-vars
+fuzz-vars: QEMU_CFLAGS := $(FUZZ_CFLAGS) $(QEMU_CFLAGS)
+fuzz-vars: QEMU_LDFLAGS := $(FUZZ_LDFLAGS) $(QEMU_LDFLAGS)
+fuzz-vars: $(QEMU_PROG_FUZZ)
+dummy := $(call unnest-vars,, fuzz-obj-y)
+
+
+$(QEMU_PROG_FUZZ): config-devices.mak $(all-obj-y) $(COMMON_LDADDS) $(fuzz-obj-y)
+	$(call LINK, $(filter-out %.mak, $^))
+
+endif
+
 install: all
 ifneq ($(PROGS),)
 	$(call install-prog,$(PROGS),$(DESTDIR)$(bindir))
diff --git a/tests/fuzz/Makefile.include b/tests/fuzz/Makefile.include
new file mode 100644
index 0000000000..324e6c1433
--- /dev/null
+++ b/tests/fuzz/Makefile.include
@@ -0,0 +1,4 @@
+# QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF)
+fuzz-obj-y = $(libqos-obj-y)
+fuzz-obj-y += tests/libqtest.o
+
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 13/21] fuzz: add configure flag --enable-fuzzing
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (12 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 14/21] fuzz: Add target/fuzz makefile rules Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 16:48   ` Philippe Mathieu-Daudé
  2019-11-29 21:34 ` [PATCH v6 15/21] fuzz: add fuzzer skeleton Oleinik, Alexander
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 configure | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/configure b/configure
index 6099be1d84..5fb2494a8e 100755
--- a/configure
+++ b/configure
@@ -504,6 +504,7 @@ debug_mutex="no"
 libpmem=""
 default_devices="yes"
 plugins="no"
+fuzzing="no"
 
 supported_cpu="no"
 supported_os="no"
@@ -633,6 +634,15 @@ int main(void) { return 0; }
 EOF
 }
 
+write_c_fuzzer_skeleton() {
+    cat > $TMPC <<EOF
+#include <stdint.h>
+#include <sys/types.h>
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; }
+EOF
+}
+
 if check_define __linux__ ; then
   targetos="Linux"
 elif check_define _WIN32 ; then
@@ -1539,6 +1549,10 @@ for opt do
   ;;
   --disable-plugins) plugins="no"
   ;;
+  --enable-fuzzing) fuzzing=yes
+  ;;
+  --disable-fuzzing) fuzzing=no
+  ;;
   *)
       echo "ERROR: unknown option $opt"
       echo "Try '$0 --help' for more information"
@@ -6018,6 +6032,15 @@ EOF
   fi
 fi
 
+##########################################
+# checks for fuzzer
+if test "$fuzzing" = "yes" ; then
+  write_c_fuzzer_skeleton
+  if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address,fuzzer" ""; then
+      have_fuzzer=yes
+  fi
+fi
+
 ##########################################
 # check for libpmem
 
@@ -6599,6 +6622,7 @@ echo "libpmem support   $libpmem"
 echo "libudev           $libudev"
 echo "default devices   $default_devices"
 echo "plugin support    $plugins"
+echo "fuzzing support   $fuzzing"
 
 if test "$supported_cpu" = "no"; then
     echo
@@ -7435,6 +7459,16 @@ fi
 if test "$sheepdog" = "yes" ; then
   echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
 fi
+if test "$fuzzing" = "yes" ; then
+  if test "$have_fuzzer" = "yes"; then
+    FUZZ_LDFLAGS=" -fsanitize=address,fuzzer"
+    FUZZ_CFLAGS=" -fsanitize=address,fuzzer"
+    CFLAGS=" -fsanitize=address"
+  else
+    error_exit "Your compiler doesn't support -fsanitize=address,fuzzer"
+    exit 1
+  fi
+fi
 
 if test "$plugins" = "yes" ; then
     echo "CONFIG_PLUGIN=y" >> $config_host_mak
@@ -7538,6 +7572,11 @@ if test "$libudev" != "no"; then
     echo "CONFIG_LIBUDEV=y" >> $config_host_mak
     echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak
 fi
+if test "$fuzzing" != "no"; then
+    echo "CONFIG_FUZZ=y" >> $config_host_mak
+    echo "FUZZ_CFLAGS=$FUZZ_CFLAGS" >> $config_host_mak
+    echo "FUZZ_LDFLAGS=$FUZZ_LDFLAGS" >> $config_host_mak
+fi
 
 if test "$edk2_blobs" = "yes" ; then
   echo "DECOMPRESS_EDK2_BLOBS=y" >> $config_host_mak
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 15/21] fuzz: add fuzzer skeleton
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (13 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 13/21] fuzz: add configure flag --enable-fuzzing Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:25   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 16/21] fuzz: add support for fork-based fuzzing Oleinik, Alexander
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

tests/fuzz/fuzz.c serves as the entry point for the virtual-device
fuzzer. Namely, libfuzzer invokes the LLVMFuzzerInitialize and
LLVMFuzzerTestOneInput functions, both of which are defined in this
file. This change adds a "FuzzTarget" struct, along with the
fuzz_add_target function, which should be used to define new fuzz
targets.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/fuzz/Makefile.include |   4 +-
 tests/fuzz/fuzz.c           | 179 ++++++++++++++++++++++++++++++++++++
 tests/fuzz/fuzz.h           |  94 +++++++++++++++++++
 3 files changed, 275 insertions(+), 2 deletions(-)
 create mode 100644 tests/fuzz/fuzz.c
 create mode 100644 tests/fuzz/fuzz.h

diff --git a/tests/fuzz/Makefile.include b/tests/fuzz/Makefile.include
index 324e6c1433..b415b056b0 100644
--- a/tests/fuzz/Makefile.include
+++ b/tests/fuzz/Makefile.include
@@ -1,4 +1,4 @@
-# QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF)
+QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF)
 fuzz-obj-y = $(libqos-obj-y)
 fuzz-obj-y += tests/libqtest.o
-
+fuzz-obj-y += tests/fuzz/fuzz.o
diff --git a/tests/fuzz/fuzz.c b/tests/fuzz/fuzz.c
new file mode 100644
index 0000000000..f4abaa3484
--- /dev/null
+++ b/tests/fuzz/fuzz.c
@@ -0,0 +1,179 @@
+/*
+ * fuzzing driver
+ *
+ * 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 <wordexp.h>
+
+#include "sysemu/qtest.h"
+#include "sysemu/runstate.h"
+#include "sysemu/sysemu.h"
+#include "qemu/main-loop.h"
+#include "tests/libqtest.h"
+#include "tests/libqos/qgraph.h"
+#include "fuzz.h"
+
+#define MAX_EVENT_LOOPS 10
+
+typedef struct FuzzTargetState {
+        FuzzTarget *target;
+        QSLIST_ENTRY(FuzzTargetState) target_list;
+} FuzzTargetState;
+
+typedef QSLIST_HEAD(, FuzzTargetState) FuzzTargetList;
+
+static const char *fuzz_arch = TARGET_NAME;
+
+static FuzzTargetList *fuzz_target_list;
+static FuzzTarget *fuzz_target;
+static QTestState *fuzz_qts;
+
+
+
+void flush_events(QTestState *s)
+{
+    int i = MAX_EVENT_LOOPS;
+    while (g_main_context_pending(NULL) && i-- > 0) {
+        main_loop_wait(false);
+    }
+}
+
+static QTestState *qtest_setup(void)
+{
+    qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts);
+    return qtest_inproc_init(&fuzz_qts, false fuzz_arch,
+            &qtest_server_inproc_recv);
+}
+
+void fuzz_add_target(const FuzzTarget *target)
+{
+    FuzzTargetState *tmp;
+    FuzzTargetState *target_state;
+    if (!fuzz_target_list) {
+        fuzz_target_list = g_new0(FuzzTargetList, 1);
+    }
+
+    QSLIST_FOREACH(tmp, fuzz_target_list, target_list) {
+        if (g_strcmp0(tmp->target->name, target->name) == 0) {
+            fprintf(stderr, "Error: Fuzz target name %s already in use\n",
+                    target->name);
+            abort();
+        }
+    }
+    target_state = g_new0(FuzzTargetState, 1);
+    target_state->target = g_new0(FuzzTarget, 1);
+    *(target_state->target) = *target;
+    QSLIST_INSERT_HEAD(fuzz_target_list, target_state, target_list);
+}
+
+
+
+static void usage(char *path)
+{
+    printf("Usage: %s --fuzz-target=FUZZ_TARGET [LIBFUZZER ARGUMENTS]\n", path);
+    printf("where FUZZ_TARGET is one of:\n");
+    FuzzTargetState *tmp;
+    if (!fuzz_target_list) {
+        fprintf(stderr, "Fuzz target list not initialized\n");
+        abort();
+    }
+    QSLIST_FOREACH(tmp, fuzz_target_list, target_list) {
+        printf(" %s  : %s\n", tmp->target->name,
+                tmp->target->description);
+    }
+    exit(0);
+}
+
+static FuzzTarget *fuzz_get_target(char* name)
+{
+    FuzzTargetState *tmp;
+    if (!fuzz_target_list) {
+        fprintf(stderr, "Fuzz target list not initialized\n");
+        abort();
+    }
+
+    QSLIST_FOREACH(tmp, fuzz_target_list, target_list) {
+        if (strcmp(tmp->target->name, name) == 0) {
+            return tmp->target;
+        }
+    }
+    return NULL;
+}
+
+
+/* Executed for each fuzzing-input */
+int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size)
+{
+    /*
+     * Do the pre-fuzz-initialization before the first fuzzing iteration,
+     * instead of before the actual fuzz loop. This is needed since libfuzzer
+     * may fork off additional workers, prior to the fuzzing loop, and if
+     * pre_fuzz() sets up e.g. shared memory, this should be done for the
+     * individual worker processes
+     */
+    static int pre_fuzz_done;
+    if (!pre_fuzz_done && fuzz_target->pre_fuzz) {
+        fuzz_target->pre_fuzz(fuzz_qts);
+        pre_fuzz_done = true;
+    }
+
+    fuzz_target->fuzz(fuzz_qts, Data, Size);
+    return 0;
+}
+
+/* Executed once, prior to fuzzing */
+int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
+{
+
+    char *target_name;
+
+    /* Initialize qgraph and modules */
+    qos_graph_init();
+    module_call_init(MODULE_INIT_FUZZ_TARGET);
+    module_call_init(MODULE_INIT_QOM);
+    module_call_init(MODULE_INIT_LIBQOS);
+
+    if (*argc <= 1) {
+        usage(**argv);
+    }
+
+    /* Identify the fuzz target */
+    target_name = (*argv)[1];
+    if (!strstr(target_name, "--fuzz-target=")) {
+        usage(**argv);
+    }
+
+    target_name += strlen("--fuzz-target=");
+
+    fuzz_target = fuzz_get_target(target_name);
+    if (!fuzz_target) {
+        usage(**argv);
+    }
+
+    fuzz_qts = qtest_setup();
+
+    if (fuzz_target->pre_vm_init) {
+        fuzz_target->pre_vm_init();
+    }
+
+    /* Run QEMU's softmmu main with the fuzz-target dependent arguments */
+    const char *init_cmdline = fuzz_target->get_init_cmdline(fuzz_target);
+
+    /* Split the runcmd into an argv and argc */
+    wordexp_t result;
+    wordexp(init_cmdline, &result, 0);
+
+    qemu_init(result.we_wordc, result.we_wordv, NULL);
+
+    return 0;
+}
diff --git a/tests/fuzz/fuzz.h b/tests/fuzz/fuzz.h
new file mode 100644
index 0000000000..5135b252bf
--- /dev/null
+++ b/tests/fuzz/fuzz.h
@@ -0,0 +1,94 @@
+/*
+ * fuzzing driver
+ *
+ * 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 FUZZER_H_
+#define FUZZER_H_
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "exec/memory.h"
+#include "tests/libqtest.h"
+
+/**
+ * A libfuzzer fuzzing target
+ *
+ * The QEMU fuzzing binary is built with all available targets, each
+ * with a unique @name that can be specified on the command-line to
+ * select which target should run.
+ *
+ * A target must implement ->fuzz() to process a random input.  If QEMU
+ * crashes in ->fuzz() then libfuzzer will record a failure.
+ *
+ * Fuzzing targets are registered with fuzz_add_target():
+ *
+ *   static const FuzzTarget fuzz_target = {
+ *       .name = "my-device-fifo",
+ *       .description = "Fuzz the FIFO buffer registers of my-device",
+ *       ...
+ *   };
+ *
+ *   static void register_fuzz_target(void)
+ *   {
+ *       fuzz_add_target(&fuzz_target);
+ *   }
+ *   fuzz_target_init(register_fuzz_target);
+ */
+typedef struct FuzzTarget {
+    const char *name;         /* command-line option(FUZZ_TARGET) for the target */
+    const char *description;  /* help text */
+
+
+    /* returns the arg-list that is passed to qemu/softmmu init()
+     * Cannot be NULL
+     */
+    const char* (*get_init_cmdline)(struct FuzzTarget *);
+
+    /*
+     * will run once, prior to running qemu/softmmu init.
+     * eg: set up shared-memory for communication with the child-process
+     * Can be NULL
+     */
+    void(*pre_vm_init)(void);
+
+    /*
+     * will run once, after QEMU has been initialized, prior to the fuzz-loop.
+     * eg: detect the memory map
+     * Can be NULL
+     */
+    void(*pre_fuzz)(QTestState *);
+
+    /*
+     * accepts and executes an input from libfuzzer. this is repeatedly
+     * executed during the fuzzing loop. Its should handle setup, input
+     * execution and cleanup.
+     * Cannot be NULL
+     */
+    void(*fuzz)(QTestState *, const unsigned char *, size_t);
+
+} FuzzTarget;
+
+void flush_events(QTestState *);
+void reboot(QTestState *);
+
+/*
+ * makes a copy of *target and adds it to the target-list.
+ * i.e. fine to set up target on the caller's stack
+ */
+void fuzz_add_target(const FuzzTarget *target);
+
+int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size);
+int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp);
+
+#endif
+
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 16/21] fuzz: add support for fork-based fuzzing.
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (14 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 15/21] fuzz: add fuzzer skeleton Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:27   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 17/21] fuzz: add support for qos-assisted fuzz targets Oleinik, Alexander
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: pbonzini, bsd, Richard Henderson, stefanha, Oleinik,  Alexander

fork() is a simple way to ensure that state does not leak in between
fuzzing runs. Unfortunately, the fuzzer mutation engine relies on
bitmaps which contain coverage information for each fuzzing run, and
these bitmaps should be copied from the child to the parent(where the
mutation occurs). These bitmaps are created through compile-time
instrumentation and they are not shared with fork()-ed processes, by
default. To address this, we create a shared memory region, adjust its
size and map it _over_ the counter region. Furthermore, libfuzzer
doesn't generally expose the globals that specify the location of the
counters/coverage bitmap. As a workaround, we rely on a custom linker
script which forces all of the bitmaps we care about to be placed in a
contiguous region, which is easy to locate and mmap over.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 exec.c                      | 12 ++++++--
 tests/fuzz/Makefile.include |  3 ++
 tests/fuzz/fork_fuzz.c      | 55 +++++++++++++++++++++++++++++++++++++
 tests/fuzz/fork_fuzz.h      | 23 ++++++++++++++++
 tests/fuzz/fork_fuzz.ld     | 37 +++++++++++++++++++++++++
 tests/fuzz/fuzz.c           |  2 +-
 6 files changed, 129 insertions(+), 3 deletions(-)
 create mode 100644 tests/fuzz/fork_fuzz.c
 create mode 100644 tests/fuzz/fork_fuzz.h
 create mode 100644 tests/fuzz/fork_fuzz.ld

diff --git a/exec.c b/exec.c
index ffdb518535..e04d97404b 100644
--- a/exec.c
+++ b/exec.c
@@ -35,6 +35,7 @@
 #include "sysemu/kvm.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/tcg.h"
+#include "sysemu/qtest.h"
 #include "qemu/timer.h"
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
@@ -2268,8 +2269,15 @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared)
     if (new_block->host) {
         qemu_ram_setup_dump(new_block->host, new_block->max_length);
         qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
-        /* MADV_DONTFORK is also needed by KVM in absence of synchronous MMU */
-        qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
+        /*
+         * MADV_DONTFORK is also needed by KVM in absence of synchronous MMU
+         * Configure it unless the machine is a qtest server, in which case it
+         * may be forked, for fuzzing purposes
+         */
+        if (!qtest_enabled()) {
+            qemu_madvise(new_block->host, new_block->max_length,
+                         QEMU_MADV_DONTFORK);
+        }
         ram_block_notify_add(new_block->host, new_block->max_length);
     }
 }
diff --git a/tests/fuzz/Makefile.include b/tests/fuzz/Makefile.include
index b415b056b0..687dacce04 100644
--- a/tests/fuzz/Makefile.include
+++ b/tests/fuzz/Makefile.include
@@ -2,3 +2,6 @@ QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF)
 fuzz-obj-y = $(libqos-obj-y)
 fuzz-obj-y += tests/libqtest.o
 fuzz-obj-y += tests/fuzz/fuzz.o
+fuzz-obj-y += tests/fuzz/fork_fuzz.o
+
+FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/fuzz/fork_fuzz.ld
diff --git a/tests/fuzz/fork_fuzz.c b/tests/fuzz/fork_fuzz.c
new file mode 100644
index 0000000000..2bd0851903
--- /dev/null
+++ b/tests/fuzz/fork_fuzz.c
@@ -0,0 +1,55 @@
+/*
+ * 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)
+{
+    char *shm_path = g_strdup_printf("/qemu-fuzz-cntrs.%d", getpid());
+    int fd = shm_open(shm_path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+    g_free(shm_path);
+
+    if (fd == -1) {
+        perror("Error: ");
+        exit(1);
+    }
+    if (ftruncate(fd, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START) == -1) {
+        perror("Error: ");
+        exit(1);
+    }
+    /* Copy what's in the counter region to the shm.. */
+    void *rptr = mmap(NULL ,
+            &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START,
+            PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    memcpy(rptr,
+           &__FUZZ_COUNTERS_START,
+           &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START);
+
+    munmap(rptr, &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START);
+
+    /* And map the shm over the counter region */
+    rptr = mmap(&__FUZZ_COUNTERS_START,
+            &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START,
+            PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
+
+    close(fd);
+
+    if (!rptr) {
+        perror("Error: ");
+        exit(1);
+    }
+}
+
+
diff --git a/tests/fuzz/fork_fuzz.h b/tests/fuzz/fork_fuzz.h
new file mode 100644
index 0000000000..9ecb8b58ef
--- /dev/null
+++ b/tests/fuzz/fork_fuzz.h
@@ -0,0 +1,23 @@
+/*
+ * 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
+
diff --git a/tests/fuzz/fork_fuzz.ld b/tests/fuzz/fork_fuzz.ld
new file mode 100644
index 0000000000..b23a59f194
--- /dev/null
+++ b/tests/fuzz/fork_fuzz.ld
@@ -0,0 +1,37 @@
+/* We adjust linker script modification to place all of the stuff that needs to
+ * persist across fuzzing runs into a contiguous seciton 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);
+  }
+  .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*);
+  }
+  .data.fuzz_end : ALIGN(4K)
+  {
+      __FUZZ_COUNTERS_END = .;
+  }
+}
+/* Dont overwrite the SECTIONS in the default linker script. Instead insert the
+ * above into the default script */
+INSERT AFTER .data;
diff --git a/tests/fuzz/fuzz.c b/tests/fuzz/fuzz.c
index f4abaa3484..1ed98f26a2 100644
--- a/tests/fuzz/fuzz.c
+++ b/tests/fuzz/fuzz.c
@@ -51,7 +51,7 @@ void flush_events(QTestState *s)
 static QTestState *qtest_setup(void)
 {
     qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts);
-    return qtest_inproc_init(&fuzz_qts, false fuzz_arch,
+    return qtest_inproc_init(&fuzz_qts, false, fuzz_arch,
             &qtest_server_inproc_recv);
 }
 
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 17/21] fuzz: add support for qos-assisted fuzz targets
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (15 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 16/21] fuzz: add support for fork-based fuzzing Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:28   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 19/21] fuzz: add virtio-net fuzz target Oleinik, Alexander
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/fuzz/qos_fuzz.c | 232 ++++++++++++++++++++++++++++++++++++++++++
 tests/fuzz/qos_fuzz.h |  33 ++++++
 2 files changed, 265 insertions(+)
 create mode 100644 tests/fuzz/qos_fuzz.c
 create mode 100644 tests/fuzz/qos_fuzz.h

diff --git a/tests/fuzz/qos_fuzz.c b/tests/fuzz/qos_fuzz.c
new file mode 100644
index 0000000000..da76e28ca3
--- /dev/null
+++ b/tests/fuzz/qos_fuzz.c
@@ -0,0 +1,232 @@
+/*
+ * 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 <wordexp.h>
+
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "libqos/qgraph_internal.h"
+
+#include "fuzz.h"
+#include "qos_fuzz.h"
+#include "tests/libqos/qgraph.h"
+#include "tests/libqos/qos_external.h"
+#include "tests/libqtest.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;
+
+    /* 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/fuzz/qos_fuzz.h b/tests/fuzz/qos_fuzz.h
new file mode 100644
index 0000000000..6c280f07c5
--- /dev/null
+++ b/tests/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/fuzz/fuzz.h"
+#include "tests/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.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 18/21] fuzz: add i440fx fuzz targets
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (17 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 19/21] fuzz: add virtio-net fuzz target Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2019-11-29 21:34 ` [PATCH v6 20/21] fuzz: add virtio-scsi fuzz target Oleinik, Alexander
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

These three targets should simply fuzz reads/writes to a couple ioports,
but they mostly serve as examples of different ways to write targets.
They demonstrate using qtest and qos for fuzzing, as well as using
rebooting and forking to reset state, or not resetting it at all.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/fuzz/Makefile.include |   3 +
 tests/fuzz/i440fx_fuzz.c    | 176 ++++++++++++++++++++++++++++++++++++
 2 files changed, 179 insertions(+)
 create mode 100644 tests/fuzz/i440fx_fuzz.c

diff --git a/tests/fuzz/Makefile.include b/tests/fuzz/Makefile.include
index 687dacce04..37d6821bee 100644
--- a/tests/fuzz/Makefile.include
+++ b/tests/fuzz/Makefile.include
@@ -3,5 +3,8 @@ fuzz-obj-y = $(libqos-obj-y)
 fuzz-obj-y += tests/libqtest.o
 fuzz-obj-y += tests/fuzz/fuzz.o
 fuzz-obj-y += tests/fuzz/fork_fuzz.o
+fuzz-obj-y += tests/fuzz/qos_fuzz.o
+
+fuzz-obj-y += tests/fuzz/i440fx_fuzz.o
 
 FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/fuzz/fork_fuzz.ld
diff --git a/tests/fuzz/i440fx_fuzz.c b/tests/fuzz/i440fx_fuzz.c
new file mode 100644
index 0000000000..56e3315a88
--- /dev/null
+++ b/tests/fuzz/i440fx_fuzz.c
@@ -0,0 +1,176 @@
+/*
+ * I440FX 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 "fuzz.h"
+#include "tests/libqtest.h"
+#include "fuzz/qos_fuzz.h"
+#include "fuzz/fork_fuzz.h"
+#include "qemu/main-loop.h"
+#include "tests/libqos/pci.h"
+#include "tests/libqos/pci-pc.h"
+
+
+#define I440FX_PCI_HOST_BRIDGE_CFG 0xcf8
+#define I440FX_PCI_HOST_BRIDGE_DATA 0xcfc
+
+enum action_id {
+    WRITEB,
+    WRITEW,
+    WRITEL,
+    READB,
+    READW,
+    READL,
+    ACTION_MAX
+};
+
+static void i440fx_fuzz_qtest(QTestState *s,
+        const unsigned char *Data, size_t Size) {
+    typedef struct QTestFuzzAction {
+        uint32_t value;
+        uint8_t id;
+        uint8_t addr;
+    } QTestFuzzAction;
+    QTestFuzzAction a;
+
+    while (Size >= sizeof(a)) {
+        memcpy(&a, Data, sizeof(a));
+        uint16_t addr = a.addr % 2 ? I440FX_PCI_HOST_BRIDGE_CFG :
+                                      I440FX_PCI_HOST_BRIDGE_DATA;
+        switch (a.id % ACTION_MAX) {
+        case WRITEB:
+            qtest_outb(s, addr, (uint8_t)a.value);
+            break;
+        case WRITEW:
+            qtest_outw(s, addr, (uint16_t)a.value);
+            break;
+        case WRITEL:
+            qtest_outl(s, addr, (uint32_t)a.value);
+            break;
+        case READB:
+            qtest_inb(s, addr);
+            break;
+        case READW:
+            qtest_inw(s, addr);
+            break;
+        case READL:
+            qtest_inl(s, addr);
+            break;
+        }
+        Size -= sizeof(a);
+        Data += sizeof(a);
+    }
+    flush_events(s);
+}
+
+static void i440fx_fuzz_qos(QTestState *s,
+        const unsigned char *Data, size_t Size) {
+
+    typedef struct QOSFuzzAction {
+        uint32_t value;
+        int devfn;
+        uint8_t offset;
+        uint8_t id;
+    } QOSFuzzAction;
+
+    static QPCIBus *bus;
+    if (!bus) {
+        bus = qpci_new_pc(s, fuzz_qos_alloc);
+    }
+
+    QOSFuzzAction a;
+    while (Size >= sizeof(a)) {
+        memcpy(&a, Data, sizeof(a));
+        switch (a.id % ACTION_MAX) {
+        case WRITEB:
+            bus->config_writeb(bus, a.devfn, a.offset, (uint8_t)a.value);
+            break;
+        case WRITEW:
+            bus->config_writew(bus, a.devfn, a.offset, (uint16_t)a.value);
+            break;
+        case WRITEL:
+            bus->config_writel(bus, a.devfn, a.offset, (uint32_t)a.value);
+            break;
+        case READB:
+            bus->config_readb(bus, a.devfn, a.offset);
+            break;
+        case READW:
+            bus->config_readw(bus, a.devfn, a.offset);
+            break;
+        case READL:
+            bus->config_readl(bus, a.devfn, a.offset);
+            break;
+        }
+        Size -= sizeof(a);
+        Data += sizeof(a);
+    }
+    flush_events(s);
+}
+
+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 {
+        wait(NULL);
+    }
+}
+
+static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest"
+                                       "-m 0 -display none";
+static const char *i440fx_argv(FuzzTarget *t)
+{
+    return i440fx_qtest_argv;
+}
+
+static void fork_init(void)
+{
+    counter_shm_init();
+}
+
+static void register_pci_fuzz_targets(void)
+{
+    /* Uses simple qtest commands and reboots to reset state */
+    fuzz_add_target(&(FuzzTarget){
+                .name = "i440fx-qtest-reboot-fuzz",
+                .description = "Fuzz the i440fx using raw qtest commands and"
+                               "rebooting after each run",
+                .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
+     reboot after each run, we would also have to redo the qos-related
+     initialization (qos_init_path) */
+    fuzz_add_qos_target(&(FuzzTarget){
+                .name = "i440fx-qos-noreset-fuzz",
+                .description = "Fuzz the i440fx using raw qtest commands and"
+                               "rebooting after each run",
+                .fuzz = i440fx_fuzz_qos,},
+                "i440FX-pcihost",
+                &(QOSGraphTestOptions){}
+                );
+}
+
+fuzz_target_init(register_pci_fuzz_targets);
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 19/21] fuzz: add virtio-net fuzz target
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (16 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 17/21] fuzz: add support for qos-assisted fuzz targets Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:30   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 18/21] fuzz: add i440fx fuzz targets Oleinik, Alexander
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

The virtio-net fuzz target feeds inputs to all three virtio-net
virtqueues, and uses forking to avoid leaking state between fuzz runs.

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 tests/fuzz/Makefile.include  |   1 +
 tests/fuzz/virtio_net_fuzz.c | 105 +++++++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 tests/fuzz/virtio_net_fuzz.c

diff --git a/tests/fuzz/Makefile.include b/tests/fuzz/Makefile.include
index 37d6821bee..f1d9b46b1c 100644
--- a/tests/fuzz/Makefile.include
+++ b/tests/fuzz/Makefile.include
@@ -6,5 +6,6 @@ fuzz-obj-y += tests/fuzz/fork_fuzz.o
 fuzz-obj-y += tests/fuzz/qos_fuzz.o
 
 fuzz-obj-y += tests/fuzz/i440fx_fuzz.o
+fuzz-obj-y += tests/fuzz/virtio_net_fuzz.o
 
 FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/fuzz/fork_fuzz.ld
diff --git a/tests/fuzz/virtio_net_fuzz.c b/tests/fuzz/virtio_net_fuzz.c
new file mode 100644
index 0000000000..f8efe3d7fd
--- /dev/null
+++ b/tests/fuzz/virtio_net_fuzz.c
@@ -0,0 +1,105 @@
+/*
+ * virtio-net 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 "fuzz.h"
+#include "fork_fuzz.h"
+#include "qos_fuzz.h"
+#include "tests/libqtest.h"
+#include "tests/libqos/virtio-net.h"
+
+
+static void virtio_net_fuzz_multi(QTestState *s,
+        const unsigned char *Data, size_t Size)
+{
+    typedef struct vq_action {
+        uint8_t queue;
+        uint8_t length;
+        uint8_t write;
+        uint8_t next;
+    } vq_action;
+
+    uint32_t free_head = 0;
+
+    QGuestAllocator *t_alloc = fuzz_qos_alloc;
+
+    QVirtioNet *net_if = fuzz_qos_obj;
+    QVirtioDevice *dev = net_if->vdev;
+    QVirtQueue *q;
+    vq_action vqa;
+    while (Size >= sizeof(vqa)) {
+        memcpy(&vqa, Data, sizeof(vqa));
+        Data += sizeof(vqa);
+        Size -= sizeof(vqa);
+
+        q = net_if->queues[vqa.queue % 3];
+
+        vqa.length = vqa.length >= Size ? Size :  vqa.length;
+
+        uint64_t req_addr = guest_alloc(t_alloc, vqa.length);
+        qtest_memwrite(s, req_addr, Data, vqa.length);
+        free_head = qvirtqueue_add(s, q, req_addr, vqa.length,
+                vqa.write, vqa.next);
+        qvirtqueue_add(s, q, req_addr, vqa.length, vqa.write , vqa.next);
+        qvirtqueue_kick(s, dev, q, free_head);
+        Data += vqa.length;
+        Size -= vqa.length;
+    }
+}
+
+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);
+        flush_events(s);
+        _Exit(0);
+    } else {
+        wait(NULL);
+    }
+}
+
+static void virtio_net_pre_fuzz(QTestState *s)
+{
+    qos_init_path(s);
+    counter_shm_init();
+}
+
+static int *sv;
+
+static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg)
+{
+    if (!sv) {
+        sv = g_new(int, 2);
+        int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
+        fcntl(sv[0], F_SETFL, O_NONBLOCK);
+        g_assert_cmpint(ret, !=, -1);
+    }
+    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", sv[1]);
+    return arg;
+}
+
+static void register_virtio_net_fuzz_targets(void)
+{
+    fuzz_add_qos_target(&(FuzzTarget){
+                .name = "virtio-net-fuzz",
+                .description = "Fuzz the virtio-net virtual queues, forking"
+                               "for each fuzz run",
+                .pre_fuzz = &virtio_net_pre_fuzz,
+                .fuzz = virtio_net_fork_fuzz,},
+                "virtio-net",
+                &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket}
+                );
+}
+
+fuzz_target_init(register_virtio_net_fuzz_targets);
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 20/21] fuzz: add virtio-scsi fuzz target
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (18 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 18/21] fuzz: add i440fx fuzz targets Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:30   ` Stefan Hajnoczi
  2019-11-29 21:34 ` [PATCH v6 21/21] fuzz: add documentation to docs/devel/ Oleinik, Alexander
                   ` (2 subsequent siblings)
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

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>
---
 tests/fuzz/Makefile.include   |   1 +
 tests/fuzz/virtio_scsi_fuzz.c | 200 ++++++++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+)
 create mode 100644 tests/fuzz/virtio_scsi_fuzz.c

diff --git a/tests/fuzz/Makefile.include b/tests/fuzz/Makefile.include
index f1d9b46b1c..65b66fbdae 100644
--- a/tests/fuzz/Makefile.include
+++ b/tests/fuzz/Makefile.include
@@ -7,5 +7,6 @@ fuzz-obj-y += tests/fuzz/qos_fuzz.o
 
 fuzz-obj-y += tests/fuzz/i440fx_fuzz.o
 fuzz-obj-y += tests/fuzz/virtio_net_fuzz.o
+fuzz-obj-y += tests/fuzz/virtio_scsi_fuzz.o
 
 FUZZ_LDFLAGS += -Xlinker -T$(SRC_PATH)/tests/fuzz/fork_fuzz.ld
diff --git a/tests/fuzz/virtio_scsi_fuzz.c b/tests/fuzz/virtio_scsi_fuzz.c
new file mode 100644
index 0000000000..591629f243
--- /dev/null
+++ b/tests/fuzz/virtio_scsi_fuzz.c
@@ -0,0 +1,200 @@
+/*
+ * 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 "fuzz.h"
+#include "fork_fuzz.h"
+#include "qos_fuzz.h"
+#include "tests/libqtest.h"
+#include "tests/libqos/virtio-net.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"
+
+#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)
+{
+    typedef struct vq_action {
+        uint8_t queue;
+        uint8_t length;
+        uint8_t write;
+        uint8_t next;
+        uint8_t kick;
+    } vq_action;
+
+    uint32_t free_head[MAX_NUM_QUEUES + 2] = {0};
+    QGuestAllocator *t_alloc = fuzz_qos_alloc;
+
+    QVirtioSCSI *scsi = fuzz_qos_obj;
+    QVirtioDevice *dev = scsi->vdev;
+    QVirtQueue *q;
+    vq_action vqa;
+    while (Size >= sizeof(vqa)) {
+        memcpy(&vqa, Data, sizeof(vqa));
+
+        Data += sizeof(vqa);
+        Size -= sizeof(vqa);
+
+        vqa.queue = vqa.queue % queues->num_queues;
+        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];
+
+        uint64_t req_addr = guest_alloc(t_alloc, vqa.length);
+        qtest_memwrite(s, req_addr, Data, vqa.length);
+        if (free_head[vqa.queue] == 0) {
+            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;
+    }
+    for (int i = 0; i < MAX_NUM_QUEUES + 2; i++) {
+        if (free_head[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-net 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-net 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.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v6 21/21] fuzz: add documentation to docs/devel/
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (19 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 20/21] fuzz: add virtio-scsi fuzz target Oleinik, Alexander
@ 2019-11-29 21:34 ` Oleinik, Alexander
  2020-01-03 11:31   ` Stefan Hajnoczi
  2020-01-03  9:55 ` [PATCH v6 00/21] Add virtual device fuzzing support Stefan Hajnoczi
  2020-01-03 11:33 ` Stefan Hajnoczi
  22 siblings, 1 reply; 53+ messages in thread
From: Oleinik, Alexander @ 2019-11-29 21:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, bsd, stefanha, Oleinik, Alexander

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
---
 docs/devel/fuzzing.txt | 119 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 docs/devel/fuzzing.txt

diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt
new file mode 100644
index 0000000000..b0cceb2a6b
--- /dev/null
+++ b/docs/devel/fuzzing.txt
@@ -0,0 +1,119 @@
+= Fuzzing =
+
+== Introduction ==
+
+This document describes the virtual-device fuzzing infrastructure in QEMU and
+how to use it to implement additional fuzzers.
+
+== Basics ==
+
+Fuzzing operates by passing inputs to an entry point/target function. The
+fuzzer tracks the code coverage triggered by the input. Based on these
+findings, the fuzzer mutates the input and repeats the fuzzing. 
+
+To fuzz QEMU, we rely on libfuzzer. Unlike other fuzzers such as AFL, libfuzzer
+is an _in-process_ fuzzer. For the developer, this means that it is their
+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 mmaps ~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):
+
+    CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing
+
+Fuzz targets are built similarly to system/softmmu:
+
+    make i386-softmmu/fuzz
+
+This builds ./i386-softmmu/qemu-fuzz-i386
+
+The first option to this command is: --fuzz_taget=FUZZ_NAME
+To list all of the available fuzzers run qemu-fuzz-i386 with no arguments.
+
+eg:
+    ./i386-softmmu/qemu-fuzz-i386 --fuzz-target=virtio-net-fork-fuzz
+
+Internally, libfuzzer parses all arguments that do not begin with "--".
+Information about these is available by passing -help=1
+
+Now the only thing left to do is wait for the fuzzer to trigger potential
+crashes.
+
+== Adding a new fuzzer ==
+Coverage over virtual devices can be improved by adding additional fuzzers. 
+Fuzzers are kept in tests/fuzz/ and should be added to
+tests/fuzz/Makefile.include
+
+Fuzzers can rely on both qtest and libqos to communicate with virtual devices.
+
+1. Create a new source file. For example ``tests/fuzz/fuzz-foo-device.c``.
+
+2. Write the fuzzing code using the libqtest/libqos API. See existing fuzzers
+for reference.
+
+3. Register the fuzzer in ``tests/fuzz/Makefile.include`` by appending the
+corresponding object to fuzz-obj-y
+
+Fuzzers can be more-or-less thought of as special qtest programs which can
+modify the qtest commands and/or qtest command arguments based on inputs
+provided by libfuzzer. Libfuzzer passes a byte array and length. Commonly the
+fuzzer loops over the byte-array interpreting it as a list of qtest commands,
+addresses, or values.
+
+
+= Implementation Details =
+
+== The Fuzzer's Lifecycle ==
+
+The fuzzer has two entrypoints that libfuzzer calls. libfuzzer provides it's
+own main(), which performs some setup, and calls the entrypoints:
+
+LLVMFuzzerInitialize: called prior to fuzzing. Used to initialize all of the
+necessary state
+
+LLVMFuzzerTestOneInput: called for each fuzzing run. Processes the input and
+resets the state at the end of each run.
+
+In more detail:
+
+LLVMFuzzerInitialize parses the arguments to the fuzzer (must start with two
+dashes, so they are ignored by libfuzzer main()). Currently, the arguments
+select the fuzz target. Then, the qtest client is initialized. If the target
+requires qos, qgraph is set up and the QOM/LIBQOS modules are initialized.
+Then the QGraph is walked and the QEMU cmd_line is determined and saved.
+
+After this, the vl.c:qemu__main is called to set up the guest. There are
+target-specific hooks that can be called before and after qemu_main, for
+additional setup(e.g. PCI setup, or VM snapshotting).
+
+LLVMFuzzerTestOneInput: Uses qtest/qos functions to act based on the fuzz
+input. It is also responsible for manually calling the main loop/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: 
+1. 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
+   device requires some initialization prior to being ready for fuzzing
+   (common for QOS-based targets), this initialization needs to be done after
+   each reboot.
+   Example target: i440fx-qtest-reboot-fuzz
+2. 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
+
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv
  2019-11-29 21:34 ` [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv Oleinik, Alexander
@ 2019-12-09 12:02   ` Thomas Huth
  2020-01-03 11:01     ` Philippe Mathieu-Daudé
  2020-01-03  9:58   ` Stefan Hajnoczi
  1 sibling, 1 reply; 53+ messages in thread
From: Thomas Huth @ 2019-12-09 12:02 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel; +Cc: Laurent Vivier, pbonzini, bsd, stefanha

On 29/11/2019 22.34, Oleinik, Alexander wrote:
> The names i2c_send and i2c_recv collide with functions defined in
> hw/i2c/core.c. This causes an error when linking against libqos and
> softmmu simultaneously (for example when using qtest inproc). Rename the
> libqos functions to avoid this.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  tests/libqos/i2c.c   | 10 +++++-----
>  tests/libqos/i2c.h   |  4 ++--
>  tests/pca9552-test.c | 10 +++++-----
>  3 files changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c
> index 156114e745..38f800dbab 100644
> --- a/tests/libqos/i2c.c
> +++ b/tests/libqos/i2c.c
> @@ -10,12 +10,12 @@
>  #include "libqos/i2c.h"
>  #include "libqtest.h"
>  
> -void i2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
> +void qi2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
>  {
>      i2cdev->bus->send(i2cdev->bus, i2cdev->addr, buf, len);
>  }
>  
> -void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
> +void qi2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
>  {
>      i2cdev->bus->recv(i2cdev->bus, i2cdev->addr, buf, len);
>  }

I'd prefer qos_i2c_send and qos_i2c_recv instead ... but that's just a
matter of taste.

Acked-by: Thomas Huth <thuth@redhat.com>



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 04/21] qtest: add qtest_server_send abstraction
  2019-11-29 21:34 ` [PATCH v6 04/21] qtest: add qtest_server_send abstraction Oleinik, Alexander
@ 2019-12-09 14:37   ` Thomas Huth
  0 siblings, 0 replies; 53+ messages in thread
From: Thomas Huth @ 2019-12-09 14:37 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel; +Cc: Laurent Vivier, pbonzini, bsd, stefanha

On 29/11/2019 22.34, Oleinik, Alexander wrote:
> qtest_server_send is a function pointer specifying the handler used to
> transmit data to the qtest client. In the standard configuration, this
> calls the CharBackend handler, but now it is possible for other types of
> handlers, e.g direct-function calls if the qtest client and server
> exist within the same process (inproc)
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  include/sysemu/qtest.h |  3 +++
>  qtest.c                | 18 ++++++++++++++++--
>  2 files changed, 19 insertions(+), 2 deletions(-)

Acked-by: Thomas Huth <thuth@redhat.com>



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/21] Add virtual device fuzzing support
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (20 preceding siblings ...)
  2019-11-29 21:34 ` [PATCH v6 21/21] fuzz: add documentation to docs/devel/ Oleinik, Alexander
@ 2020-01-03  9:55 ` Stefan Hajnoczi
  2020-01-03 11:33 ` Stefan Hajnoczi
  22 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03  9:55 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 6116 bytes --]

On Fri, Nov 29, 2019 at 09:34:35PM +0000, Oleinik, Alexander wrote:
> This series adds a framework for coverage-guided fuzzing of
> virtual-devices. Fuzzing targets are based on qtest and can make use of
> the libqos abstractions.
> 
> In this version, I added a virtio-scsi fuzzer. The actual fuzzing code
> is very similar to the the virtio-net fuzzer. I experimented with using
> a single fuzzer with device-specific initialization for each virtio
> device, but it did not come out as cleanly as I hoped, since I could not
> find an easy way to override the qos drivers for devices that have
> more-complete qos support (such as virtio-net), so these changes have
> not made it into v6.
> 
> V5/V6: (V5 did not have review tags)
>  * added virtio-scsi fuzzer
>  * add support for using fork-based fuzzers with multiple libfuzzer
>    workers
>  * misc fixes addressing V4 comments
>  * cleanup in-process handlers/globals in libqtest.c
>  * small fixes to fork-based fuzzing and support for multiple workers
>  * changes to the virtio-net fuzzer to kick after each vq add
> 
> V4:
>  * add/transfer license headers to new files
>  * restructure the added QTestClientTransportOps struct
>  * restructure the FuzzTarget struct and fuzzer skeleton
>  * fork-based fuzzer now directly mmaps shm over the coverage bitmaps
>  * fixes to i440 and virtio-net fuzz targets
>  * undo the changes to qtest_memwrite
>  * possible to build /fuzz and /all in the same build-dir
>  * misc fixes to address V3 comments
> 
> V3:
>  * rebased onto v4.1.0+
>  * add the fuzzer as a new build-target type in the build-system
>  * add indirection to qtest client/server communication functions
>  * remove ramfile and snapshot-based fuzzing support
>  * add i440fx fuzz-target as a reference for developers.
>  * add linker-script to assist with fork-based fuzzer
> 
> V2:
>  * split off changes to qos virtio-net and qtest server to other patches
>  * move vl:main initialization into new func: qemu_init
>  * moved useful functions from qos-test.c to a separate object
>  * use struct of function pointers for add_fuzz_target(), instead of
>    arguments
>  * move ramfile to migration/qemu-file
>  * rewrite fork-based fuzzer pending patch to libfuzzer
>  * pass check-patch
> 
> Alexander Bulekov (21):
>   softmmu: split off vl.c:main() into main.c
>   libqos: Rename i2c_send and i2c_recv
>   fuzz: Add FUZZ_TARGET module type
>   qtest: add qtest_server_send abstraction
>   libqtest: Add a layer of abstraciton to send/recv
>   module: check module wasn't already initialized
>   qtest: add in-process incoming command handler
>   tests: provide test variables to other targets
>   libqos: split qos-test and libqos makefile vars
>   libqos: move useful qos-test funcs to qos_external
>   libqtest: make bufwrite rely on the TransportOps
>   libqtest: add in-process qtest.c tx/rx handlers
>   fuzz: add configure flag --enable-fuzzing
>   fuzz: Add target/fuzz makefile rules
>   fuzz: add fuzzer skeleton
>   fuzz: add support for fork-based fuzzing.
>   fuzz: add support for qos-assisted fuzz targets
>   fuzz: add i440fx fuzz targets
>   fuzz: add virtio-net fuzz target
>   fuzz: add virtio-scsi fuzz target
>   fuzz: add documentation to docs/devel/
> 
>  Makefile                      |  16 ++-
>  Makefile.objs                 |   4 +
>  Makefile.target               |  18 ++-
>  configure                     |  39 ++++++
>  docs/devel/fuzzing.txt        | 119 +++++++++++++++++
>  exec.c                        |  12 +-
>  include/qemu/module.h         |   4 +-
>  include/sysemu/qtest.h        |   4 +
>  include/sysemu/sysemu.h       |   4 +
>  main.c                        |  53 ++++++++
>  qtest.c                       |  31 ++++-
>  tests/Makefile.include        |  75 +++++------
>  tests/fuzz/Makefile.include   |  12 ++
>  tests/fuzz/fork_fuzz.c        |  55 ++++++++
>  tests/fuzz/fork_fuzz.h        |  23 ++++
>  tests/fuzz/fork_fuzz.ld       |  37 ++++++
>  tests/fuzz/fuzz.c             | 179 ++++++++++++++++++++++++++
>  tests/fuzz/fuzz.h             |  94 ++++++++++++++
>  tests/fuzz/i440fx_fuzz.c      | 176 ++++++++++++++++++++++++++
>  tests/fuzz/qos_fuzz.c         | 232 ++++++++++++++++++++++++++++++++++
>  tests/fuzz/qos_fuzz.h         |  33 +++++
>  tests/fuzz/virtio_net_fuzz.c  | 105 +++++++++++++++
>  tests/fuzz/virtio_scsi_fuzz.c | 200 +++++++++++++++++++++++++++++
>  tests/libqos/i2c.c            |  10 +-
>  tests/libqos/i2c.h            |   4 +-
>  tests/libqos/qos_external.c   | 168 ++++++++++++++++++++++++
>  tests/libqos/qos_external.h   |  28 ++++
>  tests/libqtest.c              | 108 ++++++++++++++--
>  tests/libqtest.h              |   4 +
>  tests/pca9552-test.c          |  10 +-
>  tests/qos-test.c              | 140 +-------------------
>  util/module.c                 |   7 +
>  vl.c                          |  38 ++----
>  33 files changed, 1813 insertions(+), 229 deletions(-)
>  create mode 100644 docs/devel/fuzzing.txt
>  create mode 100644 main.c
>  create mode 100644 tests/fuzz/Makefile.include
>  create mode 100644 tests/fuzz/fork_fuzz.c
>  create mode 100644 tests/fuzz/fork_fuzz.h
>  create mode 100644 tests/fuzz/fork_fuzz.ld
>  create mode 100644 tests/fuzz/fuzz.c
>  create mode 100644 tests/fuzz/fuzz.h
>  create mode 100644 tests/fuzz/i440fx_fuzz.c
>  create mode 100644 tests/fuzz/qos_fuzz.c
>  create mode 100644 tests/fuzz/qos_fuzz.h
>  create mode 100644 tests/fuzz/virtio_net_fuzz.c
>  create mode 100644 tests/fuzz/virtio_scsi_fuzz.c
>  create mode 100644 tests/libqos/qos_external.c
>  create mode 100644 tests/libqos/qos_external.h

Please use "git rebase -i origin/master" with "x make" after each commit
to verify that building succeeds.  This is important for git-bisect(1)
where we need the tree to always build successfully and for
cherry-picking patches without introducing breakage.

It's not enough for the tree to build at the end of the patch series.
It should build at each step along the way.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c
  2019-11-29 21:34 ` [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c Oleinik, Alexander
@ 2020-01-03  9:58   ` Stefan Hajnoczi
  2020-01-05 19:17     ` Alexander Bulekov
  0 siblings, 1 reply; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03  9:58 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 472 bytes --]

On Fri, Nov 29, 2019 at 09:34:36PM +0000, Oleinik, Alexander wrote:
> @@ -3853,7 +3834,7 @@ int main(int argc, char **argv, char **envp)
>      set_memory_options(&ram_slots, &maxram_size, machine_class);
>  
>      os_daemonize();
> -    rcu_disable_atfork();
> +    /* rcu_disable_atfork(); */
>  
>      if (pid_file && !qemu_write_pidfile(pid_file, &err)) {
>          error_reportf_err(err, "cannot create PID file: ");

Did you find a solution for this?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv
  2019-11-29 21:34 ` [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv Oleinik, Alexander
  2019-12-09 12:02   ` Thomas Huth
@ 2020-01-03  9:58   ` Stefan Hajnoczi
  1 sibling, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03  9:58 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: Thomas Huth, pbonzini, bsd, qemu-devel, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 609 bytes --]

On Fri, Nov 29, 2019 at 09:34:38PM +0000, Oleinik, Alexander wrote:
> The names i2c_send and i2c_recv collide with functions defined in
> hw/i2c/core.c. This causes an error when linking against libqos and
> softmmu simultaneously (for example when using qtest inproc). Rename the
> libqos functions to avoid this.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  tests/libqos/i2c.c   | 10 +++++-----
>  tests/libqos/i2c.h   |  4 ++--
>  tests/pca9552-test.c | 10 +++++-----
>  3 files changed, 12 insertions(+), 12 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 08/21] tests: provide test variables to other targets
  2019-11-29 21:34 ` [PATCH v6 08/21] tests: provide test variables to other targets Oleinik, Alexander
@ 2020-01-03 10:51   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 10:51 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel, Darren Kenny

[-- Attachment #1: Type: text/plain, Size: 765 bytes --]

On Fri, Nov 29, 2019 at 09:34:44PM +0000, Oleinik, Alexander wrote:
> Before, when tests/Makefile.include was included, the contents would be
> ignored if config-host.mak was defined. Moving the ifneq responsible for
> this allows a target to depend on both testing-related and host-related
> objects. For example the virtual-device fuzzer relies on both
> libqtest/libqos objects and softmmu objects.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
> ---
>  tests/Makefile.include | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)

I've checked that "make check" is still happy when the x86_64-linux-user
target is configured:

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars
  2019-11-29 21:34 ` [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars Oleinik, Alexander
@ 2020-01-03 10:52   ` Stefan Hajnoczi
  2020-01-03 16:32   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 10:52 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel, Darren Kenny

[-- Attachment #1: Type: text/plain, Size: 747 bytes --]

On Fri, Nov 29, 2019 at 09:34:44PM +0000, Oleinik, Alexander wrote:
> Most qos-related objects were specified in the qos-test-obj-y variable.
> qos-test-obj-y also included qos-test.o which defines a main().
> This made it difficult to repurpose qos-test-obj-y to link anything
> beside tests/qos-test against libqos. This change separates objects that
> are libqos-specific and ones that are qos-test specific into different
> variables.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
> ---
>  tests/Makefile.include | 71 +++++++++++++++++++++---------------------
>  1 file changed, 36 insertions(+), 35 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv
  2019-12-09 12:02   ` Thomas Huth
@ 2020-01-03 11:01     ` Philippe Mathieu-Daudé
  2020-01-05 19:50       ` Alexander Bulekov
  0 siblings, 1 reply; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 11:01 UTC (permalink / raw)
  To: Thomas Huth, Oleinik, Alexander, qemu-devel
  Cc: Laurent Vivier, pbonzini, bsd, stefanha

On 12/9/19 1:02 PM, Thomas Huth wrote:
> On 29/11/2019 22.34, Oleinik, Alexander wrote:
>> The names i2c_send and i2c_recv collide with functions defined in
>> hw/i2c/core.c. This causes an error when linking against libqos and
>> softmmu simultaneously (for example when using qtest inproc). Rename the
>> libqos functions to avoid this.
>>
>> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
>> ---
>>   tests/libqos/i2c.c   | 10 +++++-----
>>   tests/libqos/i2c.h   |  4 ++--
>>   tests/pca9552-test.c | 10 +++++-----
>>   3 files changed, 12 insertions(+), 12 deletions(-)
>>
>> diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c
>> index 156114e745..38f800dbab 100644
>> --- a/tests/libqos/i2c.c
>> +++ b/tests/libqos/i2c.c
>> @@ -10,12 +10,12 @@
>>   #include "libqos/i2c.h"
>>   #include "libqtest.h"
>>   
>> -void i2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
>> +void qi2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
>>   {
>>       i2cdev->bus->send(i2cdev->bus, i2cdev->addr, buf, len);
>>   }
>>   
>> -void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
>> +void qi2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
>>   {
>>       i2cdev->bus->recv(i2cdev->bus, i2cdev->addr, buf, len);
>>   }
> 
> I'd prefer qos_i2c_send and qos_i2c_recv instead ... but that's just a
> matter of taste.
> 
> Acked-by: Thomas Huth <thuth@redhat.com>

Agreed.

Renamed qos_*:
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps
  2019-11-29 21:34 ` [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps Oleinik, Alexander
@ 2020-01-03 11:10   ` Stefan Hajnoczi
  2020-01-03 16:45   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:10 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: Thomas Huth, pbonzini, bsd, qemu-devel, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 692 bytes --]

On Fri, Nov 29, 2019 at 09:34:46PM +0000, Oleinik, Alexander wrote:
> When using qtest "in-process" communication, qtest_sendf directly calls
> a function in the server (qtest.c). Previously, bufwrite used
> socket_send, which bypasses the TransportOps enabling the call into
> qtest.c. This change replaces the socket_send calls with ops->send,
> maintaining the benefits of the direct socket_send call, while adding
> support for in-process qtest calls.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  tests/libqtest.c | 4 ++--
>  tests/libqtest.h | 3 +++
>  2 files changed, 5 insertions(+), 2 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers
  2019-11-29 21:34 ` [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers Oleinik, Alexander
@ 2020-01-03 11:15   ` Stefan Hajnoczi
  2020-01-05 19:55     ` Alexander Bulekov
  0 siblings, 1 reply; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:15 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: Thomas Huth, pbonzini, bsd, qemu-devel, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 1057 bytes --]

On Fri, Nov 29, 2019 at 09:34:47PM +0000, Oleinik, Alexander wrote:
> +QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
> +                    void (*send)(void*, const char*))
> +{
> +    QTestState *qts;
> +    qts = g_new0(QTestState, 1);
> +    *s = qts; /* Expose qts early on, since the query endianness relies on it */
> +    qts->wstatus = 0;
> +    for (int i = 0; i < MAX_IRQ; i++) {
> +        qts->irq_level[i] = false;
> +    }
> +
> +    qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line);
> +
> +    /* send() may not have a matching protoype, so use a type-safe wrapper */
> +    qts->ops.external_send = send;
> +    qtest_client_set_tx_handler(qts, send_wrapper);
> +
> +    qts->big_endian = qtest_query_target_endianness(qts);
> +    gchar *bin_path = g_strconcat("/qemu-system-", arch, NULL);
> +    setenv("QTEST_QEMU_BINARY", bin_path, 0);
> +    g_free(bin_path);

Is this a dummy path that is needed to make other code happy?  Or does
the user need to have an actual file at /qemu-system-ARCH?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 14/21] fuzz: Add target/fuzz makefile rules
  2019-11-29 21:34 ` [PATCH v6 14/21] fuzz: Add target/fuzz makefile rules Oleinik, Alexander
@ 2020-01-03 11:18   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:18 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel, Darren Kenny

[-- Attachment #1: Type: text/plain, Size: 904 bytes --]

On Fri, Nov 29, 2019 at 09:34:48PM +0000, Oleinik, Alexander wrote:
> diff --git a/Makefile.objs b/Makefile.objs
> index 9ff9b0c6f9..5478a554f6 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -86,10 +86,12 @@ common-obj-$(CONFIG_FDT) += device_tree.o
>  # qapi
>  
>  common-obj-y += qapi/
> +softmmu-obj-y = main.o
>  
> -softmmu-main-y = main.o
>  endif
>  
> +
> +
>  #######################################################################
>  # Target-independent parts used in system and user emulation
>  common-obj-y += cpus-common.o

Not urgent but as a general comment for future contributions:

It's nice to avoid churn in a patch series.  softmmu-main-y was
introduced in this patch series but now it's being removed again.  Can
this be consolidated with the earlier commit that introduced
softmmu-main-y?

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv
  2019-11-29 21:34 ` [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv Oleinik, Alexander
@ 2020-01-03 11:19   ` Stefan Hajnoczi
  2020-01-03 16:29   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:19 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: Thomas Huth, pbonzini, bsd, qemu-devel, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 607 bytes --]

On Fri, Nov 29, 2019 at 09:34:41PM +0000, Oleinik, Alexander wrote:
> This makes it simple to swap the transport functions for qtest commands
> to and from the qtest client. For example, now it is possible to
> directly pass qtest commands to a server handler that exists within the
> same process, without the standard way of writing to a file descriptor.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  tests/libqtest.c | 50 +++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 41 insertions(+), 9 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 07/21] qtest: add in-process incoming command handler
  2019-11-29 21:34 ` [PATCH v6 07/21] qtest: add in-process incoming command handler Oleinik, Alexander
@ 2020-01-03 11:19   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:19 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: Thomas Huth, pbonzini, bsd, qemu-devel, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 444 bytes --]

On Fri, Nov 29, 2019 at 09:34:43PM +0000, Oleinik, Alexander wrote:
> The handler allows a qtest client to send commands to the server by
> directly calling a function, rather than using a file/CharBackend
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  include/sysemu/qtest.h |  1 +
>  qtest.c                | 13 +++++++++++++
>  2 files changed, 14 insertions(+)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 15/21] fuzz: add fuzzer skeleton
  2019-11-29 21:34 ` [PATCH v6 15/21] fuzz: add fuzzer skeleton Oleinik, Alexander
@ 2020-01-03 11:25   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:25 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 420 bytes --]

On Fri, Nov 29, 2019 at 09:34:49PM +0000, Oleinik, Alexander wrote:
> +static QTestState *qtest_setup(void)
> +{
> +    qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts);
> +    return qtest_inproc_init(&fuzz_qts, false fuzz_arch,

This line isn't valid C.  I guess a later patch fixes this compilation
error.  Please squash the fix into this patch.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 16/21] fuzz: add support for fork-based fuzzing.
  2019-11-29 21:34 ` [PATCH v6 16/21] fuzz: add support for fork-based fuzzing Oleinik, Alexander
@ 2020-01-03 11:27   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:27 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel, Richard Henderson

[-- Attachment #1: Type: text/plain, Size: 1548 bytes --]

On Fri, Nov 29, 2019 at 09:34:50PM +0000, Oleinik, Alexander wrote:
> fork() is a simple way to ensure that state does not leak in between
> fuzzing runs. Unfortunately, the fuzzer mutation engine relies on
> bitmaps which contain coverage information for each fuzzing run, and
> these bitmaps should be copied from the child to the parent(where the
> mutation occurs). These bitmaps are created through compile-time
> instrumentation and they are not shared with fork()-ed processes, by
> default. To address this, we create a shared memory region, adjust its
> size and map it _over_ the counter region. Furthermore, libfuzzer
> doesn't generally expose the globals that specify the location of the
> counters/coverage bitmap. As a workaround, we rely on a custom linker
> script which forces all of the bitmaps we care about to be placed in a
> contiguous region, which is easy to locate and mmap over.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  exec.c                      | 12 ++++++--
>  tests/fuzz/Makefile.include |  3 ++
>  tests/fuzz/fork_fuzz.c      | 55 +++++++++++++++++++++++++++++++++++++
>  tests/fuzz/fork_fuzz.h      | 23 ++++++++++++++++
>  tests/fuzz/fork_fuzz.ld     | 37 +++++++++++++++++++++++++
>  tests/fuzz/fuzz.c           |  2 +-
>  6 files changed, 129 insertions(+), 3 deletions(-)
>  create mode 100644 tests/fuzz/fork_fuzz.c
>  create mode 100644 tests/fuzz/fork_fuzz.h
>  create mode 100644 tests/fuzz/fork_fuzz.ld

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 17/21] fuzz: add support for qos-assisted fuzz targets
  2019-11-29 21:34 ` [PATCH v6 17/21] fuzz: add support for qos-assisted fuzz targets Oleinik, Alexander
@ 2020-01-03 11:28   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:28 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1385 bytes --]

On Fri, Nov 29, 2019 at 09:34:51PM +0000, Oleinik, Alexander wrote:
> diff --git a/tests/fuzz/qos_fuzz.c b/tests/fuzz/qos_fuzz.c
> new file mode 100644
> index 0000000000..da76e28ca3
> --- /dev/null
> +++ b/tests/fuzz/qos_fuzz.c
> @@ -0,0 +1,232 @@
> +/*
> + * 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 <wordexp.h>

Is this header used in this source file?

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 19/21] fuzz: add virtio-net fuzz target
  2019-11-29 21:34 ` [PATCH v6 19/21] fuzz: add virtio-net fuzz target Oleinik, Alexander
@ 2020-01-03 11:30   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:30 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 534 bytes --]

On Fri, Nov 29, 2019 at 09:34:52PM +0000, Oleinik, Alexander wrote:
> The virtio-net fuzz target feeds inputs to all three virtio-net
> virtqueues, and uses forking to avoid leaking state between fuzz runs.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  tests/fuzz/Makefile.include  |   1 +
>  tests/fuzz/virtio_net_fuzz.c | 105 +++++++++++++++++++++++++++++++++++
>  2 files changed, 106 insertions(+)
>  create mode 100644 tests/fuzz/virtio_net_fuzz.c

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 20/21] fuzz: add virtio-scsi fuzz target
  2019-11-29 21:34 ` [PATCH v6 20/21] fuzz: add virtio-scsi fuzz target Oleinik, Alexander
@ 2020-01-03 11:30   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:30 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 602 bytes --]

On Fri, Nov 29, 2019 at 09:34:53PM +0000, Oleinik, Alexander 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>
> ---
>  tests/fuzz/Makefile.include   |   1 +
>  tests/fuzz/virtio_scsi_fuzz.c | 200 ++++++++++++++++++++++++++++++++++
>  2 files changed, 201 insertions(+)
>  create mode 100644 tests/fuzz/virtio_scsi_fuzz.c

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 21/21] fuzz: add documentation to docs/devel/
  2019-11-29 21:34 ` [PATCH v6 21/21] fuzz: add documentation to docs/devel/ Oleinik, Alexander
@ 2020-01-03 11:31   ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:31 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 333 bytes --]

On Fri, Nov 29, 2019 at 09:34:54PM +0000, Oleinik, Alexander wrote:
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>  docs/devel/fuzzing.txt | 119 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 119 insertions(+)
>  create mode 100644 docs/devel/fuzzing.txt

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 00/21] Add virtual device fuzzing support
  2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
                   ` (21 preceding siblings ...)
  2020-01-03  9:55 ` [PATCH v6 00/21] Add virtual device fuzzing support Stefan Hajnoczi
@ 2020-01-03 11:33 ` Stefan Hajnoczi
  22 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-03 11:33 UTC (permalink / raw)
  To: Oleinik, Alexander; +Cc: pbonzini, bsd, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1333 bytes --]

On Fri, Nov 29, 2019 at 09:34:35PM +0000, Oleinik, Alexander wrote:
> This series adds a framework for coverage-guided fuzzing of
> virtual-devices. Fuzzing targets are based on qtest and can make use of
> the libqos abstractions.
> 
> In this version, I added a virtio-scsi fuzzer. The actual fuzzing code
> is very similar to the the virtio-net fuzzer. I experimented with using
> a single fuzzer with device-specific initialization for each virtio
> device, but it did not come out as cleanly as I hoped, since I could not
> find an easy way to override the qos drivers for devices that have
> more-complete qos support (such as virtio-net), so these changes have
> not made it into v6.
> 
> V5/V6: (V5 did not have review tags)
>  * added virtio-scsi fuzzer
>  * add support for using fork-based fuzzers with multiple libfuzzer
>    workers
>  * misc fixes addressing V4 comments
>  * cleanup in-process handlers/globals in libqtest.c
>  * small fixes to fork-based fuzzing and support for multiple workers
>  * changes to the virtio-net fuzzer to kick after each vq add

Please run scripts/checkpatch.pl on all patches in case you haven't
already.

I have finished reviewing this revision and posted my Reviewed-by on
most patches.  Unless other feedback is raised the next revision could
be merged.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv
  2019-11-29 21:34 ` [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv Oleinik, Alexander
  2020-01-03 11:19   ` Stefan Hajnoczi
@ 2020-01-03 16:29   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 16:29 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel
  Cc: Laurent Vivier, pbonzini, Thomas Huth, bsd, stefanha

Hi Aleksander,

Typo in patch subject: "abstraction"

On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> This makes it simple to swap the transport functions for qtest commands
> to and from the qtest client. For example, now it is possible to
> directly pass qtest commands to a server handler that exists within the
> same process, without the standard way of writing to a file descriptor.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>   tests/libqtest.c | 50 +++++++++++++++++++++++++++++++++++++++---------
>   1 file changed, 41 insertions(+), 9 deletions(-)
> 
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 91e9cb220c..ac4b6ab5f0 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -35,6 +35,17 @@
>   #define SOCKET_TIMEOUT 50
>   #define SOCKET_MAX_FDS 16
>   
> +
> +typedef void (*QTestSendFn)(QTestState *s, const char *buf);
> +typedef void (*ExternalSendFn)(void *s, const char *buf);
> +typedef GString* (*QTestRecvFn)(QTestState *);
> +
> +typedef struct QTestClientTransportOps {
> +    QTestSendFn     send;

We use strlen() so we also send a send a string. Maybe rename it send_line?

Please add a comment here about what does each function handler in this 
structure.

> +    ExternalSendFn  external_send;

Is external_send used? Apparently in patch #12. Can you add it there, 
where it is used? I don't understand why we a "type-safe wrapper" is 
called 'external'.

> +    QTestRecvFn     recv_line;
> +} QTestTransportOps;
> +
>   struct QTestState
>   {
>       int fd;
> @@ -45,6 +56,7 @@ struct QTestState
>       bool big_endian;
>       bool irq_level[MAX_IRQ];
>       GString *rx;
> +    QTestTransportOps ops;
>   };
>   
>   static GHookList abrt_hooks;
> @@ -52,6 +64,14 @@ static struct sigaction sigact_old;
>   
>   static int qtest_query_target_endianness(QTestState *s);
>   
> +static void qtest_client_socket_send(QTestState*, const char *buf);
> +static void socket_send(int fd, const char *buf, size_t size);
> +
> +static GString *qtest_client_socket_recv_line(QTestState *);
> +
> +static void qtest_client_set_tx_handler(QTestState *s, QTestSendFn send);
> +static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv);
> +
>   static int init_socket(const char *socket_path)
>   {
>       struct sockaddr_un addr;
> @@ -234,6 +254,9 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
>       sock = init_socket(socket_path);
>       qmpsock = init_socket(qmp_socket_path);
>   
> +    qtest_client_set_rx_handler(s, qtest_client_socket_recv_line);
> +    qtest_client_set_tx_handler(s, qtest_client_socket_send);
> +
>       qtest_add_abrt_handler(kill_qemu_hook_func, s);
>   
>       command = g_strdup_printf("exec %s "
> @@ -379,13 +402,9 @@ static void socket_send(int fd, const char *buf, size_t size)
>       }
>   }
>   
> -static void socket_sendf(int fd, const char *fmt, va_list ap)
> +static void qtest_client_socket_send(QTestState *s, const char *buf)
>   {
> -    gchar *str = g_strdup_vprintf(fmt, ap);
> -    size_t size = strlen(str);
> -
> -    socket_send(fd, str, size);
> -    g_free(str);
> +    socket_send(s->fd, buf, strlen(buf));
>   }
>   
>   static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
> @@ -393,8 +412,11 @@ static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
>       va_list ap;
>   
>       va_start(ap, fmt);
> -    socket_sendf(s->fd, fmt, ap);
> +    gchar *str = g_strdup_vprintf(fmt, ap);
>       va_end(ap);
> +
> +    s->ops.send(s, str);
> +    g_free(str);
>   }
>   
>   /* Sends a message and file descriptors to the socket.
> @@ -431,7 +453,7 @@ static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
>       g_assert_cmpint(ret, >, 0);
>   }
>   
> -static GString *qtest_recv_line(QTestState *s)
> +static GString *qtest_client_socket_recv_line(QTestState *s)
>   {
>       GString *line;
>       size_t offset;
> @@ -468,7 +490,7 @@ static gchar **qtest_rsp(QTestState *s, int expected_args)
>       int i;
>   
>   redo:
> -    line = qtest_recv_line(s);
> +    line = s->ops.recv_line(s);
>       words = g_strsplit(line->str, " ", 0);
>       g_string_free(line, TRUE);
>   
> @@ -1337,3 +1359,13 @@ void qmp_assert_error_class(QDict *rsp, const char *class)
>   
>       qobject_unref(rsp);
>   }
> +
> +static void qtest_client_set_tx_handler(QTestState *s,
> +                    QTestSendFn send)
> +{
> +    s->ops.send = send;
> +}
> +static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv)
> +{
> +    s->ops.recv_line = recv;
> +}
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 06/21] module: check module wasn't already initialized
  2019-11-29 21:34 ` [PATCH v6 06/21] module: check module wasn't already initialized Oleinik, Alexander
@ 2020-01-03 16:30   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 16:30 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel; +Cc: pbonzini, bsd, stefanha, Darren Kenny

On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> The virtual-device fuzzer must initialize QOM, prior to running
> vl:qemu_init, so that it can use the qos_graph to identify the arguments
> required to initialize a guest for libqos-assisted fuzzing. This change
> prevents errors when vl:qemu_init tries to (re)initialize the previously
> initialized QOM module.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Reviewed-by: Darren Kenny <darren.kenny@oracle.com>

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> ---
>   util/module.c | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/util/module.c b/util/module.c
> index e9fe3e5422..841e490e06 100644
> --- a/util/module.c
> +++ b/util/module.c
> @@ -30,6 +30,7 @@ typedef struct ModuleEntry
>   typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
>   
>   static ModuleTypeList init_type_list[MODULE_INIT_MAX];
> +static bool modules_init_done[MODULE_INIT_MAX];
>   
>   static ModuleTypeList dso_init_list;
>   
> @@ -91,11 +92,17 @@ void module_call_init(module_init_type type)
>       ModuleTypeList *l;
>       ModuleEntry *e;
>   
> +    if (modules_init_done[type]) {
> +        return;
> +    }
> +
>       l = find_type(type);
>   
>       QTAILQ_FOREACH(e, l, node) {
>           e->init();
>       }
> +
> +    modules_init_done[type] = true;
>   }
>   
>   #ifdef CONFIG_MODULES
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars
  2019-11-29 21:34 ` [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars Oleinik, Alexander
  2020-01-03 10:52   ` Stefan Hajnoczi
@ 2020-01-03 16:32   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 16:32 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel; +Cc: pbonzini, bsd, stefanha, Darren Kenny

On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> Most qos-related objects were specified in the qos-test-obj-y variable.
> qos-test-obj-y also included qos-test.o which defines a main().
> This made it difficult to repurpose qos-test-obj-y to link anything
> beside tests/qos-test against libqos. This change separates objects that
> are libqos-specific and ones that are qos-test specific into different
> variables.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Darren Kenny <darren.kenny@oracle.com>

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> ---
>   tests/Makefile.include | 71 +++++++++++++++++++++---------------------
>   1 file changed, 36 insertions(+), 35 deletions(-)
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 3669fd1dc3..031240df4b 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -703,52 +703,53 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y)
>   
>   libqgraph-obj-y = tests/libqos/qgraph.o
>   
> -libqos-obj-y = $(libqgraph-obj-y) tests/libqos/pci.o tests/libqos/fw_cfg.o
> -libqos-obj-y += tests/libqos/malloc.o
> -libqos-obj-y += tests/libqos/libqos.o
> -libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> +libqos-core-obj-y = $(libqgraph-obj-y) tests/libqos/pci.o tests/libqos/fw_cfg.o
> +libqos-core-obj-y += tests/libqos/malloc.o
> +libqos-core-obj-y += tests/libqos/libqos.o
> +libqos-spapr-obj-y = $(libqos-core-obj-y) tests/libqos/malloc-spapr.o
>   libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>   libqos-spapr-obj-y += tests/libqos/rtas.o
>   libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> -libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> +libqos-pc-obj-y = $(libqos-core-obj-y) tests/libqos/pci-pc.o
>   libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>   libqos-pc-obj-y += tests/libqos/ahci.o
>   libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
>   
>   # Devices
> -qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
> -qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
> -qos-test-obj-y += tests/libqos/e1000e.o
> -qos-test-obj-y += tests/libqos/i2c.o
> -qos-test-obj-y += tests/libqos/i2c-imx.o
> -qos-test-obj-y += tests/libqos/i2c-omap.o
> -qos-test-obj-y += tests/libqos/sdhci.o
> -qos-test-obj-y += tests/libqos/tpci200.o
> -qos-test-obj-y += tests/libqos/virtio.o
> -qos-test-obj-$(CONFIG_VIRTFS) += tests/libqos/virtio-9p.o
> -qos-test-obj-y += tests/libqos/virtio-balloon.o
> -qos-test-obj-y += tests/libqos/virtio-blk.o
> -qos-test-obj-y += tests/libqos/virtio-mmio.o
> -qos-test-obj-y += tests/libqos/virtio-net.o
> -qos-test-obj-y += tests/libqos/virtio-pci.o
> -qos-test-obj-y += tests/libqos/virtio-pci-modern.o
> -qos-test-obj-y += tests/libqos/virtio-rng.o
> -qos-test-obj-y += tests/libqos/virtio-scsi.o
> -qos-test-obj-y += tests/libqos/virtio-serial.o
> +libqos-obj-y = $(libqgraph-obj-y)
> +libqos-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
> +libqos-obj-y += tests/libqos/e1000e.o
> +libqos-obj-y += tests/libqos/i2c.o
> +libqos-obj-y += tests/libqos/i2c-imx.o
> +libqos-obj-y += tests/libqos/i2c-omap.o
> +libqos-obj-y += tests/libqos/sdhci.o
> +libqos-obj-y += tests/libqos/tpci200.o
> +libqos-obj-y += tests/libqos/virtio.o
> +libqos-obj-$(CONFIG_VIRTFS) += tests/libqos/virtio-9p.o
> +libqos-obj-y += tests/libqos/virtio-balloon.o
> +libqos-obj-y += tests/libqos/virtio-blk.o
> +libqos-obj-y += tests/libqos/virtio-mmio.o
> +libqos-obj-y += tests/libqos/virtio-net.o
> +libqos-obj-y += tests/libqos/virtio-pci.o
> +libqos-obj-y += tests/libqos/virtio-pci-modern.o
> +libqos-obj-y += tests/libqos/virtio-rng.o
> +libqos-obj-y += tests/libqos/virtio-scsi.o
> +libqos-obj-y += tests/libqos/virtio-serial.o
>   
>   # Machines
> -qos-test-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
> -qos-test-obj-y += tests/libqos/arm-imx25-pdk-machine.o
> -qos-test-obj-y += tests/libqos/arm-n800-machine.o
> -qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
> -qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
> -qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
> -qos-test-obj-y += tests/libqos/arm-virt-machine.o
> -qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
> -qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
> -qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
> +libqos-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
> +libqos-obj-y += tests/libqos/arm-imx25-pdk-machine.o
> +libqos-obj-y += tests/libqos/arm-n800-machine.o
> +libqos-obj-y += tests/libqos/arm-raspi2-machine.o
> +libqos-obj-y += tests/libqos/arm-sabrelite-machine.o
> +libqos-obj-y += tests/libqos/arm-smdkc210-machine.o
> +libqos-obj-y += tests/libqos/arm-virt-machine.o
> +libqos-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
> +libqos-obj-y += tests/libqos/ppc64_pseries-machine.o
> +libqos-obj-y += tests/libqos/x86_64_pc-machine.o
>   
>   # Tests
> +qos-test-obj-y = tests/qos-test.o
>   qos-test-obj-y += tests/ac97-test.o
>   qos-test-obj-y += tests/ds1338-test.o
>   qos-test-obj-y += tests/e1000-test.o
> @@ -780,7 +781,7 @@ check-unit-y += tests/test-qgraph$(EXESUF)
>   tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
>   
>   check-qtest-generic-y += tests/qos-test$(EXESUF)
> -tests/qos-test$(EXESUF): $(qos-test-obj-y)
> +tests/qos-test$(EXESUF): $(qos-test-obj-y) $(libqos-obj-y)
>   
>   tests/qmp-test$(EXESUF): tests/qmp-test.o
>   tests/qmp-cmd-test$(EXESUF): tests/qmp-cmd-test.o
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 10/21] libqos: move useful qos-test funcs to qos_external
  2019-11-29 21:34 ` [PATCH v6 10/21] libqos: move useful qos-test funcs to qos_external Oleinik, Alexander
@ 2020-01-03 16:36   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 16:36 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel
  Cc: Laurent Vivier, pbonzini, Thomas Huth, bsd, stefanha

On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> The moved functions are not specific to qos-test and might be useful
> elsewhere. For example the virtual-device fuzzer makes use of them for
> qos-assisted fuzz-targets.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>   tests/Makefile.include      |   1 +
>   tests/libqos/qos_external.c | 168 ++++++++++++++++++++++++++++++++++++
>   tests/libqos/qos_external.h |  28 ++++++
>   tests/qos-test.c            | 140 ++----------------------------
>   4 files changed, 202 insertions(+), 135 deletions(-)
>   create mode 100644 tests/libqos/qos_external.c
>   create mode 100644 tests/libqos/qos_external.h
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 031240df4b..79534e9b85 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -718,6 +718,7 @@ libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
>   # Devices
>   libqos-obj-y = $(libqgraph-obj-y)
>   libqos-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
> +libqos-obj-y += tests/libqos/qos_external.o
>   libqos-obj-y += tests/libqos/e1000e.o
>   libqos-obj-y += tests/libqos/i2c.o
>   libqos-obj-y += tests/libqos/i2c-imx.o
> diff --git a/tests/libqos/qos_external.c b/tests/libqos/qos_external.c
> new file mode 100644
> index 0000000000..398556dde0
> --- /dev/null
> +++ b/tests/libqos/qos_external.c
> @@ -0,0 +1,168 @@
> +/*
> + * libqos driver framework
> + *
> + * 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 <getopt.h>
> +#include "libqtest.h"
> +#include "qapi/qmp/qdict.h"
> +#include "qapi/qmp/qbool.h"
> +#include "qapi/qmp/qstring.h"
> +#include "qemu/module.h"
> +#include "qapi/qmp/qlist.h"
> +#include "libqos/malloc.h"
> +#include "libqos/qgraph.h"
> +#include "libqos/qgraph_internal.h"
> +#include "libqos/qos_external.h"
> +
> +
> +
> +void apply_to_node(const char *name, bool is_machine, bool is_abstract)
> +{
> +    char *machine_name = NULL;
> +    if (is_machine) {
> +        const char *arch = qtest_get_arch();
> +        machine_name = g_strconcat(arch, "/", name, NULL);
> +        name = machine_name;
> +    }
> +    qos_graph_node_set_availability(name, true);
> +    if (is_abstract) {
> +        qos_delete_cmd_line(name);
> +    }
> +    g_free(machine_name);
> +}
> +
> +/**
> + * apply_to_qlist(): using QMP queries QEMU for a list of
> + * machines and devices available, and sets the respective node
> + * as true. If a node is found, also all its produced and contained
> + * child are marked available.
> + *
> + * See qos_graph_node_set_availability() for more info
> + */
> +void apply_to_qlist(QList *list, bool is_machine)
> +{
> +    const QListEntry *p;
> +    const char *name;
> +    bool abstract;
> +    QDict *minfo;
> +    QObject *qobj;
> +    QString *qstr;
> +    QBool *qbool;
> +
> +    for (p = qlist_first(list); p; p = qlist_next(p)) {
> +        minfo = qobject_to(QDict, qlist_entry_obj(p));
> +        qobj = qdict_get(minfo, "name");
> +        qstr = qobject_to(QString, qobj);
> +        name = qstring_get_str(qstr);
> +
> +        qobj = qdict_get(minfo, "abstract");
> +        if (qobj) {
> +            qbool = qobject_to(QBool, qobj);
> +            abstract = qbool_get_bool(qbool);
> +        } else {
> +            abstract = false;
> +        }
> +
> +        apply_to_node(name, is_machine, abstract);
> +        qobj = qdict_get(minfo, "alias");
> +        if (qobj) {
> +            qstr = qobject_to(QString, qobj);
> +            name = qstring_get_str(qstr);
> +            apply_to_node(name, is_machine, abstract);
> +        }
> +    }
> +}
> +
> +QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
> +{
> +    return obj->get_driver(obj, "memory");
> +}
> +
> +/**
> + * allocate_objects(): given an array of nodes @arg,
> + * walks the path invoking all constructors and
> + * passing the corresponding parameter in order to
> + * continue the objects allocation.
> + * Once the test is reached, return the object it consumes.
> + *
> + * Since the machine and QEDGE_CONSUMED_BY nodes allocate
> + * memory in the constructor, g_test_queue_destroy is used so
> + * that after execution they can be safely free'd.  (The test's
> + * ->before callback is also welcome to use g_test_queue_destroy).
> + *
> + * Note: as specified in walk_path() too, @arg is an array of
> + * char *, where arg[0] is a pointer to the command line
> + * string that will be used to properly start QEMU when executing
> + * the test, and the remaining elements represent the actual objects
> + * that will be allocated.
> + */
> +void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
> +{
> +    int current = 0;
> +    QGuestAllocator *alloc;
> +    QOSGraphObject *parent = NULL;
> +    QOSGraphEdge *edge;
> +    QOSGraphNode *node;
> +    void *edge_arg;
> +    void *obj;
> +
> +    node = qos_graph_get_node(path[current]);
> +    g_assert(node->type == QNODE_MACHINE);
> +
> +    obj = qos_machine_new(node, qts);
> +    qos_object_queue_destroy(obj);
> +
> +    alloc = get_machine_allocator(obj);
> +    if (p_alloc) {
> +        *p_alloc = alloc;
> +    }
> +
> +    for (;;) {
> +        if (node->type != QNODE_INTERFACE) {
> +            qos_object_start_hw(obj);
> +            parent = obj;
> +        }
> +
> +        /* follow edge and get object for next node constructor */
> +        current++;
> +        edge = qos_graph_get_edge(path[current - 1], path[current]);
> +        node = qos_graph_get_node(path[current]);
> +
> +        if (node->type == QNODE_TEST) {
> +            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
> +            return obj;
> +        }
> +
> +        switch (qos_graph_edge_get_type(edge)) {
> +        case QEDGE_PRODUCES:
> +            obj = parent->get_driver(parent, path[current]);
> +            break;
> +
> +        case QEDGE_CONSUMED_BY:
> +            edge_arg = qos_graph_edge_get_arg(edge);
> +            obj = qos_driver_new(node, obj, alloc, edge_arg);
> +            qos_object_queue_destroy(obj);
> +            break;
> +
> +        case QEDGE_CONTAINS:
> +            obj = parent->get_device(parent, path[current]);
> +            break;
> +        }
> +    }
> +}
> +
> diff --git a/tests/libqos/qos_external.h b/tests/libqos/qos_external.h
> new file mode 100644
> index 0000000000..7b44930c55
> --- /dev/null
> +++ b/tests/libqos/qos_external.h
> @@ -0,0 +1,28 @@
> +/*
> + * libqos driver framework
> + *
> + * 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/>
> + */
> +
> +#ifndef QOS_EXTERNAL_H
> +#define QOS_EXTERNAL_H
> +#include "libqos/qgraph.h"
> +
> +void apply_to_node(const char *name, bool is_machine, bool is_abstract);
> +void apply_to_qlist(QList *list, bool is_machine);
> +QGuestAllocator *get_machine_allocator(QOSGraphObject *obj);
> +void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc);
> +
> +#endif
> diff --git a/tests/qos-test.c b/tests/qos-test.c
> index fd70d73ea5..9d02b83e24 100644
> --- a/tests/qos-test.c
> +++ b/tests/qos-test.c
> @@ -27,65 +27,11 @@
>   #include "libqos/malloc.h"
>   #include "libqos/qgraph.h"
>   #include "libqos/qgraph_internal.h"
> +#include "libqos/qos_external.h"
>   
>   static char *old_path;
>   
> -static void apply_to_node(const char *name, bool is_machine, bool is_abstract)
> -{
> -    char *machine_name = NULL;
> -    if (is_machine) {
> -        const char *arch = qtest_get_arch();
> -        machine_name = g_strconcat(arch, "/", name, NULL);
> -        name = machine_name;
> -    }
> -    qos_graph_node_set_availability(name, true);
> -    if (is_abstract) {
> -        qos_delete_cmd_line(name);
> -    }
> -    g_free(machine_name);
> -}
>   
> -/**
> - * apply_to_qlist(): using QMP queries QEMU for a list of
> - * machines and devices available, and sets the respective node
> - * as true. If a node is found, also all its produced and contained
> - * child are marked available.
> - *
> - * See qos_graph_node_set_availability() for more info
> - */
> -static void apply_to_qlist(QList *list, bool is_machine)
> -{
> -    const QListEntry *p;
> -    const char *name;
> -    bool abstract;
> -    QDict *minfo;
> -    QObject *qobj;
> -    QString *qstr;
> -    QBool *qbool;
> -
> -    for (p = qlist_first(list); p; p = qlist_next(p)) {
> -        minfo = qobject_to(QDict, qlist_entry_obj(p));
> -        qobj = qdict_get(minfo, "name");
> -        qstr = qobject_to(QString, qobj);
> -        name = qstring_get_str(qstr);
> -
> -        qobj = qdict_get(minfo, "abstract");
> -        if (qobj) {
> -            qbool = qobject_to(QBool, qobj);
> -            abstract = qbool_get_bool(qbool);
> -        } else {
> -            abstract = false;
> -        }
> -
> -        apply_to_node(name, is_machine, abstract);
> -        qobj = qdict_get(minfo, "alias");
> -        if (qobj) {
> -            qstr = qobject_to(QString, qobj);
> -            name = qstring_get_str(qstr);
> -            apply_to_node(name, is_machine, abstract);
> -        }
> -    }
> -}
>   
>   /**
>    * qos_set_machines_devices_available(): sets availability of qgraph
> @@ -129,10 +75,6 @@ static void qos_set_machines_devices_available(void)
>       qobject_unref(response);
>   }
>   
> -static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
> -{
> -    return obj->get_driver(obj, "memory");
> -}
>   
>   static void restart_qemu_or_continue(char *path)
>   {
> @@ -159,78 +101,6 @@ void qos_invalidate_command_line(void)
>       old_path = NULL;
>   }
>   
> -/**
> - * allocate_objects(): given an array of nodes @arg,
> - * walks the path invoking all constructors and
> - * passing the corresponding parameter in order to
> - * continue the objects allocation.
> - * Once the test is reached, return the object it consumes.
> - *
> - * Since the machine and QEDGE_CONSUMED_BY nodes allocate
> - * memory in the constructor, g_test_queue_destroy is used so
> - * that after execution they can be safely free'd.  (The test's
> - * ->before callback is also welcome to use g_test_queue_destroy).
> - *
> - * Note: as specified in walk_path() too, @arg is an array of
> - * char *, where arg[0] is a pointer to the command line
> - * string that will be used to properly start QEMU when executing
> - * the test, and the remaining elements represent the actual objects
> - * that will be allocated.
> - */
> -static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
> -{
> -    int current = 0;
> -    QGuestAllocator *alloc;
> -    QOSGraphObject *parent = NULL;
> -    QOSGraphEdge *edge;
> -    QOSGraphNode *node;
> -    void *edge_arg;
> -    void *obj;
> -
> -    node = qos_graph_get_node(path[current]);
> -    g_assert(node->type == QNODE_MACHINE);
> -
> -    obj = qos_machine_new(node, qts);
> -    qos_object_queue_destroy(obj);
> -
> -    alloc = get_machine_allocator(obj);
> -    if (p_alloc) {
> -        *p_alloc = alloc;
> -    }
> -
> -    for (;;) {
> -        if (node->type != QNODE_INTERFACE) {
> -            qos_object_start_hw(obj);
> -            parent = obj;
> -        }
> -
> -        /* follow edge and get object for next node constructor */
> -        current++;
> -        edge = qos_graph_get_edge(path[current - 1], path[current]);
> -        node = qos_graph_get_node(path[current]);
> -
> -        if (node->type == QNODE_TEST) {
> -            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
> -            return obj;
> -        }
> -
> -        switch (qos_graph_edge_get_type(edge)) {
> -        case QEDGE_PRODUCES:
> -            obj = parent->get_driver(parent, path[current]);
> -            break;
> -
> -        case QEDGE_CONSUMED_BY:
> -            edge_arg = qos_graph_edge_get_arg(edge);
> -            obj = qos_driver_new(node, obj, alloc, edge_arg);
> -            qos_object_queue_destroy(obj);
> -            break;
> -
> -        case QEDGE_CONTAINS:
> -            obj = parent->get_device(parent, path[current]);
> -            break;
> -        }
> -    }
> -}
>   
>   /* The argument to run_one_test, which is the test function that is registered
>    * with GTest, is a vector of strings.  The first item is the initial command
> @@ -239,14 +109,14 @@ static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_
>    */
>   static char **current_path;
>   
> -const char *qos_get_current_command_line(void)
> +void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
>   {
> -    return current_path[0];
> +    return allocate_objects(qts, current_path + 1, p_alloc);
>   }
>   
> -void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
> +const char *qos_get_current_command_line(void)
>   {
> -    return allocate_objects(qts, current_path + 1, p_alloc);
> +    return current_path[0];

I'm not sure why you switched these functions, this is confusing (and 
unrelated to the patch description). Can you keep the unmodified?
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

>   }
>   
>   /**
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps
  2019-11-29 21:34 ` [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps Oleinik, Alexander
  2020-01-03 11:10   ` Stefan Hajnoczi
@ 2020-01-03 16:45   ` Philippe Mathieu-Daudé
  2020-01-15 20:38     ` Alexander Bulekov
  1 sibling, 1 reply; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 16:45 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel
  Cc: Laurent Vivier, pbonzini, Thomas Huth, bsd, stefanha

On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> When using qtest "in-process" communication, qtest_sendf directly calls
> a function in the server (qtest.c). Previously, bufwrite used
> socket_send, which bypasses the TransportOps enabling the call into
> qtest.c. This change replaces the socket_send calls with ops->send,
> maintaining the benefits of the direct socket_send call, while adding
> support for in-process qtest calls.
> 
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> ---
>   tests/libqtest.c | 4 ++--
>   tests/libqtest.h | 3 +++
>   2 files changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index ac4b6ab5f0..a7df92319a 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -1080,8 +1080,8 @@ void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
>   
>       bdata = g_base64_encode(data, size);
>       qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
> -    socket_send(s->fd, bdata, strlen(bdata));
> -    socket_send(s->fd, "\n", 1);
> +    s->ops.send(s, bdata);
> +    s->ops.send(s, "\n");

Ah, is this the send_line() from patch #5?

Now it makes sense to move the send("\n") there and call it send_line().

Moving the send(\n) we get this in patch #5:

  static void qtest_client_socket_send_line(QTestState *s,
                                            const char *bufline)
  {
      socket_send(s->fd, bufline, strlen(bufline));
      socket_send(s->fd, "\n", 1);
  }

>       qtest_rsp(s, 0);
>       g_free(bdata);
>   }
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index c9e21e05b3..0e9b8908ef 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -729,4 +729,7 @@ bool qtest_probe_child(QTestState *s);
>    */
>   void qtest_set_expected_status(QTestState *s, int status);
>   
> +QTestState *qtest_inproc_init(bool log, const char* arch,
> +                    void (*send)(void*, const char*));
> +void qtest_client_inproc_recv(void *opaque, const char *str);
>   #endif
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 13/21] fuzz: add configure flag --enable-fuzzing
  2019-11-29 21:34 ` [PATCH v6 13/21] fuzz: add configure flag --enable-fuzzing Oleinik, Alexander
@ 2020-01-03 16:48   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 53+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-03 16:48 UTC (permalink / raw)
  To: Oleinik, Alexander, qemu-devel; +Cc: pbonzini, bsd, stefanha

On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>   configure | 39 +++++++++++++++++++++++++++++++++++++++
>   1 file changed, 39 insertions(+)
> 
> diff --git a/configure b/configure
> index 6099be1d84..5fb2494a8e 100755
> --- a/configure
> +++ b/configure
> @@ -504,6 +504,7 @@ debug_mutex="no"
>   libpmem=""
>   default_devices="yes"
>   plugins="no"
> +fuzzing="no"
>   
>   supported_cpu="no"
>   supported_os="no"
> @@ -633,6 +634,15 @@ int main(void) { return 0; }
>   EOF
>   }
>   
> +write_c_fuzzer_skeleton() {
> +    cat > $TMPC <<EOF
> +#include <stdint.h>
> +#include <sys/types.h>
> +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
> +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; }
> +EOF
> +}
> +
>   if check_define __linux__ ; then
>     targetos="Linux"
>   elif check_define _WIN32 ; then
> @@ -1539,6 +1549,10 @@ for opt do
>     ;;
>     --disable-plugins) plugins="no"
>     ;;
> +  --enable-fuzzing) fuzzing=yes
> +  ;;
> +  --disable-fuzzing) fuzzing=no
> +  ;;
>     *)
>         echo "ERROR: unknown option $opt"
>         echo "Try '$0 --help' for more information"
> @@ -6018,6 +6032,15 @@ EOF
>     fi
>   fi
>   
> +##########################################
> +# checks for fuzzer
> +if test "$fuzzing" = "yes" ; then
> +  write_c_fuzzer_skeleton
> +  if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address,fuzzer" ""; then
> +      have_fuzzer=yes
> +  fi
> +fi
> +
>   ##########################################
>   # check for libpmem
>   
> @@ -6599,6 +6622,7 @@ echo "libpmem support   $libpmem"
>   echo "libudev           $libudev"
>   echo "default devices   $default_devices"
>   echo "plugin support    $plugins"
> +echo "fuzzing support   $fuzzing"
>   
>   if test "$supported_cpu" = "no"; then
>       echo
> @@ -7435,6 +7459,16 @@ fi
>   if test "$sheepdog" = "yes" ; then
>     echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
>   fi
> +if test "$fuzzing" = "yes" ; then
> +  if test "$have_fuzzer" = "yes"; then
> +    FUZZ_LDFLAGS=" -fsanitize=address,fuzzer"
> +    FUZZ_CFLAGS=" -fsanitize=address,fuzzer"
> +    CFLAGS=" -fsanitize=address"
> +  else
> +    error_exit "Your compiler doesn't support -fsanitize=address,fuzzer"
> +    exit 1
> +  fi
> +fi
>   
>   if test "$plugins" = "yes" ; then
>       echo "CONFIG_PLUGIN=y" >> $config_host_mak
> @@ -7538,6 +7572,11 @@ if test "$libudev" != "no"; then
>       echo "CONFIG_LIBUDEV=y" >> $config_host_mak
>       echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak
>   fi
> +if test "$fuzzing" != "no"; then

I'd use '= "yes"' here to stay consistent.
Anyway:
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> +    echo "CONFIG_FUZZ=y" >> $config_host_mak
> +    echo "FUZZ_CFLAGS=$FUZZ_CFLAGS" >> $config_host_mak
> +    echo "FUZZ_LDFLAGS=$FUZZ_LDFLAGS" >> $config_host_mak
> +fi
>   
>   if test "$edk2_blobs" = "yes" ; then
>     echo "DECOMPRESS_EDK2_BLOBS=y" >> $config_host_mak
> 



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c
  2020-01-03  9:58   ` Stefan Hajnoczi
@ 2020-01-05 19:17     ` Alexander Bulekov
  0 siblings, 0 replies; 53+ messages in thread
From: Alexander Bulekov @ 2020-01-05 19:17 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: pbonzini, bsd, qemu-devel

On 200103 0958, Stefan Hajnoczi wrote:
> On Fri, Nov 29, 2019 at 09:34:36PM +0000, Oleinik, Alexander wrote:
> > @@ -3853,7 +3834,7 @@ int main(int argc, char **argv, char **envp)
> >      set_memory_options(&ram_slots, &maxram_size, machine_class);
> >  
> >      os_daemonize();
> > -    rcu_disable_atfork();
> > +    /* rcu_disable_atfork(); */
> >  
> >      if (pid_file && !qemu_write_pidfile(pid_file, &err)) {
> >          error_reportf_err(err, "cannot create PID file: ");
> 
> Did you find a solution for this?

Yes, though obviously it didn't make it into v6 :) I'm planning to just
check qtest_enabled(), since for now we are always using qtest.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv
  2020-01-03 11:01     ` Philippe Mathieu-Daudé
@ 2020-01-05 19:50       ` Alexander Bulekov
  0 siblings, 0 replies; 53+ messages in thread
From: Alexander Bulekov @ 2020-01-05 19:50 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Laurent Vivier, Thomas Huth, qemu-devel, bsd, stefanha, pbonzini

On 200103 1201, Philippe Mathieu-Daudé wrote:
> On 12/9/19 1:02 PM, Thomas Huth wrote:
> > On 29/11/2019 22.34, Oleinik, Alexander wrote:
> > > The names i2c_send and i2c_recv collide with functions defined in
> > > hw/i2c/core.c. This causes an error when linking against libqos and
> > > softmmu simultaneously (for example when using qtest inproc). Rename the
> > > libqos functions to avoid this.
> > > 
> > > Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> > > ---
> > >   tests/libqos/i2c.c   | 10 +++++-----
> > >   tests/libqos/i2c.h   |  4 ++--
> > >   tests/pca9552-test.c | 10 +++++-----
> > >   3 files changed, 12 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c
> > > index 156114e745..38f800dbab 100644
> > > --- a/tests/libqos/i2c.c
> > > +++ b/tests/libqos/i2c.c
> > > @@ -10,12 +10,12 @@
> > >   #include "libqos/i2c.h"
> > >   #include "libqtest.h"
> > > -void i2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
> > > +void qi2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len)
> > >   {
> > >       i2cdev->bus->send(i2cdev->bus, i2cdev->addr, buf, len);
> > >   }
> > > -void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
> > > +void qi2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len)
> > >   {
> > >       i2cdev->bus->recv(i2cdev->bus, i2cdev->addr, buf, len);
> > >   }
> > 
> > I'd prefer qos_i2c_send and qos_i2c_recv instead ... but that's just a
> > matter of taste.
> > 
> > Acked-by: Thomas Huth <thuth@redhat.com>
> 
> Agreed.
> 
> Renamed qos_*:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> 
Paolo originally suggested the qi2c names in the v3 patchset, since they
are consistent with the QI2CDevice struct and the qvirtio functions.
Prior to that they had worse i2c_test... names. Scanning through the
other function names in tests/libqos, it seems most qos_ functions are
related to the internals of the qos system (eg. qos_graph_init,
qos_node_create_machine ...), while q-prefixed functions are generally
hw-specific (eg. qpci_msix_enable, qfw_cfg_read_data,
qusb_pci_init_one). Of course this pattern isn't perfectly consistent
(eg. qos_init_sdhci_mm).

Unless there is something I'm missing, I'm leaning toward leaving the
functions named qi2c_recv, qi2c_send.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers
  2020-01-03 11:15   ` Stefan Hajnoczi
@ 2020-01-05 19:55     ` Alexander Bulekov
  2020-01-08 17:03       ` Stefan Hajnoczi
  0 siblings, 1 reply; 53+ messages in thread
From: Alexander Bulekov @ 2020-01-05 19:55 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Thomas Huth, pbonzini, bsd, qemu-devel, Laurent Vivier

On 200103 1115, Stefan Hajnoczi wrote:
> On Fri, Nov 29, 2019 at 09:34:47PM +0000, Oleinik, Alexander wrote:
> > +QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
> > +                    void (*send)(void*, const char*))
> > +{
> > +    QTestState *qts;
> > +    qts = g_new0(QTestState, 1);
> > +    *s = qts; /* Expose qts early on, since the query endianness relies on it */
> > +    qts->wstatus = 0;
> > +    for (int i = 0; i < MAX_IRQ; i++) {
> > +        qts->irq_level[i] = false;
> > +    }
> > +
> > +    qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line);
> > +
> > +    /* send() may not have a matching protoype, so use a type-safe wrapper */
> > +    qts->ops.external_send = send;
> > +    qtest_client_set_tx_handler(qts, send_wrapper);
> > +
> > +    qts->big_endian = qtest_query_target_endianness(qts);
> > +    gchar *bin_path = g_strconcat("/qemu-system-", arch, NULL);
> > +    setenv("QTEST_QEMU_BINARY", bin_path, 0);
> > +    g_free(bin_path);
> 
> Is this a dummy path that is needed to make other code happy?  Or does
> the user need to have an actual file at /qemu-system-ARCH?

Yes - with the inproc mode this is only needed to make qtest_get_arch
happy, which simply returns the suffix of the env variable. Standard
qtest initialization relies on it in qtest_init_without_qmp_handshake,
but that function is not used by the fuzzer.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers
  2020-01-05 19:55     ` Alexander Bulekov
@ 2020-01-08 17:03       ` Stefan Hajnoczi
  0 siblings, 0 replies; 53+ messages in thread
From: Stefan Hajnoczi @ 2020-01-08 17:03 UTC (permalink / raw)
  To: Alexander Bulekov
  Cc: Laurent Vivier, Thomas Huth, qemu-devel, bsd, Stefan Hajnoczi, pbonzini

[-- Attachment #1: Type: text/plain, Size: 1606 bytes --]

On Sun, Jan 05, 2020 at 02:55:44PM -0500, Alexander Bulekov wrote:
> On 200103 1115, Stefan Hajnoczi wrote:
> > On Fri, Nov 29, 2019 at 09:34:47PM +0000, Oleinik, Alexander wrote:
> > > +QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
> > > +                    void (*send)(void*, const char*))
> > > +{
> > > +    QTestState *qts;
> > > +    qts = g_new0(QTestState, 1);
> > > +    *s = qts; /* Expose qts early on, since the query endianness relies on it */
> > > +    qts->wstatus = 0;
> > > +    for (int i = 0; i < MAX_IRQ; i++) {
> > > +        qts->irq_level[i] = false;
> > > +    }
> > > +
> > > +    qtest_client_set_rx_handler(qts, qtest_client_inproc_recv_line);
> > > +
> > > +    /* send() may not have a matching protoype, so use a type-safe wrapper */
> > > +    qts->ops.external_send = send;
> > > +    qtest_client_set_tx_handler(qts, send_wrapper);
> > > +
> > > +    qts->big_endian = qtest_query_target_endianness(qts);
> > > +    gchar *bin_path = g_strconcat("/qemu-system-", arch, NULL);
> > > +    setenv("QTEST_QEMU_BINARY", bin_path, 0);
> > > +    g_free(bin_path);
> > 
> > Is this a dummy path that is needed to make other code happy?  Or does
> > the user need to have an actual file at /qemu-system-ARCH?
> 
> Yes - with the inproc mode this is only needed to make qtest_get_arch
> happy, which simply returns the suffix of the env variable. Standard
> qtest initialization relies on it in qtest_init_without_qmp_handshake,
> but that function is not used by the fuzzer.

Cool, please add a comment to the code.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps
  2020-01-03 16:45   ` Philippe Mathieu-Daudé
@ 2020-01-15 20:38     ` Alexander Bulekov
  0 siblings, 0 replies; 53+ messages in thread
From: Alexander Bulekov @ 2020-01-15 20:38 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Laurent Vivier, Thomas Huth, qemu-devel, bsd, stefanha, pbonzini

On 200103 1745, Philippe Mathieu-Daudé wrote:
> On 11/29/19 10:34 PM, Oleinik, Alexander wrote:
> > When using qtest "in-process" communication, qtest_sendf directly calls
> > a function in the server (qtest.c). Previously, bufwrite used
> > socket_send, which bypasses the TransportOps enabling the call into
> > qtest.c. This change replaces the socket_send calls with ops->send,
> > maintaining the benefits of the direct socket_send call, while adding
> > support for in-process qtest calls.
> > 
> > Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
> > ---
> >   tests/libqtest.c | 4 ++--
> >   tests/libqtest.h | 3 +++
> >   2 files changed, 5 insertions(+), 2 deletions(-)
> > 
> > diff --git a/tests/libqtest.c b/tests/libqtest.c
> > index ac4b6ab5f0..a7df92319a 100644
> > --- a/tests/libqtest.c
> > +++ b/tests/libqtest.c
> > @@ -1080,8 +1080,8 @@ void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
> >       bdata = g_base64_encode(data, size);
> >       qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
> > -    socket_send(s->fd, bdata, strlen(bdata));
> > -    socket_send(s->fd, "\n", 1);
> > +    s->ops.send(s, bdata);
> > +    s->ops.send(s, "\n");
> 
> Ah, is this the send_line() from patch #5?
> 
> Now it makes sense to move the send("\n") there and call it send_line().
> 
> Moving the send(\n) we get this in patch #5:
> 
>  static void qtest_client_socket_send_line(QTestState *s,
>                                            const char *bufline)
>  {
>      socket_send(s->fd, bufline, strlen(bufline));
>      socket_send(s->fd, "\n", 1);
>  }

Would this also involve changing all of the
qtest_{clock_step,in,out,read,write...} functions to remove the '\n'
from the calls to qtest_sendf? Not that it matters much, but it also
seems to double the number of syscalls needed to send each qtest
command.

> >       qtest_rsp(s, 0);
> >       g_free(bdata);
> >   }
> > diff --git a/tests/libqtest.h b/tests/libqtest.h
> > index c9e21e05b3..0e9b8908ef 100644
> > --- a/tests/libqtest.h
> > +++ b/tests/libqtest.h
> > @@ -729,4 +729,7 @@ bool qtest_probe_child(QTestState *s);
> >    */
> >   void qtest_set_expected_status(QTestState *s, int status);
> > +QTestState *qtest_inproc_init(bool log, const char* arch,
> > +                    void (*send)(void*, const char*));
> > +void qtest_client_inproc_recv(void *opaque, const char *str);
> >   #endif
> > 
> 


^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2020-01-15 20:40 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-29 21:34 [PATCH v6 00/21] Add virtual device fuzzing support Oleinik, Alexander
2019-11-29 21:34 ` [PATCH v6 01/21] softmmu: split off vl.c:main() into main.c Oleinik, Alexander
2020-01-03  9:58   ` Stefan Hajnoczi
2020-01-05 19:17     ` Alexander Bulekov
2019-11-29 21:34 ` [PATCH v6 02/21] libqos: Rename i2c_send and i2c_recv Oleinik, Alexander
2019-12-09 12:02   ` Thomas Huth
2020-01-03 11:01     ` Philippe Mathieu-Daudé
2020-01-05 19:50       ` Alexander Bulekov
2020-01-03  9:58   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 03/21] fuzz: Add FUZZ_TARGET module type Oleinik, Alexander
2019-11-29 21:34 ` [PATCH v6 04/21] qtest: add qtest_server_send abstraction Oleinik, Alexander
2019-12-09 14:37   ` Thomas Huth
2019-11-29 21:34 ` [PATCH v6 05/21] libqtest: Add a layer of abstraciton to send/recv Oleinik, Alexander
2020-01-03 11:19   ` Stefan Hajnoczi
2020-01-03 16:29   ` Philippe Mathieu-Daudé
2019-11-29 21:34 ` [PATCH v6 06/21] module: check module wasn't already initialized Oleinik, Alexander
2020-01-03 16:30   ` Philippe Mathieu-Daudé
2019-11-29 21:34 ` [PATCH v6 07/21] qtest: add in-process incoming command handler Oleinik, Alexander
2020-01-03 11:19   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 08/21] tests: provide test variables to other targets Oleinik, Alexander
2020-01-03 10:51   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 09/21] libqos: split qos-test and libqos makefile vars Oleinik, Alexander
2020-01-03 10:52   ` Stefan Hajnoczi
2020-01-03 16:32   ` Philippe Mathieu-Daudé
2019-11-29 21:34 ` [PATCH v6 10/21] libqos: move useful qos-test funcs to qos_external Oleinik, Alexander
2020-01-03 16:36   ` Philippe Mathieu-Daudé
2019-11-29 21:34 ` [PATCH v6 11/21] libqtest: make bufwrite rely on the TransportOps Oleinik, Alexander
2020-01-03 11:10   ` Stefan Hajnoczi
2020-01-03 16:45   ` Philippe Mathieu-Daudé
2020-01-15 20:38     ` Alexander Bulekov
2019-11-29 21:34 ` [PATCH v6 12/21] libqtest: add in-process qtest.c tx/rx handlers Oleinik, Alexander
2020-01-03 11:15   ` Stefan Hajnoczi
2020-01-05 19:55     ` Alexander Bulekov
2020-01-08 17:03       ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 14/21] fuzz: Add target/fuzz makefile rules Oleinik, Alexander
2020-01-03 11:18   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 13/21] fuzz: add configure flag --enable-fuzzing Oleinik, Alexander
2020-01-03 16:48   ` Philippe Mathieu-Daudé
2019-11-29 21:34 ` [PATCH v6 15/21] fuzz: add fuzzer skeleton Oleinik, Alexander
2020-01-03 11:25   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 16/21] fuzz: add support for fork-based fuzzing Oleinik, Alexander
2020-01-03 11:27   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 17/21] fuzz: add support for qos-assisted fuzz targets Oleinik, Alexander
2020-01-03 11:28   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 19/21] fuzz: add virtio-net fuzz target Oleinik, Alexander
2020-01-03 11:30   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 18/21] fuzz: add i440fx fuzz targets Oleinik, Alexander
2019-11-29 21:34 ` [PATCH v6 20/21] fuzz: add virtio-scsi fuzz target Oleinik, Alexander
2020-01-03 11:30   ` Stefan Hajnoczi
2019-11-29 21:34 ` [PATCH v6 21/21] fuzz: add documentation to docs/devel/ Oleinik, Alexander
2020-01-03 11:31   ` Stefan Hajnoczi
2020-01-03  9:55 ` [PATCH v6 00/21] Add virtual device fuzzing support Stefan Hajnoczi
2020-01-03 11:33 ` Stefan Hajnoczi

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.