diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f87e21df2cb498c48a2f1714b7f98852f07652c5..425508c53ea933f9e101266f8260bcefee6ce50f 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -399,7 +399,7 @@ typedef struct afl_env_vars { afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems, afl_keep_timeouts, afl_no_crash_readme, afl_ignore_timeouts, - afl_no_startup_calibration, afl_no_warn_instability; + afl_no_startup_calibration, afl_no_warn_instability, afl_serialize_exec; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, @@ -596,7 +596,7 @@ typedef struct afl_state { longest_find_time, /* Longest time taken for a find */ exit_on_time, /* Delay to exit if no new paths */ sync_time, /* Sync time (ms) */ - sync_delay; /* Sync delay (ms) */ + sync_delay; /* Sync delay (ms) */ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */ subseq_tmouts; /* Number of timeouts in a row */ diff --git a/include/envs.h b/include/envs.h index 942aab669c1d1196fd5ab0d4c7c908c8c637936c..9b13295b04586e3ad2336d3f326ceeeda71d38a8 100644 --- a/include/envs.h +++ b/include/envs.h @@ -211,6 +211,7 @@ static char *afl_environment_variables[] = { "AFL_QUIET", "AFL_RANDOM_ALLOC_CANARY", "AFL_REAL_PATH", + "AFL_SERIALIZE_EXEC", "AFL_SHUFFLE_QUEUE", "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 60206b4a7e66b385bb7654a56c1fc78fe974b63b..1b47cc0046a1b3d925ff5ba07075444bc009aa41 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -584,6 +584,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { } + } else if (!strncmp(env, "AFL_SERIALIZE_EXEC", + + afl_environment_variable_len)) { + + afl->afl_env.afl_serialize_exec = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_FUZZER_STATS_UPDATE_INTERVAL", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b93b04efc83442538e4ad2bd483a0f75e0f33d00..58f90669a0a50eb0f08f0d0371923bea2908253b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -453,6 +453,12 @@ int main(int argc, char **argv_orig, char **envp) { struct timeval tv; struct timezone tz; + u8* syncpath = NULL; + s32 sync_fd; + struct flock synclock = { F_UNLCK, SEEK_SET, 0, 0, 0 }; + u64 sync_work = 0, sleep_start = 0, tot_sleep = 0; + u8 done_work = 0; + #if defined USE_COLOR && defined ALWAYS_COLORED if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) { @@ -1406,6 +1412,18 @@ int main(int argc, char **argv_orig, char **envp) { fix_up_sync(afl); + if (afl->afl_env.afl_serialize_exec) { + + syncpath = alloc_printf("%s/.serialize", afl->sync_dir); + + sync_fd = open(syncpath, O_RDWR | O_CREAT, 0644); + + if (sync_fd < 0) { + PFATAL("Unable to open fuzzer serialization file."); + } + + } + } if (!strcmp(afl->in_dir, afl->out_dir)) { @@ -2506,6 +2524,61 @@ int main(int argc, char **argv_orig, char **envp) { do { + if (afl->sync_id && afl->afl_env.afl_serialize_exec) { + + // Acquire lock on serialization sync file + if (synclock.l_type == F_UNLCK) { + + synclock.l_type = F_WRLCK; + if (fcntl(sync_fd, F_SETLKW, &synclock) < 0) { + PFATAL("Unable to fcntl() fuzzer serialization file."); + } + + if (sleep_start) { + tot_sleep += get_cur_time() - sleep_start; + } + + s64 res; + + if (lseek(sync_fd, 0, SEEK_SET) < 0 || + (res = read(sync_fd, &sync_work, sizeof(sync_work))) < 0) { + PFATAL("Unable to read fuzzer serialization file."); + } + + if (res == 0) { + sync_work = 0; + } + + } + + u64 tot_work = get_cur_time() - afl->start_time - tot_sleep; + + if (done_work && sync_work + 1000 < tot_work) { + + if (lseek(sync_fd, 0, SEEK_SET) < 0 || + write(sync_fd, &tot_work, sizeof(tot_work)) < 0) { + PFATAL("Unable to write to fuzzer serialization file."); + } + + sleep_start = get_cur_time(); + done_work = 0; + + // Release lock + synclock.l_type = F_UNLCK; + if (fcntl(sync_fd, F_SETLK, &synclock) < 0) { + PFATAL("Unable to fcntl() fuzzer serialization file."); + } + + // Yield execution + usleep(1000); + + continue; + } + + done_work = 1; + + } + if (likely(!afl->old_seed_selection)) { if (unlikely(prev_queued_items < afl->queued_items || @@ -2695,6 +2768,19 @@ stop_fuzzing: } + if (afl->sync_id && afl->afl_env.afl_serialize_exec) { + + /* TODO: This only works as intended when all fuzzer instances shut down + sequentially. Will break if one instance exits and another one joins + before all others have shut down. (Running instances keep references to + inode until all fds have been closed.)*/ + + close(sync_fd); + unlink(syncpath); + free(syncpath); + + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } fclose(afl->fsrv.plot_file);