This guide covers the installation of the complete ThreadFuzzer framework.
To specifically test AFL++ fuzzing for OpenThread, refer to the instructions in AFL++_Comparison/README.md.
Run the setup script to install dependencies, pull submodules, and apply necessary patches:
chmod +x setup.sh && sudo ./setup.shsudo docker build --pull --progress=plain -t thread_fuzzer:latest .Building the container might cause the following error: "/usr/bin/ld: warning: ../libs/libpcap/libpcap.a(pcap-linux.o) has a section extending past end of file". This means that the libpcap.a file downloaded from the repo (in third-party/wdissector/libs/libpcap) is broken. It should be about 2.7MB big, not 3.3MB. Try downloading it on its own, or try getting the correct libpcap.a from the libpcap repo.
sudo docker run --rm -it thread_fuzzerInside the container, all commands should be run without
sudo.
src/— Source filesinclude/— Header filesthird-party/— Third-party librariescommon/— Common shared librariesscripts/— Utility scriptsseeds/— Crash reproduction seedscoverage_log/— Coverage data from fuzzing runslogs/— Logs from fuzzer runsconfigs/— Configuration files:Fuzzing_Settings/— Core fuzzer settingsFuzzing_Strategies/— Fuzzing strategy configurations
sudo ./build/ThreadFuzzer [MAIN CONFIG] [FUZZ STRATEGY 1] ... [FUZZ STRATEGY N]sudo ./build/ThreadFuzzer configs/Fuzzing_Settings/main_config.json configs/Fuzzing_Strategies/random_config.jsonFor pairing Matter devices, we use chip-tool. This means the Docker container needs access to Bluetooth via sharing dbus of the host and USB access to the RCP. Be careful to not restart dbus in the container as this might lead to all kinds of mayhem on the host.
Also, make sure that mdns is not running on the host to avoid a race condition on network interface.
One can run the container using the following:
sudo docker run -v /var/run/dbus/:/var/run/dbus/:z --privileged --name=threadfuzzer --rm -it thread_fuzzer
DISCLAIMER: using the --privileged flag is considered unsafe! A slightly safer (non-privileged) way:
sudo docker run --security-opt apparmor=unconfined -v build:/app/ThreadFuzzer/build -v /var:/var -v /proc:/proc -v /run/dbus:/run/dbus -v logs:/app/ThreadFuzzer/logs --device=/dev/net/tun --device=/dev/ttyACM0 --device=/dev/ttyUSB0 --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --name=threadfuzzer --rm -it thread_fuzzer
Or more readable:
sudo docker run --security-opt apparmor=unconfined \
-v build:/app/ThreadFuzzer/build \
-v /var:/var \
-v /proc:/proc \
-v /run/dbus:/run/dbus \
-v logs:/app/ThreadFuzzer/logs \
--device=/dev/net/tun \
--device=/dev/ttyACM0 \
--device=/dev/ttyUSB0 \
--cap-add=NET_ADMIN \
--cap-add=SYS_PTRACE \
--name=threadfuzzer --rm -it thread_fuzzer
In here, ttyACM0 is the RCP, ttyUSB0 the controller for the physical device, a simple arduino. /dev/net/tun and the volumes are needed for the otbr. --cap-add is needed for creating a dummy0 network interface. Note that the volumes include the otbr settings, therefore they persist after the container is shut down.
Note for Ubuntu 24.04 If
apparmorstarts complaining about rsyslogd on the host (seedmesg), then disable it (on the host):
sudo ln -s /etc/apparmor.d/usr.sbin.rsyslogd /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.rsyslogd
Also note that one might have to disable mDNS and avahi-daemon on the host to avoid conflicts with the container. The reason is that we need access to dbus for working with the OpenThread RCP, so we share the directory, including mDNS specific ones.
A provided entrypoint script will make sure parts are correctly set up and and shut down (mainly rsyslog and mdns).
ThreadFuzzer restart and factoryresets devices via serial communication to a microcontroller board (like an Arduino) which provides power to the device and switches the button. The semantics of the protocol can be found in eve_sensor.cpp
./build/ThreadFuzzer configs/Fuzzing_Settings/phys_main_config.json configs/Fuzzing_Strategies/reboot_cnt_config.json
To reproduce predefined crashes (1–6) for virtual devices, replace X with the crash number:
sudo ./build/ThreadFuzzer seeds/crash_seeds/Crash_X/main_config.json seeds/crash_seeds/Crash_X/none_config.jsonFor physical devices. Put the right config file into configs/Fuzzing_Strategies/reboot_cnt_config.json with flag seed_paths and
enable use_existing_seeds.
Note: This cannot be done from within a Docker container.
Use the appropriate script to generate figures:
./scripts/visualize_coverage_results_greybox.sh./scripts/visualize_coverage_results_blackbox.sh./scripts/visualize_coverage_results_tlv_fuzzer.sh./scripts/visualize_coverage_results_mtd.sh
Due to a known ASan issue (see this Stack Overflow thread for details), address space layout randomization (ASLR) should be disabled to ensure stable fuzzing runs. Run the following command before starting the fuzzer, regardless of whether you are using Docker or a native setup:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_spaceWDissector is buggy, unorganized, and potentially unsafe. Always run with AddressSanitizer enabled due to possible memory leaks.
To use custom Wireshark profiles, place them in the bin/ws/ directory.