mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-13 02:28:09 +00:00
Merge branch 'replay' into tmp
This commit is contained in:
@ -424,6 +424,15 @@ checks or alter some of the more exotic semantics of the tool:
|
|||||||
- Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
|
- Setting `AFL_FORCE_UI` will force painting the UI on the screen even if
|
||||||
no valid terminal was detected (for virtual consoles)
|
no valid terminal was detected (for virtual consoles)
|
||||||
|
|
||||||
|
- If you are using persistent mode (you should, see [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md))
|
||||||
|
some targets keep inherent state due which a detected crash testcase does
|
||||||
|
not crash the target again when the testcase is given. To be able to still
|
||||||
|
re-trigger these crashes you can use the `AFL_PERSISTENT_RECORD` variable
|
||||||
|
with a value of how many previous fuzz cases to keep prio a crash.
|
||||||
|
if set to e.g. 10, then the 9 previous inputs are written to
|
||||||
|
out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008
|
||||||
|
and RECORD:000000,cnt:000009 being the crash case.
|
||||||
|
|
||||||
- If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
|
- If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`.
|
||||||
Others need not apply, unless they also want to disable the
|
Others need not apply, unless they also want to disable the
|
||||||
`/proc/sys/kernel/core_pattern` check.
|
`/proc/sys/kernel/core_pattern` check.
|
||||||
|
@ -390,7 +390,7 @@ typedef struct afl_env_vars {
|
|||||||
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
|
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
|
||||||
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
|
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
|
||||||
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
|
*afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
|
||||||
*afl_testcache_entries, *afl_kill_signal, *afl_target_env;
|
*afl_testcache_entries, *afl_kill_signal, *afl_target_env, *afl_persistent_record;
|
||||||
|
|
||||||
} afl_env_vars_t;
|
} afl_env_vars_t;
|
||||||
|
|
||||||
|
@ -73,6 +73,15 @@
|
|||||||
|
|
||||||
/* Now non-cmplog configuration options */
|
/* Now non-cmplog configuration options */
|
||||||
|
|
||||||
|
|
||||||
|
/* If a persistent target keeps state and found crashes are not reproducable
|
||||||
|
then enable this option and set the AFL_PERSISTENT_RECORD env variable
|
||||||
|
to a number. These number of testcases prior the crash will be kept and
|
||||||
|
also written to the crash/ directory */
|
||||||
|
|
||||||
|
#define AFL_PERSISTENT_RECORD
|
||||||
|
|
||||||
|
|
||||||
/* console output colors: There are three ways to configure its behavior
|
/* console output colors: There are three ways to configure its behavior
|
||||||
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
|
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
|
||||||
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
|
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
|
||||||
|
@ -130,6 +130,7 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_PASSTHROUGH",
|
"AFL_PASSTHROUGH",
|
||||||
"AFL_PATH",
|
"AFL_PATH",
|
||||||
"AFL_PERFORMANCE_FILE",
|
"AFL_PERFORMANCE_FILE",
|
||||||
|
"AFL_PERSISTENT_RECORD",
|
||||||
"AFL_PRELOAD",
|
"AFL_PRELOAD",
|
||||||
"AFL_TARGET_ENV",
|
"AFL_TARGET_ENV",
|
||||||
"AFL_PYTHON_MODULE",
|
"AFL_PYTHON_MODULE",
|
||||||
|
@ -94,6 +94,15 @@ typedef struct afl_forkserver {
|
|||||||
|
|
||||||
char *cmplog_binary; /* the name of the cmplog binary */
|
char *cmplog_binary; /* the name of the cmplog binary */
|
||||||
|
|
||||||
|
/* persistent mode replay functionality */
|
||||||
|
u32 persistent_record; /* persistent replay setting */
|
||||||
|
u32 persistent_record_idx; /* persistent replay cache ptr */
|
||||||
|
u32 persistent_record_cnt; /* persistent replay counter */
|
||||||
|
u8 * persistent_record_dir;
|
||||||
|
u8 ** persistent_record_data;
|
||||||
|
u32 * persistent_record_len;
|
||||||
|
s32 persistent_record_pid;
|
||||||
|
|
||||||
/* Function to kick off the forkserver child */
|
/* Function to kick off the forkserver child */
|
||||||
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
|
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/resource.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->last_run_timed_out = 0;
|
||||||
|
|
||||||
fsrv_to->init_child_func = from->init_child_func;
|
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);
|
list_append(&fsrv_list, fsrv_to);
|
||||||
|
|
||||||
@ -364,6 +365,23 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
|||||||
|
|
||||||
if (!be_quiet) { ACTF("Spinning up the fork server..."); }
|
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) {
|
if (fsrv->use_fauxsrv) {
|
||||||
|
|
||||||
/* TODO: Come up with some nice way to initialize this all */
|
/* TODO: Come up with some nice way to initialize this all */
|
||||||
@ -1032,6 +1050,31 @@ 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) {
|
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 (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) {
|
||||||
|
|
||||||
if (unlikely(len > MAX_FILE)) len = MAX_FILE;
|
if (unlikely(len > MAX_FILE)) len = MAX_FILE;
|
||||||
@ -1146,6 +1189,25 @@ 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 (fsrv->child_pid <= 0) {
|
||||||
|
|
||||||
if (*stop_soon_p) { return 0; }
|
if (*stop_soon_p) { return 0; }
|
||||||
@ -1244,6 +1306,38 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
|
|||||||
(fsrv->uses_crash_exitcode &&
|
(fsrv->uses_crash_exitcode &&
|
||||||
WEXITSTATUS(fsrv->child_status) == fsrv->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 */
|
/* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
|
||||||
fsrv->last_kill_signal =
|
fsrv->last_kill_signal =
|
||||||
WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
|
WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
|
||||||
|
@ -292,6 +292,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
|
|||||||
afl->afl_env.afl_autoresume =
|
afl->afl_env.afl_autoresume =
|
||||||
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
|
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",
|
} else if (!strncmp(env, "AFL_CYCLE_SCHEDULES",
|
||||||
|
|
||||||
afl_environment_variable_len)) {
|
afl_environment_variable_len)) {
|
||||||
|
@ -222,6 +222,9 @@ static void usage(u8 *argv0, int more_help) {
|
|||||||
"AFL_PATH: path to AFL support binaries\n"
|
"AFL_PATH: path to AFL support binaries\n"
|
||||||
"AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
|
"AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
|
||||||
"AFL_QUIET: suppress forkserver status messages\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_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
|
||||||
"AFL_TARGET_ENV: pass extra environment variables to target\n"
|
"AFL_TARGET_ENV: pass extra environment variables to target\n"
|
||||||
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\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",
|
SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
|
||||||
(char *)PYTHON_VERSION);
|
(char *)PYTHON_VERSION);
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
#ifdef USEMMAP
|
#ifdef USEMMAP
|
||||||
@ -263,27 +272,27 @@ static void usage(u8 *argv0, int more_help) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ASAN_BUILD
|
#ifdef ASAN_BUILD
|
||||||
SAYF("Compiled with ASAN_BUILD\n\n");
|
SAYF("Compiled with ASAN_BUILD.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NO_SPLICING
|
#ifdef NO_SPLICING
|
||||||
SAYF("Compiled with NO_SPLICING\n\n");
|
SAYF("Compiled with NO_SPLICING.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PROFILING
|
#ifdef PROFILING
|
||||||
SAYF("Compiled with PROFILING\n\n");
|
SAYF("Compiled with PROFILING.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef INTROSPECTION
|
#ifdef INTROSPECTION
|
||||||
SAYF("Compiled with INTROSPECTION\n\n");
|
SAYF("Compiled with INTROSPECTION.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
SAYF("Compiled with _DEBUG\n\n");
|
SAYF("Compiled with _DEBUG.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _AFL_DOCUMENT_MUTATIONS
|
#ifdef _AFL_DOCUMENT_MUTATIONS
|
||||||
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS\n\n");
|
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
|
SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
|
||||||
@ -1023,6 +1032,28 @@ 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;
|
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\" "
|
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
|
||||||
@ -1489,6 +1520,20 @@ int main(int argc, char **argv_orig, char **envp) {
|
|||||||
|
|
||||||
check_binary(afl, argv[optind]);
|
check_binary(afl, argv[optind]);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
|
if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
|
||||||
|
|
||||||
afl->start_time = get_cur_time();
|
afl->start_time = get_cur_time();
|
||||||
|
Reference in New Issue
Block a user