about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile2
-rw-r--r--include/afl-fuzz.h6
-rw-r--r--include/forkserver.h2
-rw-r--r--qemu_taint/README.md2
-rw-r--r--src/afl-common.c1
-rw-r--r--src/afl-forkserver.c15
-rw-r--r--src/afl-fuzz-bitmap.c32
-rw-r--r--src/afl-fuzz-run.c13
-rw-r--r--src/afl-fuzz.c51
9 files changed, 116 insertions, 8 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 9b064eb6..4d0c434e 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -98,7 +98,7 @@ ifneq "$(shell uname -m)" "x86_64"
 endif
 
 CFLAGS     ?= -O3 -funroll-loops $(CFLAGS_OPT)
-override CFLAGS += -Wall -Wextra -Werror -g -Wno-pointer-sign \
+override CFLAGS += -g -Wno-pointer-sign \
 			  -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
 			  -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
 
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index bb1bb314..eb7f8ca5 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -371,6 +371,8 @@ typedef struct afl_state {
   afl_env_vars_t   afl_env;
 
   char **argv;                                            /* argv if needed */
+  
+  char **argv_taint;                                 /* argv for taint mode */
 
   /* MOpt:
     Lots of globals, but mostly for the status UI and other things where it
@@ -581,6 +583,9 @@ typedef struct afl_state {
   char *           cmplog_binary;
   afl_forkserver_t cmplog_fsrv;     /* cmplog has its own little forkserver */
 
+  /* Taint mode */
+  afl_forkserver_t taint_fsrv;  /* taint mode has its own little forkserver */
+
   /* Custom mutators */
   struct custom_mutator *mutator;
 
@@ -889,6 +894,7 @@ u32  calculate_score(afl_state_t *, struct queue_entry *);
 
 void write_bitmap(afl_state_t *);
 u32  count_bits(afl_state_t *, u8 *);
+u32  count_bits_len(afl_state_t *, u8 *, u32);
 u32  count_bytes(afl_state_t *, u8 *);
 u32  count_non_255_bytes(afl_state_t *, u8 *);
 #ifdef WORD_SIZE_64
diff --git a/include/forkserver.h b/include/forkserver.h
index 717493db..a5fca30e 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -79,6 +79,8 @@ typedef struct afl_forkserver {
   u8 use_fauxsrv;                       /* Fauxsrv for non-forking targets? */
 
   u8 qemu_mode;                         /* if running in qemu mode or not   */
+  
+  u8 taint_mode;                        /* if running taint analysis or not */
 
   u32 *shmem_fuzz_len;                  /* length of the fuzzing test case  */
 
diff --git a/qemu_taint/README.md b/qemu_taint/README.md
index c842da0e..6a7d19af 100644
--- a/qemu_taint/README.md
+++ b/qemu_taint/README.md
@@ -18,7 +18,7 @@ Only touched bytes are then fuzzed by afl-fuzz
 
 ## How to use
 
-Add the -T flag to afl-fuzz
+Add the -A flag to afl-fuzz
 
 ## Caveats
 
diff --git a/src/afl-common.c b/src/afl-common.c
index 367dec72..134d3180 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -138,6 +138,7 @@ void argv_cpy_free(char **argv) {
 
 }
 
+
 /* Rewrite argv for QEMU. */
 
 char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 752641d7..b4f92e5b 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -481,6 +481,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
            "handle_sigill=0",
            0);
 
+fprintf(stderr, "init %p\n", fsrv->init_child_func);
     fsrv->init_child_func(fsrv, argv);
 
     /* Use a distinctive bitmap signature to tell the parent about execv()
@@ -496,10 +497,20 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
   char pid_buf[16];
   sprintf(pid_buf, "%d", fsrv->fsrv_pid);
-  if (fsrv->cmplog_binary)
+  
+  if (fsrv->qemu_mode == 2) {
+
+    setenv("__AFL_TARGET_PID3", pid_buf, 1);
+
+  } else if (fsrv->cmplog_binary) {
+  
     setenv("__AFL_TARGET_PID2", pid_buf, 1);
-  else
+  
+  } else {
+  
     setenv("__AFL_TARGET_PID1", pid_buf, 1);
+  
+  }
 
   /* Close the unneeded endpoints. */
 
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index aa8d5a18..9cb1b83f 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -177,6 +177,38 @@ u32 count_bits(afl_state_t *afl, u8 *mem) {
 
 }
 
+u32 count_bits_len(afl_state_t *afl, u8 *mem, u32 len) {
+
+  u32 *ptr = (u32 *)mem;
+  u32  i = (len >> 2);
+  u32  ret = 0;
+
+  if (len % 4) i++;
+
+  while (i--) {
+
+    u32 v = *(ptr++);
+
+    /* This gets called on the inverse, virgin bitmap; optimize for sparse
+       data. */
+
+    if (v == 0xffffffff) {
+
+      ret += 32;
+      continue;
+
+    }
+
+    v -= ((v >> 1) & 0x55555555);
+    v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+    ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24;
+
+  }
+
+  return ret;
+
+}
+
 /* Count the number of bytes set in the bitmap. Called fairly sporadically,
    mostly to update the status screen or calibrate and examine confirmed
    new paths. */
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 8d652155..207b3046 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -471,6 +471,19 @@ abort_calibration:
   afl->stage_cur = old_sc;
   afl->stage_max = old_sm;
 
+  /* if taint mode was selected, run the taint */
+  
+  if (afl->fsrv.taint_mode) {
+    write_to_testcase(afl, use_mem, q->len);
+    if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == 0) {
+      u32 len = q->len / 8;
+      if (q->len % 8) len++;
+      u32 bits = count_bits_len(afl, afl->taint_fsrv.trace_bits, len);
+      if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bits);
+
+    }
+  }
+
   if (!first_run) { show_stats(afl); }
 
   return fault;
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 031c4049..bc780b55 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -53,6 +53,9 @@ static void at_exit() {
   ptr = getenv("__AFL_TARGET_PID2");
   if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
 
+  ptr = getenv("__AFL_TARGET_PID3");
+  if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
+
   i = 0;
   while (list[i] != NULL) {
 
@@ -89,6 +92,7 @@ static void usage(u8 *argv0, int more_help) {
       "  -o dir        - output directory for fuzzer findings\n\n"
 
       "Execution control settings:\n"
+      "  -A            - use first level taint analysis (see qemu_taint/README.md)\n"
       "  -p schedule   - power schedules compute a seed's performance score. "
       "<explore\n"
       "                  (default), fast, coe, lin, quad, exploit, mmopt, "
@@ -277,10 +281,15 @@ int main(int argc, char **argv_orig, char **envp) {
 
   while ((opt = getopt(
               argc, argv,
-              "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > 0) {
+              "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QANUWe:p:s:V:E:L:hRP:")) > 0) {
 
     switch (opt) {
 
+      case 'A':
+        afl->fsrv.taint_mode = 1;
+        if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
+        break;
+
       case 'I':
         afl->infoexec = optarg;
         break;
@@ -485,7 +494,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
         if (!optarg) { FATAL("Wrong usage of -m"); }
 
-        if (!strcmp(optarg, "none")) {
+        if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) {
 
           afl->fsrv.mem_limit = 0;
           break;
@@ -815,6 +824,14 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (afl->fsrv.taint_mode && afl->fsrv.map_size < (MAX_FILE / 8) + 1) {
+
+    afl->shm.map_size = (MAX_FILE / 8);
+    if (MAX_FILE % 8) afl->shm.map_size++;
+    afl->fsrv.map_size = afl->shm.map_size;
+
+  }
+
   if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
 
   OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
@@ -869,6 +886,7 @@ int main(int argc, char **argv_orig, char **envp) {
     if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
     if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
     if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
+    if (afl->fsrv.taint_mode) { FATAL("-A and -n are mutually exclusive"); }
 
   }
 
@@ -969,7 +987,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (afl->afl_env.afl_preload) {
 
-    if (afl->fsrv.qemu_mode) {
+    if (afl->fsrv.qemu_mode || afl->fsrv.taint_mode) {
 
       u8 *qemu_preload = getenv("QEMU_SET_ENV");
       u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -1220,7 +1238,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
     ACTF("Spawning cmplog forkserver");
     afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
-    // TODO: this is semi-nice
     afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
     afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
     afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
@@ -1230,6 +1247,29 @@ int main(int argc, char **argv_orig, char **envp) {
     OKF("Cmplog forkserver successfully started");
 
   }
+  
+  if (afl->fsrv.taint_mode) {
+
+    ACTF("Spawning qemu_taint forkserver");
+    afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv);
+    afl->taint_fsrv.qemu_mode = 2;
+    afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits;
+    ck_free(afl->taint_fsrv.target_path);
+    afl->taint_fsrv.target_path = ck_strdup(afl->fsrv.target_path);
+    afl->argv_taint = get_qemu_argv(argv[0], &afl->taint_fsrv.target_path,
+                                    argc - optind, argv + optind);
+    u32 len = strlen(afl->taint_fsrv.target_path);
+    strcpy(afl->taint_fsrv.target_path + len - 5, "taint");
+    strcpy((afl->argv_taint[0]) + len - 5, "taint");
+    if (afl->fsrv.use_stdin)
+      unsetenv("AFL_TAINT_INPUT");
+    else
+      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);
+    OKF("Taint forkserver successfully started");
+
+  }
 
   perform_dry_run(afl);
 
@@ -1493,8 +1533,11 @@ stop_fuzzing:
 
   }
 
+  if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv);
+  if (afl->fsrv.taint_mode) afl_fsrv_deinit(&afl->taint_fsrv);
   afl_fsrv_deinit(&afl->fsrv);
   if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
+  if (afl->argv_taint) { ck_free(afl->argv_taint); }
   ck_free(afl->fsrv.target_path);
   ck_free(afl->fsrv.out_file);
   ck_free(afl->sync_id);