cclangfuzzing

How to force fuzzing yield coverage data?


I'm using AFL++ 4.0c to fuzz my app. It basically wraps clang compiler too instrument my code with fuzzing shenanigans. As well I provide coverage flags:

--coverage -g -fprofile-instr-generate -fcoverage-mapping

Then I try to launch my app with fuzzer

env PARAM=paramstuff                 \ # setup some env 
afl-fuzz -x dicts/dicts -f file.txt  \ # setup afl flags
-i input -o output                   \ # input and output for afl
--                                   \
./myapp --flag --flag2 --flag3        # flags for my app

It fuzzes just fine, but coverage profile is written empty.

Fuzzer works until stopped via CTRL+C. App stops the same way.


Solution

  • In my case AFL used fork server to fuzz parts of my app:

    #ifdef __AFL_HAVE_MANUAL_CONTROL
    SSH_TRACE(0, ("AFL INIT"));
      __AFL_INIT();
      while (__AFL_LOOP(1000)) {
    #endif
      /*
      * regular code to fuzz goes here
      */
    #ifdef __AFL_HAVE_MANUAL_CONTROL 
      }
    #endif
    

    So proper finalization never triggered and coverage data never dumped to profile.raw. So to force it to dump data manually I called __llvm_profile_write_file(); right after closing bracket of afl loop in the last #ifndef section. For gcc instrumentation exist similar function __gcov_flush().

    Couple notes for those who fuzz things:

    1. Don't put dump function inside fuzzing loop - it will drastically slow fuzzing performance and your profile will grow very rapidly. One such loop was able to spam about 1 GiB to profile. It probably will exhaust your disc space before you receive proper fuzzing results.
    2. Put dump function into #ifndef guards otherwise it will mess up with regular coverage dump when you just run app. Unless you close your forked processes with __exit() and know what you are doing.