Trinity v1.9 releases: A Linux System call fuzz tester
Trinity: Linux system call fuzzer
What is it?
The basic idea is fairly simple. As ‘fuzz testing‘ suggests, we call syscalls at random, with random arguments. Not an original idea, and one that has been done many times before on Linux, and on other operating systems. Where Trinity differs is that the arguments it passes are not purely random.
We found some bugs in the past by just passing random values, but once the *really* dumb bugs were found, these dumb fuzzers would just run and run. The problem was if a syscall took, for example, a file descriptor as an argument, one of the first things it would try to do was validate that fd. Being garbage, the kernel would just reject it as -EINVAL of course. So on startup, Trinity creates a list of file descriptors, by opening pipes, scanning sysfs, procfs, /dev, and creates a bunch of sockets using random network protocols. Then when a syscall needs an fd, it gets passed one of these at random.
File descriptors aren’t the only thing Trinity knows about. Every syscall has its arguments annotated, and where possible it tries to provide something at least semi-sensible. “Length” arguments, for example, get passed one of a whole bunch of potentially interesting values.
Trinity also shares those file descriptors between multiple processes, which causes havoc sometimes.
If a child process successfully creates a mmap, the pointer is stored, and fed to subsequent syscalls, sometimes with hilarious results.
Trinity supports Alpha, Aarch64, ARM, i386, IA-64, MIPS, PowerPC-32, PowerPC-64, S390, S390x, SPARC-64, x86-64.
Adding support for additional architectures is a small amount of work mostly involving just defining the order of the syscall table.
Trinity is a system call fuzzer which employs some techniques to pass semi-intelligent arguments to the syscalls being called.
The intelligence features include:
- If a system call expects a certain datatype as an argument (for example a file descriptor) it gets passed one. This is the reason for the slow initial startup, as it generates a list of fd’s of files it can read from /sys, /proc and /dev and then supplements this with fd’s for various network protocol sockets. (Information on which protocols succeed/fail is cached on the first run, greatly increasing the speed of subsequent runs).
- If a system call only accepts certain values as an argument, (for example a ‘flags’ field), Trinity has a list of all the valid flags that may be passed. Just to throw a spanner in the works, occasionally, it will bitflip one of the flags, just to make things more interesting.
- If a system call only takes a range of values, the random value passed is biased to usually fit within that range.
Trinity logs it’s output to files (1 for each child process), and fsync’s the files before it actually makes the system call. This way, should you trigger something which panics the kernel, you should be able to find out exactly what happened by examining the log.
There are several test harnesses provided (test-*.sh), which run trinity in various modes and takes care of things like CPU affinity and makes sure it runs from the tmp directory. (Handy for cleaning up any garbage named files; just rm -rf tmp afterward)
git clone https://github.com/kernelslacker/trinity.git
make && make install
Copyright (C) daveti