Home | History | Annotate | Download | only in afl
      1 //===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //===----------------------------------------------------------------------===//
      8 
      9 /* This file allows to fuzz libFuzzer-style target functions
     10  (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
     11 
     12 Usage:
     13 ################################################################################
     14 cat << EOF > test_fuzzer.cc
     15 #include <stdint.h>
     16 #include <stddef.h>
     17 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
     18   if (size > 0 && data[0] == 'H')
     19     if (size > 1 && data[1] == 'I')
     20        if (size > 2 && data[2] == '!')
     21        __builtin_trap();
     22   return 0;
     23 }
     24 EOF
     25 # Build your target with -fsanitize-coverage=trace-pc using fresh clang.
     26 clang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c
     27 # Build afl-llvm-rt.o.c from the AFL distribution.
     28 clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
     29 # Build this file, link it with afl-llvm-rt.o.o and the target code.
     30 clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
     31 # Run AFL:
     32 rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
     33 $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
     34 ################################################################################
     35 Environment Variables:
     36 There are a few environment variables that can be set to use features that
     37 afl-fuzz doesn't have.
     38 
     39 AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
     40 specified. If the file does not exist, it is created. This is useful for getting
     41 stack traces (when using ASAN for example) or original error messages on hard to
     42 reproduce bugs.
     43 
     44 AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
     45 statistics to the file specified. Currently these are peak_rss_mb
     46 (the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
     47 the file does not exist it is created. If the file does exist then
     48 afl_driver assumes it was restarted by afl-fuzz and will try to read old
     49 statistics from the file. If that fails then the process will quit.
     50 
     51 */
     52 #include <assert.h>
     53 #include <stdio.h>
     54 #include <stdint.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <unistd.h>
     58 #include <errno.h>
     59 #include <signal.h>
     60 #include <sys/resource.h>
     61 #include <sys/time.h>
     62 // Platform detection. Copied from FuzzerInternal.h
     63 #ifdef __linux__
     64 #define LIBFUZZER_LINUX 1
     65 #define LIBFUZZER_APPLE 0
     66 #elif __APPLE__
     67 #define LIBFUZZER_LINUX 0
     68 #define LIBFUZZER_APPLE 1
     69 #else
     70 #error "Support for your platform has not been implemented"
     71 #endif
     72 
     73 // Used to avoid repeating error checking boilerplate. If cond is false, a
     74 // fatal error has occured in the program. In this event print error_message
     75 // to stderr and abort(). Otherwise do nothing. Note that setting
     76 // AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
     77 // to the file as well, if the error occurs after the duplication is performed.
     78 #define CHECK_ERROR(cond, error_message)                                       \
     79   if (!(cond)) {                                                               \
     80     fprintf(stderr, (error_message));                                          \
     81     abort();                                                                   \
     82   }
     83 
     84 // libFuzzer interface is thin, so we don't include any libFuzzer headers.
     85 extern "C" {
     86 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
     87 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
     88 }
     89 
     90 // Notify AFL about persistent mode.
     91 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
     92 extern "C" int __afl_persistent_loop(unsigned int);
     93 static volatile char suppress_warning2 = AFL_PERSISTENT[0];
     94 
     95 // Notify AFL about deferred forkserver.
     96 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
     97 extern "C" void  __afl_manual_init();
     98 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
     99 
    100 // Input buffer.
    101 static const size_t kMaxAflInputSize = 1 << 20;
    102 static uint8_t AflInputBuf[kMaxAflInputSize];
    103 
    104 // Variables we need for writing to the extra stats file.
    105 static FILE *extra_stats_file = NULL;
    106 static uint32_t previous_peak_rss = 0;
    107 static time_t slowest_unit_time_secs = 0;
    108 static const int kNumExtraStats = 2;
    109 static const char *kExtraStatsFormatString = "peak_rss_mb            : %u\n"
    110                                              "slowest_unit_time_sec  : %u\n";
    111 
    112 // Copied from FuzzerUtil.cpp.
    113 size_t GetPeakRSSMb() {
    114   struct rusage usage;
    115   if (getrusage(RUSAGE_SELF, &usage))
    116     return 0;
    117   if (LIBFUZZER_LINUX) {
    118     // ru_maxrss is in KiB
    119     return usage.ru_maxrss >> 10;
    120   } else if (LIBFUZZER_APPLE) {
    121     // ru_maxrss is in bytes
    122     return usage.ru_maxrss >> 20;
    123   }
    124   assert(0 && "GetPeakRSSMb() is not implemented for your platform");
    125   return 0;
    126 }
    127 
    128 // Based on SetSigaction in FuzzerUtil.cpp
    129 static void SetSigaction(int signum,
    130                          void (*callback)(int, siginfo_t *, void *)) {
    131   struct sigaction sigact;
    132   memset(&sigact, 0, sizeof(sigact));
    133   sigact.sa_sigaction = callback;
    134   if (sigaction(signum, &sigact, 0)) {
    135     fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
    136     exit(1);
    137   }
    138 }
    139 
    140 // Write extra stats to the file specified by the user. If none is specified
    141 // this function will never be called.
    142 static void write_extra_stats() {
    143   uint32_t peak_rss = GetPeakRSSMb();
    144 
    145   if (peak_rss < previous_peak_rss)
    146     peak_rss = previous_peak_rss;
    147 
    148   int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
    149                               peak_rss, slowest_unit_time_secs);
    150 
    151   CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
    152 
    153   CHECK_ERROR(fclose(extra_stats_file) == 0,
    154               "Failed to close extra_stats_file");
    155 }
    156 
    157 // Call write_extra_stats before we exit.
    158 static void crash_handler(int, siginfo_t *, void *) {
    159   // Make sure we don't try calling write_extra_stats again if we crashed while
    160   // trying to call it.
    161   static bool first_crash = true;
    162   CHECK_ERROR(first_crash,
    163               "Crashed in crash signal handler. This is a bug in the fuzzer.");
    164 
    165   first_crash = false;
    166   write_extra_stats();
    167 }
    168 
    169 // If the user has specified an extra_stats_file through the environment
    170 // variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
    171 // to write stats to it on exit. If no file is specified, do nothing. Otherwise
    172 // install signal and exit handlers to write to the file when the process exits.
    173 // Then if the file doesn't exist create it and set extra stats to 0. But if it
    174 // does exist then read the initial values of the extra stats from the file
    175 // and check that the file is writable.
    176 static void maybe_initialize_extra_stats() {
    177   // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
    178   char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
    179   if (!extra_stats_filename)
    180     return;
    181 
    182   // Open the file and find the previous peak_rss_mb value.
    183   // This is necessary because the fuzzing process is restarted after N
    184   // iterations are completed. So we may need to get this value from a previous
    185   // process to be accurate.
    186   extra_stats_file = fopen(extra_stats_filename, "r");
    187 
    188   // If extra_stats_file already exists: read old stats from it.
    189   if (extra_stats_file) {
    190     int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
    191                          &previous_peak_rss, &slowest_unit_time_secs);
    192 
    193     // Make sure we have read a real extra stats file and that we have used it
    194     // to set slowest_unit_time_secs and previous_peak_rss.
    195     CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
    196 
    197     CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
    198 
    199     // Now open the file for writing.
    200     extra_stats_file = fopen(extra_stats_filename, "w");
    201     CHECK_ERROR(extra_stats_file,
    202                 "Failed to open extra stats file for writing");
    203   } else {
    204     // Looks like this is the first time in a fuzzing job this is being called.
    205     extra_stats_file = fopen(extra_stats_filename, "w+");
    206     CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
    207   }
    208 
    209   // Make sure that crash_handler gets called on any kind of fatal error.
    210   int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE,  SIGINT,
    211                          SIGTERM};
    212 
    213   const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
    214 
    215   for (size_t idx = 0; idx < num_signals; idx++)
    216     SetSigaction(crash_signals[idx], crash_handler);
    217 
    218   // Make sure it gets called on other kinds of exits.
    219   atexit(write_extra_stats);
    220 }
    221 
    222 // If the user asks us to duplicate stderr, then do it.
    223 static void maybe_duplicate_stderr() {
    224   char* stderr_duplicate_filename =
    225       getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
    226 
    227   if (!stderr_duplicate_filename)
    228     return;
    229 
    230   FILE* stderr_duplicate_stream =
    231       freopen(stderr_duplicate_filename, "a+", stderr);
    232 
    233   if (!stderr_duplicate_stream) {
    234     fprintf(
    235         stderr,
    236         "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
    237     abort();
    238   }
    239 }
    240 
    241 int main(int argc, char **argv) {
    242   fprintf(stderr, "Running in AFl-fuzz mode\nUsage:\n"
    243                   "afl-fuzz [afl-flags] %s [N] "
    244                   "-- run N fuzzing iterations before "
    245                   "re-spawning the process (default: 1000)\n",
    246           argv[0]);
    247   if (LLVMFuzzerInitialize)
    248     LLVMFuzzerInitialize(&argc, &argv);
    249   // Do any other expensive one-time initialization here.
    250 
    251   maybe_duplicate_stderr();
    252   maybe_initialize_extra_stats();
    253 
    254   __afl_manual_init();
    255 
    256   int N = 1000;
    257   if (argc >= 2)
    258     N = atoi(argv[1]);
    259   assert(N > 0);
    260   time_t unit_time_secs;
    261   while (__afl_persistent_loop(N)) {
    262     ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
    263     if (n_read > 0) {
    264       // Copy AflInputBuf into a separate buffer to let asan find buffer
    265       // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
    266       uint8_t *copy = new uint8_t[n_read];
    267       memcpy(copy, AflInputBuf, n_read);
    268 
    269       struct timeval unit_start_time;
    270       CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
    271                   "Calling gettimeofday failed");
    272 
    273       LLVMFuzzerTestOneInput(copy, n_read);
    274 
    275       struct timeval unit_stop_time;
    276       CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
    277                   "Calling gettimeofday failed");
    278 
    279       // Update slowest_unit_time_secs if we see a new max.
    280       unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
    281       if (slowest_unit_time_secs < unit_time_secs)
    282         slowest_unit_time_secs = unit_time_secs;
    283 
    284       delete[] copy;
    285     }
    286   }
    287 }
    288