#!/bin/sh # # american fuzzy lop++ - QEMU build script # -------------------------------------- # # Originally written by Andrew Griffiths and # Michal Zalewski # # TCG instrumentation and block chaining support by Andrea Biondo # # # QEMU 5+ port, TCG thread-safety, CompareCoverage and NeverZero # counters by Andrea Fioraldi # # Copyright 2015, 2016, 2017 Google Inc. All rights reserved. # Copyright 2019-2022 AFLplusplus Project. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # https://www.apache.org/licenses/LICENSE-2.0 # # This script downloads, patches, and builds a version of QEMU with # minor tweaks to allow non-instrumented binaries to be run under # afl-fuzz. # # The modifications reside in patches/*. The standalone QEMU binary # will be written to ../afl-qemu-trace. # QEMUAFL_VERSION="$(cat ./QEMUAFL_VERSION)" echo "=================================================" echo " QemuAFL build script" echo "=================================================" echo echo "[*] Performing basic sanity checks..." if [ ! "`uname -s`" = "Linux" ]; then echo "[-] Error: QEMU instrumentation is supported only on Linux." exit 0 fi if [ ! -f "../config.h" ]; then echo "[-] Error: key files not found - wrong working directory?" exit 1 fi if [ ! -f "../afl-showmap" ]; then echo "[-] Error: ../afl-showmap not found - compile AFL first!" exit 1 fi if echo "$CC" | grep -qF /afl-; then echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool." exit 1 fi echo "[+] All checks passed!" echo "[*] Making sure qemuafl is checked out" git status 1>/dev/null 2>/dev/null if [ $? -eq 0 ]; then echo "[*] initializing qemuafl submodule" git submodule init || exit 1 git submodule update ./qemuafl 2>/dev/null # ignore errors else echo "[*] cloning qemuafl" test -d qemuafl/.git || { CNT=1 while [ '!' -d qemuafl/.git -a "$CNT" -lt 4 ]; do echo "Trying to clone qemuafl (attempt $CNT/3)" git clone --depth 1 https://github.com/AFLplusplus/qemuafl CNT=`expr "$CNT" + 1` done } fi test -e qemuafl/.git || { echo "[-] Not checked out, please install git or check your internet connection." ; exit 1 ; } echo "[+] Got qemuafl." cd "qemuafl" || exit 1 if [ -n "$NO_CHECKOUT" ]; then echo "[*] Skipping checkout to $QEMUAFL_VERSION" else echo "[*] Checking out $QEMUAFL_VERSION" sh -c 'git stash' 1>/dev/null 2>/dev/null git pull git checkout "$QEMUAFL_VERSION" || echo Warning: could not check out to commit $QEMUAFL_VERSION fi echo "[*] Making sure imported headers matches" cp "../../include/config.h" "./qemuafl/imported/" || exit 1 cp "../../include/cmplog.h" "./qemuafl/imported/" || exit 1 cp "../../include/snapshot-inl.h" "./qemuafl/imported/" || exit 1 cp "../../include/types.h" "./qemuafl/imported/" || exit 1 if [ -n "$HOST" ]; then echo "[+] Configuring host architecture to $HOST..." CROSS_PREFIX=$HOST- else CROSS_PREFIX= fi echo "[*] Configuring QEMU for $CPU_TARGET..." ORIG_CPU_TARGET="$CPU_TARGET" if [ "$ORIG_CPU_TARGET" = "" ]; then CPU_TARGET="`uname -m`" test "$CPU_TARGET" = "i686" && CPU_TARGET="i386" test "$CPU_TARGET" = "arm64v8" && CPU_TARGET="aarch64" case "$CPU_TARGET" in *arm*) CPU_TARGET="arm" ;; esac fi echo "Building for CPU target $CPU_TARGET" # --enable-pie seems to give a couple of exec's a second performance # improvement, much to my surprise. Not sure how universal this is.. QEMU_CONF_FLAGS=" \ --audio-drv-list= \ --disable-blobs \ --disable-bochs \ --disable-brlapi \ --disable-bsd-user \ --disable-bzip2 \ --disable-cap-ng \ --disable-cloop \ --disable-curl \ --disable-curses \ --disable-dmg \ --disable-fdt \ --disable-gcrypt \ --disable-glusterfs \ --disable-gnutls \ --disable-gtk \ --disable-guest-agent \ --disable-iconv \ --disable-libiscsi \ --disable-libnfs \ --disable-libssh \ --disable-libusb \ --disable-linux-aio \ --disable-live-block-migration \ --disable-lzo \ --disable-nettle \ --disable-numa \ --disable-opengl \ --disable-parallels \ --disable-plugins \ --disable-qcow1 \ --disable-qed \ --disable-rbd \ --disable-rdma \ --disable-replication \ --disable-sdl \ --disable-seccomp \ --disable-sheepdog \ --disable-smartcard \ --disable-snappy \ --disable-spice \ --disable-system \ --disable-tools \ --disable-tpm \ --disable-usb-redir \ --disable-vde \ --disable-vdi \ --disable-vhost-crypto \ --disable-vhost-kernel \ --disable-vhost-net \ --disable-vhost-scsi \ --disable-vhost-user \ --disable-vhost-vdpa \ --disable-vhost-vsock \ --disable-virglrenderer \ --disable-virtfs \ --disable-vnc \ --disable-vnc-jpeg \ --disable-vnc-png \ --disable-vnc-sasl \ --disable-vte \ --disable-vvfat \ --disable-xen \ --disable-xen-pci-passthrough \ --disable-xfsctl \ --target-list="${CPU_TARGET}-linux-user" \ --without-default-devices \ " if [ -n "${CROSS_PREFIX}" ]; then QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS --cross-prefix=$CROSS_PREFIX" fi if [ "$STATIC" = "1" ]; then echo Building STATIC binary # static PIE causes https://github.com/AFLplusplus/AFLplusplus/issues/892 QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \ --static --disable-pie \ --extra-cflags=-DAFL_QEMU_STATIC_BUILD=1 \ " else QEMU_CONF_FLAGS="${QEMU_CONF_FLAGS} --enable-pie " fi if [ "$DEBUG" = "1" ]; then echo Building DEBUG binary # --enable-gcov might go here but incurs a mesonbuild error on meson # versions prior to 0.56: # https://github.com/qemu/meson/commit/903d5dd8a7dc1d6f8bef79e66d6ebc07c QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \ --disable-strip \ --enable-debug \ --enable-debug-info \ --enable-debug-mutex \ --enable-debug-stack-usage \ --enable-debug-tcg \ --enable-qom-cast-debug \ --enable-werror \ " else QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \ --disable-debug-info \ --disable-debug-mutex \ --disable-debug-tcg \ --disable-qom-cast-debug \ --disable-stack-protector \ --disable-werror \ " fi if [ "$PROFILING" = "1" ]; then echo Building PROFILED binary QEMU_CONF_FLAGS="$QEMU_CONF_FLAGS \ --enable-gprof \ --enable-profiler \ " fi # shellcheck disable=SC2086 ./configure $QEMU_CONF_FLAGS || exit 1 echo "[+] Configuration complete." echo "[*] Attempting to build QEMU (fingers crossed!)..." make -j$(nproc) || exit 1 echo "[+] Build process successful!" echo "[*] Copying binary..." cp -f "build/${CPU_TARGET}-linux-user/qemu-${CPU_TARGET}" "../../afl-qemu-trace" || exit 1 cd .. ls -l ../afl-qemu-trace || exit 1 echo "[+] Successfully created '../afl-qemu-trace'." if [ "$ORIG_CPU_TARGET" = "" ]; then echo "[*] Testing the build..." cd .. make >/dev/null || exit 1 cc test-instr.c -o test-instr || exit 1 unset AFL_INST_RATIO export ASAN_OPTIONS=detect_leaks=0 echo "[*] Comparing two afl-showmap -Q outputs..." echo 0 | ./afl-showmap -m none -Q -q -o .test-instr0 ./test-instr || exit 1 echo 1 | ./afl-showmap -m none -Q -q -o .test-instr1 ./test-instr || exit 1 rm -f test-instr cmp -s .test-instr0 .test-instr1 DR="$?" rm -f .test-instr0 .test-instr1 if [ "$DR" = "0" ]; then echo "[-] Error: afl-qemu-trace instrumentation doesn't seem to work!" exit 1 fi echo "[+] Instrumentation tests passed. " echo "[+] All set, you can now use the -Q mode in afl-fuzz!" cd qemu_mode || exit 1 else echo "[!] Note: can't test instrumentation when CPU_TARGET set." echo "[+] All set, you can now (hopefully) use the -Q mode in afl-fuzz!" fi ORIG_CROSS="$CROSS" if [ "$ORIG_CROSS" = "" ]; then CROSS=$CPU_TARGET-linux-gnu-gcc if ! command -v "$CROSS" > /dev/null then # works on Arch Linux CROSS=$CPU_TARGET-pc-linux-gnu-gcc fi if ! command -v "$CROSS" > /dev/null && [ "$CPU_TARGET" = "i386" ] then CROSS=i686-linux-gnu-gcc if ! command -v "$CROSS" > /dev/null then # works on Arch Linux CROSS=i686-pc-linux-gnu-gcc fi if ! command -v "$CROSS" > /dev/null && [ "`uname -m`" = "x86_64" ] then # set -m32 test "$CC" = "" && CC="gcc" CROSS="$CC" CROSS_FLAGS=-m32 fi fi fi if ! command -v "$CROSS" > /dev/null ; then if [ "$CPU_TARGET" = "$(uname -m)" ] ; then echo "[+] Building afl++ qemu support libraries with CC=$CC" echo "[+] Building libcompcov ..." make -C libcompcov && echo "[+] libcompcov ready" echo "[+] Building unsigaction ..." make -C unsigaction && echo "[+] unsigaction ready" echo "[+] Building libqasan ..." make -C libqasan && echo "[+] unsigaction ready" echo "[+] Building qemu libfuzzer helpers ..." make -C ../utils/aflpp_driver else echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction" fi else echo "[+] Building afl++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\"" echo "[+] Building libcompcov ..." make -C libcompcov CC="$CROSS $CROSS_FLAGS" && echo "[+] libcompcov ready" echo "[+] Building unsigaction ..." make -C unsigaction CC="$CROSS $CROSS_FLAGS" && echo "[+] unsigaction ready" echo "[+] Building libqasan ..." make -C libqasan CC="$CROSS $CROSS_FLAGS" && echo "[+] unsigaction ready" fi echo "[+] All done for qemu_mode, enjoy!" exit 0