lxfuzz is a grey-box kernel fuzzer used for linux. it is scalable because of qemu being used to emulate in a way to be able to freely choose the number of instances and their memory.
first, install build dependencies (example debian-based):
wget git make gcc g++ flex bc bison pkg-config ninja-build libssl-dev libglib2.0-dev bzip2 libpixman-1-dev libelf-dev libncurses5-dev
of course, you will need a properly built linux kernel. following options should be enabled
CONFIG_USER_NS=y
CONFIG_NET_DEV_REFCNT_TRACKER=y
CONFIG_NET_NS_REFCNT_TRACKER=y
CONFIG_KASAN=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_KCOV=y # make sure /sys/kernel/debug/kcov is rw for user
CONFIG_KCOV_INSTRUMENT_ALL=y
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NET_9P=y
CONFIG_NET_9P_DEBUG=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_DEBUG_INFO=y
# CONFIG_RANDOMIZE_BASE is not set
enabling extra options that add more code to be fuzzed is always a good idea
now, to build the fuzzer simply run
make all
this will build a custom qemu emulator (x86-64) plus the fuzzer, a reproducer and manager programs for both of those.
before running the manager, you have to configure how QEMU should run your kernel. you can do that by editing the cmdline.cfg
file (which already contains an example configuration)
you're completely free in choosing how the kernel should be running. however make sure to have qemu exit on a kernel panic or similar. be careful to use the modified qemu emulator. (located in ./tools/qemu-7.1.0/build/
)
if everything is set up you can start the fuzzing manager
./fuzz_manager -n <instances> [--timeout <inactive log timeout>] [--daemon] [--userns]
with -n
, you can choose as many qemu instances as your hardware can take.
--timeout
specifies in seconds, how long no log activity should be ignored, until the fuzz_manager
checks for hangs or crashes. (default 60s)
use --daemon
to run the fuzzer as a daemon in the background.
--userns
tells the fuzzer to make use of user namespaces.
lxfuzz uses kcov for coverage information gaining. reached addresses in the kernel are saved in ./coverage/kcov.txt
, which is accessible by the guests and host. it is essential for lxfuzz
to function properly, so make sure the path exists. this information can also be processed by syzkallers's syz-cover
.
all fuzzing logs are saved in ./kernel/data/
. each instance got an own directory in which each core/thread got an own log file.
WARNING: the log folders and files grow extremely large after some time. make sure to keep track of them and keep removing old log data (i.e. by a shell script)
if the manager encounters a crash, the whole log directory of the corresponding instance is copied and saved. the active logfiles get cleared whenever a crash or hang occurs
to reproduce crashes, copy the folder containing the crashes to the default startup working directory of the machine alongside with the reproducer
binary. make sure the folder is named crash/
. running repro_manager
will try to reproduce the crash and will notify if successful. you can try to reduce the log data in crash/
while still reproducing successfully, until you get to a point where you're able to understand the crash and create a POC.