diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-07-21 10:24:38 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-07-21 10:24:38 +0100 |
commit | 90218a9a393c7925f330e7dcc08658e2a01d3bd4 (patch) | |
tree | 6f21ee31b7408198bc21391806e04010b076e5f2 | |
parent | af3d69058e09bede9900f266a618ed11f76f49f3 (diff) | |
parent | 7ad36e2e241bd924f774a1f9fb208c102da58e50 (diff) | |
download | qemu-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.yml | 22 | ||||
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rwxr-xr-x | configure | 10 | ||||
-rw-r--r-- | docs/devel/fuzzing.txt | 63 | ||||
-rw-r--r-- | hw/arm/allwinner-h3.c | 1 | ||||
-rw-r--r-- | hw/arm/msf2-soc.c | 9 | ||||
-rw-r--r-- | hw/arm/xlnx-versal.c | 1 | ||||
-rw-r--r-- | hw/arm/xlnx-zynqmp.c | 1 | ||||
-rw-r--r-- | hw/dma/sparc32_dma.c | 1 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 1 | ||||
-rwxr-xr-x | scripts/oss-fuzz/build.sh | 2 | ||||
-rw-r--r-- | tests/qtest/fuzz/fuzz.c | 12 |
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> @@ -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=")) { |