docs/fuzzing.md
This document is for bpftrace developers.
Fuzzing is a method to find bugs in a program automatically. In fuzzing, a fuzzer generates the program input and give it and observes whether the program crashes or not. The most commonly used fuzzing method is called gray box fuzzing, which uses coverage (which parts the program executes) information to generate input efficiently.
Fuzzing can be divided into two types according to the target of fuzzing: one that targets the entire program for fuzzing, such as AFL, and the other that targets a specific function, such as libFuzzer. In the former case, a fuzzer generates and supplies the program's input, so you don't need to modify the program. This is not always efficient for large programs, but still can find many bugs. The latter is efficient for a function to be fuzzed because a fuzzer directly targets the function, but we need to write some glue code to connect a fuzzer and the function.
Before starting, it is highly recommended to read the AFL or AFLPlusPlus documentation.
The fuzzing setup relies on nix. See the nix instructions.
To use AFL, we need to compile the program with the AFL compiler. If you are
using nix, you would enter a development shell and build as follows:
nix develop #.bpftrace-fuzz
CC=afl-clang-fast CXX=afl-clang-fast++ cmake -B build-fuzz -DCMAKE_BUILD_TYPE=Debug -DBUILD_ASAN=1
then, in order to build the tree:
cd build-fuzz && AFL_USE_ASAN=1 make -j$(nproc)
Note that the address sanitizer might take a lot of memory. If you want to fuzz
without it, please remove AFL_USE_ASAN and -DBUILD_ASAN.
AFL recommends some settings for efficient fuzzing:
echo core | sudo tee -a /proc/sys/kernel/core_pattern
cd /sys/devices/system/cpu
echo performance | sudo tee cpu*/cpufreq/scaling_governor
Then, fuzz away! AFL and the address sanitizer have a lot of settings, so
please read documentation for the details. The currently recommended way to run
the fuzzer is by using the --test=codegen mode and providing overrides:
AFL_NO_AFFINITY=1 \
ASAN_OPTIONS=abort_on_error=1,symbolize=0 \
BPFTRACE_BTF= \
afl-fuzz -a text -M 0 -m none -i ./input -o ./output -t 3000 -- \
src/bpftrace --test=codegen @@ 2>/dev/null
In the above, -i specifics the input directory, and -o specifies the output
directory. In the input directory, you need to put something to start fuzzing.
The most simple example is echo a > input/a. More sophisticated inputs can be
created by using sample bpftrace programs from the source directory, tests or
other locations. If some inputs that cause a program crash is found,
output/crashes contains them.
The timeout for each execution (in milliseconds) is provided by -t.
Finally, '@@' will be replaced by the input file generated by the fuzzer.