about summary refs log tree commit diff
path: root/src/afl-fuzz.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/afl-fuzz.c')
-rw-r--r--src/afl-fuzz.c383
1 files changed, 362 insertions, 21 deletions
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index a7ddef6e..8a84d447 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -36,6 +36,67 @@
   #include <sys/ipc.h>
   #include <sys/shm.h>
 #endif
+#ifdef HAVE_ZLIB
+
+  #define ck_gzread(fd, buf, len, fn)                            \
+    do {                                                         \
+                                                                 \
+      s32 _len = (s32)(len);                                     \
+      s32 _res = gzread(fd, buf, _len);                          \
+      if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
+                                                                 \
+    } while (0)
+
+  #define ck_gzwrite(fd, buf, len, fn)                                    \
+    do {                                                                  \
+                                                                          \
+      if (len <= 0) break;                                                \
+      s32 _written = 0, _off = 0, _len = (s32)(len);                      \
+                                                                          \
+      do {                                                                \
+                                                                          \
+        s32 _res = gzwrite(fd, (buf) + _off, _len);                       \
+        if (_res != _len && (_res > 0 && _written + _res != _len)) {      \
+                                                                          \
+          if (_res > 0) {                                                 \
+                                                                          \
+            _written += _res;                                             \
+            _len -= _res;                                                 \
+            _off += _res;                                                 \
+                                                                          \
+          } else {                                                        \
+                                                                          \
+            RPFATAL(_res, "Short write to %s (%d of %d bytes)", fn, _res, \
+                    _len);                                                \
+                                                                          \
+          }                                                               \
+                                                                          \
+        } else {                                                          \
+                                                                          \
+          break;                                                          \
+                                                                          \
+        }                                                                 \
+                                                                          \
+      } while (1);                                                        \
+                                                                          \
+                                                                          \
+                                                                          \
+    } while (0)
+
+  #include <zlib.h>
+  #define ZLIBOPEN gzopen
+  #define ZLIBREAD ck_gzread
+  #define NZLIBREAD gzread
+  #define ZLIBWRITE ck_gzwrite
+  #define ZLIBCLOSE gzclose
+  #define ZLIB_EXTRA "9"
+#else
+  #define ZLIBOPEN open
+  #define NZLIBREAD read
+  #define ZLIBREAD ck_read
+  #define ZLIBWRITE ck_write
+  #define ZLIBCLOSE close
+#endif
 
 #ifdef __APPLE__
   #include <sys/qos.h>
@@ -181,7 +242,7 @@ static void usage(u8 *argv0, int more_help) {
       "it.\n"
       "                  if using QEMU/FRIDA or the fuzzing target is "
       "compiled\n"
-      "                  for CmpLog then use '-c 0'. To disable Cmplog use '-c "
+      "                  for CmpLog then use '-c 0'. To disable CMPLOG use '-c "
       "-'.\n"
       "  -l cmplog_opts - CmpLog configuration values (e.g. \"2ATR\"):\n"
       "                  1=small files, 2=larger files (default), 3=all "
@@ -335,6 +396,7 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
       "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
       "                        suported formats: dogstatsd, librato, signalfx, influxdb\n"
+      "AFL_NO_FASTRESUME: do not read or write a fast resume file\n"
       "AFL_NO_SYNC: disables all syncing\n"
       "AFL_SYNC_TIME: sync time between fuzzing instances (in minutes)\n"
       "AFL_FINAL_SYNC: sync a final time when exiting (will delay the exit!)\n"
@@ -960,7 +1022,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
         }
 
-        if (afl->fsrv.mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+        if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 5) {
+
+          FATAL("Dangerously low value of -m");
+
+        }
 
         if (sizeof(rlim_t) == 4 && afl->fsrv.mem_limit > 2000) {
 
@@ -1868,6 +1934,15 @@ int main(int argc, char **argv_orig, char **envp) {
 
           OKF("Using Frida Address Sanitizer Mode");
 
+          if (afl->fsrv.mem_limit) {
+
+            WARNF(
+                "in the Frida Address Sanitizer Mode we disable all memory "
+                "limits");
+            afl->fsrv.mem_limit = 0;
+
+          }
+
           fasan_check_afl_preload(afl_preload);
 
           setenv("ASAN_OPTIONS", "detect_leaks=false", 1);
@@ -2067,6 +2142,31 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (afl->custom_mutators_count && afl->afl_env.afl_custom_mutator_late_send) {
+
+    u32 count_send = 0;
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+      if (el->afl_custom_fuzz_send) {
+
+        if (count_send) {
+
+          FATAL(
+              "You can only have one custom send() function if you are using "
+              "AFL_CUSTOM_MUTATOR_LATE_SEND!");
+
+        }
+
+        afl->fsrv.late_send = el->afl_custom_fuzz_send;
+        afl->fsrv.custom_data_ptr = el->data;
+        count_send = 1;
+
+      }
+
+    });
+
+  }
+
   if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
 
     if (afl->custom_only) {
@@ -2101,13 +2201,92 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  setup_cmdline_file(afl, argv + optind);
+  check_binary(afl, argv[optind]);
+
+  u64 prev_target_hash = 0;
+  s32 fast_resume = 0;
+  #ifdef HAVE_ZLIB
+  gzFile fr_fd = NULL;
+  #else
+  s32 fr_fd = -1;
+  #endif
+
+  if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) {
+
+    u8 fn[PATH_MAX], buf[32];
+    snprintf(fn, PATH_MAX, "%s/target_hash", afl->out_dir);
+    s32 fd = open(fn, O_RDONLY);
+    if (fd >= 0) {
+
+      if (read(fd, buf, 32) >= 16) {
+
+        sscanf(buf, "%p", (void **)&prev_target_hash);
+
+      }
+
+      close(fd);
+
+    }
+
+  }
+
   write_setup_file(afl, argc, argv);
 
-  setup_cmdline_file(afl, argv + optind);
+  if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) {
+
+    u64 target_hash = get_binary_hash(afl->fsrv.target_path);
+
+    if (!target_hash || prev_target_hash != target_hash) {
+
+      ACTF("Target binary is different, cannot perform FAST RESUME!");
+
+    } else {
+
+      u8 fn[PATH_MAX];
+      snprintf(fn, PATH_MAX, "%s/fastresume.bin", afl->out_dir);
+  #ifdef HAVE_ZLIB
+      if ((fr_fd = ZLIBOPEN(fn, "rb")) != NULL) {
+
+  #else
+      if ((fr_fd = open(fn, O_RDONLY)) >= 0) {
+
+  #endif
+
+        u8   ver_string[8];
+        u64 *ver = (u64 *)ver_string;
+        u64  expect_ver =
+            afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1);
+
+        if (NZLIBREAD(fr_fd, ver_string, sizeof(ver_string)) !=
+            sizeof(ver_string))
+          WARNF("Emtpy fastresume.bin, ignoring, cannot perform FAST RESUME");
+        else if (expect_ver != *ver)
+          WARNF(
+              "Different AFL++ version or feature usage, cannot perform FAST "
+              "RESUME");
+        else {
+
+          OKF("Will perform FAST RESUME");
+          fast_resume = 1;
+
+        }
+
+      } else {
+
+        ACTF("fastresume.bin not found, cannot perform FAST RESUME!");
+
+      }
+
+      // If the fast resume file is not valid we will be unable to start, so
+      // we remove the file but keep the file descriptor open.
+      unlink(fn);
+
+    }
+
+  }
 
   read_testcases(afl, NULL);
-  // read_foreign_testcases(afl, 1); for the moment dont do this
-  OKF("Loaded a total of %u seeds.", afl->queued_items);
 
   pivot_inputs(afl);
 
@@ -2140,6 +2319,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  // read_foreign_testcases(afl, 1); for the moment dont do this
+  OKF("Loaded a total of %u seeds.", afl->queued_items);
+
   /* If we don't have a file name chosen yet, use a safe default. */
 
   if (!afl->fsrv.out_file) {
@@ -2196,8 +2378,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  check_binary(afl, argv[optind]);
-
   #ifdef AFL_PERSISTENT_RECORD
   if (unlikely(afl->fsrv.persistent_record)) {
 
@@ -2416,7 +2596,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    OKF("Cmplog forkserver successfully started");
+    OKF("CMPLOG forkserver successfully started");
 
   }
 
@@ -2454,29 +2634,102 @@ int main(int argc, char **argv_orig, char **envp) {
   dedup_extras(afl);
   if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }
 
-  // after we have the correct bitmap size we can read the bitmap -B option
-  // and set the virgin maps
-  if (afl->in_bitmap) {
+  if (unlikely(fast_resume)) {
 
-    read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
+    u64 resume_start = get_cur_time_us();
+    // if we get here then we should abort on errors
+    ZLIBREAD(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits");
+    ZLIBREAD(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout");
+    ZLIBREAD(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash");
+    ZLIBREAD(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes");
 
-  } else {
+    u8                  res[1] = {0};
+    u8                 *o_start = (u8 *)&(afl->queue_buf[0]->colorized);
+    u8                 *o_end = (u8 *)&(afl->queue_buf[0]->mother);
+    u32                 r = 8 + afl->fsrv.map_size * 4;
+    u32                 q_len = o_end - o_start;
+    u32                 m_len = (afl->fsrv.map_size >> 3);
+    struct queue_entry *q;
 
-    memset(afl->virgin_bits, 255, map_size);
+    for (u32 i = 0; i < afl->queued_items; i++) {
 
-  }
+      q = afl->queue_buf[i];
+      ZLIBREAD(fr_fd, (u8 *)&(q->colorized), q_len, "queue data");
+      ZLIBREAD(fr_fd, res, 1, "check map");
+      if (res[0]) {
+
+        q->trace_mini = ck_alloc(m_len);
+        ZLIBREAD(fr_fd, q->trace_mini, m_len, "trace_mini");
+        r += q_len + m_len + 1;
+
+      } else {
+
+        r += q_len + 1;
+
+      }
+
+      afl->total_bitmap_size += q->bitmap_size;
+      ++afl->total_bitmap_entries;
+      update_bitmap_score(afl, q);
+
+      if (q->was_fuzzed) { --afl->pending_not_fuzzed; }
 
-  memset(afl->virgin_tmout, 255, map_size);
-  memset(afl->virgin_crash, 255, map_size);
+      if (q->disabled) {
+
+        if (!q->was_fuzzed) { --afl->pending_not_fuzzed; }
+        --afl->active_items;
+
+      }
+
+      if (q->var_behavior) { ++afl->queued_variable; }
+      if (q->favored) {
+
+        ++afl->queued_favored;
+        if (!q->was_fuzzed) { ++afl->pending_favored; }
+
+      }
+
+    }
 
-  if (likely(!afl->afl_env.afl_no_startup_calibration)) {
+    u8 buf[4];
+    if (NZLIBREAD(fr_fd, buf, 3) > 0) {
 
-    perform_dry_run(afl);
+      FATAL("invalid trailing data in fastresume.bin");
+
+    }
+
+    OKF("Successfully loaded fastresume.bin (%u bytes)!", r);
+    ZLIBCLOSE(fr_fd);
+    afl->reinit_table = 1;
+    update_calibration_time(afl, &resume_start);
 
   } else {
 
-    ACTF("skipping initial seed calibration due option override!");
-    usleep(1000);
+    // after we have the correct bitmap size we can read the bitmap -B option
+    // and set the virgin maps
+    if (afl->in_bitmap) {
+
+      read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
+
+    } else {
+
+      memset(afl->virgin_bits, 255, map_size);
+
+    }
+
+    memset(afl->virgin_tmout, 255, map_size);
+    memset(afl->virgin_crash, 255, map_size);
+
+    if (likely(!afl->afl_env.afl_no_startup_calibration)) {
+
+      perform_dry_run(afl);
+
+    } else {
+
+      ACTF("Skipping initial seed calibration due option override!");
+      usleep(1000);
+
+    }
 
   }
 
@@ -2984,6 +3237,28 @@ stop_fuzzing:
   write_bitmap(afl);
   save_auto(afl);
 
+  #ifdef __AFL_CODE_COVERAGE
+  if (afl->fsrv.persistent_trace_bits) {
+
+    char cfn[4096];
+    snprintf(cfn, sizeof(cfn), "%s/covmap.dump", afl->out_dir);
+
+    FILE *cov_fd;
+    if ((cov_fd = fopen(cfn, "w")) == NULL) {
+
+      PFATAL("could not create '%s'", cfn);
+
+    }
+
+    // Write the real map size, as the map size must exactly match the pointer
+    // map in length.
+    fwrite(afl->fsrv.persistent_trace_bits, 1, afl->fsrv.real_map_size, cov_fd);
+    fclose(cov_fd);
+
+  }
+
+  #endif
+
   if (afl->pizza_is_served) {
 
     SAYF(CURSOR_SHOW cLRD "\n\n+++ Baking aborted %s +++\n" cRST,
@@ -3067,6 +3342,72 @@ stop_fuzzing:
   fclose(afl->fsrv.det_plot_file);
   #endif
 
+  if (!afl->afl_env.afl_no_fastresume) {
+
+    /* create fastresume.bin */
+    u8 fr[PATH_MAX];
+    snprintf(fr, PATH_MAX, "%s/fastresume.bin", afl->out_dir);
+    ACTF("Writing %s ...", fr);
+  #ifdef HAVE_ZLIB
+    if ((fr_fd = ZLIBOPEN(fr, "wb9")) != NULL) {
+
+  #else
+    if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >=
+  #endif
+
+      u8   ver_string[8];
+      u32  w = 0;
+      u64 *ver = (u64 *)ver_string;
+      *ver = afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1);
+
+      ZLIBWRITE(fr_fd, ver_string, sizeof(ver_string), "ver_string");
+      ZLIBWRITE(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits");
+      ZLIBWRITE(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout");
+      ZLIBWRITE(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash");
+      ZLIBWRITE(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes");
+      w += sizeof(ver_string) + afl->fsrv.map_size * 4;
+
+      u8                  on[1] = {1}, off[1] = {0};
+      u8                 *o_start = (u8 *)&(afl->queue_buf[0]->colorized);
+      u8                 *o_end = (u8 *)&(afl->queue_buf[0]->mother);
+      u32                 q_len = o_end - o_start;
+      u32                 m_len = (afl->fsrv.map_size >> 3);
+      struct queue_entry *q;
+
+      afl->pending_not_fuzzed = afl->queued_items;
+      afl->active_items = afl->queued_items;
+
+      for (u32 i = 0; i < afl->queued_items; i++) {
+
+        q = afl->queue_buf[i];
+        ZLIBWRITE(fr_fd, (u8 *)&(q->colorized), q_len, "queue data");
+        if (!q->trace_mini) {
+
+          ZLIBWRITE(fr_fd, off, 1, "no_mini");
+          w += q_len + 1;
+
+        } else {
+
+          ZLIBWRITE(fr_fd, on, 1, "yes_mini");
+          ZLIBWRITE(fr_fd, q->trace_mini, m_len, "trace_mini");
+          w += q_len + m_len + 1;
+
+        }
+
+      }
+
+      ZLIBCLOSE(fr_fd);
+      afl->var_byte_count = count_bytes(afl, afl->var_bytes);
+      OKF("Written fastresume.bin with %u bytes!", w);
+
+    } else {
+
+      WARNF("Could not create fastresume.bin");
+
+    }
+
+  }
+
   destroy_queue(afl);
   destroy_extras(afl);
   destroy_custom_mutators(afl);