aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-07-21 10:24:38 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-07-21 10:24:38 +0100
commit90218a9a393c7925f330e7dcc08658e2a01d3bd4 (patch)
tree6f21ee31b7408198bc21391806e04010b076e5f2
parentaf3d69058e09bede9900f266a618ed11f76f49f3 (diff)
parent7ad36e2e241bd924f774a1f9fb208c102da58e50 (diff)
downloadqemu-90218a9a393c7925f330e7dcc08658e2a01d3bd4.zip
qemu-90218a9a393c7925f330e7dcc08658e2a01d3bd4.tar.gz
qemu-90218a9a393c7925f330e7dcc08658e2a01d3bd4.tar.bz2
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2020-07-21' into staging
* Fix memory leak in fuzzer * Fuzzer documentation updates * Some other minor fuzzer updates * Fix "make check-qtest SPEED=slow" (bug in msf2 instance_init) # gpg: Signature made Tue 21 Jul 2020 07:48:10 BST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * remotes/huth-gitlab/tags/pull-request-2020-07-21: hw: Mark nd_table[] misuse in realize methods FIXME msf2: Unbreak device-list-properties for "msf-soc" MAINTAINERS: Extend the device fuzzing section docs/fuzz: add instructions for generating a coverage report docs/fuzz: add information about useful libFuzzer flags docs/fuzz: describe building fuzzers with enable-sanitizers fuzz: build without AddressSanitizer, by default gitlab-ci.yml: Add oss-fuzz build tests fuzz: Fix leak when assembling datadir path string scripts/oss-fuzz: Limit target list to i386-softmmu Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--.gitlab-ci.yml22
-rw-r--r--MAINTAINERS2
-rwxr-xr-xconfigure10
-rw-r--r--docs/devel/fuzzing.txt63
-rw-r--r--hw/arm/allwinner-h3.c1
-rw-r--r--hw/arm/msf2-soc.c9
-rw-r--r--hw/arm/xlnx-versal.c1
-rw-r--r--hw/arm/xlnx-zynqmp.c1
-rw-r--r--hw/dma/sparc32_dma.c1
-rw-r--r--hw/riscv/sifive_u.c1
-rwxr-xr-xscripts/oss-fuzz/build.sh2
-rw-r--r--tests/qtest/fuzz/fuzz.c12
12 files changed, 96 insertions, 29 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 41597c3..362e5ee 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -164,22 +164,20 @@ build-clang:
ppc-softmmu s390x-softmmu arm-linux-user
MAKE_CHECK_ARGS: check
-build-fuzzer:
+build-oss-fuzz:
<<: *native_build_job_definition
variables:
IMAGE: fedora
script:
- - mkdir build
- - cd build
- - ../configure --cc=clang --cxx=clang++ --enable-fuzzing
- --enable-sanitizers --target-list=x86_64-softmmu
- - make -j"$JOBS" all check-build x86_64-softmmu/fuzz
- - make check
- - for fuzzer in i440fx-qos-fork-fuzz i440fx-qos-noreset-fuzz
- i440fx-qtest-reboot-fuzz virtio-scsi-flags-fuzz virtio-scsi-fuzz ; do
- echo Testing ${fuzzer} ... ;
- x86_64-softmmu/qemu-fuzz-x86_64 --fuzz-target=${fuzzer} -runs=1000
- || exit 1 ;
+ - mkdir build-oss-fuzz
+ - CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
+ ./scripts/oss-fuzz/build.sh
+ - for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
+ | grep -v slirp); do
+ grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
+ echo Testing ${fuzzer} ... ;
+ ASAN_OPTIONS="fast_unwind_on_malloc=0"
+ "${fuzzer}" -runs=1000 -seed=1 || exit 1 ;
done
build-tci:
diff --git a/MAINTAINERS b/MAINTAINERS
index 5e86168..3395abd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2449,9 +2449,11 @@ M: Alexander Bulekov <alxndr@bu.edu>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
+R: Thomas Huth <thuth@redhat.com>
S: Maintained
F: tests/qtest/fuzz/
F: scripts/oss-fuzz/
+F: docs/devel/fuzzing.txt
Register API
M: Alistair Francis <alistair@alistair23.me>
diff --git a/configure b/configure
index 33cee41..4bd80ed 100755
--- a/configure
+++ b/configure
@@ -6337,7 +6337,7 @@ fi
# checks for fuzzer
if test "$fuzzing" = "yes" ; then
write_c_fuzzer_skeleton
- if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address,fuzzer" ""; then
+ if compile_prog "$CPU_CFLAGS -Werror -fsanitize=fuzzer" ""; then
have_fuzzer=yes
fi
fi
@@ -7893,11 +7893,11 @@ if test "$have_mlockall" = "yes" ; then
fi
if test "$fuzzing" = "yes" ; then
if test "$have_fuzzer" = "yes"; then
- FUZZ_LDFLAGS=" -fsanitize=address,fuzzer"
- FUZZ_CFLAGS=" -fsanitize=address,fuzzer"
- CFLAGS="$CFLAGS -fsanitize=address,fuzzer-no-link"
+ FUZZ_LDFLAGS=" -fsanitize=fuzzer"
+ FUZZ_CFLAGS=" -fsanitize=fuzzer"
+ CFLAGS="$CFLAGS -fsanitize=fuzzer-no-link"
else
- error_exit "Your compiler doesn't support -fsanitize=address,fuzzer"
+ error_exit "Your compiler doesn't support -fsanitize=fuzzer"
exit 1
fi
fi
diff --git a/docs/devel/fuzzing.txt b/docs/devel/fuzzing.txt
index db5641d..96d71c9 100644
--- a/docs/devel/fuzzing.txt
+++ b/docs/devel/fuzzing.txt
@@ -23,9 +23,12 @@ 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):
+Configure with (substitute the clang binaries with the version you installed).
+Here, enable-sanitizers, is optional but it allows us to reliably detect bugs
+such as out-of-bounds accesses, use-after-frees, double-frees etc.
- CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing
+ CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing \
+ --enable-sanitizers
Fuzz targets are built similarly to system/softmmu:
@@ -45,6 +48,62 @@ 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.
+== Useful libFuzzer flags ==
+
+As mentioned above, libFuzzer accepts some arguments. Passing -help=1 will list
+the available arguments. In particular, these arguments might be helpful:
+
+$CORPUS_DIR/ : Specify a directory as the last argument to libFuzzer. libFuzzer
+stores each "interesting" input in this corpus directory. The next time you run
+libFuzzer, it will read all of the inputs from the corpus, and continue fuzzing
+from there. You can also specify multiple directories. libFuzzer loads existing
+inputs from all specified directories, but will only write new ones to the
+first one specified.
+
+-max_len=4096 : specify the maximum byte-length of the inputs libFuzzer will
+generate.
+
+-close_fd_mask={1,2,3} : close, stderr, or both. Useful for targets that
+trigger many debug/error messages, or create output on the serial console.
+
+-jobs=4 -workers=4 : These arguments configure libFuzzer to run 4 fuzzers in
+parallel (4 fuzzing jobs in 4 worker processes). Alternatively, with only
+-jobs=N, libFuzzer automatically spawns a number of workers less than or equal
+to half the available CPU cores. Replace 4 with a number appropriate for your
+machine. Make sure to specify a $CORPUS_DIR, which will allow the parallel
+fuzzers to share information about the interesting inputs they find.
+
+-use_value_profile=1 : For each comparison operation, libFuzzer computes
+(caller_pc&4095) | (popcnt(Arg1 ^ Arg2) << 12) and places this in the coverage
+table. Useful for targets with "magic" constants. If Arg1 came from the fuzzer's
+input and Arg2 is a magic constant, then each time the Hamming distance
+between Arg1 and Arg2 decreases, libFuzzer adds the input to the corpus.
+
+-shrink=1 : Tries to make elements of the corpus "smaller". Might lead to
+better coverage performance, depending on the target.
+
+Note that libFuzzer's exact behavior will depend on the version of
+clang and libFuzzer used to build the device fuzzers.
+
+== Generating Coverage Reports ==
+Code coverage is a crucial metric for evaluating a fuzzer's performance.
+libFuzzer's output provides a "cov: " column that provides a total number of
+unique blocks/edges covered. To examine coverage on a line-by-line basis we
+can use Clang coverage:
+
+ 1. Configure libFuzzer to store a corpus of all interesting inputs (see
+ CORPUS_DIR above)
+ 2. ./configure the QEMU build with:
+ --enable-fuzzing \
+ --extra-cflags="-fprofile-instr-generate -fcoverage-mapping"
+ 3. Re-run the fuzzer. Specify $CORPUS_DIR/* as an argument, telling libfuzzer
+ to execute all of the inputs in $CORPUS_DIR and exit. Once the process
+ exits, you should find a file, "default.profraw" in the working directory.
+ 4. Execute these commands to generate a detailed HTML coverage-report:
+ llvm-profdata merge -output=default.profdata default.profraw
+ llvm-cov show ./path/to/qemu-fuzz-i386 -instr-profile=default.profdata \
+ --format html -output-dir=/path/to/output/report
+
== Adding a new fuzzer ==
Coverage over virtual devices can be improved by adding additional fuzzers.
Fuzzers are kept in tests/qtest/fuzz/ and should be added to
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 8e09468e..ff92ded 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -358,6 +358,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
"sd-bus");
/* EMAC */
+ /* FIXME use qdev NIC properties instead of nd_table[] */
if (nd_table[0].used) {
qemu_check_nic_model(&nd_table[0], TYPE_AW_SUN8I_EMAC);
qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c
index 16bb7c9..33ea7df 100644
--- a/hw/arm/msf2-soc.c
+++ b/hw/arm/msf2-soc.c
@@ -82,10 +82,6 @@ static void m2sxxx_soc_initfn(Object *obj)
}
object_initialize_child(obj, "emac", &s->emac, TYPE_MSS_EMAC);
- if (nd_table[0].used) {
- qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC);
- qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
- }
}
static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -187,6 +183,11 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
g_free(bus_name);
}
+ /* FIXME use qdev NIC properties instead of nd_table[] */
+ if (nd_table[0].used) {
+ qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC);
+ qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
+ }
dev = DEVICE(&s->emac);
object_property_set_link(OBJECT(&s->emac), "ahb-bus",
OBJECT(get_system_memory()), &error_abort);
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index ead038b..e3aa4bd 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -160,6 +160,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i],
TYPE_CADENCE_GEM);
dev = DEVICE(&s->lpd.iou.gem[i]);
+ /* FIXME use qdev NIC properties instead of nd_table[] */
if (nd->used) {
qemu_check_nic_model(nd, "cadence_gem");
qdev_set_nic_properties(dev, nd);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 772cfa3..5855e5d 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -455,6 +455,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
NICInfo *nd = &nd_table[i];
+ /* FIXME use qdev NIC properties instead of nd_table[] */
if (nd->used) {
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index 9459178..bcd1626 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -341,6 +341,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp)
DeviceState *d;
NICInfo *nd = &nd_table[0];
+ /* FIXME use qdev NIC properties instead of nd_table[] */
qemu_check_nic_model(nd, TYPE_LANCE);
d = qdev_new(TYPE_LANCE);
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 19a976c..e5682c3 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -714,6 +714,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
+ /* FIXME use qdev NIC properties instead of nd_table[] */
if (nd->used) {
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(DEVICE(&s->gem), nd);
diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh
index f5cee3d..a07b302 100755
--- a/scripts/oss-fuzz/build.sh
+++ b/scripts/oss-fuzz/build.sh
@@ -68,7 +68,7 @@ mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here
# Build once to get the list of dynamic lib paths, and copy them over
../configure --disable-werror --cc="$CC" --cxx="$CXX" \
- --extra-cflags="$EXTRA_CFLAGS"
+ --extra-cflags="$EXTRA_CFLAGS" --target-list="i386-softmmu"
if ! make CONFIG_FUZZ=y CFLAGS="$LIB_FUZZING_ENGINE" "-j$(nproc)" \
i386-softmmu/fuzz; then
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
index 6bc17ef..031594a 100644
--- a/tests/qtest/fuzz/fuzz.c
+++ b/tests/qtest/fuzz/fuzz.c
@@ -143,7 +143,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
{
char *target_name;
- char *dir;
+ char *bindir, *datadir;
bool serialize = false;
/* Initialize qgraph and modules */
@@ -164,11 +164,13 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
* location of the executable. Using this we add exec_dir/pc-bios to
* the datadirs.
*/
- dir = g_build_filename(g_path_get_dirname(**argv), "pc-bios", NULL);
- if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
- qemu_add_data_dir(dir);
+ bindir = g_path_get_dirname(**argv);
+ datadir = g_build_filename(bindir, "pc-bios", NULL);
+ g_free(bindir);
+ if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) {
+ qemu_add_data_dir(datadir);
}
- g_free(dir);
+ g_free(datadir);
} else if (*argc > 1) { /* The target is specified as an argument */
target_name = (*argv)[1];
if (!strstr(target_name, "--fuzz-target=")) {