From 63d79213e1dea7d683dffd3dc656baef239f1ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulf=20Karg=C3=A9n?= <ulf.kargen@liu.se> Date: Fri, 10 May 2024 20:34:00 +0200 Subject: [PATCH] implement fuzzer execution serialization --- include/afl-fuzz.h | 4 +-- include/envs.h | 1 + src/afl-fuzz-state.c | 7 ++++ src/afl-fuzz.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f87e21df..425508c5 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 942aab66..9b13295b 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 60206b4a..1b47cc00 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 b93b04ef..58f90669 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); -- GitLab