about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-08-09 20:24:56 +0200
committervan Hauser <vh@thc.org>2020-08-09 20:24:56 +0200
commite99d7e973001adea65c68113b08792144d6aa5c8 (patch)
treec14ca381bfc47c30afa1a5aab99a66ad71668064
parentb60663c0318b8baf21b36b549d765ddd2eeeb54e (diff)
downloadafl++-e99d7e973001adea65c68113b08792144d6aa5c8.tar.gz
integration in fuzz_one
-rw-r--r--include/afl-fuzz.h10
-rw-r--r--src/afl-fuzz-one.c111
-rw-r--r--src/afl-fuzz-run.c25
-rw-r--r--src/afl-fuzz.c12
4 files changed, 142 insertions, 16 deletions
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 19807880..88392867 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -430,7 +430,9 @@ typedef struct afl_state {
       *in_bitmap,                       /* Input bitmap                     */
       *file_extension,                  /* File extension                   */
       *orig_cmdline,                    /* Original command line            */
-      *infoexec;                       /* Command to execute on a new crash */
+      *infoexec,                       /* Command to execute on a new crash */
+      *taint_input_file,                /* fuzz_input_one input file        */
+      *taint_src, *taint_map;
 
   u32 hang_tmout;                       /* Timeout used for hang det (ms)   */
 
@@ -441,7 +443,8 @@ typedef struct afl_state {
       custom_only,                      /* Custom mutator only mode         */
       python_only,                      /* Python-only mode                 */
       is_main_node,                     /* if this is the main node         */
-      is_secondary_node;                /* if this is a secondary instance  */
+      is_secondary_node,                /* if this is a secondary instance  */
+      taint_needs_splode;               /* explode fuzz input               */
 
   u32 stats_update_freq;                /* Stats update frequency (execs)   */
 
@@ -502,7 +505,8 @@ typedef struct afl_state {
       useless_at_start,                 /* Number of useless starting paths */
       var_byte_count,                   /* Bitmap bytes with var behavior   */
       current_entry,                    /* Current queue entry ID           */
-      havoc_div;                        /* Cycle count divisor for havoc    */
+      havoc_div,                        /* Cycle count divisor for havoc    */
+      taint_len;
 
   u64 total_crashes,                    /* Total number of crashes          */
       unique_crashes,                   /* Crashes with unique signatures   */
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 74e09ee3..ec7c4772 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -458,27 +458,102 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
   }
 
-  /* Map the test case into memory. */
+  if (unlikely(afl->fsrv.taint_mode && (afl->queue_cycle % 3))) {
 
-  fd = open(afl->queue_cur->fname, O_RDONLY);
+    if (unlikely(afl->queue_cur->cal_failed)) goto abandon_entry;
 
-  if (unlikely(fd < 0)) {
+    u32 dst = 0, i;
 
-    PFATAL("Unable to open '%s'", afl->queue_cur->fname);
+    fd = open(afl->queue_cur->fname, O_RDONLY);
+    afl->taint_src = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+    if (fd < 0 || (size_t)afl->taint_src == -1)
+      FATAL("unable to open '%s'", afl->queue_cur->fname);
+    close(fd);
 
-  }
+    switch (afl->queue_cycle % 3) {
 
-  len = afl->queue_cur->len;
+      case 0:  // do nothing, but cannot happen -> else
+        break;
 
-  orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+      case 1:  // fuzz only tainted bytes
+        if (!afl->queue_cur->taint_bytes_all) goto abandon_entry;
+        afl->taint_needs_splode = 1;
 
-  if (unlikely(orig_in == MAP_FAILED)) {
+        fd = open(afl->taint_input_file, O_RDONLY);
+        len = afl->taint_len = afl->queue_cur->taint_bytes_all;
+        orig_in = in_buf =
+            mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+        if (fd < 0 || (size_t)in_buf == -1)
+          FATAL("unable to open '%s'", afl->taint_input_file);
+        close(fd);
 
-    PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len);
+        fd = open(afl->queue_cur->fname_taint, O_RDWR);
+        afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE, fd, 0);
+        if (fd < 0 || (size_t)in_buf == -1)
+          FATAL("unable to open '%s'", afl->queue_cur->fname_taint);
+        close(fd);
 
-  }
+        for (i = 0; i < afl->queue_cur->len && dst < len; i++)
+          if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i];
 
-  close(fd);
+        break;
+
+      case 2:  // fuzz only newly tainted bytes
+        if (!afl->queue_cur->taint_bytes_new) goto abandon_entry;
+        afl->taint_needs_splode = 1;
+
+        fd = open(afl->taint_input_file, O_RDONLY);
+        len = afl->taint_len = afl->queue_cur->taint_bytes_new;
+        orig_in = in_buf =
+            mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+        if (fd < 0 || (size_t)in_buf == -1)
+          FATAL("unable to open '%s'", afl->taint_input_file);
+        close(fd);
+
+        u8 *fn = alloc_printf("%s.new", afl->queue_cur->fname_taint);
+        fd = open(fn, O_RDWR);
+        afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE, fd, 0);
+        if (fd < 0 || (size_t)in_buf == -1) FATAL("unable to open '%s'", fn);
+        close(fd);
+        ck_free(fn);
+
+        for (i = 0; i < afl->queue_cur->len && dst < len; i++)
+          if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i];
+
+        break;
+
+    }
+
+    goto havoc_stage;  // we let the normal cycles do deterministic mode - if
+
+  } else {
+
+    /* Map the test case into memory. */
+    afl->taint_needs_splode = 0;
+
+    fd = open(afl->queue_cur->fname, O_RDONLY);
+
+    if (unlikely(fd < 0)) {
+
+      PFATAL("Unable to open '%s'", afl->queue_cur->fname);
+
+    }
+
+    len = afl->queue_cur->len;
+
+    orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+    if (unlikely(orig_in == MAP_FAILED)) {
+
+      PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len);
+
+    }
+
+    close(fd);
+
+  }
 
   /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every
      single byte anyway, so it wouldn't give us any performance or memory usage
@@ -527,7 +602,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
    ************/
 
   if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
-      !afl->disable_trim) {
+      !afl->disable_trim && !afl->taint_needs_splode) {
 
     u8 res = trim_case(afl, afl->queue_cur, in_buf);
 
@@ -2568,7 +2643,17 @@ abandon_entry:
 
   ++afl->queue_cur->fuzz_level;
 
-  munmap(orig_in, afl->queue_cur->len);
+  if (afl->taint_needs_splode) {
+
+    munmap(afl->taint_src, afl->queue_cur->len);
+    munmap(orig_in, afl->taint_len);
+    munmap(afl->taint_map, afl->queue_cur->len);
+
+  } else {
+
+    munmap(orig_in, afl->queue_cur->len);
+
+  }
 
   return ret_val;
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index ddbd5524..31db4d7c 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -863,6 +863,8 @@ abort_trimming:
 
 }
 
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
+
 /* Write a modified test case, run program, process results. Handle
    error conditions, returning 1 if it's time to bail out. This is
    a helper function for fuzz_one(). */
@@ -871,6 +873,27 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   u8 fault;
 
+  if (unlikely(afl->taint_needs_splode)) {
+
+    s32 new_len = afl->queue_cur->len + len - afl->taint_len;
+    if (new_len < 4) new_len = 4;
+    u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len);
+
+    u32 i, taint = 0;
+    for (i = 0; i < new_len; i++) {
+
+      if (afl->taint_map[i] || i > afl->queue_cur->len)
+        new_buf[i] = out_buf[taint++];
+      else
+        new_buf[i] = afl->taint_src[i];
+
+    }
+
+    out_buf = new_buf;
+    len = new_len;
+
+  }
+
   write_to_testcase(afl, out_buf, len);
 
   fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
@@ -918,3 +941,5 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
 }
 
+#undef BUF_PARAMS
+
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 6f143db7..70a99dec 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1260,12 +1260,15 @@ int main(int argc, char **argv_orig, char **envp) {
   if (afl->fsrv.taint_mode) {
 
     ACTF("Spawning qemu_taint forkserver");
+
     u8 *disable = getenv("AFL_DISABLE_LLVM_INSTRUMENTATION");
     setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
+
     afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv);
     afl->taint_fsrv.qemu_mode = 2;
     afl->taint_fsrv.taint_mode = 1;
     afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits;
+
     ck_free(afl->taint_fsrv.target_path);
     afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind));
     afl->taint_fsrv.target_path =
@@ -1290,7 +1293,16 @@ int main(int argc, char **argv_orig, char **envp) {
       setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1);
     afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon,
                    afl->afl_env.afl_debug_child_output);
+
+    afl->taint_input_file = alloc_printf("%s/taint/.input", afl->out_dir);
+    int fd = open(afl->taint_input_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
+    if (fd < 0)
+      FATAL("Cannot create taint inpu file '%s'", afl->taint_input_file);
+    lseek(fd, MAX_FILE, SEEK_SET);
+    ck_write(fd, "\0", 1, afl->taint_input_file);
+
     if (!disable) unsetenv("AFL_DISABLE_LLVM_INSTRUMENTATION");
+
     OKF("Taint forkserver successfully started");
 
   }