From 39ad3b89467d6de12cbb9d08ccd77d331c0d1f9e Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Wed, 28 Apr 2021 09:25:26 +0100 Subject: Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name --- instrumentation/afl-compiler-rt.o.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 552bbea8..2089ce78 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -79,8 +79,9 @@ #endif #if defined(__HAIKU__) - extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); -#endif // HAIKU +extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, + size_t bufferSize); +#endif // HAIKU u8 __afl_area_initial[MAP_INITIAL_SIZE]; u8 * __afl_area_ptr_dummy = __afl_area_initial; @@ -1754,11 +1755,11 @@ static int area_is_valid(void *ptr, size_t len) { if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; } - #ifndef __HAIKU__ - long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); - #else - long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); - #endif // HAIKU +#ifndef __HAIKU__ + long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); +#else + long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); +#endif // HAIKU if (r <= 0 || r > len) return 0; -- cgit 1.4.1 From beb97cdc89c9b47f797b309139478da6eca48190 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 3 Jun 2021 15:12:14 +0200 Subject: dynamic_list and afl-compiler-rt rework --- dynamic_list.txt | 62 +++++++++++++++++++++---------------- instrumentation/afl-compiler-rt.o.c | 17 +++++----- 2 files changed, 44 insertions(+), 35 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/dynamic_list.txt b/dynamic_list.txt index d1905d43..7293ae77 100644 --- a/dynamic_list.txt +++ b/dynamic_list.txt @@ -1,48 +1,56 @@ { + "__afl_already_initialized_first"; + "__afl_already_initialized_forkserver"; + "__afl_already_initialized_second"; + "__afl_already_initialized_shm"; "__afl_area_ptr"; + "__afl_auto_early"; + "__afl_auto_first"; + "__afl_auto_init"; + "__afl_auto_second"; + "__afl_coverage_discard"; + "__afl_coverage_interesting"; + "__afl_coverage_off"; + "__afl_coverage_on"; + "__afl_coverage_skip"; + "__afl_dictionary"; + "__afl_dictionary_len"; + "__afl_final_loc"; + "__afl_fuzz_len"; + "__afl_fuzz_ptr"; "__afl_manual_init"; + "__afl_map_addr"; "__afl_persistent_loop"; - "__afl_auto_init"; - "__afl_area_initial"; - "__afl_prev_loc"; "__afl_prev_caller"; "__afl_prev_ctx"; - "__afl_final_loc"; - "__afl_map_addr"; - "__afl_dictionary"; - "__afl_dictionary_len"; + "__afl_prev_loc"; "__afl_selective_coverage"; "__afl_selective_coverage_start_off"; "__afl_selective_coverage_temp"; - "__afl_coverage_discard"; - "__afl_coverage_skip"; - "__afl_coverage_on"; - "__afl_coverage_off"; - "__afl_coverage_interesting"; - "__afl_fuzz_len"; - "__afl_fuzz_ptr"; "__afl_sharedmem_fuzzing"; - "__sanitizer_cov_trace_pc_guard"; - "__sanitizer_cov_trace_pc_guard_init"; + "__afl_trace"; "__cmplog_ins_hook1"; + "__cmplog_ins_hook16"; "__cmplog_ins_hook2"; "__cmplog_ins_hook4"; + "__cmplog_ins_hook8"; "__cmplog_ins_hookN"; - "__cmplog_ins_hook16"; + "__cmplog_rtn_gcc_stdstring_cstring"; + "__cmplog_rtn_gcc_stdstring_stdstring"; + "__cmplog_rtn_hook"; + "__cmplog_rtn_llvm_stdstring_cstring"; + "__cmplog_rtn_llvm_stdstring_stdstring"; "__sanitizer_cov_trace_cmp1"; - "__sanitizer_cov_trace_const_cmp1"; + "__sanitizer_cov_trace_cmp16"; "__sanitizer_cov_trace_cmp2"; - "__sanitizer_cov_trace_const_cmp2"; "__sanitizer_cov_trace_cmp4"; - "__sanitizer_cov_trace_const_cmp4"; "__sanitizer_cov_trace_cmp8"; - "__sanitizer_cov_trace_const_cmp8"; - "__sanitizer_cov_trace_cmp16"; + "__sanitizer_cov_trace_const_cmp1"; "__sanitizer_cov_trace_const_cmp16"; + "__sanitizer_cov_trace_const_cmp2"; + "__sanitizer_cov_trace_const_cmp4"; + "__sanitizer_cov_trace_const_cmp8"; + "__sanitizer_cov_trace_pc_guard"; + "__sanitizer_cov_trace_pc_guard_init"; "__sanitizer_cov_trace_switch"; - "__cmplog_rtn_hook"; - "__cmplog_rtn_gcc_stdstring_cstring"; - "__cmplog_rtn_gcc_stdstring_stdstring"; - "__cmplog_rtn_llvm_stdstring_cstring"; - "__cmplog_rtn_llvm_stdstring_stdstring"; }; diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 2089ce78..5dacf961 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -83,13 +83,14 @@ extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); #endif // HAIKU -u8 __afl_area_initial[MAP_INITIAL_SIZE]; -u8 * __afl_area_ptr_dummy = __afl_area_initial; +static u8 __afl_area_initial[MAP_INITIAL_SIZE]; +static u8 * __afl_area_ptr_dummy = __afl_area_initial; +static u8 * __afl_area_ptr_backup = __afl_area_initial; + u8 * __afl_area_ptr = __afl_area_initial; -u8 * __afl_area_ptr_backup = __afl_area_initial; u8 * __afl_dictionary; u8 * __afl_fuzz_ptr; -u32 __afl_fuzz_len_dummy; +static u32 __afl_fuzz_len_dummy; u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy; u32 __afl_final_loc; @@ -100,7 +101,7 @@ u64 __afl_map_addr; // for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work: int __afl_selective_coverage __attribute__((weak)); int __afl_selective_coverage_start_off __attribute__((weak)); -int __afl_selective_coverage_temp = 1; +static int __afl_selective_coverage_temp = 1; #if defined(__ANDROID__) || defined(__HAIKU__) PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; @@ -147,7 +148,7 @@ static int __afl_dummy_fd[2] = {2, 2}; /* ensure we kill the child on termination */ -void at_exit(int signal) { +static void at_exit(int signal) { if (child_pid > 0) { kill(child_pid, SIGKILL); } @@ -179,7 +180,7 @@ void __afl_trace(const u32 x) { /* Error reporting to forkserver controller */ -void send_forkserver_error(int error) { +static void send_forkserver_error(int error) { u32 status; if (!error || error > 0xffff) return; @@ -1668,7 +1669,7 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { } -void __sanitizer_cov_trace_cost_cmp4(uint32_t arg1, uint32_t arg2) { +void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) { __cmplog_ins_hook4(arg1, arg2, 0); -- cgit 1.4.1 From 92fcef4520fe65fc641fd2e8d86a7c17845031c0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 09:26:53 +0200 Subject: write target errors to out_dir/error.txt --- instrumentation/afl-compiler-rt.o.c | 134 +++++++++++++++++++++++++++++------- src/afl-analyze.c | 2 - src/afl-fuzz-stats.c | 7 +- src/afl-fuzz.c | 2 + 4 files changed, 116 insertions(+), 29 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 5dacf961..a4760153 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -83,15 +83,15 @@ extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); #endif // HAIKU -static u8 __afl_area_initial[MAP_INITIAL_SIZE]; -static u8 * __afl_area_ptr_dummy = __afl_area_initial; -static u8 * __afl_area_ptr_backup = __afl_area_initial; +static u8 __afl_area_initial[MAP_INITIAL_SIZE]; +static u8 *__afl_area_ptr_dummy = __afl_area_initial; +static u8 *__afl_area_ptr_backup = __afl_area_initial; -u8 * __afl_area_ptr = __afl_area_initial; -u8 * __afl_dictionary; -u8 * __afl_fuzz_ptr; -static u32 __afl_fuzz_len_dummy; -u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy; +u8 * __afl_area_ptr = __afl_area_initial; +u8 * __afl_dictionary; +u8 * __afl_fuzz_ptr; +static u32 __afl_fuzz_len_dummy; +u32 * __afl_fuzz_len = &__afl_fuzz_len_dummy; u32 __afl_final_loc; u32 __afl_map_size = MAP_SIZE; @@ -99,8 +99,8 @@ u32 __afl_dictionary_len; u64 __afl_map_addr; // for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work: -int __afl_selective_coverage __attribute__((weak)); -int __afl_selective_coverage_start_off __attribute__((weak)); +int __afl_selective_coverage __attribute__((weak)); +int __afl_selective_coverage_start_off __attribute__((weak)); static int __afl_selective_coverage_temp = 1; #if defined(__ANDROID__) || defined(__HAIKU__) @@ -630,6 +630,30 @@ static void __afl_unmap_shm(void) { } +void write_error(char *text) { + + u8 * o = getenv("__AFL_OUT_DIR"); + char *e = strerror(errno); + + if (o) { + + char buf[4096]; + snprintf(buf, sizeof(buf), "%s/error.txt", o); + FILE *f = fopen(buf, "a"); + + if (f) { + + fprintf(f, "Error(%s): %s\n", text, e); + fclose(f); + + } + + } + + fprintf(stderr, "Error(%s): %s\n", text, e); + +} + #ifdef __linux__ static void __afl_start_snapshots(void) { @@ -656,7 +680,12 @@ static void __afl_start_snapshots(void) { if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { - if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); } + if (read(FORKSRV_FD, &was_killed, 4) != 4) { + + write_error("read to afl-fuzz"); + _exit(1); + + } if (__afl_debug) { @@ -725,7 +754,12 @@ static void __afl_start_snapshots(void) { } else { /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (read(FORKSRV_FD, &was_killed, 4) != 4) { + + write_error("reading from afl-fuzz"); + _exit(1); + + } } @@ -762,7 +796,12 @@ static void __afl_start_snapshots(void) { if (child_stopped && was_killed) { child_stopped = 0; - if (waitpid(child_pid, &status, 0) < 0) _exit(1); + if (waitpid(child_pid, &status, 0) < 0) { + + write_error("child_stopped && was_killed"); + _exit(1); // TODO why exit? + + } } @@ -771,7 +810,12 @@ static void __afl_start_snapshots(void) { /* Once woken up, create a clone of our process. */ child_pid = fork(); - if (child_pid < 0) _exit(1); + if (child_pid < 0) { + + write_error("fork"); + _exit(1); + + } /* In child process: close fds, resume execution. */ @@ -811,9 +855,19 @@ static void __afl_start_snapshots(void) { /* In parent process: write PID to pipe, then wait for child. */ - if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { + + write_error("write to afl-fuzz"); + _exit(1); + + } - if (waitpid(child_pid, &status, WUNTRACED) < 0) _exit(1); + if (waitpid(child_pid, &status, WUNTRACED) < 0) { + + write_error("waitpid"); + _exit(1); + + } /* In persistent mode, the child stops itself with SIGSTOP to indicate a successful run. In this case, we want to wake it up without forking @@ -823,7 +877,12 @@ static void __afl_start_snapshots(void) { /* Relay wait status to pipe, then loop back. */ - if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &status, 4) != 4) { + + write_error("writing to afl-fuzz"); + _exit(1); + + } } @@ -956,7 +1015,12 @@ static void __afl_start_forkserver(void) { } else { - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (read(FORKSRV_FD, &was_killed, 4) != 4) { + + write_error("read from afl-fuzz"); + _exit(1); + + } } @@ -993,7 +1057,12 @@ static void __afl_start_forkserver(void) { if (child_stopped && was_killed) { child_stopped = 0; - if (waitpid(child_pid, &status, 0) < 0) _exit(1); + if (waitpid(child_pid, &status, 0) < 0) { + + write_error("child_stopped && was_killed"); + _exit(1); + + } } @@ -1002,7 +1071,12 @@ static void __afl_start_forkserver(void) { /* Once woken up, create a clone of our process. */ child_pid = fork(); - if (child_pid < 0) _exit(1); + if (child_pid < 0) { + + write_error("fork"); + _exit(1); + + } /* In child process: close fds, resume execution. */ @@ -1031,11 +1105,20 @@ static void __afl_start_forkserver(void) { /* In parent process: write PID to pipe, then wait for child. */ - if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { - if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) + write_error("write to afl-fuzz"); _exit(1); + } + + if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) { + + write_error("waitpid"); + _exit(1); + + } + /* In persistent mode, the child stops itself with SIGSTOP to indicate a successful run. In this case, we want to wake it up without forking again. */ @@ -1044,7 +1127,12 @@ static void __afl_start_forkserver(void) { /* Relay wait status to pipe, then loop back. */ - if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &status, 4) != 4) { + + write_error("writing to afl-fuzz"); + _exit(1); + + } } diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 5d5c4b8c..d43278b9 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -225,7 +225,6 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) { } - /* Handle timeout signal. */ static void handle_timeout(int sig) { @@ -238,7 +237,6 @@ static void handle_timeout(int sig) { } - /* Execute target application. Returns exec checksum, or 0 if program times out. */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 89d2c37d..9648d795 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -768,7 +768,7 @@ void show_stats(afl_state_t *afl) { SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bH2 bHB bH bSTOP cCYA - " map coverage" bSTG bHT bH20 bH2 bVL "\n"); + " map coverage" bSTG bHT bH20 bH2 bVL "\n"); /* This gets funny because we want to print several variable-length variables together, but then cram them into a fixed-width field - so we need to @@ -873,9 +873,8 @@ void show_stats(afl_state_t *afl) { /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP - " fuzzing strategy yields " bSTG bH10 bH2 bHT bH10 bH2 bH bHB bH bSTOP cCYA - " path geometry " bSTG bH5 bH2 bVL "\n"); + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bH2 bHT bH10 bH2 + bH bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); if (unlikely(afl->custom_only)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index dc594b30..9a3780fb 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1205,6 +1205,8 @@ int main(int argc, char **argv_orig, char **envp) { } + setenv("__AFL_OUT_DIR", afl->out_dir, 1); + if (get_afl_env("AFL_DISABLE_TRIM")) { afl->disable_trim = 1; } if (getenv("AFL_NO_UI") && getenv("AFL_FORCE_UI")) { -- cgit 1.4.1 From 2449866f21fd66f04d0da51394b6604b406095c3 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Mon, 7 Jun 2021 13:47:27 +0200 Subject: more info for error logging --- instrumentation/afl-compiler-rt.o.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index a4760153..50117012 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -630,7 +630,9 @@ static void __afl_unmap_shm(void) { } -void write_error(char *text) { +#define write_error(text) write_error_with_location(text, __FILE__, __LINE__) + +void write_error_with_location(char *text, char* filename, int linenumber) { u8 * o = getenv("__AFL_OUT_DIR"); char *e = strerror(errno); @@ -643,14 +645,14 @@ void write_error(char *text) { if (f) { - fprintf(f, "Error(%s): %s\n", text, e); + fprintf(f, "File %s, line %d: Error(%s): %s\n", filename, linenumber, text, e); fclose(f); } } - fprintf(stderr, "Error(%s): %s\n", text, e); + fprintf(stderr, "File %s, line %d: Error(%s): %s\n", filename, linenumber, text, e); } @@ -2079,3 +2081,4 @@ void __afl_coverage_interesting(u8 val, u32 id) { } +#undef write_error -- cgit 1.4.1 From c46f8c1f70918056e95c801b1a81f11c79304b05 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 16 Jun 2021 13:03:42 +0200 Subject: make afl-cmin actually work with subdirectories --- afl-cmin | 42 ++++++++++++++++++-------------- docs/Changelog.md | 4 ++-- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-showmap.c | 48 +++++++++++++++++++++---------------- 4 files changed, 54 insertions(+), 42 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/afl-cmin b/afl-cmin index 9fa63ec6..e71873d3 100755 --- a/afl-cmin +++ b/afl-cmin @@ -296,13 +296,13 @@ BEGIN { exit 1 } - if (0 == system( "test -d "in_dir"/default" )) { - in_dir = in_dir "/default" - } - - if (0 == system( "test -d "in_dir"/queue" )) { - in_dir = in_dir "/queue" - } + #if (0 == system( "test -d "in_dir"/default" )) { + # in_dir = in_dir "/default" + #} + # + #if (0 == system( "test -d "in_dir"/queue" )) { + # in_dir = in_dir "/queue" + #} system("rm -rf "trace_dir" 2>/dev/null"); system("rm "out_dir"/id[:_]* 2>/dev/null") @@ -355,30 +355,35 @@ BEGIN { } else { stat_format = "-f '%z %N'" # *BSD, MacOS } - cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" + cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r" while (cmdline | getline) { sub(/^[0-9]+ (\.\/)?/,"",$0) - infilesSmallToBig[i++] = $0 + infilesSmallToBigFull[i] = $0 + sub(/.*\//, "", $0) + infilesSmallToBig[i] = $0 + infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i] + infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i] + i++ } in_count = i - first_file = infilesSmallToBig[0] + first_file = infilesSmallToBigFull[0] - # Make sure that we're not dealing with a directory. - - if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { - print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" - exit 1 - } + #if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { + # print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" + # exit 1 + #} - if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) { + system(">\""in_dir"/.afl-cmin.test\"") + if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) { cp_tool = "ln" } else { cp_tool = "cp" } + system("rm -f \""in_dir"/.afl-cmin.test\"") if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) { # Make sure that we can actually get anything out of afl-showmap before we @@ -511,7 +516,8 @@ BEGIN { # copy file unless already done if (! (fn in file_already_copied)) { - system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"") + realfile = infilesSmallToBigMap[fn] + system(cp_tool" \""in_dir"/"realfile"\" \""out_dir"/"fn"\"") file_already_copied[fn] = "" ++out_count #printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log" diff --git a/docs/Changelog.md b/docs/Changelog.md index 530dd941..9fd2a1a9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,8 +31,8 @@ sending a mail to . - afl_analyze: - fix timeout handling - add forkserver support for better performance - - afl-cmin, afl-cmin.bash and afl-showmap -i do now descend into - subdirectories (like afl-fuzz does) + - afl-cmin and afl-showmap -i do now descend into subdirectories + (like afl-fuzz does) - note that afl-cmin.bash does not! - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 50117012..404b761f 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1019,7 +1019,7 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) { - write_error("read from afl-fuzz"); + //write_error("read from afl-fuzz"); _exit(1); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 03050d91..646396ad 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -233,7 +233,11 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), caa = !!getenv("AFL_CMIN_ALLOW_ANY"); - if (!outfile) { FATAL("Output filename not set (Bug in AFL++?)"); } + if (!outfile || !*outfile) { + + FATAL("Output filename not set (Bug in AFL++?)"); + + } if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { @@ -753,7 +757,9 @@ u32 execute_testcases(u8 *dir) { } - // DO + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name); + if (read_file(fn2)) { if (wait_for_gdb) { @@ -800,31 +806,31 @@ static void usage(u8 *argv0) { "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" "Required parameters:\n" - " -o file - file to write the trace data to\n\n" + " -o file - file to write the trace data to\n\n" "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" - " (Not necessary, here for consistency with other afl-* " + " -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" + " (Not necessary, here for consistency with other afl-* " "tools)\n\n" "Other settings:\n" - " -i dir - process all files in this directory, must be combined " + " -i dir - process all files below this directory, must be combined " "with -o.\n" - " With -C, -o is a file, without -C it must be a " + " With -C, -o is a file, without -C it must be a " "directory\n" - " and each bitmap will be written there individually.\n" - " -C - collect coverage, writes all edges to -o and gives a " + " and each bitmap will be written there individually.\n" + " -C - collect coverage, writes all edges to -o and gives a " "summary\n" - " Must be combined with -i.\n" - " -q - sink program's output and don't show messages\n" - " -e - show edge coverage only, ignore hit counts\n" - " -r - show real tuple values instead of AFL filter values\n" - " -s - do not classify the map\n" - " -c - allow core dumps\n\n" + " Must be combined with -i.\n" + " -q - sink program's output and don't show messages\n" + " -e - show edge coverage only, ignore hit counts\n" + " -r - show real tuple values instead of AFL filter values\n" + " -s - do not classify the map\n" + " -c - allow core dumps\n\n" "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" @@ -1259,7 +1265,7 @@ int main(int argc, char **argv_orig, char **envp) { } else { - if ((coverage_map = (u8 *)malloc(map_size)) == NULL) + if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL) FATAL("coult not grab memory"); edges_only = false; raw_instr_output = true; -- cgit 1.4.1 From 35153e9b495e3f61c032a3d911e4906fed0b50d6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 16 Jun 2021 15:33:03 +0200 Subject: correct map size for small targets --- TODO.md | 2 -- include/forkserver.h | 1 + instrumentation/afl-compiler-rt.o.c | 6 ------ src/afl-forkserver.c | 10 ++++++---- src/afl-fuzz-run.c | 3 +-- src/afl-fuzz-stats.c | 17 +++++++++-------- 6 files changed, 17 insertions(+), 22 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/TODO.md b/TODO.md index 398f3d11..1c616b4a 100644 --- a/TODO.md +++ b/TODO.md @@ -2,13 +2,11 @@ ## Roadmap 3.00+ - - align map to 64 bytes but keep real IDs - Update afl->pending_not_fuzzed for MOpt - put fuzz target in top line of UI - afl-plot to support multiple plot_data - afl_custom_fuzz_splice_optin() - afl_custom_splice() - - intel-pt tracer - better autodetection of shifting runtime timeout values - cmplog: use colorization input for havoc? - parallel builds for source-only targets diff --git a/include/forkserver.h b/include/forkserver.h index 2baa6f0a..c6f7de00 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -54,6 +54,7 @@ typedef struct afl_forkserver { u32 exec_tmout; /* Configurable exec timeout (ms) */ u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ + u32 real_map_size; /* real map size, unaligned */ u32 snapshot; /* is snapshot feature used */ u64 mem_limit; /* Memory cap for child (MB) */ diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 404b761f..92deff6a 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -271,12 +271,6 @@ static void __afl_map_shm(void) { if (__afl_final_loc) { - if (__afl_final_loc % 64) { - - __afl_final_loc = (((__afl_final_loc + 63) >> 6) << 6); - - } - __afl_map_size = __afl_final_loc; if (__afl_final_loc > MAP_SIZE) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3d472b36..8fb8a75a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -90,6 +90,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { /* exec related stuff */ fsrv->child_pid = -1; fsrv->map_size = get_map_size(); + fsrv->real_map_size = fsrv->map_size; fsrv->use_fauxsrv = false; fsrv->last_run_timed_out = false; fsrv->debug = false; @@ -110,6 +111,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->init_tmout = from->init_tmout; fsrv_to->mem_limit = from->mem_limit; fsrv_to->map_size = from->map_size; + fsrv_to->real_map_size = from->real_map_size; fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz; fsrv_to->out_file = from->out_file; fsrv_to->dev_urandom_fd = from->dev_urandom_fd; @@ -691,15 +693,15 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } - if (unlikely(tmp_map_size % 64)) { + fsrv->real_map_size = tmp_map_size; + + if (tmp_map_size % 64) { - // should not happen - WARNF("Target reported non-aligned map size of %u", tmp_map_size); tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); } - if (!be_quiet) { ACTF("Target map size: %u", tmp_map_size); } + if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } if (tmp_map_size > fsrv->map_size) { FATAL( diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 49856a9f..3de67955 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -424,8 +424,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = - afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; + afl->stage_max = afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 9648d795..e0930234 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -264,6 +264,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, "peak_rss_mb : %lu\n" "cpu_affinity : %d\n" "edges_found : %u\n" + "total_edges : %u\n" "var_byte_count : %u\n" "havoc_expansion : %u\n" "testcache_size : %llu\n" @@ -303,10 +304,10 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, #else -1, #endif - t_bytes, afl->var_byte_count, afl->expand_havoc, - afl->q_testcase_cache_size, afl->q_testcase_cache_count, - afl->q_testcase_evictions, afl->use_banner, - afl->unicorn_mode ? "unicorn" : "", + t_bytes, afl->fsrv.real_map_size, afl->var_byte_count, + afl->expand_havoc, afl->q_testcase_cache_size, + afl->q_testcase_cache_count, afl->q_testcase_evictions, + afl->use_banner, afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", afl->non_instrumented_mode ? " non_instrumented " : "", afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", @@ -326,7 +327,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, u32 i = 0; fprintf(f, "virgin_bytes :"); - for (i = 0; i < afl->fsrv.map_size; i++) { + for (i = 0; i < afl->fsrv.real_map_size; i++) { if (afl->virgin_bits[i] != 0xff) { @@ -338,7 +339,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, fprintf(f, "\n"); fprintf(f, "var_bytes :"); - for (i = 0; i < afl->fsrv.map_size; i++) { + for (i = 0; i < afl->fsrv.real_map_size; i++) { if (afl->var_bytes[i]) { fprintf(f, " %u", i); } @@ -520,7 +521,7 @@ void show_stats(afl_state_t *afl) { /* Do some bitmap stats. */ t_bytes = count_non_255_bytes(afl, afl->virgin_bits); - t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size; + t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.real_map_size; if (likely(t_bytes) && unlikely(afl->var_byte_count)) { @@ -781,7 +782,7 @@ void show_stats(afl_state_t *afl) { SAYF(bV bSTOP " now processing : " cRST "%-18s " bSTG bV bSTOP, tmp); sprintf(tmp, "%0.02f%% / %0.02f%%", - ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size, + ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.real_map_size, t_byte_ratio); SAYF(" map density : %s%-19s" bSTG bV "\n", -- cgit 1.4.1 From ff4d45eed25d9ab80441f813916034bb38cff01e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 22 Jun 2021 22:05:28 +0200 Subject: cmplog fix for qemu and frida --- docs/Changelog.md | 4 +++- instrumentation/afl-compiler-rt.o.c | 17 +++++++++-------- src/afl-forkserver.c | 3 +-- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/docs/Changelog.md b/docs/Changelog.md index afa5491b..4dd68cd2 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -25,10 +25,12 @@ sending a mail to . - support partial linking - We do support llvm versions from 3.8 to 5.0 again - frida_mode: - - fix for cmplog + - several fixes for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) + - qemu_mode: + - performance fix when cmplog was used - afl_analyze: - fix timeout handling - add forkserver support for better performance diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 92deff6a..d4529e2c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -617,6 +617,7 @@ static void __afl_unmap_shm(void) { #endif __afl_cmp_map = NULL; + __afl_cmp_map_backup = NULL; } @@ -1684,7 +1685,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr, void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (k >> 4) ^ (k << 8); @@ -1788,7 +1789,7 @@ void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) { void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; for (uint64_t i = 0; i < cases[0]; i++) { @@ -1885,7 +1886,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { fprintf(stderr, "\n"); */ - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); int l1, l2; if ((l1 = area_is_valid(ptr1, 32)) <= 0 || @@ -1969,7 +1970,7 @@ static u8 *get_llvm_stdstring(u8 *string) { void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -1979,7 +1980,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -1990,7 +1991,7 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -2000,7 +2001,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -2034,7 +2035,7 @@ void __afl_coverage_on() { if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) { __afl_area_ptr = __afl_area_ptr_backup; - __afl_cmp_map = __afl_cmp_map_backup; + if (__afl_cmp_map_backup) { __afl_cmp_map = __afl_cmp_map_backup; } } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 8fb8a75a..5e8fb9b5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -418,8 +418,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && - fsrv->frida_mode == false) { + if (!fsrv->cmplog_binary) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv -- cgit 1.4.1 From 1fcb52957e59c89d6ad39ead753eefb4cf6683df Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 24 Jun 2021 09:59:00 +0200 Subject: fix frida --- frida_mode/src/cmplog/cmplog.c | 7 --- instrumentation/afl-compiler-rt.o.c | 11 ++-- instrumentation/split-compares-pass.so.cc | 10 ++-- test/test-int_cases.c | 95 ++++++++++++++++++------------- test/test-uint_cases.c | 73 ++++++++++++++---------- 5 files changed, 114 insertions(+), 82 deletions(-) (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 0e3fbe53..8814f7f3 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -83,13 +83,6 @@ void cmplog_init(void) { } - /* - * We can't use /dev/null or /dev/zero for this since it appears that they - * don't validate the input buffer. Persumably as an optimization because they - * don't actually write any data. The file will be deleted on close. - */ - fd_tmp = cmplog_create_temp(); - } static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index d4529e2c..3f518b55 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -627,7 +627,7 @@ static void __afl_unmap_shm(void) { #define write_error(text) write_error_with_location(text, __FILE__, __LINE__) -void write_error_with_location(char *text, char* filename, int linenumber) { +void write_error_with_location(char *text, char *filename, int linenumber) { u8 * o = getenv("__AFL_OUT_DIR"); char *e = strerror(errno); @@ -640,14 +640,16 @@ void write_error_with_location(char *text, char* filename, int linenumber) { if (f) { - fprintf(f, "File %s, line %d: Error(%s): %s\n", filename, linenumber, text, e); + fprintf(f, "File %s, line %d: Error(%s): %s\n", filename, linenumber, + text, e); fclose(f); } } - fprintf(stderr, "File %s, line %d: Error(%s): %s\n", filename, linenumber, text, e); + fprintf(stderr, "File %s, line %d: Error(%s): %s\n", filename, linenumber, + text, e); } @@ -1014,7 +1016,7 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) { - //write_error("read from afl-fuzz"); + // write_error("read from afl-fuzz"); _exit(1); } @@ -2077,3 +2079,4 @@ void __afl_coverage_interesting(u8 val, u32 id) { } #undef write_error + diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 68f6c329..13f45b69 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -1397,11 +1397,13 @@ bool SplitComparesTransform::runOnModule(Module &M) { } bool brokenDebug = false; - if (verifyModule( M, &errs() -#if LLVM_VERSION_MAJOR > 3 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9) - ,&brokenDebug // 9th May 2016 + if (verifyModule(M, &errs() +#if LLVM_VERSION_MAJOR > 3 || \ + (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9) + , + &brokenDebug // 9th May 2016 #endif - )) { + )) { reportError( "Module Verifier failed! Consider reporting a bug with the AFL++ " diff --git a/test/test-int_cases.c b/test/test-int_cases.c index c76206c5..93848d21 100644 --- a/test/test-int_cases.c +++ b/test/test-int_cases.c @@ -13,7 +13,7 @@ int main() { volatile INT_TYPE a, b; /* different values */ a = -21; - b = -2; /* signs equal */ + b = -2; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -22,7 +22,7 @@ int main() { assert(!(a == b)); a = 1; - b = 8; /* signs equal */ + b = 8; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -30,10 +30,10 @@ int main() { assert((a != b)); assert(!(a == b)); - if ((unsigned)(INT_TYPE)(~0) > 255) { /* short or bigger */ + if ((unsigned)(INT_TYPE)(~0) > 255) { /* short or bigger */ volatile short a, b; a = 2; - b = 256+1; /* signs equal */ + b = 256 + 1; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -42,7 +42,7 @@ int main() { assert(!(a == b)); a = -1 - 256; - b = -8; /* signs equal */ + b = -8; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -50,10 +50,10 @@ int main() { assert((a != b)); assert(!(a == b)); - if ((unsigned)(INT_TYPE)(~0) > 65535) { /* int or bigger */ + if ((unsigned)(INT_TYPE)(~0) > 65535) { /* int or bigger */ volatile int a, b; a = 2; - b = 65536+1; /* signs equal */ + b = 65536 + 1; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -62,7 +62,7 @@ int main() { assert(!(a == b)); a = -1 - 65536; - b = -8; /* signs equal */ + b = -8; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -70,10 +70,10 @@ int main() { assert((a != b)); assert(!(a == b)); - if ((unsigned)(INT_TYPE)(~0) > 4294967295) { /* long or bigger */ + if ((unsigned)(INT_TYPE)(~0) > 4294967295) { /* long or bigger */ volatile long a, b; a = 2; - b = 4294967296+1; /* signs equal */ + b = 4294967296 + 1; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -82,7 +82,7 @@ int main() { assert(!(a == b)); a = -1 - 4294967296; - b = -8; /* signs equal */ + b = -8; /* signs equal */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -91,11 +91,13 @@ int main() { assert(!(a == b)); } + } + } a = -1; - b = 1; /* signs differ */ + b = 1; /* signs differ */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -104,7 +106,7 @@ int main() { assert(!(a == b)); a = -1; - b = 0; /* signs differ */ + b = 0; /* signs differ */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -113,7 +115,7 @@ int main() { assert(!(a == b)); a = -2; - b = 8; /* signs differ */ + b = 8; /* signs differ */ assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -122,7 +124,7 @@ int main() { assert(!(a == b)); a = -1; - b = -2; /* signs equal */ + b = -2; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -131,7 +133,7 @@ int main() { assert(!(a == b)); a = 8; - b = 1; /* signs equal */ + b = 1; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -140,9 +142,10 @@ int main() { assert(!(a == b)); if ((unsigned)(INT_TYPE)(~0) > 255) { + volatile short a, b; a = 1 + 256; - b = 3; /* signs equal */ + b = 3; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -151,7 +154,7 @@ int main() { assert(!(a == b)); a = -1; - b = -256; /* signs equal */ + b = -256; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -160,9 +163,10 @@ int main() { assert(!(a == b)); if ((unsigned)(INT_TYPE)(~0) > 65535) { + volatile int a, b; a = 1 + 65536; - b = 3; /* signs equal */ + b = 3; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -171,7 +175,7 @@ int main() { assert(!(a == b)); a = -1; - b = -65536; /* signs equal */ + b = -65536; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -180,30 +184,34 @@ int main() { assert(!(a == b)); if ((unsigned)(INT_TYPE)(~0) > 4294967295) { + volatile long a, b; a = 1 + 4294967296; - b = 3; /* signs equal */ + b = 3; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); assert(!(a <= b)); assert((a != b)); assert(!(a == b)); - + a = -1; - b = -4294967296; /* signs equal */ + b = -4294967296; /* signs equal */ assert((a > b)); assert((a >= b)); assert(!(a < b)); assert(!(a <= b)); assert((a != b)); assert(!(a == b)); + } + } + } a = 1; - b = -1; /* signs differ */ + b = -1; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -212,7 +220,7 @@ int main() { assert(!(a == b)); a = 0; - b = -1; /* signs differ */ + b = -1; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -221,7 +229,7 @@ int main() { assert(!(a == b)); a = 8; - b = -2; /* signs differ */ + b = -2; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -230,7 +238,7 @@ int main() { assert(!(a == b)); a = 1; - b = -2; /* signs differ */ + b = -2; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -239,9 +247,10 @@ int main() { assert(!(a == b)); if ((unsigned)(INT_TYPE)(~0) > 255) { + volatile short a, b; a = 1 + 256; - b = -2; /* signs differ */ + b = -2; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -250,7 +259,7 @@ int main() { assert(!(a == b)); a = -1; - b = -2 - 256; /* signs differ */ + b = -2 - 256; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -259,18 +268,19 @@ int main() { assert(!(a == b)); if ((unsigned)(INT_TYPE)(~0) > 65535) { + volatile int a, b; a = 1 + 65536; - b = -2; /* signs differ */ + b = -2; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); assert(!(a <= b)); assert((a != b)); assert(!(a == b)); - + a = -1; - b = -2 - 65536; /* signs differ */ + b = -2 - 65536; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -279,18 +289,19 @@ int main() { assert(!(a == b)); if ((unsigned)(INT_TYPE)(~0) > 4294967295) { + volatile long a, b; a = 1 + 4294967296; - b = -2; /* signs differ */ + b = -2; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); assert(!(a <= b)); assert((a != b)); assert(!(a == b)); - + a = -1; - b = -2 - 4294967296; /* signs differ */ + b = -2 - 4294967296; /* signs differ */ assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -299,7 +310,9 @@ int main() { assert(!(a == b)); } + } + } /* equal values */ @@ -358,6 +371,7 @@ int main() { assert((a == b)); if ((unsigned)(INT_TYPE)(~0) > 255) { + volatile short a, b; a = 1 + 256; b = 1 + 256; @@ -378,6 +392,7 @@ int main() { assert((a == b)); if ((unsigned)(INT_TYPE)(~0) > 65535) { + volatile int a, b; a = 1 + 65536; b = 1 + 65536; @@ -387,7 +402,7 @@ int main() { assert((a >= b)); assert(!(a != b)); assert((a == b)); - + a = -2 - 65536; b = -2 - 65536; assert(!(a < b)); @@ -398,6 +413,7 @@ int main() { assert((a == b)); if ((unsigned)(INT_TYPE)(~0) > 4294967295) { + volatile long a, b; a = 1 + 4294967296; b = 1 + 4294967296; @@ -407,7 +423,7 @@ int main() { assert((a >= b)); assert(!(a != b)); assert((a == b)); - + a = -2 - 4294967296; b = -2 - 4294967296; assert(!(a < b)); @@ -416,9 +432,12 @@ int main() { assert((a >= b)); assert(!(a != b)); assert((a == b)); - + } + } + } + } diff --git a/test/test-uint_cases.c b/test/test-uint_cases.c index a277e28a..bb57f408 100644 --- a/test/test-uint_cases.c +++ b/test/test-uint_cases.c @@ -22,9 +22,10 @@ int main() { assert(!(a == b)); if ((INT_TYPE)(~0) > 255) { + volatile unsigned short a, b; - a = 256+2; - b = 256+21; + a = 256 + 2; + b = 256 + 21; assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -33,7 +34,7 @@ int main() { assert(!(a == b)); a = 21; - b = 256+1; + b = 256 + 1; assert((a < b)); assert((a <= b)); assert(!(a > b)); @@ -42,46 +43,51 @@ int main() { assert(!(a == b)); if ((INT_TYPE)(~0) > 65535) { + volatile unsigned int a, b; - a = 65536+2; - b = 65536+21; + a = 65536 + 2; + b = 65536 + 21; assert((a < b)); assert((a <= b)); assert(!(a > b)); assert(!(a >= b)); assert((a != b)); assert(!(a == b)); - + a = 21; - b = 65536+1; + b = 65536 + 1; assert((a < b)); assert((a <= b)); assert(!(a > b)); assert(!(a >= b)); assert((a != b)); assert(!(a == b)); + } if ((INT_TYPE)(~0) > 4294967295) { + volatile unsigned long a, b; - a = 4294967296+2; - b = 4294967296+21; + a = 4294967296 + 2; + b = 4294967296 + 21; assert((a < b)); assert((a <= b)); assert(!(a > b)); assert(!(a >= b)); assert((a != b)); assert(!(a == b)); - + a = 21; - b = 4294967296+1; + b = 4294967296 + 1; assert((a < b)); assert((a <= b)); assert(!(a > b)); assert(!(a >= b)); assert((a != b)); assert(!(a == b)); + } + } a = 8; @@ -94,9 +100,10 @@ int main() { assert(!(a == b)); if ((INT_TYPE)(~0) > 255) { + volatile unsigned short a, b; - a = 256+2; - b = 256+1; + a = 256 + 2; + b = 256 + 1; assert((a > b)); assert((a >= b)); assert(!(a < b)); @@ -104,7 +111,7 @@ int main() { assert((a != b)); assert(!(a == b)); - a = 256+2; + a = 256 + 2; b = 6; assert((a > b)); assert((a >= b)); @@ -114,17 +121,18 @@ int main() { assert(!(a == b)); if ((INT_TYPE)(~0) > 65535) { + volatile unsigned int a, b; - a = 65536+2; - b = 65536+1; + a = 65536 + 2; + b = 65536 + 1; assert((a > b)); assert((a >= b)); assert(!(a < b)); assert(!(a <= b)); assert((a != b)); assert(!(a == b)); - - a = 65536+2; + + a = 65536 + 2; b = 6; assert((a > b)); assert((a >= b)); @@ -134,17 +142,18 @@ int main() { assert(!(a == b)); if ((INT_TYPE)(~0) > 4294967295) { + volatile unsigned long a, b; - a = 4294967296+2; - b = 4294967296+1; + a = 4294967296 + 2; + b = 4294967296 + 1; assert((a > b)); assert((a >= b)); assert(!(a < b)); assert(!(a <= b)); assert((a != b)); assert(!(a == b)); - - a = 4294967296+2; + + a = 4294967296 + 2; b = 6; assert((a > b)); assert((a >= b)); @@ -154,9 +163,10 @@ int main() { assert(!(a == b)); } + } - } + } a = 0; b = 0; @@ -177,9 +187,10 @@ int main() { assert((a == b)); if ((INT_TYPE)(~0) > 255) { + volatile unsigned short a, b; - a = 256+5; - b = 256+5; + a = 256 + 5; + b = 256 + 5; assert(!(a < b)); assert((a <= b)); assert(!(a > b)); @@ -188,9 +199,10 @@ int main() { assert((a == b)); if ((INT_TYPE)(~0) > 65535) { + volatile unsigned int a, b; - a = 65536+5; - b = 65536+5; + a = 65536 + 5; + b = 65536 + 5; assert(!(a < b)); assert((a <= b)); assert(!(a > b)); @@ -199,16 +211,19 @@ int main() { assert((a == b)); if ((INT_TYPE)(~0) > 4294967295) { + volatile unsigned long a, b; - a = 4294967296+5; - b = 4294967296+5; + a = 4294967296 + 5; + b = 4294967296 + 5; assert(!(a < b)); assert((a <= b)); assert(!(a > b)); assert((a >= b)); assert(!(a != b)); assert((a == b)); + } + } } -- cgit 1.4.1 From 3a3ef7b6b4efcd8ed12bef80cca51f82e65a985f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 12:16:52 +0200 Subject: update documentation --- README.md | 55 ++++++++++++- docs/Changelog.md | 1 + docs/QuickStartGuide.md | 9 +-- docs/README.MOpt.md | 54 ------------- docs/historical_notes.md | 143 -------------------------------- docs/notes_for_asan.md | 157 ------------------------------------ docs/perf_tips.md | 47 ++++------- docs/power_schedules.md | 32 -------- docs/technical_details.md | 4 + instrumentation/afl-compiler-rt.o.c | 5 +- 10 files changed, 79 insertions(+), 428 deletions(-) delete mode 100644 docs/README.MOpt.md delete mode 100644 docs/historical_notes.md delete mode 100644 docs/notes_for_asan.md delete mode 100644 docs/power_schedules.md (limited to 'instrumentation/afl-compiler-rt.o.c') diff --git a/README.md b/README.md index bc5b333c..50f514ab 100644 --- a/README.md +++ b/README.md @@ -387,7 +387,56 @@ afl++ performs "never zero" counting in its bitmap. You can read more about this here: * [instrumentation/README.neverzero.md](instrumentation/README.neverzero.md) -#### c) Modify the target +#### c) Sanitizers + +It is possible to use sanitizers when instrumenting targets for fuzzing, +which allows you to find bugs that would not necessarily result in a crash. + +Note that sanitizers have a huge impact on CPU (= less executions per second) +and RAM usage. Also you should only run one afl-fuz instance per sanitizer type. +This is enough because a user-after-free bug will be picked up, e.g. by +ASAN (address sanitizer) anyway when syncing to other fuzzing instances, +so not all fuzzing instances need to be instrumented with ASAN. + +The wolloing sanitizers have built-in support in afl++: + * ASAN = Address SANitizer, finds memory corruption vulnerabilities like + use-after-free, NULL pointer dereference, buffer overruns, etc. + Enabled with `export AFL_USE_ASAN=1` before compiling. + * MSAN = Memory SANitizer, finds read access to uninitialized memory, eg. + a local variable that is defined and read before it is even set. + Enabled with `export AFL_USE_MSAN=1` before compiling. + * UBSAN = Undefined Behaviour SANitizer, finds instances where - by the + C and C++ standards - undefined behaviour happens, e.g. adding two + signed integers together where the result is larger than a signed integer + can hold. + Enabled with `export AFL_USE_UBSAN=1` before compiling. + * CFISAN = Control Flow Integrity SANitizer, finds instances where the + control flow is found to be illegal. Originally this was rather to + prevent return oriented programming exploit chains from functioning, + in fuzzing this is mostly reduced to detecting type confusion + vulnerabilities - which is however one of the most important and dangerous + C++ memory corruption classes! + Enabled with `export AFL_USE_CFISAN=1` before compiling. + * LSAN = Leak SANitizer, finds memory leaks in a program. This is not really + a security issue, but for developers this can be very valuable. + Note that unlike the other sanitizers above this needs + `__AFL_LEAK_CHECK();` added to all areas of the target source code where you + find a leak check necessary! + Enabled with `export AFL_USE_LSAN=1` before compiling. + +It is possible to further modify the behaviour of the sanitizers at run-time +by setting `ASAN_OPTIONS=...`, `LSAN_OPTIONS` etc. - the availabel parameter +can be looked up in the sanitizer documentation of llvm/clang. +afl-fuzz however requires some specific parameters important for fuzzing to be +set if you want to set your own, and will bail and report what it is missing. + +Note that some sanitizers cannot be used together, e.g. ASAN and MSAN, and +others often cannot work together because of target weirdness, e.g. ASAN and +CFISAN. You might need to experiment which sanitizers you can combine in a +target (which means more instances can be run without a sanitized target, +which is more effective). + +#### d) Modify the target If the target has features that make fuzzing more difficult, e.g. checksums, HMAC, etc. then modify the source code so that this is @@ -405,7 +454,7 @@ these checks within this specific defines: All afl++ compilers will set this preprocessor definition automatically. -#### d) Instrument the target +#### e) Instrument the target In this step the target source code is compiled so that it can be fuzzed. @@ -462,7 +511,7 @@ non-standard way to set this, otherwise set up the build normally and edit the generated build environment afterwards manually to point it to the right compiler (and/or ranlib and ar). -#### d) Better instrumentation +#### f) Better instrumentation If you just fuzz a target program as-is you are wasting a great opportunity for much more fuzzing speed. diff --git a/docs/Changelog.md b/docs/Changelog.md index aebd3fa9..705daa40 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -38,6 +38,7 @@ sending a mail to . - ensure afl-compiler-rt is built for gcc_module - added `AFL_NO_FORKSRV` env variable support to afl-cmin, afl-tmin, and afl-showmap, by @jhertz + - removed outdated documents, improved existing documentation ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md index d1966170..2d056ecf 100644 --- a/docs/QuickStartGuide.md +++ b/docs/QuickStartGuide.md @@ -18,14 +18,12 @@ how to hit the ground running: custom SIGSEGV or SIGABRT handlers and background processes. For tips on detecting non-crashing flaws, see section 11 in [README.md](README.md) . -3) Compile the program / library to be fuzzed using afl-gcc. A common way to +3) Compile the program / library to be fuzzed using afl-cc. A common way to do this would be: - CC=/path/to/afl-gcc CXX=/path/to/afl-g++ ./configure --disable-shared + CC=/path/to/afl-cc CXX=/path/to/afl-c++ ./configure --disable-shared make clean all - If program build fails, ping . - 4) Get a small but valid input file that makes sense to the program. When fuzzing verbose syntax (SQL, HTTP, etc), create a dictionary as described in dictionaries/README.md, too. @@ -41,9 +39,6 @@ how to hit the ground running: 6) Investigate anything shown in red in the fuzzer UI by promptly consulting [status_screen.md](status_screen.md). -7) compile and use llvm_mode (afl-clang-fast/afl-clang-fast++) as it is way - faster and has a few cool features - 8) There is a basic docker build with 'docker build -t aflplusplus .' That's it. Sit back, relax, and - time permitting - try to skim through the diff --git a/docs/README.MOpt.md b/docs/README.MOpt.md deleted file mode 100644 index 3de6d670..00000000 --- a/docs/README.MOpt.md +++ /dev/null @@ -1,54 +0,0 @@ -# MOpt(imized) AFL by - -### 1. Description -MOpt-AFL is a AFL-based fuzzer that utilizes a customized Particle Swarm -Optimization (PSO) algorithm to find the optimal selection probability -distribution of operators with respect to fuzzing effectiveness. -More details can be found in the technical report. - -### 2. Cite Information -Chenyang Lyu, Shouling Ji, Chao Zhang, Yuwei Li, Wei-Han Lee, Yu Song and -Raheem Beyah, MOPT: Optimized Mutation Scheduling for Fuzzers, -USENIX Security 2019. - -### 3. Seed Sets -We open source all the seed sets used in the paper -"MOPT: Optimized Mutation Scheduling for Fuzzers". - -### 4. Experiment Results -The experiment results can be found in -https://drive.google.com/drive/folders/184GOzkZGls1H2NuLuUfSp9gfqp1E2-lL?usp=sharing. -We only open source the crash files since the space is limited. - -### 5. Technical Report -MOpt_TechReport.pdf is the technical report of the paper -"MOPT: Optimized Mutation Scheduling for Fuzzers", which contains more deatails. - -### 6. Parameter Introduction -Most important, you must add the parameter `-L` (e.g., `-L 0`) to launch the -MOpt scheme. - -Option '-L' controls the time to move on to the pacemaker fuzzing mode. -'-L t': when MOpt-AFL finishes the mutation of one input, if it has not -discovered any new unique crash or path for more than t minutes, MOpt-AFL will -enter the pacemaker fuzzing mode. - -Setting 0 will enter the pacemaker fuzzing mode at first, which is -recommended in a short time-scale evaluation. - -Setting -1 will enable both pacemaker mode and normal aflmutation fuzzing in -parallel. - -Other important parameters can be found in afl-fuzz.c, for instance, - -'swarm_num': the number of the PSO swarms used in the fuzzing process. -'period_pilot': how many times MOpt-AFL will execute the target program - in the pilot fuzzing module, then it will enter the core fuzzing module. -'period_core': how many times MOpt-AFL will execute the target program in the - core fuzzing module, then it will enter the PSO updating module. -'limit_time_bound': control how many interesting test cases need to be found - before MOpt-AFL quits the pacemaker fuzzing mode and reuses the deterministic stage. - 0 < 'limit_time_bound' < 1, MOpt-AFL-tmp. - 'limit_time_bound' >= 1, MOpt-AFL-ever. - -Have fun with MOpt in AFL! diff --git a/docs/historical_notes.md b/docs/historical_notes.md deleted file mode 100644 index b5d3d157..00000000 --- a/docs/historical_notes.md +++ /dev/null @@ -1,143 +0,0 @@ -# Historical notes - - This doc talks about the rationale of some of the high-level design decisions - for American Fuzzy Lop. It's adopted from a discussion with Rob Graham. - See README.md for the general instruction manual, and technical_details.md for - additional implementation-level insights. - -## 1) Influences - -In short, `afl-fuzz` is inspired chiefly by the work done by Tavis Ormandy back -in 2007. Tavis did some very persuasive experiments using `gcov` block coverage -to select optimal test cases out of a large corpus of data, and then using -them as a starting point for traditional fuzzing workflows. - -(By "persuasive", I mean: netting a significant number of interesting -vulnerabilities.) - -In parallel to this, both Tavis and I were interested in evolutionary fuzzing. -Tavis had his experiments, and I was working on a tool called bunny-the-fuzzer, -released somewhere in 2007. - -Bunny used a generational algorithm not much different from `afl-fuzz`, but -also tried to reason about the relationship between various input bits and -the internal state of the program, with hopes of deriving some additional value -from that. The reasoning / correlation part was probably in part inspired by -other projects done around the same time by Will Drewry and Chris Evans. - -The state correlation approach sounded very sexy on paper, but ultimately, made -the fuzzer complicated, brittle, and cumbersome to use; every other target -program would require a tweak or two. Because Bunny didn't fare a whole lot -better than less sophisticated brute-force tools, I eventually decided to write -it off. You can still find its original documentation at: - - https://code.google.com/p/bunny-the-fuzzer/wiki/BunnyDoc - -There has been a fair amount of independent work, too. Most notably, a few -weeks earlier that year, Jared DeMott had a Defcon presentation about a -coverage-driven fuzzer that relied on coverage as a fitness function. - -Jared's approach was by no means identical to what afl-fuzz does, but it was in -the same ballpark. His fuzzer tried to explicitly solve for the maximum coverage -with a single input file; in comparison, afl simply selects for cases that do -something new (which yields better results - see [technical_details.md](technical_details.md)). - -A few years later, Gabriel Campana released fuzzgrind, a tool that relied purely -on Valgrind and a constraint solver to maximize coverage without any brute-force -bits; and Microsoft Research folks talked extensively about their still -non-public, solver-based SAGE framework. - -In the past six years or so, I've also seen a fair number of academic papers -that dealt with smart fuzzing (focusing chiefly on symbolic execution) and a -couple papers that discussed proof-of-concept applications of genetic -algorithms with the same goals in mind. I'm unconvinced how practical most of -these experiments were; I suspect that many of them suffer from the -bunny-the-fuzzer's curse of being cool on paper and in carefully designed -experiments, but failing the ultimate test of being able to find new, -worthwhile security bugs in otherwise well-fuzzed, real-world software. - -In some ways, the baseline that the "cool" solutions have to compete against is -a lot more impressive than it may seem, making it difficult for competitors to -stand out. For a singular example, check out the work by Gynvael and Mateusz -Jurczyk, applying "dumb" fuzzing to ffmpeg, a prominent and security-critical -component of modern browsers and media players: - - http://googleonlinesecurity.blogspot.com/2014/01/ffmpeg-and-thousand-fixes.html - -Effortlessly getting comparable results with state-of-the-art symbolic execution -in equally complex software still seems fairly unlikely, and hasn't been -demonstrated in practice so far. - -But I digress; ultimately, attribution is hard, and glorying the fundamental -concepts behind AFL is probably a waste of time. The devil is very much in the -often-overlooked details, which brings us to... - -## 2. Design goals for afl-fuzz - -In short, I believe that the current implementation of afl-fuzz takes care of -several itches that seemed impossible to scratch with other tools: - -1) Speed. It's genuinely hard to compete with brute force when your "smart" - approach is resource-intensive. If your instrumentation makes it 10x more - likely to find a bug, but runs 100x slower, your users are getting a bad - deal. - - To avoid starting with a handicap, `afl-fuzz` is meant to let you fuzz most of - the intended targets at roughly their native speed - so even if it doesn't - add value, you do not lose much. - - On top of this, the tool leverages instrumentation to actually reduce the - amount of work in a couple of ways: for example, by carefully trimming the - corpus or skipping non-functional but non-trimmable regions in the input - files. - -2) Rock-solid reliability. It's hard to compete with brute force if your - approach is brittle and fails unexpectedly. Automated testing is attractive - because it's simple to use and scalable; anything that goes against these - principles is an unwelcome trade-off and means that your tool will be used - less often and with less consistent results. - - Most of the approaches based on symbolic execution, taint tracking, or - complex syntax-aware instrumentation are currently fairly unreliable with - real-world targets. Perhaps more importantly, their failure modes can render - them strictly worse than "dumb" tools, and such degradation can be difficult - for less experienced users to notice and correct. - - In contrast, `afl-fuzz` is designed to be rock solid, chiefly by keeping it - simple. In fact, at its core, it's designed to be just a very good - traditional fuzzer with a wide range of interesting, well-researched - strategies to go by. The fancy parts just help it focus the effort in - places where it matters the most. - -3) Simplicity. The author of a testing framework is probably the only person - who truly understands the impact of all the settings offered by the tool - - and who can dial them in just right. Yet, even the most rudimentary fuzzer - frameworks often come with countless knobs and fuzzing ratios that need to - be guessed by the operator ahead of the time. This can do more harm than - good. - - AFL is designed to avoid this as much as possible. The three knobs you - can play with are the output file, the memory limit, and the ability to - override the default, auto-calibrated timeout. The rest is just supposed to - work. When it doesn't, user-friendly error messages outline the probable - causes and workarounds, and get you back on track right away. - -4) Chainability. Most general-purpose fuzzers can't be easily employed - against resource-hungry or interaction-heavy tools, necessitating the - creation of custom in-process fuzzers or the investment of massive CPU - power (most of which is wasted on tasks not directly related to the code - we actually want to test). - - AFL tries to scratch this itch by allowing users to use more lightweight - targets (e.g., standalone image parsing libraries) to create small - corpora of interesting test cases that can be fed into a manual testing - process or a UI harness later on. - -As mentioned in [technical_details.md](technical_details.md), AFL does all this not by systematically -applying a single overarching CS concept, but by experimenting with a variety -of small, complementary methods that were shown to reliably yields results -better than chance. The use of instrumentation is a part of that toolkit, but is -far from being the most important one. - -Ultimately, what matters is that `afl-fuzz` is designed to find cool bugs - and -has a pretty robust track record of doing just that. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md deleted file mode 100644 index f55aeaf2..00000000 --- a/docs/notes_for_asan.md +++ /dev/null @@ -1,157 +0,0 @@ -# Notes for using ASAN with afl-fuzz - - This file discusses some of the caveats for fuzzing under ASAN, and suggests - a handful of alternatives. See README.md for the general instruction manual. - -## 1) Short version - -ASAN on 64-bit systems requests a lot of memory in a way that can't be easily -distinguished from a misbehaving program bent on crashing your system. - -Because of this, fuzzing with ASAN is recommended only in four scenarios: - - - On 32-bit systems, where we can always enforce a reasonable memory limit - (-m 800 or so is a good starting point), - - - On 64-bit systems only if you can do one of the following: - - - Compile the binary in 32-bit mode (gcc -m32), - - - Precisely gauge memory needs using http://jwilk.net/software/recidivm . - - - Limit the memory available to process using cgroups on Linux (see - utils/asan_cgroups). - -To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The -afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags. -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_LEAK_CHECK();. -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. - -There is also the option of generating a corpus using a non-ASAN binary, and -then feeding it to an ASAN-instrumented one to check for bugs. This is faster, -and can give you somewhat comparable results. You can also try using -libdislocator (see [utils/libdislocator/README.dislocator.md](../utils/libdislocator/README.dislocator.md) in the parent directory) as a -lightweight and hassle-free (but less thorough) alternative. - -## 2) Long version - -ASAN allocates a huge region of virtual address space for bookkeeping purposes. -Most of this is never actually accessed, so the OS never has to allocate any -real pages of memory for the process, and the VM grabbed by ASAN is essentially -"free" - but the mapping counts against the standard OS-enforced limit -(RLIMIT_AS, aka ulimit -v). - -On our end, afl-fuzz tries to protect you from processes that go off-rails -and start consuming all the available memory in a vain attempt to parse a -malformed input file. This happens surprisingly often, so enforcing such a limit -is important for almost any fuzzer: the alternative is for the kernel OOM -handler to step in and start killing random processes to free up resources. -Needless to say, that's not a very nice prospect to live with. - -Unfortunately, un*x systems offer no portable way to limit the amount of -pages actually given to a process in a way that distinguishes between that -and the harmless "land grab" done by ASAN. In principle, there are three standard -ways to limit the size of the heap: - - - The RLIMIT_AS mechanism (ulimit -v) caps the size of the virtual space - - but as noted, this pays no attention to the number of pages actually - in use by the process, and doesn't help us here. - - - The RLIMIT_DATA mechanism (ulimit -d) seems like a good fit, but it applies - only to the traditional sbrk() / brk() methods of requesting heap space; - modern allocators, including the one in glibc, routinely rely on mmap() - instead, and circumvent this limit completely. - - - Finally, the RLIMIT_RSS limit (ulimit -m) sounds like what we need, but - doesn't work on Linux - mostly because nobody felt like implementing it. - -There are also cgroups, but they are Linux-specific, not universally available -even on Linux systems, and they require root permissions to set up; I'm a bit -hesitant to make afl-fuzz require root permissions just for that. That said, -if you are on Linux and want to use cgroups, check out the contributed script -that ships in utils/asan_cgroups/. - -In settings where cgroups aren't available, we have no nice, portable way to -avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for -binaries compiled in 32-bit mode (-m32), this is not a big deal: ASAN needs -around 600-800 MB or so, depending on the compiler - so all you need to do is -to specify -m that is a bit higher than that. - -On 64-bit systems, the situation is more murky, because the ASAN allocation -is completely outlandish - around 17.5 TB in older versions, and closer to -20 TB with newest ones. The actual amount of memory on your system is -(probably!) just a tiny fraction of that - so unless you dial the limit -with surgical precision, you will get no protection from OOM bugs. - -On my system, the amount of memory grabbed by ASAN with a slightly older -version of gcc is around 17,825,850 MB; for newest clang, it's 20,971,600. -But there is no guarantee that these numbers are stable, and if you get them -wrong by "just" a couple gigs or so, you will be at risk. - -To get the precise number, you can use the recidivm tool developed by Jakub -Wilk (http://jwilk.net/software/recidivm). In absence of this, ASAN is *not* -recommended when fuzzing 64-bit binaries, unless you are confident that they -are robust and enforce reasonable memory limits (in which case, you can -specify '-m none' when calling afl-fuzz). - -Using recidivm or running with no limits aside, there are two other decent -alternatives: build a corpus of test cases using a non-ASAN binary, and then -examine them with ASAN, Valgrind, or other heavy-duty tools in a more -controlled setting; or compile the target program with -m32 (32-bit mode) -if your system supports that. - -## 3) Interactions with the QEMU mode - -ASAN, MSAN, and other sanitizers appear to be incompatible with QEMU user -emulation, so please do not try to use them with the -Q option; QEMU doesn't -seem to appreciate the shadow VM trick used by these tools, and will likely -just allocate all your physical memory, then crash. - -You can, however, use QASan to run binaries that are not instrumented with ASan -under QEMU with the AFL++ instrumentation. - -https://github.com/andreafioraldi/qasan - -## 4) ASAN and OOM crashes - -By default, ASAN treats memory allocation failures as fatal errors, immediately -causing the program to crash. Since this is a departure from normal POSIX -semantics (and creates the appearance of security issues in otherwise -properly-behaving programs), we try to disable this by specifying -allocator_may_return_null=1 in ASAN_OPTIONS. - -Unfortunately, it's been reported that this setting still causes ASAN to -trigger phantom crashes in situations where the standard allocator would -simply return NULL. If this is interfering with your fuzzing jobs, you may -want to cc: yourself on this bug: - - https://bugs.llvm.org/show_bug.cgi?id=22026 - -## 5) What about UBSAN? - -New versions of UndefinedBehaviorSanitizer offers the --fsanitize=undefined-trap-on-error compiler flag that tells UBSan to insert an -istruction that will cause SIGILL (ud2 on x86) when an undefined behaviour -is detected. This is the option that you want to use when combining AFL++ -and UBSan. - -AFL_USE_UBSAN=1 env var will add this compiler flag to afl-clang-fast, -afl-gcc-fast and afl-gcc for you. - -Old versions of UBSAN don't offer a consistent way -to abort() on fault conditions or to terminate with a distinctive exit code -but there are some versions of the library can be binary-patched to address this -issue. You can also preload a shared library that substitute all the UBSan -routines used to report errors with abort(). diff --git a/docs/perf_tips.md b/docs/perf_tips.md index c5968206..7c14cbbc 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -48,13 +48,9 @@ be then manually fed to a more resource-hungry program later on. Also note that reading the fuzzing input via stdin is faster than reading from a file. -## 3. Use LLVM instrumentation +## 3. Use LLVM persistent instrumentation -When fuzzing slow targets, you can gain 20-100% performance improvement by -using the LLVM-based instrumentation mode described in [the instrumentation README](../instrumentation/README.llvm.md). -Note that this mode requires the use of clang and will not work with GCC. - -The LLVM mode also offers a "persistent", in-process fuzzing mode that can +The LLVM mode offers a "persistent", in-process fuzzing mode that can work well for certain types of self-contained libraries, and for fast targets, can offer performance gains up to 5-10x; and a "deferred fork server" mode that can offer huge benefits for programs with high startup overhead. Both @@ -138,8 +134,7 @@ misses, or similar factors, but they are less likely to be a concern.) ## 7. Keep memory use and timeouts in check -If you have increased the `-m` or `-t` limits more than truly necessary, consider -dialing them back down. +Consider setting low values for -m and -t. For programs that are nominally very fast, but get sluggish for some inputs, you can also try setting `-t` values that are more punishing than what `afl-fuzz` @@ -164,6 +159,20 @@ There are several OS-level factors that may affect fuzzing speed: - Network filesystems, either used for fuzzer input / output, or accessed by the fuzzed binary to read configuration files (pay special attention to the home directory - many programs search it for dot-files). + - Disable all the spectre, meltdown etc. security countermeasures in the + kernel if your machine is properly separated: + +``` +ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off +no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable +nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off +spectre_v2=off stf_barrier=off +``` + In most Linux distributions you can put this into a `/etc/default/grub` + variable. + +The following list of changes are made when executing `afl-system-config`: + - On-demand CPU scaling. The Linux `ondemand` governor performs its analysis on a particular schedule and is known to underestimate the needs of short-lived processes spawned by `afl-fuzz` (or any other fuzzer). On Linux, @@ -196,26 +205,4 @@ There are several OS-level factors that may affect fuzzing speed: Setting a different scheduling policy for the fuzzer process - say `SCHED_RR` - can usually speed things up, too, but needs to be done with care. - - Use the `afl-system-config` script to set all proc/sys settings above in one go. - - Disable all the spectre, meltdown etc. security countermeasures in the - kernel if your machine is properly separated: - -``` -ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off -no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable -nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off -spectre_v2=off stf_barrier=off -``` - In most Linux distributions you can put this into a `/etc/default/grub` - variable. - -## 9. If all other options fail, use `-d` - -For programs that are genuinely slow, in cases where you really can't escape -using huge input files, or when you simply want to get quick and dirty results -early on, you can always resort to the `-d` mode. -The mode causes `afl-fuzz` to skip all the deterministic fuzzing steps, which -makes output a lot less neat and can ultimately make the testing a bit less -in-depth, but it will give you an experience more familiar from other fuzzing -tools. diff --git a/docs/power_schedules.md b/docs/power_schedules.md deleted file mode 100644 index 493f9609..00000000 --- a/docs/power_schedules.md +++ /dev/null @@ -1,32 +0,0 @@ -# afl++'s power schedules based on AFLfast - - -Power schedules implemented by Marcel Böhme \. -AFLFast is an extension of AFL which is written and maintained by -Michal Zalewski \. - -AFLfast has helped in the success of Team Codejitsu at the finals of the DARPA Cyber Grand Challenge where their bot Galactica took **2nd place** in terms of #POVs proven (see red bar at https://www.cybergrandchallenge.com/event#results). AFLFast exposed several previously unreported CVEs that could not be exposed by AFL in 24 hours and otherwise exposed vulnerabilities significantly faster than AFL while generating orders of magnitude more unique crashes. - -Essentially, we observed that most generated inputs exercise the same few "high-frequency" paths and developed strategies to gravitate towards low-frequency paths, to stress significantly more program behavior in the same amount of time. We devised several **search strategies** that decide in which order the seeds should be fuzzed and **power schedules** that smartly regulate the number of inputs generated from a seed (i.e., the time spent fuzzing a seed). We call the number of inputs generated from a seed, the seed's **energy**. - -We find that AFL's exploitation-based constant schedule assigns **too much energy to seeds exercising high-frequency paths** (e.g., paths that reject invalid inputs) and not enough energy to seeds exercising low-frequency paths (e.g., paths that stress interesting behaviors). Technically, we modified the computation of a seed's performance score (`calculate_score`), which seed is marked as favourite (`update_bitmap_score`), and which seed is chosen next from the circular queue (`main`). We implemented the following schedules (in the order of their effectiveness, best first): - -| AFL flag | Power Schedule | -| ------------- | -------------------------- | -| `-p explore` | ![EXPLORE](http://latex.codecogs.com/gif.latex?p%28i%29%3D%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D) | -| `-p fast` (default)| ![FAST](http://latex.codecogs.com/gif.latex?p(i)=\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) | -| `-p coe` | ![COE](http://latex.codecogs.com/gif.latex?p%28i%29%3D%5Cbegin%7Bcases%7D%200%20%26%20%5Ctext%7B%20if%20%7D%20f%28i%29%20%3E%20%5Cmu%5C%5C%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%202%5E%7Bs%28i%29%7D%2C%20M%5Cright%29%20%26%20%5Ctext%7B%20otherwise.%7D%20%5Cend%7Bcases%7D) | -| `-p quad` | ![QUAD](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%5E2%7D%7Bf%28i%29%7D%2CM%5Cright%29) | -| `-p lin` | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%7D%7Bf%28i%29%7D%2CM%5Cright%29) | -| `-p exploit` (AFL) | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Calpha%28i%29) | -| `-p mmopt` | Experimental: `explore` with no weighting to runtime and increased weighting on the last 5 queue entries | -| `-p rare` | Experimental: `rare` puts focus on queue entries that hit rare edges | -| `-p seek` | Experimental: `seek` is EXPLORE but ignoring the runtime of the queue input and less focus on the size | -where *α(i)* is the performance score that AFL uses to compute for the seed input *i*, *β(i)>1* is a constant, *s(i)* is the number of times that seed *i* has been chosen from the queue, *f(i)* is the number of generated inputs that exercise the same path as seed *i*, and *μ* is the average number of generated inputs exercising a path. - -More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/). - -PS: In parallel mode (several instances with shared queue), we suggest to run the main node using the exploit schedule (-p exploit) and the secondary nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast; default), and explore (-p explore) schedules. In single mode, the default settings will do. **EDIT:** In parallel mode, AFLFast seems to perform poorly because the path probability estimates are incorrect for the imported seeds. Pull requests to fix this issue by syncing the estimates across instances are appreciated :) - -Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. -Released under terms and conditions of Apache License, Version 2.0. diff --git a/docs/technical_details.md b/docs/technical_details.md index a0453c91..6a4660a2 100644 --- a/docs/technical_details.md +++ b/docs/technical_details.md @@ -1,5 +1,9 @@ # Technical "whitepaper" for afl-fuzz + +NOTE: this document is rather outdated! + + This document provides a quick overview of the guts of American Fuzzy Lop. See README.md for the general instruction manual; and for a discussion of motivations and design goals behind AFL, see historical_notes.md. diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 3f518b55..b01ea987 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -299,8 +299,9 @@ static void __afl_map_shm(void) { if (!getenv("AFL_QUIET")) fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u " - "to be able to run this instrumented program!\n", + "Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u " + "to be able to run this instrumented program if this " + "crashes!\n", __afl_final_loc); } -- cgit 1.4.1