implementation without testing
MODIFY
include/forkserver.h
include/forkserver.h
@@ -55,9 +55,6 @@ typedef struct afl_forkserver {
u32 init_tmout; /* Configurable init timeout (ms) */
u32 map_size; /* map size used by the target */
u32 snapshot; /* is snapshot feature used */
- u32 persistent_replay; /* persistent replay setting */
- u32 persistent_replay_idx; /* persistent replay cache ptr */
- u32 persistent_replay_cnt; /* persistent replay counter */
u64 mem_limit; /* Memory cap for child (MB) */
u64 total_execs; /* How often run_target was called */
@@ -97,6 +94,14 @@ typedef struct afl_forkserver {
char *cmplog_binary; /* the name of the cmplog binary */
+ /* persistent mode replay functionality */
+ u32 persistent_replay; /* persistent replay setting */
+ u32 persistent_replay_idx; /* persistent replay cache ptr */
+ u32 persistent_replay_cnt; /* persistent replay counter */
+ u8 * persistent_replay_dir;
+ u8 ** persistent_replay_data;
+ u32 **persistent_replay_len;
+
/* Function to kick off the forkserver child */
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);

MODIFY
src/afl-forkserver.c
src/afl-forkserver.c
@@ -364,6 +364,21 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!be_quiet) { ACTF("Spinning up the fork server..."); }
+ if (unlikely(fsrv->persistent_replay)) {
+
+ fsrv->persistent_replay_data =
+ (u8 **)ck_alloc(fsrv->persistent_replay * sizeof(size_t));
+ fsrv->persistent_replay_len =
+ (u32 **)ck_alloc(fsrv->persistent_replay * sizeof(u32));
+
+ if (!fsrv->persistent_replay_data || !fsrv->persistent_replay_len) {
+
+ FATAL("Unable to allocate memory for persistent replay.");
+
+ }
+
+ }
+
if (fsrv->use_fauxsrv) {
/* TODO: Come up with some nice way to initialize this all */
@@ -998,6 +1013,29 @@ 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) {
+ if (unlikely(fsrv->persistent_replay)) {
+
+ *fsrv->persistent_replay_len[fsrv->persistent_replay_idx] = len;
+ fsrv->persistent_replay_data[fsrv->persistent_replay_idx] = afl_realloc(
+ (void **)&fsrv->persistent_replay_data[fsrv->persistent_replay_idx],
+ len);
+
+ if (unlikely(!fsrv->persistent_replay_data[fsrv->persistent_replay_idx])) {
+
+ FATAL("allocating replay memory failed.");
+
+ }
+
+ memcpy(fsrv->persistent_replay_data[fsrv->persistent_replay_idx], buf, len);
+
+ if (unlikely(++fsrv->persistent_replay_idx >= fsrv->persistent_replay)) {
+
+ fsrv->persistent_replay_idx = 0;
+
+ }
+
+ }
+
if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) {
if (unlikely(len > MAX_FILE)) len = MAX_FILE;
@@ -1208,6 +1246,36 @@ 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))) {
+ if (unlikely(fsrv->persistent_replay)) {
+
+ char fn[4096];
+ u32 i, writecnt = 0;
+ for (i = 0; i < fsrv->persistent_replay; ++i) {
+
+ u32 entry = (i + fsrv->persistent_replay_idx) % fsrv->persistent_replay;
+ u8 *data = fsrv->persistent_replay_data[entry];
+ u32 *len = fsrv->persistent_replay_len[entry];
+ if (likely(len && *len && data)) {
+
+ snprintf(fn, sizeof(fn), "%s/replay_%u_%u.bin",
+ fsrv->persistent_replay_dir, fsrv->persistent_replay_cnt,
+ writecnt++);
+ int fd = open(fn, O_WRONLY, 0644);
+ if (fd >= 0) {
+
+ ck_write(fd, data, *len, fn);
+ close(fd);
+
+ }
+
+ }
+
+ }
+
+ ++fsrv->persistent_replay_cnt;
+
+ }
+
/* 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;

MODIFY
src/afl-fuzz.c
src/afl-fuzz.c
@@ -1239,9 +1239,10 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (afl->afl_env.afl_persistent_replay) {
+ if (unlikely(afl->afl_env.afl_persistent_replay)) {
afl->fsrv.persistent_replay = atoi(afl->afl_env.afl_persistent_replay);
+ afl->fsrv.persistent_replay_dir = alloc_printf("%s/crashes", afl->out_dir);
}

implementation without testing