Search code examples
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.

  • If some of my configuration is off and fuzzer fails to properly start the profile generated by coverage is not empty as well as .gcda output. How to allow fuzzer to trigger dump coverage as well?
  • if I launch my app with params profile also generated

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.