about summary refs log tree commit diff
path: root/src/afl-fuzz-queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/afl-fuzz-queue.c')
-rw-r--r--src/afl-fuzz-queue.c177
1 files changed, 173 insertions, 4 deletions
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index f35df914..43794018 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -103,6 +103,169 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
 
 }
 
+void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname,
+                       u8 *mem, u32 len) {
+
+  u8 *                ptr, *fn = fname;
+  u32                 bytes = 0, plen = len;
+  struct queue_entry *prev = q->prev;
+
+  if (plen % 4) plen = plen + 4 - (len % 4);
+
+  if ((ptr = strrchr(fname, '/')) != NULL) fn = ptr + 1;
+  q->fname_taint = alloc_printf("%s/taint/%s", afl->out_dir, fn);
+
+  if (q->fname_taint) {
+
+    u8 *save = ck_maybe_grow(BUF_PARAMS(out_scratch), afl->fsrv.map_size);
+    memcpy(save, afl->taint_fsrv.trace_bits, afl->fsrv.map_size);
+
+    afl->taint_fsrv.map_size = plen;  // speed :)
+    write_to_testcase(afl, mem, len);
+    if (afl_fsrv_run_target(&afl->taint_fsrv, afl->fsrv.exec_tmout * 4,
+                            &afl->stop_soon) == 0) {
+
+      bytes = q->taint_bytes_all =
+          count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen);
+      if (afl->debug)
+        fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, len);
+
+      /* DEBUG FIXME TODO XXX */
+      u32 i;
+      for (i = 0; i < len; i++) {
+
+        if (afl->taint_fsrv.trace_bits[i] &&
+            afl->taint_fsrv.trace_bits[i] != '!')
+          FATAL("invalid taint map value %02x at pos %d",
+                afl->taint_fsrv.trace_bits[i], i);
+
+      }
+
+      if (len < plen)
+        for (i = len; i < plen; i++) {
+
+          if (afl->taint_fsrv.trace_bits[i])
+            FATAL("invalid taint map value %02x in padding at pos %d",
+                  afl->taint_fsrv.trace_bits[i], i);
+
+        }
+
+    }
+
+    // if all is tainted we do not need to write taint data away
+    if (bytes && bytes < len) {
+
+      // save the bytes away
+      int w = open(q->fname_taint, O_CREAT | O_WRONLY, 0644);
+      if (w >= 0) {
+
+        ck_write(w, afl->taint_fsrv.trace_bits, len, q->fname_taint);
+        close(w);
+
+        // find the highest tainted offset in the input (for trim opt)
+        s32 i = len;
+        while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1])
+          i--;
+        q->taint_bytes_highest = i;
+
+        afl->taint_count++;
+
+      } else {
+
+        FATAL("could not create %s", q->fname_taint);
+        q->taint_bytes_all = bytes = 0;
+
+      }
+
+      // it is possible that there is no main taint file - if the whole file
+      // is tainted - but a .new taint file if it had new tainted bytes
+
+      // check if there is a previous queue entry and if it had taint
+      if (bytes && prev && prev->taint_bytes_all &&
+          prev->taint_bytes_all < prev->len) {
+
+        // check if there are new bytes in the taint vs the previous
+        int r = open(prev->fname_taint, O_RDONLY);
+
+        if (r >= 0) {
+
+          u8 *bufr = mmap(0, prev->len, PROT_READ, MAP_PRIVATE, r, 0);
+
+          if ((ssize_t)bufr != -1) {
+
+            u32 i;
+            u8 *tmp = ck_maybe_grow(BUF_PARAMS(in_scratch), plen);
+            memset(tmp, 0, plen);
+
+            for (i = 0; i < len; i++)
+              if (afl->taint_fsrv.trace_bits[i] && (i >= prev->len || !bufr[i]))
+                tmp[i] = '!';
+
+            q->taint_bytes_new = count_bytes_len(afl, tmp, plen);
+
+            if (afl->debug)
+              fprintf(stderr, "Debug: %u new taint out of %u bytes\n", bytes,
+                      len);
+
+            if (q->taint_bytes_new) {
+
+              u8 *fnw = alloc_printf("%s.new", q->fname_taint);
+              if (fnw) {
+
+                int w = open(fnw, O_CREAT | O_WRONLY, 0644);
+                if (w >= 0) {
+
+                  ck_write(w, tmp, plen, fnw);
+                  close(w);
+
+                } else {
+
+                  FATAL("count not create '%s'", fnw);
+                  q->taint_bytes_new = 0;
+
+                }
+
+                ck_free(fnw);
+
+              } else {
+
+                q->taint_bytes_new = 0;
+
+              }
+
+            }
+
+            munmap(bufr, prev->len);
+
+          }
+
+          close(r);
+
+        }
+
+      }
+
+    }
+
+    memcpy(afl->taint_fsrv.trace_bits, save, afl->fsrv.map_size);
+
+  }
+
+  if (!bytes) {
+
+    q->taint_bytes_highest = q->taint_bytes_all = q->taint_bytes_new = 0;
+
+    if (q->fname_taint) {
+
+      ck_free(q->fname_taint);
+      q->fname_taint = NULL;
+
+    }
+
+  }
+
+}
+
 /* check if ascii or UTF-8 */
 
 static u8 check_if_text(struct queue_entry *q) {
@@ -212,10 +375,12 @@ static u8 check_if_text(struct queue_entry *q) {
 
 /* Append new test case to the queue. */
 
-void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
+void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
+                  struct queue_entry *prev_q, u8 passed_det) {
 
   struct queue_entry *q = ck_alloc(sizeof(struct queue_entry));
 
+  q->prev = prev_q;
   q->fname = fname;
   q->len = len;
   q->depth = afl->cur_depth + 1;
@@ -254,6 +419,13 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   afl->last_path_time = get_cur_time();
 
+  /* trigger the tain gathering if this is not a dry run */
+  if (afl->taint_mode && mem) { perform_taint_run(afl, q, fname, mem, len); }
+
+  /* only redqueen currently uses is_ascii */
+  if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
+
+  /* run custom mutators afl_custom_queue_new_entry() */
   if (afl->custom_mutators_count) {
 
     LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
@@ -273,9 +445,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   }
 
-  /* only redqueen currently uses is_ascii */
-  if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
-
 }
 
 /* Destroy the entire queue. */