From 84f0b4f1874a9c3a5f2da4056f974df8273093d9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 7 Feb 2021 08:27:35 +0100 Subject: persistent replay env setup --- include/afl-fuzz.h | 2 +- include/envs.h | 1 + include/forkserver.h | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c3a8c2ee..3b6f2285 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -390,7 +390,7 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries, *afl_kill_signal; + *afl_testcache_entries, *afl_kill_signal, *afl_persistent_replay; } afl_env_vars_t; diff --git a/include/envs.h b/include/envs.h index 210b34a6..f82bb803 100644 --- a/include/envs.h +++ b/include/envs.h @@ -123,6 +123,7 @@ static char *afl_environment_variables[] = { "AFL_MAX_DET_EXTRAS", "AFL_PATH", "AFL_PERFORMANCE_FILE", + "AFL_PERSISTEN_REPLAY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV", diff --git a/include/forkserver.h b/include/forkserver.h index ac027f81..a0a60e0f 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -55,6 +55,9 @@ 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 */ -- cgit 1.4.1 From 81442ba3f953c939e2cde9c16b9cd0d5fe7f12b5 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 15:48:49 +0100 Subject: implementation without testing --- include/forkserver.h | 11 ++++++--- src/afl-forkserver.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/afl-fuzz.c | 3 ++- 3 files changed, 78 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/forkserver.h b/include/forkserver.h index a0a60e0f..ddbc36ef 100644 --- a/include/forkserver.h +++ b/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); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 7968f69c..05aba2e5 100644 --- a/src/afl-forkserver.c +++ b/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; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 77e6e2ce..f3aea2c7 100644 --- a/src/afl-fuzz.c +++ b/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); } -- cgit 1.4.1 From 4a0d4c50fc8bec11a090156ab970414d4897ea6c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 19:12:25 +0100 Subject: complete implemenation, still no test --- include/afl-fuzz.h | 2 +- include/forkserver.h | 13 ++++++----- src/afl-forkserver.c | 63 +++++++++++++++++++++++++++++++++------------------- src/afl-fuzz-state.c | 4 ++-- src/afl-fuzz.c | 22 +++++++++++++++--- 5 files changed, 69 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 3b6f2285..b1fba884 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -390,7 +390,7 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries, *afl_kill_signal, *afl_persistent_replay; + *afl_testcache_entries, *afl_kill_signal, *afl_persistent_record; } afl_env_vars_t; diff --git a/include/forkserver.h b/include/forkserver.h index ddbc36ef..850c5b0d 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -95,12 +95,13 @@ 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; + 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 */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 05aba2e5..78e5efe7 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -126,7 +126,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 or ->persistent_replay* + // Note: do not copy ->add_extra_func or ->persistent_record* list_append(&fsrv_list, fsrv_to); @@ -364,14 +364,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the fork server..."); } - if (unlikely(fsrv->persistent_replay)) { + if (unlikely(fsrv->persistent_record)) { - 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)); + fsrv->persistent_record_data = + (u8 **)ck_alloc(fsrv->persistent_record * sizeof(size_t)); + fsrv->persistent_record_len = + (u32 **)ck_alloc(fsrv->persistent_record * sizeof(u32)); - if (!fsrv->persistent_replay_data || !fsrv->persistent_replay_len) { + if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) { FATAL("Unable to allocate memory for persistent replay."); @@ -1013,24 +1013,24 @@ 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)) { + if (unlikely(fsrv->persistent_record)) { - *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], + *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_replay_data[fsrv->persistent_replay_idx])) { + if (unlikely(!fsrv->persistent_record_data[fsrv->persistent_record_idx])) { FATAL("allocating replay memory failed."); } - memcpy(fsrv->persistent_replay_data[fsrv->persistent_replay_idx], buf, len); + memcpy(fsrv->persistent_record_data[fsrv->persistent_record_idx], buf, len); - if (unlikely(++fsrv->persistent_replay_idx >= fsrv->persistent_replay)) { + if (unlikely(++fsrv->persistent_record_idx >= fsrv->persistent_record)) { - fsrv->persistent_replay_idx = 0; + fsrv->persistent_record_idx = 0; } @@ -1148,6 +1148,23 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } + // 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; + + } + if (fsrv->child_pid <= 0) { if (*stop_soon_p) { return 0; } @@ -1246,19 +1263,19 @@ 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)) { + if (unlikely(fsrv->persistent_record)) { char fn[4096]; u32 i, writecnt = 0; - for (i = 0; i < fsrv->persistent_replay; ++i) { + for (i = 0; i < fsrv->persistent_record; ++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]; + 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 && *len && data)) { - snprintf(fn, sizeof(fn), "%s/replay_%u_%u.bin", - fsrv->persistent_replay_dir, fsrv->persistent_replay_cnt, + snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u", + fsrv->persistent_record_dir, fsrv->persistent_record_cnt, writecnt++); int fd = open(fn, O_WRONLY, 0644); if (fd >= 0) { @@ -1272,7 +1289,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } - ++fsrv->persistent_replay_cnt; + ++fsrv->persistent_record_cnt; } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 075aef1e..514414f3 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -292,11 +292,11 @@ 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_REPLAY", + } else if (!strncmp(env, "AFL_PERSISTENT_RECORD", afl_environment_variable_len)) { - afl->afl_env.afl_persistent_replay = + afl->afl_env.afl_persistent_record = get_afl_env(afl_environment_variables[i]); } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f3aea2c7..afaa8f5f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1239,10 +1239,26 @@ int main(int argc, char **argv_orig, char **envp) { } - if (unlikely(afl->afl_env.afl_persistent_replay)) { + if (unlikely(afl->afl_env.afl_persistent_record)) { - afl->fsrv.persistent_replay = atoi(afl->afl_env.afl_persistent_replay); - afl->fsrv.persistent_replay_dir = alloc_printf("%s/crashes", afl->out_dir); + afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); + afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); + + if (afl->fsrv.persistent_record < 2) { + + FATAL( + "AFL_PERSISTENT_RECORD vallue must be be at least 2, recommended is " + "100 or 1000."); + + } + + if (!getenv(PERSIST_ENV_VAR)) { + + FATAL( + "Target binary is not compiled in persistent mode, " + "AFL_PERSISTENT_RECORD makes no sense."); + + } } -- cgit 1.4.1 From 7f062524c97ab18306d42e59ab0223e04ff78f24 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 23:01:13 +0100 Subject: fixes --- include/envs.h | 2 +- include/forkserver.h | 2 +- src/afl-forkserver.c | 14 +++++++------- src/afl-fuzz.c | 50 +++++++++++++++++++++++++++----------------------- 4 files changed, 36 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/envs.h b/include/envs.h index f82bb803..6ba69f26 100644 --- a/include/envs.h +++ b/include/envs.h @@ -123,7 +123,7 @@ static char *afl_environment_variables[] = { "AFL_MAX_DET_EXTRAS", "AFL_PATH", "AFL_PERFORMANCE_FILE", - "AFL_PERSISTEN_REPLAY", + "AFL_PERSISTENT_RECORD", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV", diff --git a/include/forkserver.h b/include/forkserver.h index 850c5b0d..c894ad80 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -100,7 +100,7 @@ typedef struct afl_forkserver { u32 persistent_record_cnt; /* persistent replay counter */ u8 * persistent_record_dir; u8 ** persistent_record_data; - u32 **persistent_record_len; + u32 * persistent_record_len; s32 persistent_record_pid; /* Function to kick off the forkserver child */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a6128220..e6738a71 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -370,7 +370,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, fsrv->persistent_record_data = (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *)); fsrv->persistent_record_len = - (u32 **)ck_alloc(fsrv->persistent_record * sizeof(u32)); + (u32 *)ck_alloc(fsrv->persistent_record * sizeof(u32)); if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) { @@ -1016,7 +1016,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { if (unlikely(fsrv->persistent_record)) { - *fsrv->persistent_record_len[fsrv->persistent_record_idx] = len; + 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); @@ -1159,10 +1159,10 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, idx = fsrv->persistent_record - 1; else idx = fsrv->persistent_record_idx - 1; - val = *fsrv->persistent_record_len[idx]; + val = fsrv->persistent_record_len[idx]; memset((void *)fsrv->persistent_record_len, 0, fsrv->persistent_record * sizeof(u32)); - *fsrv->persistent_record_len[idx] = val; + fsrv->persistent_record_len[idx] = val; } @@ -1272,8 +1272,8 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, 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 && *len && data)) { + 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, @@ -1281,7 +1281,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, int fd = open(fn, O_WRONLY, 0644); if (fd >= 0) { - ck_write(fd, data, *len, fn); + ck_write(fd, data, len, fn); close(fd); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index afaa8f5f..4ee71120 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -986,6 +986,21 @@ int main(int argc, char **argv_orig, char **envp) { } + if (unlikely(afl->afl_env.afl_persistent_record)) { + + afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); + afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); + + if (afl->fsrv.persistent_record < 2) { + + FATAL( + "AFL_PERSISTENT_RECORD value must be be at least 2, recommended is " + "100 or 1000."); + + } + + } + if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) { u8 *preload = getenv("AFL_PRELOAD"); @@ -1239,29 +1254,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (unlikely(afl->afl_env.afl_persistent_record)) { - - afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); - afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); - - if (afl->fsrv.persistent_record < 2) { - - FATAL( - "AFL_PERSISTENT_RECORD vallue must be be at least 2, recommended is " - "100 or 1000."); - - } - - if (!getenv(PERSIST_ENV_VAR)) { - - FATAL( - "Target binary is not compiled in persistent mode, " - "AFL_PERSISTENT_RECORD makes no sense."); - - } - - } - if (afl->afl_env.afl_crash_exitcode) { long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10); @@ -1531,6 +1523,18 @@ int main(int argc, char **argv_orig, char **envp) { 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."); + + } + + } + if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); } afl->start_time = get_cur_time(); -- cgit 1.4.1 From ee5078f43c44a022831cf83b6963930975188168 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 11:22:37 +0100 Subject: v3.13a init --- docs/Changelog.md | 3 +++ include/config.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/docs/Changelog.md b/docs/Changelog.md index 5b7d6ab6..6b7ebf15 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.13a (development) + - ... + ### Version ++3.12c (release) - afl-fuzz: - added AFL_TARGET_ENV variable to pass extra env vars to the target diff --git a/include/config.h b/include/config.h index c93a6d51..8ac74c45 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.12c" +#define VERSION "++3.13a" /****************************************************** * * -- cgit 1.4.1 From 958436be4ba057e8409787e7ff4ddcfa095c46da Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 18:18:05 +0100 Subject: ifdef for record --- include/config.h | 9 +++++++++ src/afl-forkserver.c | 8 ++++++++ src/afl-fuzz.c | 30 +++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/config.h b/include/config.h index 60872785..f6dbfae0 100644 --- a/include/config.h +++ b/include/config.h @@ -60,6 +60,15 @@ /* 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 * 1. default: colored outputs fixed on: defined USE_COLOR && defined * ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 2ab1304e..4e4f92d6 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -365,6 +365,7 @@ 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 = @@ -379,6 +380,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } } +#endif if (fsrv->use_fauxsrv) { @@ -1014,6 +1016,7 @@ 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; @@ -1036,6 +1039,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } } +#endif if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { @@ -1149,6 +1153,7 @@ 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)) { @@ -1165,6 +1170,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, fsrv->persistent_record_len[idx] = val; } +#endif if (fsrv->child_pid <= 0) { @@ -1264,6 +1270,7 @@ 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]; @@ -1293,6 +1300,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, ++fsrv->persistent_record_cnt; } +#endif /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */ fsrv->last_kill_signal = diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b2c81580..d622db71 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -218,7 +218,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_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" @@ -249,7 +251,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 @@ -259,27 +267,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); @@ -989,6 +997,8 @@ 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) { @@ -999,6 +1009,12 @@ int main(int argc, char **argv_orig, char **envp) { } +#else + + FATAL("afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in config.h!"); + +#endif + } if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) { -- cgit 1.4.1 From 55224e5150b3acfc4c1db3975ef6a2b5e173f626 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 18:24:52 +0100 Subject: AFL_PERSISTENT_RECORD not a default --- include/config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/config.h b/include/config.h index ab4c49f2..4691624a 100644 --- a/include/config.h +++ b/include/config.h @@ -71,16 +71,16 @@ /* Maximum allowed fails per CMP value. Default: 128 */ #define CMPLOG_FAIL_MAX 96 +/* -------------------------------------*/ /* 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 - +//#define AFL_PERSISTENT_RECORD /* console output colors: There are three ways to configure its behavior * 1. default: colored outputs fixed on: defined USE_COLOR && defined -- cgit 1.4.1 From e1384b5086e918350426cd0ece7dbe9c451f771f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 18 Mar 2021 09:11:00 +0000 Subject: Add support for FRIDA mode --- .gitignore | 1 + frida_mode/.gitignore | 5 + frida_mode/Makefile | 310 +++++++++++++++++++++++++++++++++ frida_mode/README.md | 48 ++++++ frida_mode/inc/instrument.h | 7 + frida_mode/inc/interceptor.h | 4 + frida_mode/inc/prefetch.h | 5 + frida_mode/inc/ranges.h | 6 + frida_mode/src/instrument.c | 265 +++++++++++++++++++++++++++++ frida_mode/src/interceptor.c | 16 ++ frida_mode/src/main.c | 149 ++++++++++++++++ frida_mode/src/prefetch.c | 121 +++++++++++++ frida_mode/src/ranges.c | 395 +++++++++++++++++++++++++++++++++++++++++++ frida_mode/test/testinstr.c | 105 ++++++++++++ frida_mode/test/testinstr.py | 32 ++++ include/envs.h | 7 + include/forkserver.h | 2 + src/afl-analyze.c | 50 +++++- src/afl-fuzz-init.c | 7 +- src/afl-fuzz.c | 54 +++++- src/afl-showmap.c | 47 ++++- src/afl-tmin.c | 49 +++++- 22 files changed, 1668 insertions(+), 17 deletions(-) create mode 100644 frida_mode/.gitignore create mode 100644 frida_mode/Makefile create mode 100644 frida_mode/README.md create mode 100644 frida_mode/inc/instrument.h create mode 100644 frida_mode/inc/interceptor.h create mode 100644 frida_mode/inc/prefetch.h create mode 100644 frida_mode/inc/ranges.h create mode 100644 frida_mode/src/instrument.c create mode 100644 frida_mode/src/interceptor.c create mode 100644 frida_mode/src/main.c create mode 100644 frida_mode/src/prefetch.c create mode 100644 frida_mode/src/ranges.c create mode 100644 frida_mode/test/testinstr.c create mode 100755 frida_mode/test/testinstr.py (limited to 'include') diff --git a/.gitignore b/.gitignore index 3f440730..2aaaf9ef 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,4 @@ libAFLDriver.a libAFLQemuDriver.a test/.afl_performance gmon.out +afl-frida-trace.so diff --git a/frida_mode/.gitignore b/frida_mode/.gitignore new file mode 100644 index 00000000..956b9911 --- /dev/null +++ b/frida_mode/.gitignore @@ -0,0 +1,5 @@ +build/ +frida_test.dat +qemu_test.dat +frida_out/** +qemu_out/** diff --git a/frida_mode/Makefile b/frida_mode/Makefile new file mode 100644 index 00000000..73a4142c --- /dev/null +++ b/frida_mode/Makefile @@ -0,0 +1,310 @@ +PWD:=$(shell pwd)/ +INC_DIR:=$(PWD)inc/ +SRC_DIR:=$(PWD)src/ +INCLUDES:=$(wildcard $(INC_DIR)*.h) +SOURCES:=$(wildcard $(SRC_DIR)*.c) +BUILD_DIR:=$(PWD)build/ +CFLAGS:= $(CFLAGS) \ + -fPIC \ + -D_GNU_SOURCE + +FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ +FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" +ARCH:=arm64 +TESTINSTR_BASE:=0x0000aaaaaaaaa000 +endif + +ifeq "$(ARCH)" "x86_64" +TESTINSTR_BASE:=0x0000555555554000 +endif + +ifeq "$(shell uname)" "Darwin" +OS:=macos +AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF +CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations +TEST_LDFLAGS:=-undefined dynamic_lookup +endif +ifeq "$(shell uname)" "Linux" +OS:=linux +AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) +CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor +TEST_LDFLAGS:= +endif + +ifndef OS +$(error "Operating system unsupported") +endif + +VERSION=14.2.13 +GUM_DEVKIT_FILENAME=frida-gum-devkit-$(VERSION)-$(OS)-$(ARCH).tar.xz +GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(VERSION)/$(GUM_DEVKIT_FILENAME)" +GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) +GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a +GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h + +TEST_BUILD_DIR:=$(BUILD_DIR)test/ + +LIBPNG_FILE:=$(TEST_BUILD_DIR)libpng-1.2.56.tar.gz +LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz +LIBPNG_DIR:=$(TEST_BUILD_DIR)libpng-1.2.56/ +LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile +LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a + +HARNESS_FILE:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +PNGTEST_FILE:=$(TEST_BUILD_DIR)target.cc +PNGTEST_OBJ:=$(TEST_BUILD_DIR)target.o +PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc" + +TEST_BIN:=$(TEST_BUILD_DIR)pngtest + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)test/testinstr.c + +TEST_DATA_DIR:=$(PWD)build/test/libpng-1.2.56/contrib/pngsuite/ + +TESTINSTR_DATA_DIR:=$(BUILD_DIR)testinstr_in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)test.dat +FRIDA_OUT:=$(PWD)frida_out +QEMU_OUT:=$(PWD)qemu_out + +.PHONY: all frida test clean format test_frida test_qemu compare testinstr test_testinstr standalone + +all: $(FRIDA_TRACE) + +frida: $(FRIDA_TRACE) + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +############################# FRIDA ############################################ +$(FRIDA_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) + wget -O $@ $(GUM_DEVKIT_URL) + +$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(SOURCES) Makefile | $(FRIDA_BUILD_DIR) + $(CC) -shared \ + $(CFLAGS) \ + -o $@ $(SOURCES) \ + $(GUM_DEVIT_LIBRARY) \ + -I $(FRIDA_BUILD_DIR) \ + -I .. \ + -I ../include \ + -I $(INC_DIR) \ + ../instrumentation/afl-compiler-rt.o.c \ + -lpthread -ldl -lresolv + + cp -v $(FRIDA_TRACE) ../ + +############################# TEST ############################################# + +test: $(TEST_BIN) + +$(TEST_BUILD_DIR): $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(TEST_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) -o $@ -c $< + +$(PNGTEST_FILE): | $(TEST_BUILD_DIR) + wget -O $@ $(PNGTEST_URL) + +$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) + $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< + +$(LIBPNG_FILE): | $(TEST_BUILD_DIR) + wget -O $@ $(LIBPNG_URL) + +$(LIBPNG_DIR): $(LIBPNG_FILE) + tar zxvf $(LIBPNG_FILE) -C $(TEST_BUILD_DIR) + +$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) + cd $(LIBPNG_DIR) && ./configure + +$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) + make -C $(LIBPNG_DIR) + +$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) + $(CXX) \ + -o $@ \ + $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ + -lz \ + $(TEST_LDFLAGS) + +############################# TESTINSR ######################################### +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) -o $@ $< + +testinstr: $(TESTINSTBIN) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd .. && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i + cd .. && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i + cd .. && ./.custom-format.py -i $(TESTINSTSRC) + +############################# RUN ############################################# + +# Add the environment variable AFL_DEBUG_CHILD=1 to show printf's from the target + +png_frida: $(FRIDA_TRACE) $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-fuzz \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +png_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-fuzz \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +compare: $(FRIDA_TRACE) $(TEST_BIN) + cd .. && \ + ./afl-fuzz \ + -V30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + cd .. && \ + ./afl-fuzz \ + -V30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + cat frida_out/default/fuzzer_stats + cat qemu_out/default/fuzzer_stats + +testinstr_qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + make -C .. + cd .. && \ + AFL_QEMU_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + ./afl-fuzz \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +testinstr_frida: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + make -C .. + cd .. && \ + AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + AFL_FRIDA_INST_NO_OPTIMIZE=1 \ + AFL_FRIDA_INST_NO_PREFETCH=1 \ + AFL_FRIDA_INST_STRICT=1 \ + ./afl-fuzz \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +standalone: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + cd .. && \ + AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + AFL_DEBUG_CHILD=1 \ + AFL_FRIDA_DEBUG_MAPS=1 \ + AFL_FRIDA_INST_NO_OPTIMIZE=1 \ + AFL_FRIDA_INST_NO_PREFETCH=1 \ + AFL_FRIDA_INST_TRACE=1 \ + AFL_FRIDA_INST_STRICT=1 \ + LD_PRELOAD=$(FRIDA_TRACE) \ + DYLD_INSERT_LIBRARIES=$(FRIDA_TRACE) \ + $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + +tmin_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-tmin \ + -Q \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -o $(QEMU_OUT)/qemu-min-basn0g01.png \ + -- \ + $(TEST_BIN) @@ + +tmin_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-tmin \ + -O \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -o $(FRIDA_OUT)/qemu-min-basn0g01.png \ + -- \ + $(TEST_BIN) + +showmap_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-showmap \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +showmap_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-showmap \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +analyze_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-analyze \ + -Q \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -- \ + $(TEST_BIN) @@ + +analyze_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-analyze \ + -O \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -- \ + $(TEST_BIN) @@ \ No newline at end of file diff --git a/frida_mode/README.md b/frida_mode/README.md new file mode 100644 index 00000000..c5436e8b --- /dev/null +++ b/frida_mode/README.md @@ -0,0 +1,48 @@ +# FRIDA MODE +The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AFL +just like that provided by QEMU mode. The intention is to provide a very similar +user experience, right down to the options provided through environment variables. + +Additionally, the intention is to be able to make a direct performance comparison +between the two approaches. Hopefully, we should also be able to leverage the same +approaches for adding features which QEMU uses, possibly even sharing code. + +## Limitations +The current focus is on x64 support for Intel. Although parts may be architecturally +dependent, the approach itself should remain architecture agnostic. + +## Usage +FRIDA mode requires some small modifications to the afl-fuzz and similar tools in +AFLplusplus. The intention is that it behaves identically to QEMU, but uses the 'O' +switch rather than 'Q'. + +## Design +AFL Frida works by means of a shared library injected into a binary program using +LD_PRELOAD, similar to the way which other fuzzing features are injected into targets. + +## Testing +Alongside the FRIDA mode, we also include a test program for fuzzing. This test +program is built using the libpng benchmark from fuzz-bench and integrating the +StandaloneFuzzTargetMain from the llvm project. This is built and linked without +any special modifications to suit FRIDA or QEMU. However, at present we don't have +a representative corpus. + +## Getting Started +To build everything run `make`. + +To run the benchmark sample with qemu run `make test_qemu`. +To run the benchmark sample with frida run `make test_frida`. + +# Configuration options +* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` +* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` +* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use `AFL_FRIDA_INST_TRACE`. +* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. +* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES` +* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into excluded regions and generate both instrumented blocks and coverage data (e.g. indirect calls on x86). The excluded block is generally honoured as soon as another function is called within the excluded region. The overhead of generating, running and instrumenting these few additional blocks is likely to be fairly small, but it may hinder you when checking that the correct number of paths are found for testing purposes or similar. There is a performance penatly for this option during block compilation where we check the block isn't in a list of excluded ranges. +* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. + +# TODO +* Add AARCH64 inline assembly optimization from libFuzz +* Fix issues running on OSX +* Identify cause of erroneous additional paths diff --git a/frida_mode/inc/instrument.h b/frida_mode/inc/instrument.h new file mode 100644 index 00000000..ff71bed4 --- /dev/null +++ b/frida_mode/inc/instrument.h @@ -0,0 +1,7 @@ +#include "frida-gum.h" + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); + +void instrument_init(); + diff --git a/frida_mode/inc/interceptor.h b/frida_mode/inc/interceptor.h new file mode 100644 index 00000000..5ed3cf49 --- /dev/null +++ b/frida_mode/inc/interceptor.h @@ -0,0 +1,4 @@ +#include "frida-gum.h" + +void intercept(void *address, gpointer replacement, gpointer user_data); + diff --git a/frida_mode/inc/prefetch.h b/frida_mode/inc/prefetch.h new file mode 100644 index 00000000..b7f25a97 --- /dev/null +++ b/frida_mode/inc/prefetch.h @@ -0,0 +1,5 @@ +void prefetch_init(); +void prefetch_start(GumStalker *stalker); +void prefetch_write(void *addr); +void prefetch_read(GumStalker *stalker); + diff --git a/frida_mode/inc/ranges.h b/frida_mode/inc/ranges.h new file mode 100644 index 00000000..b9394dbc --- /dev/null +++ b/frida_mode/inc/ranges.h @@ -0,0 +1,6 @@ +#include "frida-gum.h" + +void ranges_init(GumStalker *stalker); + +gboolean range_is_excluded(gpointer address); + diff --git a/frida_mode/src/instrument.c b/frida_mode/src/instrument.c new file mode 100644 index 00000000..042fdab8 --- /dev/null +++ b/frida_mode/src/instrument.c @@ -0,0 +1,265 @@ +#include "frida-gum.h" +#include "config.h" +#include "debug.h" +#include "prefetch.h" +#include "ranges.h" +#include "unistd.h" + +extern uint8_t *__afl_area_ptr; +extern u32 __afl_map_size; + +uint64_t __thread previous_pc = 0; +GumAddress current_log_impl = GUM_ADDRESS(0); + +static gboolean tracing = false; +static gboolean optimize = false; +static gboolean strict = false; + +#if defined(__x86_64__) +static const guint8 afl_log_code[] = { + + 0x9c, /* pushfq */ + 0x50, /* push rax */ + 0x51, /* push rcx */ + 0x52, /* push rdx */ + + 0x48, 0x8d, 0x05, 0x27, + 0x00, 0x00, 0x00, /* lea rax, sym._afl_area_ptr_ptr */ + 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ + 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ + 0x48, 0x8d, 0x0d, 0x22, + 0x00, 0x00, 0x00, /* lea rcx, sym.previous_pc */ + 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ + 0x48, 0x8b, 0x12, /* mov rdx, qword [rdx] */ + 0x48, 0x31, 0xfa, /* xor rdx, rdi */ + 0xfe, 0x04, 0x10, /* inc byte [rax + rdx] */ + 0x48, 0xd1, 0xef, /* shr rdi, 1 */ + 0x48, 0x8b, 0x01, /* mov rax, qword [rcx] */ + 0x48, 0x89, 0x38, /* mov qword [rax], rdi */ + + 0x5a, /* pop rdx */ + 0x59, /* pop rcx */ + 0x58, /* pop rax */ + 0x9d, /* popfq */ + + 0xc3, /* ret */ + + /* Read-only data goes here: */ + /* uint8_t** afl_area_ptr_ptr */ + /* uint64_t* afl_prev_loc_ptr */ + +}; + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumX86Writer *cw = output->writer.x86; + + if (current_log_impl == 0 || + !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || + !gum_x86_writer_can_branch_directly_between(cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, + sizeof(afl_area_ptr_ptr)); + gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_x86_writer_put_label(cw, after_log_impl); + + } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -GUM_RED_ZONE_SIZE); + gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); + gum_x86_writer_put_call_address(cw, current_log_impl); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + GUM_RED_ZONE_SIZE); + +} + +#elif defined(__aarch64__) +static const guint8 afl_log_code[] = { + + // __afl_area_ptr[current_pc ^ previous_pc]++; + // previous_pc = current_pc >> 1; + 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]! + 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]! + + // x0 = current_pc + 0xc1, 0x01, 0x00, 0x58, // ldr x1, #0x38, =&__afl_area_ptr + 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) + + 0xc2, 0x01, 0x00, 0x58, // ldr x2, #0x38, =&previous_pc + 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc) + + // __afl_area_ptr[current_pc ^ previous_pc]++; + 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0 + 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2] + 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1 + 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2] + + // previous_pc = current_pc >> 1; + 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1 + 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc + 0x40, 0x00, 0x00, 0xf9, // str x0, [x2] + + 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10 + 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10 + 0xC0, 0x03, 0x5F, 0xD6, // ret + + // &afl_area_ptr_ptr + // &afl_prev_loc_ptr + +}; + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumArm64Writer *cw = output->writer.arm64; + + if (current_log_impl == 0 || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc, + current_log_impl) || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_arm64_writer_put_b_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, + sizeof(afl_area_ptr_ptr)); + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_arm64_writer_put_label(cw, after_log_impl); + + } + + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), + GUM_INDEX_PRE_ADJUST); + gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset); + gum_arm64_writer_put_bl_imm(cw, current_log_impl); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, + GUM_INDEX_POST_ADJUST); + +} + +#endif + +static void on_basic_block(GumCpuContext *context, gpointer user_data) { + + /* Avoid stack operations in potentially performance critical code */ + static char buffer[200]; + int len; + guint64 current_pc = (guint64)user_data; + if (tracing) { + + /* Avoid any functions which may cause an allocation since the target app + * may already be running inside malloc and it isn't designed to be + * re-entrant on a single thread */ + len = snprintf(buffer, sizeof(buffer), + "current_pc: 0x%016" G_GINT64_MODIFIER + "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", + current_pc, previous_pc); + + write(STDOUT_FILENO, buffer, len + 1); + + } + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + __afl_area_ptr[current_pc ^ previous_pc]++; + previous_pc = current_pc >> 1; + +} + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data) { + + const cs_insn *instr; + gboolean begin = TRUE; + while (gum_stalker_iterator_next(iterator, &instr)) { + + if (begin) { + + prefetch_write((void *)instr->address); + if (!strict || !range_is_excluded((void *)instr->address)) { + + if (optimize) { + + instrument_coverage_optimize(instr, output); + + } else { + + gum_stalker_iterator_put_callout(iterator, on_basic_block, + (gpointer)instr->address, NULL); + + } + + } + + begin = FALSE; + + } + + gum_stalker_iterator_keep(iterator); + + } + +} + +void instrument_init() { + + optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); + tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); + strict = (getenv("AFL_FRIDA_INST_STRICT") != NULL); + +#if !defined(__x86_64__) && !defined(__aarch64__) + optimize = false; +#endif + + OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); + OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); + OKF("Instrumentation - strict [%c]", strict ? 'X' : ' '); + + if (tracing && optimize) { + + FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); + + } + + if (__afl_map_size != 0x10000) { + + FATAL("Bad map size: 0x%08x", __afl_map_size); + + } + +} + diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/interceptor.c new file mode 100644 index 00000000..ba05a80a --- /dev/null +++ b/frida_mode/src/interceptor.c @@ -0,0 +1,16 @@ +#include "frida-gum.h" +#include "debug.h" + +#include "interceptor.h" + +void intercept(void *address, gpointer replacement, gpointer user_data) { + + GumInterceptor *interceptor = gum_interceptor_obtain(); + gum_interceptor_begin_transaction(interceptor); + GumReplaceReturn ret = + gum_interceptor_replace(interceptor, address, replacement, user_data); + if (ret != GUM_ATTACH_OK) { FATAL("gum_interceptor_attach: %d", ret); } + gum_interceptor_end_transaction(interceptor); + +} + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c new file mode 100644 index 00000000..444c9583 --- /dev/null +++ b/frida_mode/src/main.c @@ -0,0 +1,149 @@ +#include +#include + +#ifdef __APPLE__ + #include + #include +#else + #include + #include +#endif + +#include "frida-gum.h" +#include "config.h" +#include "debug.h" + +#include "interceptor.h" +#include "instrument.h" +#include "prefetch.h" +#include "ranges.h" + +#ifdef __APPLE__ +extern mach_port_t mach_task_self(); +extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); +#else +extern int __libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)); +#endif + +typedef int *(*main_fn_t)(int argc, char **argv, char **envp); + +static main_fn_t main_fn = NULL; +static GumStalker * stalker = NULL; +static GumMemoryRange code_range = {0}; + +extern void __afl_manual_init(); +extern __thread uint64_t previous_pc; + +static int on_fork() { + + prefetch_read(stalker); + return fork(); + +} + +#ifdef __APPLE__ +static void on_main_os(int argc, char **argv, char **envp) { + +} + +#else +static void on_main_os(int argc, char **argv, char **envp) { + + /* Personality doesn't affect the current process, it only takes effect on + * evec */ + int persona = personality(ADDR_NO_RANDOMIZE); + if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); } + + GumInterceptor *interceptor = gum_interceptor_obtain(); + + gum_interceptor_begin_transaction(interceptor); + gum_interceptor_revert(interceptor, __libc_start_main); + gum_interceptor_end_transaction(interceptor); + gum_interceptor_flush(interceptor); + +} + +#endif + +static int *on_main(int argc, char **argv, char **envp) { + + on_main_os(argc, argv, envp); + + stalker = gum_stalker_new(); + if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + + gum_stalker_set_trust_threshold(stalker, 0); + + GumStalkerTransformer *transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + + instrument_init(); + prefetch_init(); + ranges_init(stalker); + + intercept(fork, on_fork, stalker); + + gum_stalker_follow_me(stalker, transformer, NULL); + gum_stalker_deactivate(stalker); + + __afl_manual_init(); + + /* Child here */ + previous_pc = 0; + prefetch_start(stalker); + main_fn(argc, argv, envp); + _exit(0); + +} + +#ifdef __APPLE__ +static void intercept_main() { + + mach_port_t task = mach_task_self(); + OKF("Task Id: %u", task); + GumAddress entry = gum_darwin_find_entrypoint(task); + OKF("Entry Point: 0x%016" G_GINT64_MODIFIER "x", entry); + void *main = GSIZE_TO_POINTER(entry); + main_fn = main; + intercept(main, on_main, NULL); + +} + +#else +static int on_libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)) { + + main_fn = main; + intercept(main, on_main, NULL); + return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, + stack_end); + +} + +static void intercept_main() { + + intercept(__libc_start_main, on_libc_start_main, NULL); + +} + +#endif + +__attribute__((constructor)) static void init() { + + gum_init_embedded(); + if (!gum_stalker_is_supported()) { + + gum_deinit_embedded(); + FATAL("Failed to initialize embedded"); + + } + + intercept_main(); + +} + diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c new file mode 100644 index 00000000..64633c1c --- /dev/null +++ b/frida_mode/src/prefetch.c @@ -0,0 +1,121 @@ +#include +#include +#include + +#include "frida-gum.h" +#include "prefetch.h" +#include "debug.h" + +#define TRUST 0 +#define PREFETCH_SIZE 65536 +#define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) + +typedef struct { + + size_t count; + void * entry[PREFETCH_ENTRIES]; + +} prefetch_data_t; + +static prefetch_data_t *prefetch_data = NULL; + +static int prefetch_shm_id = -1; + +/* + * We do this from the transformer since we need one anyway for coverage, this + * saves the need to use an event sink. + */ +void prefetch_write(void *addr) { + + /* Bail if we aren't initialized */ + if (prefetch_data == NULL) return; + + /* + * Our shared memory IPC is large enough for about 1000 entries, we can fine + * tune this if we need to. But if we have more new blocks that this in a + * single run then we ignore them and we'll pick them up next time. + */ + if (prefetch_data->count >= PREFETCH_ENTRIES) return; + + /* + * Write the block address to the SHM IPC and increment the number of entries. + */ + + prefetch_data->entry[prefetch_data->count] = addr; + prefetch_data->count++; + +} + +/* + * Read the IPC region one block at the time and prefetch it + */ +void prefetch_read(GumStalker *stalker) { + + if (prefetch_data == NULL) return; + + for (size_t i = 0; i < prefetch_data->count; i++) { + + void *addr = prefetch_data->entry[i]; + gum_stalker_prefetch(stalker, addr, 1); + + } + + /* + * Reset the entry count to indicate we have finished with it and it can be + * refilled by the child. + */ + prefetch_data->count = 0; + +} + +void prefetch_init() { + + g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); + gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); + + OKF("Instrumentation - prefetch [%c]", prefetch ? 'X' : ' '); + + if (!prefetch) { return; } + /* + * Make our shared memory, we can attach before we fork, just like AFL does + * with the coverage bitmap region and fork will take care of ensuring both + * the parent and child see the same consistent memory region. + */ + prefetch_shm_id = + shmget(IPC_PRIVATE, sizeof(prefetch_data_t), IPC_CREAT | IPC_EXCL | 0600); + if (prefetch_shm_id < 0) { + + FATAL("prefetch_shm_id < 0 - errno: %d\n", errno); + + } + + prefetch_data = shmat(prefetch_shm_id, NULL, 0); + g_assert(prefetch_data != MAP_FAILED); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(prefetch_shm_id, IPC_RMID, NULL) < 0) { + + FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); + + } + + /* Clear it, not sure it's necessary, just seems like good practice */ + memset(prefetch_data, '\0', sizeof(prefetch_data_t)); + +} + +__attribute__((noinline)) static void prefetch_activation() { + + asm volatile(""); + +} + +void prefetch_start(GumStalker *stalker) { + + gum_stalker_activate(stalker, prefetch_activation); + prefetch_activation(); + +} + diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c new file mode 100644 index 00000000..fc14710f --- /dev/null +++ b/frida_mode/src/ranges.c @@ -0,0 +1,395 @@ +// 0x123-0x321 +// module.so + +#include "ranges.h" +#include "debug.h" + +#define MAX_RANGES 20 + +typedef struct { + + gchar * suffix; + GumMemoryRange *range; + gboolean done; + +} convert_name_ctx_t; + +typedef struct { + + GumStalker *stalker; + GArray * array; + +} include_range_ctx_t; + +GArray * ranges = NULL; +gboolean exclude_ranges = false; + +static void convert_address_token(gchar *token, GumMemoryRange *range) { + + gchar **tokens; + int token_count; + tokens = g_strsplit(token, "-", 2); + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + if (token_count != 2) { + + FATAL("Invalid range (should have two addresses seperated by a '-'): %s\n", + token); + + } + + gchar *from_str = tokens[0]; + gchar *to_str = tokens[1]; + + if (!g_str_has_prefix(from_str, "0x")) { + + FATAL("Invalid range: %s - Start address should have 0x prefix: %s\n", + token, from_str); + + } + + if (!g_str_has_prefix(to_str, "0x")) { + + FATAL("Invalid range: %s - End address should have 0x prefix: %s\n", token, + to_str); + + } + + from_str = &from_str[2]; + to_str = &to_str[2]; + + for (char *c = from_str; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid range: %s - Start address not formed of hex digits: %s\n", + token, from_str); + + } + + } + + for (char *c = to_str; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid range: %s - End address not formed of hex digits: %s\n", + token, to_str); + + } + + } + + guint64 from = g_ascii_strtoull(from_str, NULL, 16); + if (from == 0) { + + FATAL("Invalid range: %s - Start failed hex conversion: %s\n", token, + from_str); + + } + + guint64 to = g_ascii_strtoull(to_str, NULL, 16); + if (to == 0) { + + FATAL("Invalid range: %s - End failed hex conversion: %s\n", token, to_str); + + } + + if (from >= to) { + + FATAL("Invalid range: %s - Start (0x%016" G_GINT64_MODIFIER + "x) must be less than end " + "(0x%016" G_GINT64_MODIFIER "x)\n", + token, from, to); + + } + + range->base_address = from; + range->size = to - from; + + g_strfreev(tokens); + +} + +static gboolean convert_name_token_for_module(const GumModuleDetails *details, + gpointer user_data) { + + convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data; + if (details->path == NULL) { return true; }; + + if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; }; + + OKF("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x %s", + ctx->suffix, details->range->base_address, + details->range->base_address + details->range->size, details->path); + + *ctx->range = *details->range; + ctx->done = true; + return false; + +} + +static void convert_name_token(gchar *token, GumMemoryRange *range) { + + gchar * suffix = g_strconcat("/", token, NULL); + convert_name_ctx_t ctx = {.suffix = suffix, .range = range, .done = false}; + + gum_process_enumerate_modules(convert_name_token_for_module, &ctx); + if (!ctx.done) { FATAL("Failed to resolve module: %s\n", token); } + g_free(suffix); + +} + +static void convert_token(gchar *token, GumMemoryRange *range) { + + if (g_strrstr(token, "-")) { + + convert_address_token(token, range); + + } else { + + convert_name_token(token, range); + + } + + OKF("Converted token: %s -> 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x\n", + token, range->base_address, range->base_address + range->size); + +} + +static gboolean include_ranges(const GumRangeDetails *details, + gpointer user_data) { + + include_range_ctx_t *ctx = (include_range_ctx_t *)user_data; + GArray * array = (GArray *)ctx->array; + GumAddress base = details->range->base_address; + GumAddress limit = details->range->base_address + details->range->size; + + OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + base, limit); + + for (int i = 0; i < array->len; i++) { + + GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i); + GumAddress range_base = range->base_address; + GumAddress range_limit = range->base_address + range->size; + + /* Before the region */ + if (range_limit < base) { continue; } + + /* After the region */ + if (range_base > limit) { + + GumMemoryRange exclude = {.base_address = base, .size = limit - base}; + OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER + "x", + base, limit); + gum_stalker_exclude(ctx->stalker, &exclude); + return true; + + } + + /* Overlap the start of the region */ + if (range_base < base) { + + /* Range contains the region */ + if (range_limit > limit) { + + return true; + + } else { + + base = range_limit; + continue; + + } + + /* Overlap the end of the region */ + + } else { + + GumMemoryRange exclude = {.base_address = base, + .size = range_base - base}; + OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER + "x", + base, range_base); + gum_stalker_exclude(ctx->stalker, &exclude); + /* Extend past the end of the region */ + if (range_limit >= limit) { + + return true; + + /* Contained within the region */ + + } else { + + base = range_limit; + continue; + + } + + } + + } + + GumMemoryRange exclude = {.base_address = base, .size = limit - base}; + OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", + base, limit); + gum_stalker_exclude(ctx->stalker, &exclude); + return true; + +} + +gint range_sort(gconstpointer a, gconstpointer b) { + + return ((GumMemoryRange *)a)->base_address - + ((GumMemoryRange *)b)->base_address; + +} + +static gboolean print_ranges(const GumRangeDetails *details, + gpointer user_data) { + + if (details->file == NULL) { + + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", + details->range->base_address, + details->range->base_address + details->range->size); + + } else { + + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER + "X %s(0x%016" G_GINT64_MODIFIER "x)", + details->range->base_address, + details->range->base_address + details->range->size, + details->file->path, details->file->offset); + + } + + return true; + +} + +void ranges_init(GumStalker *stalker) { + + char * showmaps; + char * include; + char * exclude; + char * list; + gchar ** tokens; + int token_count; + GumMemoryRange range; + + int i; + + showmaps = getenv("AFL_FRIDA_DEBUG_MAPS"); + include = getenv("AFL_FRIDA_INST_RANGES"); + exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES"); + + if (showmaps) { + + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL); + + } + + if (include != NULL && exclude != NULL) { + + FATAL( + "Cannot specifify both AFL_FRIDA_INST_RANGES and " + "AFL_FRIDA_EXCLUDE_RANGES"); + + } + + if (include == NULL && exclude == NULL) { return; } + + list = include == NULL ? exclude : include; + exclude_ranges = include == NULL ? true : false; + + tokens = g_strsplit(list, ",", MAX_RANGES); + + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count); + + for (i = 0; i < token_count; i++) { + + convert_token(tokens[i], &range); + g_array_append_val(ranges, range); + + } + + g_array_sort(ranges, range_sort); + + /* Check for overlaps */ + for (i = 1; i < token_count; i++) { + + GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1); + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress prev_limit = prev->base_address + prev->size; + GumAddress curr_limit = curr->base_address + curr->size; + if (prev_limit > curr->base_address) { + + FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + prev->base_address, prev_limit, curr->base_address, curr_limit); + + } + + } + + for (i = 0; i < token_count; i++) { + + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", + i, curr->base_address, curr_limit); + + } + + if (include == NULL) { + + for (i = 0; i < token_count; i++) { + + gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i)); + + } + + } else { + + include_range_ctx_t ctx = {.stalker = stalker, .array = ranges}; + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx); + + } + + g_strfreev(tokens); + +} + +gboolean range_is_excluded(gpointer address) { + + int i; + GumAddress test = GUM_ADDRESS(address); + + if (ranges == NULL) { return false; } + + for (i = 0; i < ranges->len; i++) { + + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + + if (test < curr->base_address) { return !exclude_ranges; } + + if (test < curr_limit) { return exclude_ranges; } + + } + + return !exclude_ranges; + +} + diff --git a/frida_mode/test/testinstr.c b/frida_mode/test/testinstr.c new file mode 100644 index 00000000..2c3d5144 --- /dev/null +++ b/frida_mode/test/testinstr.c @@ -0,0 +1,105 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +TESTINSTR_SECTION void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/testinstr.py b/frida_mode/test/testinstr.py new file mode 100755 index 00000000..8f5fe886 --- /dev/null +++ b/frida_mode/test/testinstr.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, section, base): + with open(file, 'rb') as f: + for sect in ELFFile(f).iter_sections(): + if (sect.name == section): + start = base + sect.header['sh_offset'] + end = start + sect.header['sh_size'] + print ("0x%016x-0x%016x" % (start, end)) + return + + print ("Section '%s' not found in '%s'" % (section, file)) + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--section', dest='section', type=str, + help='elf section name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + process_file (args.file, args.section, args.base) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/include/envs.h b/include/envs.h index d7578045..1e383b0c 100644 --- a/include/envs.h +++ b/include/envs.h @@ -50,6 +50,13 @@ static char *afl_environment_variables[] = { "AFL_EXIT_WHEN_DONE", "AFL_FAST_CAL", "AFL_FORCE_UI", + "AFL_FRIDA_DEBUG_MAPS", + "AFL_FRIDA_EXCLUDE_RANGES", + "AFL_FRIDA_INST_NO_OPTIMIZE", + "AFL_FRIDA_INST_NO_PREFETCH", + "AFL_FRIDA_INST_RANGES", + "AFL_FRIDA_INST_STRICT", + "AFL_FRIDA_INST_TRACE", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", diff --git a/include/forkserver.h b/include/forkserver.h index ac027f81..4709f6a5 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,6 +77,8 @@ typedef struct afl_forkserver { bool qemu_mode; /* if running in qemu mode or not */ + bool frida_mode; /* if running in frida mode or not */ + bool use_stdin; /* use stdin for sending data */ bool no_unlink; /* do not unlink cur_input */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index e106cd31..6ff119ac 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -83,6 +83,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ static u8 *target_path; +static u8 frida_mode; static u8 qemu_mode; static u32 map_size = MAP_SIZE; @@ -717,9 +718,11 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(void) { +static void set_up_environment(char **argv) { - u8 *x; + u8 * x; + char *afl_preload; + char *frida_afl_preload = NULL; dev_null_fd = open("/dev/null", O_RDWR); if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -824,6 +827,26 @@ static void set_up_environment(void) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -831,8 +854,18 @@ static void set_up_environment(void) { } + } else if (frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + } /* Setup signal handlers, duh. */ @@ -872,6 +905,7 @@ static void usage(u8 *argv0) { " -f file - input file read by the tested program (stdin)\n" " -t msec - timeout for each run (%u ms)\n" " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -914,7 +948,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0) { + while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) { switch (opt) { @@ -1008,6 +1042,14 @@ int main(int argc, char **argv_orig, char **envp) { break; + case 'O': /* FRIDA mode */ + + if (frida_mode) { FATAL("Multiple -O options not supported"); } + + frida_mode = 1; + + break; + case 'Q': if (qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -1062,7 +1104,7 @@ int main(int argc, char **argv_orig, char **envp) { atexit(at_exit_handler); setup_signal_handlers(); - set_up_environment(); + set_up_environment(argv); target_path = find_binary(argv[optind]); detect_file_args(argv + optind, prog_in, &use_stdin); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 70a49a6b..cb0190a0 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2692,7 +2692,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { #endif /* ^!__APPLE__ */ - if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && + if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode && !afl->non_instrumented_mode && !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { @@ -2720,7 +2720,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if ((afl->fsrv.qemu_mode) && + if ((afl->fsrv.qemu_mode || afl->fsrv.frida_mode) && memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST @@ -2757,7 +2757,8 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) { + if (afl->fsrv.frida_mode || + memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) { OKF(cPIN "Deferred forkserver binary detected."); setenv(DEFER_ENV_VAR, "1", 1); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index d70ffd31..34e9d420 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -109,6 +109,7 @@ static void usage(u8 *argv0, int more_help) { "maximum.\n" " -m megs - memory limit for child process (%u MB, 0 = no limit " "[default])\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -320,6 +321,8 @@ int main(int argc, char **argv_orig, char **envp) { u8 *extras_dir[4]; u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0 /*, have_p = 0*/; + char * afl_preload; + char * frida_afl_preload = NULL; char **use_argv; struct timeval tv; @@ -363,7 +366,7 @@ int main(int argc, char **argv_orig, char **envp) { while ((opt = getopt( argc, argv, - "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { + "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { switch (opt) { @@ -755,6 +758,18 @@ int main(int argc, char **argv_orig, char **envp) { afl->use_banner = optarg; break; + case 'O': /* FRIDA mode */ + + if (afl->fsrv.frida_mode) { + + FATAL("Multiple -O options not supported"); + + } + + afl->fsrv.frida_mode = 1; + + break; + case 'Q': /* QEMU mode */ if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -1085,6 +1100,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->non_instrumented_mode) { if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); } + if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); } if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); } if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); } @@ -1289,6 +1305,26 @@ int main(int argc, char **argv_orig, char **envp) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (afl->fsrv.frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -1296,6 +1332,14 @@ int main(int argc, char **argv_orig, char **envp) { } + } else if (afl->fsrv.frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } if (getenv("AFL_LD_PRELOAD")) { @@ -1479,7 +1523,8 @@ int main(int argc, char **argv_orig, char **envp) { } - if (!afl->fsrv.qemu_mode && !afl->non_instrumented_mode) { + if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && + !afl->non_instrumented_mode) { check_binary(afl, afl->cmplog_binary); @@ -1513,7 +1558,8 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->unicorn_mode) { + if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || + afl->fsrv.frida_mode || afl->unicorn_mode) { map_size = afl->fsrv.map_size = MAP_SIZE; afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size); @@ -2074,6 +2120,8 @@ stop_fuzzing: } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + fclose(afl->fsrv.plot_file); destroy_queue(afl); destroy_extras(afl); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 558665a2..aea90b3b 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -555,8 +555,10 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(afl_forkserver_t *fsrv) { +static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { + char *afl_preload; + char *frida_afl_preload = NULL; setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -600,6 +602,26 @@ static void set_up_environment(afl_forkserver_t *fsrv) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (fsrv->frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -607,8 +629,18 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + } else if (fsrv->frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + } /* Setup signal handlers, duh. */ @@ -655,6 +687,7 @@ static void usage(u8 *argv0) { "Execution control settings:\n" " -t msec - timeout for each run (none)\n" " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine mode)\n" @@ -723,7 +756,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrsh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { @@ -857,6 +890,14 @@ int main(int argc, char **argv_orig, char **envp) { at_file = optarg; break; + case 'O': /* FRIDA mode */ + + if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } + + fsrv->frida_mode = 1; + + break; + case 'Q': if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -943,7 +984,7 @@ int main(int argc, char **argv_orig, char **envp) { shm.cmplog_mode = 0; setup_signal_handlers(); - set_up_environment(fsrv); + set_up_environment(fsrv, argv); fsrv->target_path = find_binary(argv[optind]); fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index fc974262..68e61109 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -640,9 +640,11 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(afl_forkserver_t *fsrv) { +static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { - u8 *x; + u8 * x; + char *afl_preload; + char *frida_afl_preload = NULL; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -755,6 +757,26 @@ static void set_up_environment(afl_forkserver_t *fsrv) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (fsrv->frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -762,8 +784,18 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + } else if (fsrv->frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + } /* Setup signal handlers, duh. */ @@ -804,6 +836,7 @@ static void usage(u8 *argv0) { " -f file - input file read by the tested program (stdin)\n" " -t msec - timeout for each run (%u ms)\n" " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -859,7 +892,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeOQUWHh")) > 0) { switch (opt) { @@ -971,6 +1004,14 @@ int main(int argc, char **argv_orig, char **envp) { break; + case 'O': /* FRIDA mode */ + + if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } + + fsrv->frida_mode = 1; + + break; + case 'Q': if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -1054,7 +1095,7 @@ int main(int argc, char **argv_orig, char **envp) { atexit(at_exit_handler); setup_signal_handlers(); - set_up_environment(fsrv); + set_up_environment(fsrv, argv); fsrv->target_path = find_binary(argv[optind]); fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); -- cgit 1.4.1 From ab394836a9fe3faadb9d1af3a7d377bbcf5b5eee Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 08:40:33 +0100 Subject: remove warnings --- include/afl-fuzz.h | 3 ++- include/config.h | 5 +++-- include/forkserver.h | 16 +++++++++------- src/afl-forkserver.c | 4 ++++ src/afl-fuzz.c | 13 +++++++++---- src/afl-showmap.c | 1 - 6 files changed, 27 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 691ba148..046b0177 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -390,7 +390,8 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries, *afl_kill_signal, *afl_target_env, *afl_persistent_record; + *afl_testcache_entries, *afl_kill_signal, *afl_target_env, + *afl_persistent_record; } afl_env_vars_t; diff --git a/include/config.h b/include/config.h index 4691624a..75f363f7 100644 --- a/include/config.h +++ b/include/config.h @@ -77,8 +77,9 @@ /* 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 */ + to a number. These number of testcases prior and including the crash case + will be kept and written to the crash/ directory as RECORD:... files. + Note that every crash will be written, not only unique ones! */ //#define AFL_PERSISTENT_RECORD diff --git a/include/forkserver.h b/include/forkserver.h index c894ad80..808f6bd2 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -95,13 +95,15 @@ typedef struct afl_forkserver { 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; + u32 persistent_record; /* persistent replay setting */ +#ifdef AFL_PERSISTENT_RECORD + 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; +#endif /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 979d7e9e..0037d2d5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -380,6 +380,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } } + #endif if (fsrv->use_fauxsrv) { @@ -1073,6 +1074,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } } + #endif if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { @@ -1206,6 +1208,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, fsrv->persistent_record_len[idx] = val; } + #endif if (fsrv->child_pid <= 0) { @@ -1336,6 +1339,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, ++fsrv->persistent_record_cnt; } + #endif /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f89c1938..23343ade 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1034,7 +1034,7 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->afl_env.afl_persistent_record)) { -#ifdef AFL_PERSISTENT_RECORD + #ifdef AFL_PERSISTENT_RECORD afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); @@ -1046,11 +1046,13 @@ int main(int argc, char **argv_orig, char **envp) { } -#else + #else - FATAL("afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in config.h!"); + FATAL( + "afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in " + "config.h!"); -#endif + #endif } @@ -1520,6 +1522,7 @@ 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)) { @@ -1534,6 +1537,8 @@ int main(int argc, char **argv_orig, char **envp) { } + #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. */ -- cgit 1.4.1 From c89264205779635ec43f2913a94fa3ae5e6a5186 Mon Sep 17 00:00:00 2001 From: Jiangen Jiao Date: Thu, 25 Mar 2021 12:29:27 +0800 Subject: android: support host and target 32bit build --- Android.bp | 144 ++++++++++++++++++++- custom_mutators/Android.bp | 6 + .../libprotobuf-mutator-example/Android.bp | 6 + include/android-ashmem.h | 29 ++--- src/afl-cc.c | 6 +- 5 files changed, 168 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/Android.bp b/Android.bp index ee076d1e..64794e19 100644 --- a/Android.bp +++ b/Android.bp @@ -1,8 +1,5 @@ cc_defaults { name: "afl-defaults", - sanitize: { - never: true, - }, local_include_dirs: [ "include", @@ -23,18 +20,45 @@ cc_defaults { "-DBIN_PATH=\"out/host/linux-x86/bin\"", "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"", "-D__USE_GNU", - "-D__aarch64__", "-DDEBUG_BUILD", "-U_FORTIFY_SOURCE", "-ggdb3", "-g", "-O0", "-fno-omit-frame-pointer", + "-fPIC", ], + + target: { + android_arm64: { + cflags: [ + "-D__aarch64__", + "-D__ANDROID__", + ], + }, + android_arm: { + cflags: [ + "-D__ANDROID__", + ], + }, + android_x86_64: { + cflags: [ + "-D__ANDROID__", + ], + }, + android_x86: { + cflags: [ + "-D__ANDROID__", + ], + }, + }, } cc_binary { name: "afl-fuzz", + sanitize: { + never: true, + }, host_supported: true, compile_multilib: "64", @@ -128,7 +152,6 @@ cc_binary_host { ], cflags: [ - "-D__ANDROID__", "-DAFL_PATH=\"out/host/linux-x86/lib64\"", "-DAFL_CLANG_FLTO=\"-flto=full\"", "-DUSE_BINDIR=1", @@ -199,6 +222,7 @@ cc_library_headers { export_include_dirs: [ "include", + "instrumentation", ], } @@ -268,6 +292,116 @@ cc_binary { ], } +cc_binary { + name: "afl-fuzz-32", + sanitize: { + never: true, + }, + host_supported: true, + compile_multilib: "32", + + defaults: [ + "afl-defaults", + ], + + srcs: [ + "src/afl-fuzz*.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", + ], +} + +cc_binary_host { + name: "afl-cc-32", + compile_multilib: "32", + static_executable: true, + + defaults: [ + "afl-defaults", + ], + + cflags: [ + "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + "-DAFL_CLANG_FLTO=\"-flto=full\"", + "-DUSE_BINDIR=1", + "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"", + "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"", + "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"", + "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"", + "-DLLVM_LTO=1", + "-DLLVM_MAJOR=11", + "-DLLVM_MINOR=2", + ], + + srcs: [ + "src/afl-cc.c", + "src/afl-common.c", + ], + + symlinks: [ + "afl-clang-fast-32", + "afl-clang-fast++-32", + ], +} + +cc_library_static { + name: "afl-llvm-rt-32", + compile_multilib: "32", + vendor_available: true, + host_supported: true, + recovery_available: true, + sdk_version: "9", + + apex_available: [ + "com.android.adbd", + "com.android.appsearch", + "com.android.art", + "com.android.bluetooth.updatable", + "com.android.cellbroadcast", + "com.android.conscrypt", + "com.android.extservices", + "com.android.cronet", + "com.android.neuralnetworks", + "com.android.media", + "com.android.media.swcodec", + "com.android.mediaprovider", + "com.android.permission", + "com.android.runtime", + "com.android.resolv", + "com.android.tethering", + "com.android.wifi", + "com.android.sdkext", + "com.android.os.statsd", + "//any", + ], + + defaults: [ + "afl-defaults", + ], + + srcs: [ + "instrumentation/afl-compiler-rt.o.c", + ], +} + +cc_prebuilt_library_static { + name: "libfrida-gum-32", + compile_multilib: "32", + strip: { + none: true, + }, + + srcs: [ + "utils/afl_frida/android/arm/libfrida-gum.a", + ], + + export_include_dirs: [ + "utils/afl_frida/android/arm", + ], +} + subdirs = [ "custom_mutators", ] diff --git a/custom_mutators/Android.bp b/custom_mutators/Android.bp index 89abc3e9..5c7e06e3 100644 --- a/custom_mutators/Android.bp +++ b/custom_mutators/Android.bp @@ -10,6 +10,8 @@ cc_library_shared { "-fPIC", "-fpermissive", "-std=c++11", + "-Wno-unused-parameter", + "-Wno-unused-variable", ], srcs: [ @@ -77,6 +79,8 @@ cc_library_shared { "-O0", "-funroll-loops", "-fPIC", + "-Wno-unused-parameter", + "-Wno-unused-function", ], srcs: [ @@ -99,6 +103,8 @@ cc_library_shared { "-O0", "-funroll-loops", "-fPIC", + "-Wno-unused-parameter", + "-Wno-pointer-sign", ], srcs: [ diff --git a/custom_mutators/libprotobuf-mutator-example/Android.bp b/custom_mutators/libprotobuf-mutator-example/Android.bp index 01f1c23e..4f579735 100644 --- a/custom_mutators/libprotobuf-mutator-example/Android.bp +++ b/custom_mutators/libprotobuf-mutator-example/Android.bp @@ -8,6 +8,7 @@ cc_library_shared { "-O0", "-fPIC", "-Wall", + "-Wno-unused-parameter", ], srcs: [ @@ -29,4 +30,9 @@ cc_binary { srcs: [ "vuln.c", ], + + cflags: [ + "-Wno-unused-result", + "-Wno-unused-parameter", + ], } diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 91699b27..44fe556a 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -2,32 +2,31 @@ #ifndef _ANDROID_ASHMEM_H #define _ANDROID_ASHMEM_H + #define _GNU_SOURCE + #include + #include #include #include #include #include - - #if __ANDROID_API__ >= 26 - #define shmat bionic_shmat - #define shmctl bionic_shmctl - #define shmdt bionic_shmdt - #define shmget bionic_shmget - #endif #include - #undef shmat - #undef shmctl - #undef shmdt - #undef shmget #include - #define ASHMEM_DEVICE "/dev/ashmem" +int shmdt(const void* address) { +#if defined(SYS_shmdt) + return syscall(SYS_shmdt, address); +#else + return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0); +#endif +} + int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); @@ -78,6 +77,6 @@ void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { } - #endif /* !_ANDROID_ASHMEM_H */ -#endif /* !__ANDROID__ */ + #endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/src/afl-cc.c b/src/afl-cc.c index 80fc0742..2ee840d7 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -588,9 +588,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_PCGUARD) { #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) - #ifdef __ANDROID__ + #if defined __ANDROID__ || ANDROID cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; - instrument_mode != INSTRUMENT_LLVMNATIVE; + instrument_mode = INSTRUMENT_LLVMNATIVE; #else if (have_instr_list) { @@ -2023,7 +2023,7 @@ int main(int argc, char **argv, char **envp) { if (!be_quiet && cmplog_mode) printf("CmpLog mode by \n"); -#ifndef __ANDROID__ +#if !defined(__ANDROID__) && !defined(ANDROID) ptr = find_object("afl-compiler-rt.o", argv[0]); if (!ptr) { -- cgit 1.4.1 From c169cb3911b33fbc3974005788ade1c9218ade98 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 20:10:09 +0100 Subject: integrate frida_mode, code-format --- GNUmakefile | 3 +++ docs/Changelog.md | 2 ++ docs/env_variables.md | 5 +++-- frida_mode/Makefile | 32 +++++++++++++++----------------- frida_mode/inc/instrument.h | 7 ------- frida_mode/inc/interceptor.h | 4 ---- frida_mode/inc/prefetch.h | 5 ----- frida_mode/inc/ranges.h | 6 ------ frida_mode/include/instrument.h | 7 +++++++ frida_mode/include/interceptor.h | 4 ++++ frida_mode/include/prefetch.h | 5 +++++ frida_mode/include/ranges.h | 6 ++++++ frida_mode/src/main.c | 8 ++++---- include/forkserver.h | 2 +- qemu_mode/qemuafl | 2 +- src/afl-cc.c | 18 ++++++++++++------ src/afl-common.c | 11 ++++++++++- src/afl-ld-lto.c | 15 +++++++++------ 18 files changed, 82 insertions(+), 60 deletions(-) delete mode 100644 frida_mode/inc/instrument.h delete mode 100644 frida_mode/inc/interceptor.h delete mode 100644 frida_mode/inc/prefetch.h delete mode 100644 frida_mode/inc/ranges.h create mode 100644 frida_mode/include/instrument.h create mode 100644 frida_mode/include/interceptor.h create mode 100644 frida_mode/include/prefetch.h create mode 100644 frida_mode/include/ranges.h (limited to 'include') diff --git a/GNUmakefile b/GNUmakefile index ac8fe796..963004bd 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -593,6 +593,7 @@ distrib: all $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing + -$(MAKE) -C frida_mode -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -603,6 +604,7 @@ binary-only: test_shm test_python ready $(PROGS) $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing + -$(MAKE) -C frida_mode -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -648,6 +650,7 @@ install: all $(MANPAGES) @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi + @if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi @if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 730791da..6ae42b04 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,8 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - frida_mode - new mode that uses frida to fuzz binary-only targets, + thanks to @WorksButNotTested! - afl-fuzz: - added patch by @realmadsci to support @@ as part of command line options, e.g. `afl-fuzz ... -- ./target --infile=@@` diff --git a/docs/env_variables.md b/docs/env_variables.md index 572fad01..899b36cc 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -372,7 +372,8 @@ checks or alter some of the more exotic semantics of the tool: may complain of high load prematurely, especially on systems with low core counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`. - - In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace. + - In QEMU mode (-Q), Unicorn mode (-U) and Frida mode (-O), `AFL_PATH` will + be searched for afl-qemu-trace. - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip prepending `afl-qemu-trace` to your command line. Use this if you wish to use a @@ -605,7 +606,7 @@ optimal values if not already present in the environment: override this by setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless. - - By default, `ASAN_OPTIONS` are set to: + - By default, `ASAN_OPTIONS` are set to (among others): ``` abort_on_error=1 detect_leaks=0 diff --git a/frida_mode/Makefile b/frida_mode/Makefile index efae5ebf..822f1c6a 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -1,41 +1,39 @@ PWD:=$(shell pwd)/ -INC_DIR:=$(PWD)inc/ +INC_DIR:=$(PWD)include/ SRC_DIR:=$(PWD)src/ INCLUDES:=$(wildcard $(INC_DIR)*.h) SOURCES:=$(wildcard $(SRC_DIR)*.c) BUILD_DIR:=$(PWD)build/ -CFLAGS:= $(CFLAGS) \ - -fPIC \ - -D_GNU_SOURCE +CFLAGS+=-fPIC -D_GNU_SOURCE FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" -ARCH:=arm64 -TESTINSTR_BASE:=0x0000aaaaaaaaa000 + ARCH:=arm64 + TESTINSTR_BASE:=0x0000aaaaaaaaa000 endif ifeq "$(ARCH)" "x86_64" -TESTINSTR_BASE:=0x0000555555554000 + TESTINSTR_BASE:=0x0000555555554000 endif ifeq "$(shell uname)" "Darwin" -OS:=macos -AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF -CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations -TEST_LDFLAGS:=-undefined dynamic_lookup + OS:=macos + AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF + CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations + TEST_LDFLAGS:=-undefined dynamic_lookup endif ifeq "$(shell uname)" "Linux" -OS:=linux -AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) -CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor -TEST_LDFLAGS:= + OS:=linux + AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) + CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor + TEST_LDFLAGS:= endif ifndef OS -$(error "Operating system unsupported") + $(error "Operating system unsupported") endif VERSION=14.2.13 @@ -347,4 +345,4 @@ cmin_bash_frida: $(TEST_BIN) -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TEST_BIN) @@ \ No newline at end of file + $(TEST_BIN) @@ diff --git a/frida_mode/inc/instrument.h b/frida_mode/inc/instrument.h deleted file mode 100644 index ff71bed4..00000000 --- a/frida_mode/inc/instrument.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "frida-gum.h" - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); - -void instrument_init(); - diff --git a/frida_mode/inc/interceptor.h b/frida_mode/inc/interceptor.h deleted file mode 100644 index 5ed3cf49..00000000 --- a/frida_mode/inc/interceptor.h +++ /dev/null @@ -1,4 +0,0 @@ -#include "frida-gum.h" - -void intercept(void *address, gpointer replacement, gpointer user_data); - diff --git a/frida_mode/inc/prefetch.h b/frida_mode/inc/prefetch.h deleted file mode 100644 index b7f25a97..00000000 --- a/frida_mode/inc/prefetch.h +++ /dev/null @@ -1,5 +0,0 @@ -void prefetch_init(); -void prefetch_start(GumStalker *stalker); -void prefetch_write(void *addr); -void prefetch_read(GumStalker *stalker); - diff --git a/frida_mode/inc/ranges.h b/frida_mode/inc/ranges.h deleted file mode 100644 index b9394dbc..00000000 --- a/frida_mode/inc/ranges.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "frida-gum.h" - -void ranges_init(GumStalker *stalker); - -gboolean range_is_excluded(gpointer address); - diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h new file mode 100644 index 00000000..ff71bed4 --- /dev/null +++ b/frida_mode/include/instrument.h @@ -0,0 +1,7 @@ +#include "frida-gum.h" + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); + +void instrument_init(); + diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h new file mode 100644 index 00000000..5ed3cf49 --- /dev/null +++ b/frida_mode/include/interceptor.h @@ -0,0 +1,4 @@ +#include "frida-gum.h" + +void intercept(void *address, gpointer replacement, gpointer user_data); + diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h new file mode 100644 index 00000000..b7f25a97 --- /dev/null +++ b/frida_mode/include/prefetch.h @@ -0,0 +1,5 @@ +void prefetch_init(); +void prefetch_start(GumStalker *stalker); +void prefetch_write(void *addr); +void prefetch_read(GumStalker *stalker); + diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h new file mode 100644 index 00000000..b9394dbc --- /dev/null +++ b/frida_mode/include/ranges.h @@ -0,0 +1,6 @@ +#include "frida-gum.h" + +void ranges_init(GumStalker *stalker); + +gboolean range_is_excluded(gpointer address); + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 444c9583..7505c2f9 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -22,10 +22,10 @@ extern mach_port_t mach_task_self(); extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); #else -extern int __libc_start_main(int *(main)(int, char **, char **), int argc, - char **ubp_av, void (*init)(void), - void (*fini)(void), void (*rtld_fini)(void), - void(*stack_end)); +extern int __libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)); #endif typedef int *(*main_fn_t)(int argc, char **argv, char **envp); diff --git a/include/forkserver.h b/include/forkserver.h index cc759545..48db94c7 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,7 +77,7 @@ typedef struct afl_forkserver { bool qemu_mode; /* if running in qemu mode or not */ - bool frida_mode; /* if running in frida mode or not */ + bool frida_mode; /* if running in frida mode or not */ bool use_stdin; /* use stdin for sending data */ diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index 0fb212da..ddc4a974 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit 0fb212daab492411b3e323bc18a3074c1aecfd37 +Subproject commit ddc4a9748d59857753fb33c30a356f354595f36d diff --git a/src/afl-cc.c b/src/afl-cc.c index d134f013..1b4edbb9 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -638,8 +638,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); } @@ -1247,7 +1246,9 @@ int main(int argc, char **argv, char **envp) { strcasecmp(ptr, "CFG") == 0) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and " + "PCGUARD (default in afl-cc).\n"); } else if (strcasecmp(ptr, "AFL") == 0 || @@ -1313,7 +1314,9 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || getenv("INSTRIM_LIB")) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD " + "(default in afl-cc).\n"); } @@ -1400,7 +1403,9 @@ int main(int argc, char **argv, char **envp) { if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and " + "PCGUARD (default in afl-cc).\n"); } @@ -1765,7 +1770,8 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 ..-16\n" + " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 " + "..-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" " AFL_LLVM_CALLER: use single context sensitive coverage (for " diff --git a/src/afl-common.c b/src/afl-common.c index 087aa113..0fb1462e 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -336,7 +336,16 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) { } - target_path = alloc_printf("%s/%s", BIN_PATH, fname); + if (perm == X_OK) { + + target_path = alloc_printf("%s/%s", BIN_PATH, fname); + + } else { + + target_path = alloc_printf("%s/%s", AFL_PATH, fname); + + } + if (!access(target_path, perm)) { return target_path; diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 8928ddc9..d0113af9 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -73,7 +73,8 @@ static u32 ld_param_cnt = 1; /* Number of params to 'ld' */ so we exploit this property to keep the code "simple". */ static void edit_params(int argc, char **argv) { - u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, inst_present = 0; + u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, + inst_present = 0; char *ptr; ld_params = ck_alloc(4096 * sizeof(u8 *)); @@ -185,10 +186,12 @@ static void edit_params(int argc, char **argv) { } - if (getenv("AFL_LLVM_INSTRIM") || + if (getenv("AFL_LLVM_INSTRIM") || ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && - (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) - FATAL("InsTrim was removed because it is not effective. Use a modern LLVM and PCGUARD (which is the default in afl-cc).\n"); + (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) + FATAL( + "InsTrim was removed because it is not effective. Use a modern LLVM " + "and PCGUARD (which is the default in afl-cc).\n"); if (debug) DEBUGF( @@ -228,8 +231,8 @@ static void edit_params(int argc, char **argv) { if (!inst_present) { - ld_params[ld_param_cnt++] = alloc_printf( - "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); + ld_params[ld_param_cnt++] = alloc_printf( + "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); } -- cgit 1.4.1 From 7ca51fab19adfcda211282d4a1134eada7b60d2b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 27 Mar 2021 12:53:09 +0100 Subject: ensure one fuzzer sync per cycle, cycle introspection --- docs/Changelog.md | 1 + include/afl-fuzz.h | 1 + src/afl-fuzz-run.c | 1 + src/afl-fuzz.c | 22 +++++++++++++++------- 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6ae42b04..91d1a8cc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -18,6 +18,7 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - ensure one fuzzer sync per cycle - afl-cc: - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 046b0177..40a7fc85 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -572,6 +572,7 @@ typedef struct afl_state { blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ last_sync_time, /* Time of last sync */ + last_sync_cycle, /* Cycle no. of the last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 83133dad..832f17bb 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -712,6 +712,7 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); afl->last_sync_time = get_cur_time(); + afl->last_sync_cycle = afl->queue_cycle; } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a7edb924..9688c84f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1867,6 +1867,14 @@ int main(int argc, char **argv_orig, char **envp) { runs_in_current_cycle > afl->queued_paths) || (afl->old_seed_selection && !afl->queue_cur))) { + if (unlikely((afl->last_sync_cycle < afl->queue_cycle || + (!afl->queue_cycle && afl->afl_env.afl_import_first)) && + afl->sync_id)) { + + sync_fuzzers(afl); + + } + ++afl->queue_cycle; runs_in_current_cycle = (u32)-1; afl->cur_skipped_paths = 0; @@ -1980,6 +1988,13 @@ int main(int argc, char **argv_orig, char **envp) { } + #ifdef INTROSPECTION + fprintf(afl->introspection_file, + "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n", + afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc, + afl->queued_paths); + #endif + if (afl->cycle_schedules) { /* we cannot mix non-AFLfast schedules with others */ @@ -2031,13 +2046,6 @@ int main(int argc, char **argv_orig, char **envp) { prev_queued = afl->queued_paths; - if (afl->sync_id && afl->queue_cycle == 1 && - afl->afl_env.afl_import_first) { - - sync_fuzzers(afl); - - } - } ++runs_in_current_cycle; -- cgit 1.4.1 From 920e9402a4d6101bbbed2ef7584d85a3c3de0eaa Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 2 Apr 2021 22:23:11 +0000 Subject: Add support for standalone leak-sanitizer, introducting the environment variable AFL_USE_LSAN. AFL_USE_LSAN introduces the macro __AFL_CHECK_LEAK() which will check for a memory leak when the macro is run. This is especially helpful when using __AFL_LOOP(). If __AFL_LEAK_CHECK() is not used when AFL_USE_LSAN=1 is set, the leak checker will run when the program exits. --- GNUmakefile | 4 ++-- README.md | 2 +- docs/env_variables.md | 20 ++++++++++++++++---- docs/notes_for_asan.md | 7 +++++++ include/config.h | 4 ++++ include/envs.h | 1 + src/afl-analyze.c | 19 +++++++++++++++++++ src/afl-as.c | 7 ++++--- src/afl-cc.c | 16 ++++++++++++++-- src/afl-forkserver.c | 17 +++++++++++++---- src/afl-fuzz-init.c | 17 ++++++++++++++++- src/afl-showmap.c | 4 ++++ src/afl-tmin.c | 18 ++++++++++++++++++ test/test-pre.sh | 1 + 14 files changed, 120 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/GNUmakefile b/GNUmakefile index f885f998..a6314a8b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -517,7 +517,7 @@ code-format: ifndef AFL_NO_X86 test_build: afl-cc afl-gcc afl-as afl-showmap @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." - @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) + @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @@ -525,7 +525,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap @echo @echo "[+] All right, the instrumentation of afl-cc seems to be working!" # @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..." -# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) +# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) # ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null # echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr # @rm -f test-instr diff --git a/README.md b/README.md index 2528e1d1..41d55e9c 100644 --- a/README.md +++ b/README.md @@ -601,7 +601,7 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same For every secondary fuzzer there should be a variation, e.g.: * one should fuzz the target that was compiled differently: with sanitizers activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; - export AFL_USE_CFISAN=1 ; ` + export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN`) * one should fuzz the target with CMPLOG/redqueen (see above) * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV diff --git a/docs/env_variables.md b/docs/env_variables.md index c6ad0aa4..682ab7f1 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead: overridden. - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your - compiler supports that. Note that fuzzing with ASAN is mildly challenging + compiler supports itt. Note that fuzzing with ASAN is mildly challenging - see [notes_for_asan.md](notes_for_asan.md). (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the @@ -64,6 +64,13 @@ make fairly broad use of environmental variables instead: there is the Control Flow Integrity sanitizer that can be activated by `AFL_USE_CFISAN=1`) + - Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided + that your compiler supports it. To perform a leak check within your + program at a certain point (such as at the end of an __AFL_LOOP, + you can run the macro __AFL_CHECK_LEAK(); which will cause + an abort if any memory is leaked (you can combine this with the + LSAN_OPTIONS=suppressions option to supress some known leaks). + - Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries in your `$PATH`. @@ -628,7 +635,12 @@ optimal values if not already present in the environment: msan_track_origins=0 allocator_may_return_null=1 ``` - Be sure to include the first one when customizing anything, since some - MSAN versions don't call `abort()` on error, and we need a way to detect - faults. + - Similarly, the default `LSAN_OPTIONS` are set to: +``` + exit_code=86 + fast_unwind_on_malloc=0 +```` + Be sure to include the first ones for LSAN and MSAN when customizing + anything, since some MSAN and LSAN versions don't call `abort()` on + error, and we need a way to detect faults. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md index 2b3bc028..26f34fad 100644 --- a/docs/notes_for_asan.md +++ b/docs/notes_for_asan.md @@ -28,6 +28,13 @@ Note that ASAN is incompatible with -static, so be mindful of that. (You can also use AFL_USE_MSAN=1 to enable MSAN instead.) +When compiling with AFL_USE_LSAN, the leak sanitizer will normally run +when the program exits. In order to utilize this check at different times, +such as at the end of a loop, you may use the macro __AFL_CHECK_LEAK();. +This macro will report a crash in afl-fuzz if any memory is left leaking +at this stage. You can also use LSAN_OPTIONS and a supressions file +for more fine-tuned checking, however make sure you keep exitcode=23. + NOTE: if you run several secondary instances, only one should run the target compiled with ASAN (and UBSAN, CFISAN), the others should run the target with no sanitizers compiled in. diff --git a/include/config.h b/include/config.h index 29225f6b..6490a5fe 100644 --- a/include/config.h +++ b/include/config.h @@ -393,6 +393,10 @@ #define MSAN_ERROR 86 +/* Distinctive exit code used to indicate LSAN trip condition: */ + +#define LSAN_ERROR 23 + /* Designated file descriptors for forkserver commands (the application will use FORKSRV_FD and FORKSRV_FD + 1): */ diff --git a/include/envs.h b/include/envs.h index 2ce50be7..d1856c50 100644 --- a/include/envs.h +++ b/include/envs.h @@ -172,6 +172,7 @@ static char *afl_environment_variables[] = { "AFL_USE_TRACE_PC", "AFL_USE_UBSAN", "AFL_USE_CFISAN", + "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 86b0f7e9..90305714 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -781,6 +781,19 @@ static void set_up_environment(void) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -818,6 +831,12 @@ static void set_up_environment(void) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(MSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); + + if (get_afl_env("AFL_PRELOAD")) { if (qemu_mode) { diff --git a/src/afl-as.c b/src/afl-as.c index 7de267a3..dfae44f2 100644 --- a/src/afl-as.c +++ b/src/afl-as.c @@ -517,11 +517,12 @@ static void add_instrumentation(void) { } else { char modeline[100]; - snprintf(modeline, sizeof(modeline), "%s%s%s%s", + snprintf(modeline, sizeof(modeline), "%s%s%s%s%s", getenv("AFL_HARDEN") ? "hardened" : "non-hardened", getenv("AFL_USE_ASAN") ? ", ASAN" : "", getenv("AFL_USE_MSAN") ? ", MSAN" : "", - getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); + getenv("AFL_USE_UBSAN") ? ", UBSAN" : "", + getenv("AFL_USE_LSAN") ? ", LSAN" : ""); OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines, use_64bit ? "64" : "32", modeline, inst_ratio); @@ -585,7 +586,7 @@ int main(int argc, char **argv) { "AFL_QUIET: suppress verbose output\n" "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n" "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n" - "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN:\n" + "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n" " used in the instrumentation summary message\n", argv[0]); diff --git a/src/afl-cc.c b/src/afl-cc.c index 5251465b..e0478503 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -758,7 +758,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) have_instr_list = 1; - if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) + if (!(strcmp(cur, "-fsanitize=address") && strcmp(cur, "-fsanitize=memory"))) asan_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; @@ -817,6 +817,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-fsanitize=leak"; + } + if (getenv("AFL_USE_CFISAN")) { if (!lto_mode) { @@ -914,6 +918,13 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; + } + + cc_params[cc_par_cnt++] = + "-D__AFL_CHECK_LEAK()=__lsan_do_leak_check()"; + cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " "1;"; @@ -1740,7 +1751,8 @@ int main(int argc, char **argv, char **envp) { " AFL_USE_ASAN: activate address sanitizer\n" " AFL_USE_CFISAN: activate control flow sanitizer\n" " AFL_USE_MSAN: activate memory sanitizer\n" - " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"); + " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n" + " AFL_USE_LSAN: activate leak-checker sanitizer\n"); if (have_gcc_plugin) SAYF( diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 68995388..fa89713a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -483,7 +483,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); } - /* Set sane defaults for ASAN if nothing else specified. */ + /* Set sane defaults for ASAN if nothing else is specified. */ if (!getenv("ASAN_OPTIONS")) setenv("ASAN_OPTIONS", @@ -500,7 +500,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 1); - /* Set sane defaults for UBSAN if nothing else specified. */ + /* Set sane defaults for UBSAN if nothing else is specified. */ if (!getenv("UBSAN_OPTIONS")) setenv("UBSAN_OPTIONS", @@ -538,6 +538,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 1); + /* LSAN, too, does not support abort_on_error=1. */ + + if (!getenv("LSAN_OPTIONS")) + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 1); + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -1210,8 +1218,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (unlikely( /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || - /* special handling for msan */ - (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + /* special handling for msan and lsan */ + (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 82c1799e..24f5c5b5 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2466,6 +2466,20 @@ void check_asan_opts(afl_state_t *afl) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + + } /* Handle stop signal (Ctrl-C, etc). */ @@ -2711,7 +2725,8 @@ void check_binary(afl_state_t *afl, u8 *fname) { } if (memmem(f_data, f_len, "__asan_init", 11) || - memmem(f_data, f_len, "__msan_init", 11)) { + memmem(f_data, f_len, "__msan_init", 11) || + memmem(f_data, f_len, "__lsan_init", 11)) { afl->fsrv.uses_asan = 1; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 7bf5a9c7..bf076683 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -570,6 +570,10 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); setenv("UBSAN_OPTIONS", "halt_on_error=1:" diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 7ef8b9bf..a2741a07 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -712,6 +712,19 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -749,6 +762,11 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); + if (get_afl_env("AFL_PRELOAD")) { if (fsrv->qemu_mode) { diff --git a/test/test-pre.sh b/test/test-pre.sh index 85ac320b..174f2f7f 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -71,6 +71,7 @@ unset AFL_HARDEN unset AFL_USE_ASAN unset AFL_USE_MSAN unset AFL_USE_UBSAN +unset AFL_USE_LSAN unset AFL_TMPDIR unset AFL_CC unset AFL_PRELOAD -- cgit 1.4.1 From 3c846859eef4d17d2587ea28db83c680b51723a7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Apr 2021 20:05:02 +0200 Subject: cleanup --- GNUmakefile | 38 ++++++++++++---------- GNUmakefile.gcc_plugin | 12 ++++--- GNUmakefile.llvm | 8 +++-- docs/Changelog.md | 3 ++ include/android-ashmem.h | 16 +++++---- instrumentation/afl-llvm-lto-instrumentation.so.cc | 2 +- src/afl-analyze.c | 3 +- src/afl-cc.c | 5 +-- src/afl-forkserver.c | 7 ++-- src/afl-fuzz-init.c | 1 - src/afl-tmin.c | 2 +- 11 files changed, 55 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/GNUmakefile b/GNUmakefile index fdbcd542..d5fb570d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -36,6 +36,11 @@ SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 ASAN_OPTIONS=detect_leaks=0 +SYS = $(shell uname -s) +ARCH = $(shell uname -m) + +$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH)) + ifdef NO_SPLICING override CFLAGS += -DNO_SPLICING endif @@ -82,7 +87,7 @@ endif # endif #endif -ifneq "$(shell uname)" "Darwin" +ifneq "$(SYS)" "Darwin" #ifeq "$(HAVE_MARCHNATIVE)" "1" # SPECIAL_PERFORMANCE += -march=native #endif @@ -92,7 +97,7 @@ ifneq "$(shell uname)" "Darwin" endif endif -ifeq "$(shell uname)" "SunOS" +ifeq "$(SYS)" "SunOS" CFLAGS_OPT += -Wno-format-truncation LDFLAGS = -lkstat -lrt endif @@ -119,11 +124,10 @@ ifdef INTROSPECTION CFLAGS_OPT += -DINTROSPECTION=1 endif - -ifneq "$(shell uname -m)" "x86_64" - ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386" - ifneq "$(shell uname -m)" "amd64" - ifneq "$(shell uname -m)" "i86pc" +ifneq "$(ARCH)" "x86_64" + ifneq "$(patsubst i%86,i386,$(ARCH))" "i386" + ifneq "$(ARCH)" "amd64" + ifneq "$(ARCH)" "i86pc" AFL_NO_X86=1 endif endif @@ -141,27 +145,27 @@ override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpoi -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" -ifeq "$(shell uname -s)" "FreeBSD" +ifeq "$(SYS)" "FreeBSD" override CFLAGS += -I /usr/local/include/ LDFLAGS += -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "DragonFly" +ifeq "$(SYS)" "DragonFly" override CFLAGS += -I /usr/local/include/ LDFLAGS += -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" override CFLAGS += -I /usr/local/include/ -mno-retpoline LDFLAGS += -Wl,-z,notext -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "NetBSD" +ifeq "$(SYS)" "NetBSD" override CFLAGS += -I /usr/pkg/include/ LDFLAGS += -L /usr/pkg/lib/ endif -ifeq "$(shell uname -s)" "Haiku" +ifeq "$(SYS)" "Haiku" SHMAT_OK=0 override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC LDFLAGS += -Wno-deprecated-declarations -lgnu @@ -236,24 +240,24 @@ else BUILD_DATE ?= $(shell date "+%Y-%m-%d") endif -ifneq "$(filter Linux GNU%,$(shell uname))" "" +ifneq "$(filter Linux GNU%,$(SYS))" "" ifndef DEBUG override CFLAGS += -D_FORTIFY_SOURCE=2 endif LDFLAGS += -ldl -lrt -lm endif -ifneq "$(findstring FreeBSD, $(shell uname))" "" +ifneq "$(findstring FreeBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring NetBSD, $(shell uname))" "" +ifneq "$(findstring NetBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring OpenBSD, $(shell uname))" "" +ifneq "$(findstring OpenBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif @@ -485,7 +489,7 @@ unit_clean: @rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o .PHONY: unit -ifneq "$(shell uname)" "Darwin" +ifneq "$(ARCH)" "Darwin" unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash else unit: diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index aa93c688..b0f90f1b 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -41,6 +41,8 @@ CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11 CC ?= gcc CXX ?= g++ +SYS = $(shell uname -s) + ifeq "clang" "$(CC)" CC = gcc CXX = g++ @@ -75,25 +77,25 @@ ifeq "$(TEST_MMAP)" "1" override CFLAGS_SAFE += -DUSEMMAP=1 endif -ifneq "$(shell uname -s)" "Haiku" -ifneq "$(shell uname -s)" "OpenBSD" +ifneq "$(SYS)" "Haiku" +ifneq "$(SYS)" "OpenBSD" LDFLAGS += -lrt endif else CFLAGS_SAFE += -DUSEMMAP=1 endif -ifeq "$(shell uname -s)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" CC = egcc CXX = eg++ PLUGIN_FLAGS += -I/usr/local/include endif -ifeq "$(shell uname -s)" "DragonFly" +ifeq "$(SYS)" "DragonFly" PLUGIN_FLAGS += -I/usr/local/include endif -ifeq "$(shell uname -s)" "SunOS" +ifeq "$(SYS)" "SunOS" PLUGIN_FLAGS += -I/usr/include/gmp endif diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 4b5ac520..61c17e92 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -30,7 +30,9 @@ BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/nul VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) -ifeq "$(shell uname)" "OpenBSD" +SYS = $(shell uname -s) + +ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" @@ -275,13 +277,13 @@ CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) # User teor2345 reports that this is required to make things work on MacOS X. -ifeq "$(shell uname)" "Darwin" +ifeq "$(SYS)" "Darwin" CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress else CLANG_CPPFL += -Wl,-znodelete endif -ifeq "$(shell uname)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so CLANG_CPPFL += -mno-retpoline CFLAGS += -mno-retpoline diff --git a/docs/Changelog.md b/docs/Changelog.md index 91d1a8cc..24877f9a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,8 @@ sending a mail to . ### Version ++3.13a (development) - frida_mode - new mode that uses frida to fuzz binary-only targets, thanks to @WorksButNotTested! + - create a fuzzing dictionary with the help of CodeQL thanks to + @microsvuln! see utils/autodict_ql - afl-fuzz: - added patch by @realmadsci to support @@ as part of command line options, e.g. `afl-fuzz ... -- ./target --infile=@@` @@ -20,6 +22,7 @@ sending a mail to . - default cmplog level (-l) is now 2, better efficiency. - ensure one fuzzer sync per cycle - afl-cc: + - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD ### Version ++3.12c (release) diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 44fe556a..1bfd3220 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -13,12 +13,14 @@ #include #define ASHMEM_DEVICE "/dev/ashmem" -int shmdt(const void* address) { -#if defined(SYS_shmdt) +int shmdt(const void *address) { + + #if defined(SYS_shmdt) return syscall(SYS_shmdt, address); -#else + #else return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0); -#endif + #endif + } int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { @@ -26,7 +28,7 @@ int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); @@ -77,6 +79,6 @@ void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { } - #endif /* !_ANDROID_ASHMEM_H */ -#endif /* !__ANDROID__ */ + #endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 50306224..6eb19060 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -176,7 +176,7 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (debug) { fprintf(stderr, "map address is 0x%lx\n", map_addr); } + if (debug) { fprintf(stderr, "map address is 0x%llx\n", map_addr); } /* Get/set the globals for the SHM region. */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 7d7519fa..aabdbf1a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -833,14 +833,13 @@ static void set_up_environment(char **argv) { "handle_sigfpe=0:" "handle_sigill=0", 0); - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" "print_suppressions=0", 0); - if (get_afl_env("AFL_PRELOAD")) { if (qemu_mode) { diff --git a/src/afl-cc.c b/src/afl-cc.c index d4c0a6b7..3af31b3c 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -820,10 +820,11 @@ static void edit_params(u32 argc, char **argv, char **envp) { } if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-fsanitize=leak"; cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; - cc_params[cc_par_cnt++] = - "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; + cc_params[cc_par_cnt++] = "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; + } if (getenv("AFL_USE_CFISAN")) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index cd04e23d..2c502621 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -560,7 +560,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* LSAN, too, does not support abort_on_error=1. */ if (!getenv("LSAN_OPTIONS")) - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" @@ -1314,8 +1314,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || /* special handling for msan and lsan */ - (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || - WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || + (fsrv->uses_asan && + (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 48f3289d..e505abd4 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2502,7 +2502,6 @@ void check_asan_opts(afl_state_t *afl) { } - } /* Handle stop signal (Ctrl-C, etc). */ diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 6aad748c..6656712a 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -763,7 +763,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { "handle_sigfpe=0:" "handle_sigill=0", 0); - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" -- cgit 1.4.1 From 2e6e1e566b6b58081969d179c67398fa1316c49b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 Apr 2021 22:16:56 +0200 Subject: add missing env --- include/envs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/envs.h b/include/envs.h index 887e2c4f..466ab087 100644 --- a/include/envs.h +++ b/include/envs.h @@ -26,6 +26,7 @@ static char *afl_environment_variables[] = { "AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", + "AFL_CC_COMPILER", "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW", -- cgit 1.4.1 From 50bb931ea604a83784609dc71934a4a8f8feb156 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 11:26:27 +0200 Subject: ui custom mutator only display --- include/afl-fuzz.h | 1 - src/afl-fuzz-stats.c | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 40a7fc85..325168f2 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -483,7 +483,6 @@ typedef struct afl_state { no_unlink, /* do not unlink cur_input */ debug, /* Debug mode */ custom_only, /* Custom mutator only mode */ - python_only, /* Python-only mode */ is_main_node, /* if this is the main node */ is_secondary_node; /* if this is a secondary instance */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index ed4787ea..e0e24a18 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -861,7 +861,11 @@ void show_stats(afl_state_t *afl) { " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); - if (likely(afl->skip_deterministic)) { + if (unlikely(afl->custom_only)) { + + strcpy(tmp, "disabled (custom mutator only mode)"); + + } else if (likely(afl->skip_deterministic)) { strcpy(tmp, "disabled (default, enable with -D)"); @@ -939,7 +943,7 @@ void show_stats(afl_state_t *afl) { u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]), u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO])); - } else if (unlikely(!afl->extras_cnt)) { + } else if (unlikely(!afl->extras_cnt || afl->custom_only)) { strcpy(tmp, "n/a"); -- cgit 1.4.1 From be880f2476963b8ebebe9d8cc196e4e74104c7a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 13:01:50 +0200 Subject: add AFL_EXIT_ON_SEED_ISSUES --- docs/Changelog.md | 3 +++ docs/env_variables.md | 3 +++ include/afl-fuzz.h | 3 ++- include/envs.h | 1 + src/afl-fuzz-init.c | 8 +++++++- src/afl-fuzz-state.c | 7 +++++++ 6 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/docs/Changelog.md b/docs/Changelog.md index 4139a9b3..14a0bdaf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -24,6 +24,9 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in + -i dir crashes the target or results in a timeout. By default + afl++ ignores these and uses them for splicing instead. - afl-cc: - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 8d482e20..1f4dfef9 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -284,6 +284,9 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour + which does not allow crashes or timeout seeds in the initial -i corpus. + - `AFL_MAP_SIZE` sets the size of the shared map that afl-fuzz, afl-showmap, afl-tmin and afl-analyze create to gather instrumentation data from the target. This must be equal or larger than the size the target was diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 325168f2..f201782a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -384,7 +384,8 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, - afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new; + afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, + afl_exit_on_seed_issues; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/envs.h b/include/envs.h index 466ab087..ebe98257 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,6 +49,7 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index e505abd4..b6bfbc29 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -881,7 +881,7 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_TMOUT: - if (afl->timeout_given) { + if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) { /* if we have a timeout but a timeout value was given then always skip. The '+' meaning has been changed! */ @@ -1036,6 +1036,12 @@ void perform_dry_run(afl_state_t *afl) { } + if (afl->afl_env.afl_exit_on_seed_issues) { + + FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits."); + + } + /* Remove from fuzzing queue but keep for splicing */ struct queue_entry *p = afl->queue; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f65ff1bb..28d3339a 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -306,6 +306,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->cycle_schedules = afl->afl_env.afl_cycle_schedules = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_SEED_ISSUES", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_seed_issues = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW", afl_environment_variable_len)) { -- cgit 1.4.1