afl-fuzz on ppc
afl-fuzz gives you great fuzzer coverage for very little investment of development time. Its primary target platform is Linux on x86 / x86-64, however since the introduction of LLVM mode / afl-clang-fast
, the docs (link is to an unofficial mirror) offer some hope for those of us working on less mainstream architectures:
The instrumentation is CPU-independent. At least in principle, you should be able to rely on it to fuzz programs on non-x86 architectures (after building afl-fuzz with
AFL_NO_X86=1
).
This is, however, the grand total of the documentation available for using afl on other architectures. I’m pleased to report that it works in practice as well as principle, though it’s not straight forward. Here is what I did to start fuzzing with afl when cross compiling for PowerPC targets (ppc & ppc64).
(Update 2017-07-17: minor improvements and a cleaner approach that doesn’t involve installing afl.)
- Prerequisites
- Aside: cross compilation with clang
- Cross compile afl-fuzz and the afl runtime
- Usage
- Summary
Prerequisites
For this to work you need to be able to compile the software to be fuzzed with vanilla clang and successfully run it on the target. How you do this depends on your software, see below for some difficulties I encountered.
Then you need to compile the afl LLVM mode compilers in the usual fashion for your host system, we’re going to put it in a directory called afl-cross
:
Aside: cross compilation with clang
This isn’t afl specific, but is another problem I needed to solve before I could use afl’s LLVM mode compiler.
On the one hand, cross compiling with clang is a breeze because it has built in support for it - you don’t need to compile a dedicated cross-compiler for the job. On the other hand….
With gcc cross compilation we normally specify two different paths - the sysroot for the target headers, and the path to the host’s cross compilation tools. clang doesn’t support this concept properly, having only the concept of the sysroot where it expects everything to be. As clang doesn’t have full support for cross compiling to ppc, it still needs to use your cross-tools version of ld and as. To fix this you can use the undocumented -B
switch which instructs clang to search for its guts there first, before its standard paths. Very unsatisfactory, but it does work. You get an invocation that looks like this:
Actually working out the correct magic-target-triple was far harder than it should have been. Hopefully these improvements to clang will be implemented to help you enumerate the supported targets - until then, searching + guessing was all I had. 32bit ppc target triples seem to take the form powerpc-<vendor>-linux
.
If you’re cross compiling for a target that has full support in LLVM then this should be a lot easier.
Cross compile afl-fuzz and the afl runtime
Now we need two things that are compiled to run on the ppc target: afl-fuzz
(and any other utilities like afl-analyze); and the tiny blob of afl code that afl-clang-fast
will add to every object you compile - afl-llvm-rt.o
(and potentially its 64bit companion). Unpack another copy of afl into a new directory, let’s call it afl-target
. The appropriate invocation will look something like:
(I’m using export to avoid repeating CFLAGS for each make command, and a ( subshell )
so the export doesn’t taint the parent.)
Note that the final step in the Makefile is to run a test by compiling something and executing it - this will fail, because the host architecture is different to the target. That’s fine.
Now replace the cross-compiler’s version of this object with the target one, so our cross compiling afl-clang-fast
injects the right code:
Usage
At this point everything just works. Cross compile your target software, e.g. with CC="/path/to/afl-cross/afl-clang-fast" CFLAGS="<all-the-flags>" ./configure && make
; copy the instrumented binaries to the target; copy afl-fuzz
from the afl-target
directory to the target; and fuzz in the normal way.
Summary
You can use afl on non-x86 targets, but need to (a) be able to cross compile for your target with clang, and (b) compile the target architecture variant of afl-llvm-rt*.o
for use by the host version of afl-clang-fast
. afl-fuzz
and other utilities compiled for the target can then be copied on to the target, enabling you to start torturing non-x86 software.