VirtFuzz is a Linux Kernel Fuzzer that uses VirtIO to provide inputs into the kernels subsystem. It is built with LibAFL.
Read our paper: Sönke Huster, Matthias Hollick, Jiska Classen: "To Boldly Go Where No Fuzzer Has Gone Before: Finding Bugs in Linux’ Wireless Stacks through VirtIO Devices". 45th IEEE Symposium on Security and Privacy (S&P), 2024.
- Rust with the cargo toolchain
- Patched QEMU
- Image for VM
- Patched Kernel
Please see QEMUs requirements for building here. QEMU with our universal VirtIO device is built as follows:
curl https://download.qemu.org/qemu-8.2.2.tar.xz -o qemu.tar.xz
tar xvJf qemu.tar.xz
mv qemu-8.2.2 qemu
cd qemu
patch -p1 < $SCRIPT_DIR/../qemu-patch.patch
mkdir build
cd build
../configure --target-list=x86_64-softmmu
make -j$(nproc)
This script is adopted from Syzkaller. To generate a guestimage for the VM, run the following:
cd guestimage
./create-image.sh -d stretch
Finally, VirtFuzz requires a patched kernel. Therefore, pull a kernel version and apply our patches. For example:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v6.0
../virtfuzz/kernel-patches/apply.sh
# Depending on the target, apply the patches to annotate for a specific device
../virtfuzz/kernel-patches/annotate-80211.sh
# Make the config
make x86_64_defconfig
make kvm_guest.config
scripts/kconfig/merge_config.sh -m .config ../virtfuzz/kernel-config/base.config
# For example enable KASAN
scripts/kconfig/merge_config.sh -m .config ../virtfuzz/kernel-config/kasan.config
make olddefconfig
make -j$(nproc)
The following programs exist:
- virtfuzz-fuzz - the fuzzer
- virtfuzz-proxy - the proxy
- virtfuzz-replay - several utility scripts to e.g. minimize and replay crashes
See cargo run --release --bin virtfuzz-fuzz
for all options.
For example, to fuzz the WLAN stack compiled in the requirements, run the following:
export QEMU=PATH_TO-qemu-system-x86_64
export IMAGE=guestimage/stretch.img
export KERNEL=PATH_TO/linux/arch/x86/boot/bzImage
cargo run --release --package virtfuzz-fuzz -- --device-definition device-definitions/hwsim-scan.json --cores 0-1 --stages standard
Now, the fuzzer runs two instances on the 802.11 stack through the mac802.11_hwsim driver.
Run cargo run --release --package virtfuzz-fuzz -- --help
to see all available options.
During the development, several options to support fuzzing where introduced. We'll explain selected ones here in the following:
By now, a JSON file with a device definition can be passed to our fuzzer with the argument --device-definition
. Still, pre-built device definitions can be used instead, using the --device
argument.
-d, --device <DEVICE>
Device that should be fuzzed
[possible values: bluetooth, bluetooth-scan, net, wifi-scan, wifi-ap, wifi-ibss, wifi-syzkaller, console, input]
--device-definition <DEVICE_DEFINITION>
A JSON device defintion to be used instead of --device
The argument --stages
chooses the kind of coverage that should be used: Either AFL-Map style (standard) or tracking comparisons (cmplog).
-s, --stages <STAGES>
Stages to be used
[possible values: standard, cmplog]
Some subsystems, e.g., the Bluetooth subsystem, usually exchange some messages for initialization with the hardware before being fully available. To speed up fuzzing, a PCAP file with such a recorded initialization can be provided. When the VM starts, the fuzzer first sends the messages from the PCAP file before starting to fuzz. See our recorded example in resources/setup.pcap
.
--init-path <INIT_PATH>
Path to a PCAP file containing the initialization sequence
Similarly, wait until the VM sends a first frame before starting to fuzz.
--wait-for-rx
Start fuzzing after receiving a frame from the VM
If the VM sends a command, the fuzzer fakes a command complete message when provided with the following argument.
--bt-fake-cc
Respond to Bluetooth commands with dummy command complete frames
Our fuzzer evolved from a Linux Kernel fuzzer purely focused on the Bluetooth stack to a more universal kernel fuzzer.