about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-03-25 08:54:21 +0100
committerGitHub <noreply@github.com>2021-03-25 08:54:21 +0100
commit3b860c1dd63036ee99fbb548c5c0ba0c67f9af08 (patch)
tree66d0555fbe862fdbe083450f6fe087bd72945bd7 /src
parentd319b4a3819052de5bf576c560da6e4687c31de9 (diff)
parentab394836a9fe3faadb9d1af3a7d377bbcf5b5eee (diff)
downloadafl++-3b860c1dd63036ee99fbb548c5c0ba0c67f9af08.tar.gz
Merge pull request #844 from AFLplusplus/replay
AFL_PERSISTENT_RECORD support
Diffstat (limited to 'src')
-rw-r--r--src/afl-forkserver.c100
-rw-r--r--src/afl-fuzz-state.c7
-rw-r--r--src/afl-fuzz.c64
-rw-r--r--src/afl-showmap.c1
4 files changed, 163 insertions, 9 deletions
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index c2d552cd..0037d2d5 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -42,6 +42,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
@@ -126,7 +127,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   fsrv_to->last_run_timed_out = 0;
 
   fsrv_to->init_child_func = from->init_child_func;
-  // Note: do not copy ->add_extra_func
+  // Note: do not copy ->add_extra_func or ->persistent_record*
 
   list_append(&fsrv_list, fsrv_to);
 
@@ -364,6 +365,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
   if (!be_quiet) { ACTF("Spinning up the fork server..."); }
 
+#ifdef AFL_PERSISTENT_RECORD
+  if (unlikely(fsrv->persistent_record)) {
+
+    fsrv->persistent_record_data =
+        (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *));
+    fsrv->persistent_record_len =
+        (u32 *)ck_alloc(fsrv->persistent_record * sizeof(u32));
+
+    if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) {
+
+      FATAL("Unable to allocate memory for persistent replay.");
+
+    }
+
+  }
+
+#endif
+
   if (fsrv->use_fauxsrv) {
 
     /* TODO: Come up with some nice way to initialize this all */
@@ -1032,6 +1051,32 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
 
 void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
 
+#ifdef AFL_PERSISTENT_RECORD
+  if (unlikely(fsrv->persistent_record)) {
+
+    fsrv->persistent_record_len[fsrv->persistent_record_idx] = len;
+    fsrv->persistent_record_data[fsrv->persistent_record_idx] = afl_realloc(
+        (void **)&fsrv->persistent_record_data[fsrv->persistent_record_idx],
+        len);
+
+    if (unlikely(!fsrv->persistent_record_data[fsrv->persistent_record_idx])) {
+
+      FATAL("allocating replay memory failed.");
+
+    }
+
+    memcpy(fsrv->persistent_record_data[fsrv->persistent_record_idx], buf, len);
+
+    if (unlikely(++fsrv->persistent_record_idx >= fsrv->persistent_record)) {
+
+      fsrv->persistent_record_idx = 0;
+
+    }
+
+  }
+
+#endif
+
   if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) {
 
     if (unlikely(len > MAX_FILE)) len = MAX_FILE;
@@ -1146,6 +1191,26 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   }
 
+#ifdef AFL_PERSISTENT_RECORD
+  // end of persistent loop?
+  if (unlikely(fsrv->persistent_record &&
+               fsrv->persistent_record_pid != fsrv->child_pid)) {
+
+    fsrv->persistent_record_pid = fsrv->child_pid;
+    u32 idx, val;
+    if (unlikely(!fsrv->persistent_record_idx))
+      idx = fsrv->persistent_record - 1;
+    else
+      idx = fsrv->persistent_record_idx - 1;
+    val = fsrv->persistent_record_len[idx];
+    memset((void *)fsrv->persistent_record_len, 0,
+           fsrv->persistent_record * sizeof(u32));
+    fsrv->persistent_record_len[idx] = val;
+
+  }
+
+#endif
+
   if (fsrv->child_pid <= 0) {
 
     if (*stop_soon_p) { return 0; }
@@ -1244,6 +1309,39 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
           (fsrv->uses_crash_exitcode &&
            WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
 
+#ifdef AFL_PERSISTENT_RECORD
+    if (unlikely(fsrv->persistent_record)) {
+
+      char fn[PATH_MAX];
+      u32  i, writecnt = 0;
+      for (i = 0; i < fsrv->persistent_record; ++i) {
+
+        u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
+        u8 *data = fsrv->persistent_record_data[entry];
+        u32 len = fsrv->persistent_record_len[entry];
+        if (likely(len && data)) {
+
+          snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
+                   fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
+                   writecnt++);
+          int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+          if (fd >= 0) {
+
+            ck_write(fd, data, len, fn);
+            close(fd);
+
+          }
+
+        }
+
+      }
+
+      ++fsrv->persistent_record_cnt;
+
+    }
+
+#endif
+
     /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
     fsrv->last_kill_signal =
         WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 0ddf8cf3..10a0b869 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -292,6 +292,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_autoresume =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_PERSISTENT_RECORD",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_persistent_record =
+                get_afl_env(afl_environment_variables[i]);
+
           } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES",
 
                               afl_environment_variable_len)) {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index d70ffd31..23343ade 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -222,6 +222,9 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_PATH: path to AFL support binaries\n"
       "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
       "AFL_QUIET: suppress forkserver status messages\n"
+#ifdef AFL_PERSISTENT_RECORD
+      "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in out/crashes\n"
+#endif
       "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
       "AFL_TARGET_ENV: pass extra environment variables to target\n"
       "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
@@ -253,7 +256,13 @@ static void usage(u8 *argv0, int more_help) {
   SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
        (char *)PYTHON_VERSION);
 #else
-  SAYF("Compiled without python module support\n");
+  SAYF("Compiled without python module support.\n");
+#endif
+
+#ifdef AFL_PERSISTENT_RECORD
+  SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
+#else
+  SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
 #endif
 
 #ifdef USEMMAP
@@ -263,27 +272,27 @@ static void usage(u8 *argv0, int more_help) {
 #endif
 
 #ifdef ASAN_BUILD
-  SAYF("Compiled with ASAN_BUILD\n\n");
+  SAYF("Compiled with ASAN_BUILD.\n");
 #endif
 
 #ifdef NO_SPLICING
-  SAYF("Compiled with NO_SPLICING\n\n");
+  SAYF("Compiled with NO_SPLICING.\n");
 #endif
 
 #ifdef PROFILING
-  SAYF("Compiled with PROFILING\n\n");
+  SAYF("Compiled with PROFILING.\n");
 #endif
 
 #ifdef INTROSPECTION
-  SAYF("Compiled with INTROSPECTION\n\n");
+  SAYF("Compiled with INTROSPECTION.\n");
 #endif
 
 #ifdef _DEBUG
-  SAYF("Compiled with _DEBUG\n\n");
+  SAYF("Compiled with _DEBUG.\n");
 #endif
 
 #ifdef _AFL_DOCUMENT_MUTATIONS
-  SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS\n\n");
+  SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
 #endif
 
   SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
@@ -1023,6 +1032,30 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (unlikely(afl->afl_env.afl_persistent_record)) {
+
+  #ifdef AFL_PERSISTENT_RECORD
+
+    afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);
+
+    if (afl->fsrv.persistent_record < 2) {
+
+      FATAL(
+          "AFL_PERSISTENT_RECORD value must be be at least 2, recommended is "
+          "100 or 1000.");
+
+    }
+
+  #else
+
+    FATAL(
+        "afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in "
+        "config.h!");
+
+  #endif
+
+  }
+
   if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
 
   OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
@@ -1489,6 +1522,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
   check_binary(afl, argv[optind]);
 
+  #ifdef AFL_PERSISTENT_RECORD
+  if (unlikely(afl->fsrv.persistent_record)) {
+
+    if (!getenv(PERSIST_ENV_VAR)) {
+
+      FATAL(
+          "Target binary is not compiled in persistent mode, "
+          "AFL_PERSISTENT_RECORD makes no sense.");
+
+    }
+
+    afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir);
+
+  }
+
+  #endif
+
   if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
 
   afl->start_time = get_cur_time();
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 558665a2..bedf7806 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -955,7 +955,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-
   if (in_dir) {
 
     /* If we don't have a file name chosen yet, use a safe default. */