This is an old revision of the document!
The purpose of this exercise is to identify where bottlenecks appear in a real-world application. For this we will use perf and American Fuzzy Lop (AFL).
afl is a fuzzing tool. Fuzzing is the process of detecting bugs empirically. Starting from a seed input file, a certain program is executed and its behavior observed. The meaning of “behavior” is not fixed, but in the simplest sense, let's say that it means “order in which instructions are executed”. After executing the binary under test, the fuzzer will mutate the input file. Following another execution, with the updated input, the fuzzer decides whether or not the mutations were useful. This determination is made based on deviations from known paths during runtime. Fuzzers usually run over a period of days, weeks, or even months, all in the hope of finding an input that crashes the program.
First, let's compile AFL and all related tools. We initialize / update a few environment variables to make them more accessible.
$ git clone https://github.com/google/AFL $ pushd AFL $ make -j $(nproc) $ export PATH="${PATH}:$(pwd)" $ export AFL_PATH="$(pwd)" $ popd
Now, check that it worked:
$ afl-fuzz --help $ afl-gcc --version
The program under test will be fuzzgoat, a vulnerable program made for the express purpose of illustrating fuzzer behaviour. To prepare the program for fuzzing, the source code has to be compiled with afl-gcc. afl-gcc is a wrapper over gcc that statically instruments the compiled program. This analysis code that is introduced is leveraged by afl-fuzz to track what branches are taken during execution. In turn, this information is used to guide the input mutation procedure.
$ git clone https://github.com/fuzzstati0n/fuzzgoat.git $ pushd fuzzgoat $ CC=afl-gcc make $ popd
If everything went well, we finally have our instrumented binary. Time to run afl. For this, we will use the sample seed files provided by fuzzgoat. Here is how we call afl-fuzz:
-i
flag specifies the directory containing the initial seed-o
flag specifies the active workspace for the afl instance--
separates the afl flag from the binary invocation command--
separator is how the target binary would normally be invoked in bash; the only difference is that the input file name will be replaced by @@
$ afl-fuzz -i fuzzgoat/in -o afl_output -- ./fuzzgoat/fuzzgoat @@
If you look in the afl_output/ directory, you will see a few files and directories; here is what they are:
@@
in the program invocation.
$ perf record -e <event> <command recorded>
$ perf record -e cycles afl-fuzz -i ./fuzzgoat/in -o afl_out -- ./fuzzgoat/fuzzgoat @@ #and let it run for a few minutes $ perf report #to print the recorded info
As a result you should get a report showing a list of the most used functions. Make sure to add a ss of it.