From 6aa6af04acb8f024696e8723e6d73514006b3dd5 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 10 Apr 2020 16:45:45 +0200 Subject: files opened with fdopen should be closed with fclose --- src/afl-fuzz-cmplog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index f932f33b..98f7db05 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -121,7 +121,7 @@ void init_cmplog_forkserver(afl_state_t *afl) { #ifndef HAVE_ARC4RANDOM close(afl->fsrv.dev_urandom_fd); #endif - close(afl->fsrv.plot_file == NULL ? -1 : fileno(afl->fsrv.plot_file)); + if (afl->fsrv.plot_file != NULL) fclose(afl->fsrv.plot_file); /* This should improve performance a bit, since it stops the linker from doing extra work post-fork(). */ -- cgit 1.4.1 From f0f83bab5299098a441af40236f3758171b69889 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 10 Apr 2020 17:47:22 +0200 Subject: resize fix + code format --- include/common.h | 4 +++- include/forkserver.h | 3 ++- src/afl-common.c | 8 +++++--- src/afl-forkserver.c | 5 +++-- src/afl-fuzz-cmplog.c | 6 ++++-- src/afl-fuzz-init.c | 6 ++---- src/afl-fuzz-run.c | 6 ++++-- src/afl-fuzz-stats.c | 14 +++++++------- src/afl-showmap.c | 2 +- src/afl-tmin.c | 2 +- 10 files changed, 32 insertions(+), 24 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/include/common.h b/include/common.h index c9436e81..8dd66355 100644 --- a/include/common.h +++ b/include/common.h @@ -99,9 +99,11 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms); /* Wrapper for select() and read(), reading exactly len bytes. Returns the time passed to read. + stop_soon should point to a variable indicating ctrl+c was pressed. If the wait times out, returns timeout_ms + 1; Returns 0 if an error occurred (fd closed, signal, ...); */ -u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms); +u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms, + volatile u8 *stop_soon_p); #endif diff --git a/include/forkserver.h b/include/forkserver.h index 5d1bd2cf..4110df7d 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -67,7 +67,8 @@ typedef struct afl_forkserver { } afl_forkserver_t; void afl_fsrv_init(afl_forkserver_t *fsrv); -void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv); +void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, + volatile u8 *stop_soon_p); void afl_fsrv_deinit(afl_forkserver_t *fsrv); void afl_fsrv_killall(); diff --git a/src/afl-common.c b/src/afl-common.c index 7eee5265..12b0355e 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -40,6 +40,7 @@ u8 be_quiet = 0; u8 *doc_path = ""; +u8 last_intr = 0; char *afl_environment_variables[] = { @@ -754,7 +755,8 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) { Returns the time passed to read. If the wait times out, returns timeout_ms + 1; Returns 0 if an error occurred (fd closed, signal, ...); */ -u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) { +u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms, + volatile u8 *stop_soon_p) { struct timeval timeout; fd_set readfds; @@ -779,8 +781,8 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) { } else if (sret < 0) { - // perror("sret malloc"); - // TODO: catch other (errno == EINTR) than ctrl+c? + /* Retry select for all signals other than than ctrl+c */ + if (errno == EINTR && !*stop_soon_p) { continue; } return 0; } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index b3b86685..56c3c9d5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -160,7 +160,8 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { cloning a stopped child. So, we just execute once, and then send commands through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ -void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { +void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, + volatile u8 *stop_soon_p) { int st_pipe[2], ctl_pipe[2]; int status; @@ -317,7 +318,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { rlen = 4; u32 time = read_timed(fsrv->fsrv_st_fd, &status, rlen, - fsrv->exec_tmout * FORK_WAIT_MULT); + fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p); if (time > fsrv->exec_tmout * FORK_WAIT_MULT) { diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 98f7db05..5ad73539 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -187,7 +187,8 @@ void init_cmplog_forkserver(afl_state_t *afl) { rlen = 4; u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT; /* Reuse readfds as exceptfds to see when the child closed the pipe */ - u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms); + u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms, + &afl->stop_soon); if (!exec_ms) { @@ -416,7 +417,8 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { /* Configure timeout, as requested by user, then wait for child to terminate. */ - exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout); + exec_ms = + read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); if (exec_ms > timeout) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index ce30e599..6e0485e5 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -134,14 +134,12 @@ void bind_to_free_cpu(afl_state_t *afl) { for (i = 0; i < proccount; i++) { #if defined(__FreeBSD__) - if (!strcmp(procs[i].ki_comm, "idle")) - continue; + if (!strcmp(procs[i].ki_comm, "idle")) continue; // fix when ki_oncpu = -1 int oncpu; oncpu = procs[i].ki_oncpu; - if (oncpu == -1) - oncpu = procs[i].ki_lastcpu; + if (oncpu == -1) oncpu = procs[i].ki_lastcpu; if (oncpu != -1 && oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60) cpu_used[oncpu] = 1; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 47f6e9d9..9bbdd23a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -67,7 +67,8 @@ u8 run_target(afl_state_t *afl, u32 timeout) { if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - exec_ms = read_timed(afl->fsrv.fsrv_st_fd, &status, 4, timeout); + exec_ms = + read_timed(afl->fsrv.fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); if (exec_ms > timeout) { @@ -308,7 +309,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ - if (!afl->fsrv.fsrv_pid) afl_fsrv_start(&afl->fsrv, afl->argv); + if (!afl->fsrv.fsrv_pid) + afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon); if (afl->dumb_mode != 1 && !afl->no_forkserver && !afl->cmplog_fsrv_pid && afl->shm.cmplog_mode) init_cmplog_forkserver(afl); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 850555b5..ab84bf3f 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -366,9 +366,9 @@ void show_stats(afl_state_t *afl) { /* Lord, forgive me this. */ - SAYF(SET_G1 bSTG bLT bH bSTOP cCYA + SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA - " overall results " bSTG bH2 bH2 bRT "\n"); + " overall results " bSTG bH2 bH2 bRT "\n"); if (afl->dumb_mode) { @@ -450,9 +450,9 @@ void show_stats(afl_state_t *afl) { " uniq hangs : " cRST "%-6s" bSTG bV "\n", time_tmp, tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA - " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); + " map coverage " bSTG bH 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 @@ -481,9 +481,9 @@ void show_stats(afl_state_t *afl) { SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA - " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); + " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored), ((double)afl->queued_favored) * 100 / afl->queued_paths); @@ -557,7 +557,7 @@ void show_stats(afl_state_t *afl) { /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index e4463dc4..2fd17fb1 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -951,7 +951,7 @@ int main(int argc, char **argv_orig, char **envp) { } - afl_fsrv_start(fsrv, use_argv); + afl_fsrv_start(fsrv, use_argv, &stop_soon); while (done == 0 && (dir_ent = readdir(dir_in))) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 30e76d42..f899a6b5 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1133,7 +1133,7 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv); + afl_fsrv_start(fsrv, use_argv, &stop_soon); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : ""); -- cgit 1.4.1 From 3a509c61689112cc321c4c78f058014abff66c8a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 10 Apr 2020 22:33:11 +0200 Subject: LTO optimization, variable map size, autodictionary (#307) * lto module clean-up * step 1/3 * step 1/3 completed * if tmp is ever made non-static * parts 2 and 3 - autodictionary is complete * variable map_size support * variable map size: changed overlooked functions * remove debug for autodict * 64 bit alignment of map size * fix review comments * force 64 bit alignment on both sides * typo --- docs/env_variables.md | 11 +- gcc_plugin/afl-gcc-rt.o.c | 4 +- include/afl-fuzz.h | 22 +- include/config.h | 14 +- include/forkserver.h | 6 + llvm_mode/GNUmakefile | 3 +- llvm_mode/README.lto.md | 41 ++-- llvm_mode/afl-clang-fast.c | 3 + llvm_mode/afl-llvm-lto-instrumentation.so.cc | 330 +++++++++++++++++++++++++-- llvm_mode/afl-llvm-rt.o.c | 170 ++++++++++++-- qemu_mode/patches/afl-qemu-cpu-inl.h | 2 +- src/afl-common.c | 1 + src/afl-forkserver.c | 96 +++++++- src/afl-fuzz-bitmap.c | 61 +++-- src/afl-fuzz-cmplog.c | 6 +- src/afl-fuzz-extras.c | 10 +- src/afl-fuzz-init.c | 4 +- src/afl-fuzz-mutators.c | 7 +- src/afl-fuzz-one.c | 16 +- src/afl-fuzz-queue.c | 19 +- src/afl-fuzz-redqueen.c | 14 +- src/afl-fuzz-run.c | 27 +-- src/afl-fuzz-state.c | 4 + src/afl-fuzz-stats.c | 11 +- src/afl-tmin.c | 4 +- 25 files changed, 726 insertions(+), 160 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/docs/env_variables.md b/docs/env_variables.md index cd002145..7890da35 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -111,10 +111,15 @@ Then there are a few specific features that are only available in llvm_mode: instrumentation which is 100% collision free (collisions are a big issue in afl and afl-like instrumentations). This is performed by using afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only - built if LLVM 9 or newer is used. + built if LLVM 11 or newer is used. - None of these options are necessary to be used and are rather for manual - use (which only ever the author of this LTO implementation will use ;-) + - AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target + binary based on string compare and memory compare functions. + afl-fuzz will automatically get these transmitted when starting to + fuzz. + + None of the following options are necessary to be used and are rather for + manual use (which only ever the author of this LTO implementation will use). These are used if several seperated instrumentation are performed which are then later combined. diff --git a/gcc_plugin/afl-gcc-rt.o.c b/gcc_plugin/afl-gcc-rt.o.c index 30606150..b157b50f 100644 --- a/gcc_plugin/afl-gcc-rt.o.c +++ b/gcc_plugin/afl-gcc-rt.o.c @@ -138,8 +138,8 @@ static void __afl_map_shm(void) { static void __afl_start_forkserver(void) { - static u8 tmp[4]; - s32 child_pid; + u8 tmp[4] = {0, 0, 0, 0}; + s32 child_pid; u8 child_stopped = 0; diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 56135d0e..edda81e1 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -577,7 +577,9 @@ typedef struct afl_state { u32 document_counter; #endif - /* statis file */ + void *maybe_add_auto; + + /* statistics file */ double last_bitmap_cvg, last_stability, last_eps; /* plot file saves from last run */ @@ -840,18 +842,18 @@ u32 calculate_score(afl_state_t *, struct queue_entry *); void read_bitmap(afl_state_t *, u8 *); void write_bitmap(afl_state_t *); -u32 count_bits(u8 *); -u32 count_bytes(u8 *); -u32 count_non_255_bytes(u8 *); +u32 count_bits(afl_state_t *, u8 *); +u32 count_bytes(afl_state_t *, u8 *); +u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 -void simplify_trace(u64 *); -void classify_counts(u64 *); +void simplify_trace(afl_state_t *, u64 *); +void classify_counts(afl_state_t *, u64 *); #else -void simplify_trace(u32 *); -void classify_counts(u32 *); +void simplify_trace(afl_state_t *, u32 *); +void classify_counts(afl_state_t *, u32 *); #endif void init_count_class16(void); -void minimize_bits(u8 *, u8 *); +void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES u8 *describe_op(afl_state_t *, u8); #endif @@ -862,7 +864,7 @@ u8 has_new_bits(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); -void maybe_add_auto(afl_state_t *, u8 *, u32); +void maybe_add_auto(void *, u8 *, u32); void save_auto(afl_state_t *); void load_auto(afl_state_t *); void destroy_extras(afl_state_t *); diff --git a/include/config.h b/include/config.h index cf73772f..f0274fd3 100644 --- a/include/config.h +++ b/include/config.h @@ -201,8 +201,8 @@ (first value), and to keep in memory as candidates. The latter should be much higher than the former. */ -#define USE_AUTO_EXTRAS 50 -#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) +#define USE_AUTO_EXTRAS 128 +#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64) /* Scaling factor for the effector map used to skip some of the more expensive deterministic steps. The actual divisor is set to @@ -400,5 +400,15 @@ #endif #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ +/* Extended forkserver option values */ + +#define FS_OPT_ENABLED 0x8f000001 +#define FS_OPT_MAPSIZE 0x40000000 +#define FS_OPT_SNAPSHOT 0x20000000 +#define FS_OPT_AUTODICT 0x10000000 +#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1) +#define FS_OPT_SET_MAPSIZE(x) \ + (x <= 1 || x > MAP_SIZE || x > 0x1000000 ? 0 : ((x - 1) << 1)) + #endif /* ! _HAVE_CONFIG_H */ diff --git a/include/forkserver.h b/include/forkserver.h index 4110df7d..7470dbbc 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -51,6 +51,8 @@ typedef struct afl_forkserver { fsrv_st_fd; /* Fork server status pipe (read) */ u32 exec_tmout; /* Configurable exec timeout (ms) */ + u32 map_size; /* map size used by the target */ + u32 snapshot; /* is snapshot feature used */ u64 mem_limit; /* Memory cap for child (MB) */ u8 *out_file, /* File to fuzz, if any */ @@ -64,6 +66,10 @@ typedef struct afl_forkserver { u32 prev_timed_out; /* if prev forkserver run timed out */ + u8 *function_opt; /* for autodictionary: afl ptr */ + + void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len); + } afl_forkserver_t; void afl_fsrv_init(afl_forkserver_t *fsrv); diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 7432b061..b176a24f 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -273,6 +273,7 @@ endif ../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) + $(CC) $(CFLAGS) -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o endif # laf @@ -318,7 +319,7 @@ all_done: test_build install: all install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi + if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-rt-lto.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index a3c7ddc3..48d0e36c 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -12,6 +12,8 @@ This version requires a current llvm 11 compiled from the github master. 3. It only works with llvm 11 (current github master state) +4. AUTODICTIONARY feature! see below + ## Introduction and problem description A big issue with how afl/afl++ works is that the basic block IDs that are @@ -33,33 +35,22 @@ and many dead ends until we got to this: * Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the correct LTO options and runs our own afl-ld linker instead of the system linker - * Our linker collects all LTO files to link and instruments them so that + * The LLVM linker collects all LTO files to link and instruments them so that we have non-colliding edge overage * We use a new (for afl) edge coverage - which is the same as in llvm -fsanitize=coverage edge coverage mode :) - * after inserting our instrumentation in all interesting edges we link - all parts of the program together to our executable The result: - * 10-15% speed gain compared to llvm_mode + * 10-20% speed gain compared to llvm_mode * guaranteed non-colliding edge coverage :-) * The compile time especially for libraries can be longer Example build output from a libtiff build: ``` -/bin/bash ../libtool --tag=CC --mode=link afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/libtiff.la ../port/libport.la -llzma -ljbig -ljpeg -lz -lm libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm -afl-clang-lto++2.62d by Marc "vanHauser" Heuse -afl-ld++2.62d by Marc "vanHauser" Heuse (level 0) -[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../libtiff/.libs/libtiff.a into /tmp/.afl-3914343-1583339800.dir -[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../port/.libs/libport.a into /tmp/.afl-3914343-1583339800.dir -[+] Running bitcode linker, creating /tmp/.afl-3914343-1583339800-1.ll -[+] Performing optimization via opt, creating /tmp/.afl-3914343-1583339800-2.bc -[+] Performing instrumentation via opt, creating /tmp/.afl-3914343-1583339800-3.bc -afl-llvm-lto++2.62d by Marc "vanHauser" Heuse -[+] Instrumented 15833 locations with no collisions (on average 1767 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). -[+] Running real linker /bin/x86_64-linux-gnu-ld -[+] Linker was successful +afl-clang-lto++2.63d by Marc "vanHauser" Heuse in mode LTO +afl-llvm-lto++2.63d by Marc "vanHauser" Heuse +[+] Instrumented 11836 locations with no collisions (on average 1007 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). ``` ## Building llvm 11 @@ -70,8 +61,8 @@ $ git clone https://github.com/llvm/llvm-project $ cd llvm-project $ mkdir build $ cd build -$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/ -$ make +$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/ +$ make -j $(nproc) $ export PATH=`pwd`/bin:$PATH $ export LLVM_CONFIG=`pwd`/bin/llcm-config $ cd /path/to/AFLplusplus/ @@ -96,6 +87,13 @@ CC=afl-clang-lto CXX=afl-clang-lto++ ./configure make ``` +## AUTODICTIONARY feature + +Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the +target binary based on string compare and memory compare functions. +afl-fuzz will automatically get these transmitted when starting to fuzz. +This improves coverage on a lot of targets. + ## Potential issues ### compiling libraries fails @@ -121,11 +119,8 @@ Please report issues at: ## Upcoming Work -1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions -2. Modify the forkserver + afl-fuzz so that only the necessary map size is - loaded and used - and communicated to afl-fuzz too. - Result: faster fork in the target and faster map analysis in afl-fuzz - => more speed :-) +1. Currently the LTO whitelist feature does not allow to not instrument main, + start and init functions ## History diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 26ee0bab..cdb22cb9 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -477,6 +477,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (instrument_mode == INSTRUMENT_LTO) + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-lto.o", obj_path); + #ifndef __ANDROID__ switch (bit_mode) { diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 93968984..f387e79c 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -38,17 +38,24 @@ #include #include "llvm/Config/llvm-config.h" +#include "llvm/ADT/Statistic.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Module.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Verifier.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemorySSAUpdater.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/CFG.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Pass.h" + +#include using namespace llvm; @@ -145,7 +152,7 @@ class AFLLTOPass : public ModulePass { bool runOnModule(Module &M) override; protected: - int afl_global_id = 1, debug = 0; + int afl_global_id = 1, debug = 0, autodictionary = 0; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0; }; @@ -154,7 +161,9 @@ class AFLLTOPass : public ModulePass { bool AFLLTOPass::runOnModule(Module &M) { - LLVMContext &C = M.getContext(); + LLVMContext & C = M.getContext(); + std::vector dictionary; + std::vector calls; IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); @@ -172,6 +181,10 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; + if (getenv("AFL_LLVM_AUTODICTIONARY") || + getenv("AFL_LLVM_LTO_AUTODICTIONARY")) + autodictionary = 1; + /* Get globals for the SHM region and the previous location. Note that __afl_prev_loc is thread-local. */ @@ -193,6 +206,110 @@ bool AFLLTOPass::runOnModule(Module &M) { std::vector InsBlocks; + if (autodictionary) { + + for (auto &BB : F) { + + for (auto &IN : BB) { + + CallInst *callInst = nullptr; + + if ((callInst = dyn_cast(&IN))) { + + bool isStrcmp = true; + bool isMemcmp = true; + bool isStrncmp = true; + bool isStrcasecmp = true; + bool isStrncasecmp = true; + + Function *Callee = callInst->getCalledFunction(); + if (!Callee) continue; + if (callInst->getCallingConv() != llvm::CallingConv::C) continue; + StringRef FuncName = Callee->getName(); + isStrcmp &= !FuncName.compare(StringRef("strcmp")); + isMemcmp &= !FuncName.compare(StringRef("memcmp")); + isStrncmp &= !FuncName.compare(StringRef("strncmp")); + isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp")); + isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp")); + + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && + !isStrncasecmp) + continue; + + /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function + * prototype */ + FunctionType *FT = Callee->getFunctionType(); + + isStrcmp &= FT->getNumParams() == 2 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()); + isStrcasecmp &= FT->getNumParams() == 2 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()); + isMemcmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0)->isPointerTy() && + FT->getParamType(1)->isPointerTy() && + FT->getParamType(2)->isIntegerTy(); + isStrncmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()) && + FT->getParamType(2)->isIntegerTy(); + isStrncasecmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()) && + FT->getParamType(2)->isIntegerTy(); + + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && + !isStrncasecmp) + continue; + + /* is a str{n,}{case,}cmp/memcmp, check if we have + * str{case,}cmp(x, "const") or str{case,}cmp("const", x) + * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..) + * memcmp(x, "const", ..) or memcmp("const", x, ..) */ + Value *Str1P = callInst->getArgOperand(0), + *Str2P = callInst->getArgOperand(1); + StringRef Str1, Str2; + bool HasStr1 = getConstantStringInfo(Str1P, Str1); + bool HasStr2 = getConstantStringInfo(Str2P, Str2); + + /* handle cases of one string is const, one string is variable */ + if (!(HasStr1 ^ HasStr2)) continue; + + if (isMemcmp || isStrncmp || isStrncasecmp) { + + /* check if third operand is a constant integer + * strlen("constStr") and sizeof() are treated as constant */ + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast(op2); + if (!ilen) continue; + /* final precaution: if size of compare is larger than constant + * string skip it*/ + uint64_t literalLength = + HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P); + if (literalLength < ilen->getZExtValue()) continue; + + } + + calls.push_back(callInst); + + } + + } + + } + + } + for (auto &BB : F) { uint32_t succ = 0; @@ -282,32 +399,201 @@ bool AFLLTOPass::runOnModule(Module &M) { } + // save highest location ID to global variable + // do this after each function to fail faster + if (afl_global_id > MAP_SIZE) { + + uint32_t pow2map = 1, map = afl_global_id; + while ((map = map >> 1)) + pow2map++; + FATAL( + "We have %u blocks to instrument but the map size is only %u! Edit " + "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " + "afl-fuzz and llvm_mode.", + afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map); + + } + } - // save highest location ID to global variable + if (calls.size()) { - if (afl_global_id > MAP_SIZE) { + for (auto &callInst : calls) { - uint32_t pow2map = 1, map = afl_global_id; - while ((map = map >> 1)) - pow2map++; - FATAL( - "We have %u blocks to instrument but the map size is only %u! Edit " - "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " - "afl-fuzz and llvm_mode.", - afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map); + Value *Str1P = callInst->getArgOperand(0), + *Str2P = callInst->getArgOperand(1); + StringRef Str1, Str2, ConstStr; + std::string TmpConstStr; + Value * VarStr; + bool HasStr1 = getConstantStringInfo(Str1P, Str1); + getConstantStringInfo(Str2P, Str2); + uint64_t constLen, sizedLen; + bool isMemcmp = !callInst->getCalledFunction()->getName().compare( + StringRef("memcmp")); + bool isSizedcmp = isMemcmp || + !callInst->getCalledFunction()->getName().compare( + StringRef("strncmp")) || + !callInst->getCalledFunction()->getName().compare( + StringRef("strncasecmp")); + + if (isSizedcmp) { + + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast(op2); + sizedLen = ilen->getZExtValue(); + + } else { + + sizedLen = 0; + + } + + if (HasStr1) { + + TmpConstStr = Str1.str(); + VarStr = Str2P; + constLen = isMemcmp ? sizedLen : GetStringLength(Str1P); + + } else { + + TmpConstStr = Str2.str(); + VarStr = Str1P; + constLen = isMemcmp ? sizedLen : GetStringLength(Str2P); + + } + + /* properly handle zero terminated C strings by adding the terminating 0 + * to the StringRef (in comparison to std::string a StringRef has built-in + * runtime bounds checking, which makes debugging easier) */ + TmpConstStr.append("\0", 1); + ConstStr = StringRef(TmpConstStr); + + if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; } + + /* + if (!be_quiet) + errs() << callInst->getCalledFunction()->getName() << ": len " + << constLen << ": " << ConstStr << "\n"; + */ + + if (constLen && constLen < MAX_DICT_FILE) + dictionary.push_back(ConstStr.str().substr(0, constLen)); + + } } - if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) { + if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) { + + // yes we could create our own function, insert it into ctors ... + // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o - GlobalVariable *AFLFinalLoc = new GlobalVariable( - M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0, - GlobalVariable::GeneralDynamicTLSModel, 0, false); - ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id); - MaybeAlign Align = MaybeAlign(4); - AFLFinalLoc->setAlignment(Align); - AFLFinalLoc->setInitializer(const_loc); + Function *f = M.getFunction("__afl_auto_init_globals"); + + if (!f) { + + fprintf(stderr, + "Error: init function could not be found (this hould not " + "happen)\n"); + exit(-1); + + } + + BasicBlock *bb = &f->getEntryBlock(); + if (!bb) { + + fprintf(stderr, + "Error: init function does not have an EntryBlock (this should " + "not happen)\n"); + exit(-1); + + } + + BasicBlock::iterator IP = bb->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + + if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) { + + GlobalVariable *AFLFinalLoc = new GlobalVariable( + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", + 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + ConstantInt *const_loc = ConstantInt::get(Int32Ty, (((afl_global_id + 8) >> 3) << 3)); + StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + if (dictionary.size()) { + + size_t memlen = 0, count = 0, offset = 0; + char * ptr; + + for (auto token : dictionary) { + + memlen += token.length(); + count++; + + } + + if (!be_quiet) printf("AUTODICTIONARY: %lu strings found\n", count); + + if (count) { + + if ((ptr = (char *)malloc(memlen + count)) == NULL) { + + fprintf(stderr, "Error: malloc for %lu bytes failed!\n", + memlen + count); + exit(-1); + + } + + for (auto token : dictionary) { + + if (offset + token.length() < 0xfffff0) { + + ptr[offset++] = (uint8_t)token.length(); + memcpy(ptr + offset, token.c_str(), token.length()); + offset += token.length(); + + } + + } + + GlobalVariable *AFLDictionaryLen = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, + "__afl_dictionary_len", 0, GlobalVariable::GeneralDynamicTLSModel, + 0, false); + ConstantInt *const_len = ConstantInt::get(Int32Ty, offset); + StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen); + StoreDictLen->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset); + GlobalVariable *AFLInternalDictionary = new GlobalVariable( + M, ArrayTy, true, GlobalValue::ExternalLinkage, + ConstantDataArray::get(C, + *(new ArrayRef((char *)ptr, offset))), + "__afl_internal_dictionary", 0, + GlobalVariable::GeneralDynamicTLSModel, 0, false); + AFLInternalDictionary->setInitializer(ConstantDataArray::get( + C, *(new ArrayRef((char *)ptr, offset)))); + AFLInternalDictionary->setConstant(true); + + GlobalVariable *AFLDictionary = new GlobalVariable( + M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage, + 0, "__afl_dictionary"); + + Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero); + Value *AFLDictPtr = + IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0)); + StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary); + StoreDict->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + } } diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 3651fd97..cbc4648d 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -50,11 +50,7 @@ Basically, we need to make sure that the forkserver is initialized after the LLVM-generated runtime initialization pass, not before. */ -#ifdef USE_TRACE_PC #define CONST_PRIO 5 -#else -#define CONST_PRIO 0 -#endif /* ^USE_TRACE_PC */ #include #include @@ -65,17 +61,20 @@ u8 __afl_area_initial[MAP_SIZE]; u8 *__afl_area_ptr = __afl_area_initial; +u8 *__afl_dictionary; #ifdef __ANDROID__ PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; u32 __afl_final_loc; u32 __afl_prev_ctx; u32 __afl_cmp_counter; +u32 __afl_dictionary_len; #else __thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; __thread u32 __afl_final_loc; __thread u32 __afl_prev_ctx; __thread u32 __afl_cmp_counter; +__thread u32 __afl_dictionary_len; #endif struct cmp_map *__afl_cmp_map; @@ -100,6 +99,10 @@ static void __afl_map_shm(void) { const char * shm_file_path = id_str; int shm_fd = -1; unsigned char *shm_base = NULL; + unsigned int map_size = MAP_SIZE + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) map_size = + __afl_final_loc; /* create the shared memory segment as if it was a file */ shm_fd = shm_open(shm_file_path, O_RDWR, 0600); @@ -111,7 +114,7 @@ static void __afl_map_shm(void) { } /* map the shared memory segment to the address space of the process */ - shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + shm_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (shm_base == MAP_FAILED) { close(shm_fd); @@ -187,8 +190,15 @@ static void __afl_map_shm(void) { #ifdef __linux__ static void __afl_start_snapshots(void) { - static u8 tmp[4]; + static u8 tmp[4] = {0, 0, 0, 0}; s32 child_pid; + u32 status = 0; + u32 map_size = MAP_SIZE; + u32 already_read_first = 0; + u32 was_killed; + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) + map_size = __afl_final_loc; u8 child_stopped = 0; @@ -197,16 +207,74 @@ static void __afl_start_snapshots(void) { /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ + status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT); + if (map_size <= 0x1000000) + status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); + if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; + memcpy(tmp, &status, 4); + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (__afl_dictionary_len > 0 && __afl_dictionary) { + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == + (FS_OPT_ENABLED | FS_OPT_AUTODICT)) { + + // great lets pass the dictionary through the forkserver FD + u32 len = __afl_dictionary_len, offset = 0; + s32 ret; + + if (write(FORKSRV_FD + 1, &len, 4) != 4) { + + write(2, "Error: could not send dictionary len\n", + strlen("Error: could not send dictionary len\n")); + _exit(1); + + } + + while (len != 0) { + + ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); + + if (ret < 1) { + + write(2, "Error: could not send dictionary\n", + strlen("Error: could not send dictionary\n")); + _exit(1); + + } + + len -= ret; + offset += ret; + + } + + } else { + + // uh this forkserver master does not understand extended option passing + // or does not want the dictionary + already_read_first = 1; + + } + + } + while (1) { - u32 was_killed; int status; - /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (already_read_first) { - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + already_read_first = 0; + + } else { + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + } /* If we stopped the child in persistent mode, but there was a race condition and afl-fuzz already issued SIGKILL, write off the old @@ -291,26 +359,92 @@ static void __afl_start_forkserver(void) { #endif - static u8 tmp[4]; - s32 child_pid; + u8 tmp[4] = {0, 0, 0, 0}; + s32 child_pid; + u32 status = 0; + u32 map_size = MAP_SIZE; + u32 already_read_first = 0; + u32 was_killed; + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) + map_size = __afl_final_loc; u8 child_stopped = 0; void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); + if (map_size <= 0x1000000) + status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); + if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (__afl_dictionary_len > 0 && __afl_dictionary) { + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == + (FS_OPT_ENABLED | FS_OPT_AUTODICT)) { + + // great lets pass the dictionary through the forkserver FD + u32 len = __afl_dictionary_len, offset = 0; + s32 ret; + + if (write(FORKSRV_FD + 1, &len, 4) != 4) { + + write(2, "Error: could not send dictionary len\n", + strlen("Error: could not send dictionary len\n")); + _exit(1); + + } + + while (len != 0) { + + ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); + + if (ret < 1) { + + write(2, "Error: could not send dictionary\n", + strlen("Error: could not send dictionary\n")); + _exit(1); + + } + + len -= ret; + offset += ret; + + } + + } else { + + // uh this forkserver master does not understand extended option passing + // or does not want the dictionary + already_read_first = 1; + + } + + } + while (1) { - u32 was_killed; int status; /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (already_read_first) { + + already_read_first = 0; + + } else { + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + } /* If we stopped the child in persistent mode, but there was a race condition and afl-fuzz already issued SIGKILL, write off the old @@ -378,8 +512,12 @@ static void __afl_start_forkserver(void) { int __afl_persistent_loop(unsigned int max_cnt) { - static u8 first_pass = 1; - static u32 cycle_cnt; + static u8 first_pass = 1; + static u32 cycle_cnt; + unsigned int map_size = MAP_SIZE; + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) + map_size = __afl_final_loc; if (first_pass) { @@ -390,7 +528,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { if (is_persistent) { - memset(__afl_area_ptr, 0, MAP_SIZE); + memset(__afl_area_ptr, 0, map_size); __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 3bd107d7..d73566fc 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -293,7 +293,7 @@ static void print_mappings(void) { void afl_forkserver(CPUState *cpu) { - static unsigned char tmp[4]; + static unsigned char tmp[4] = {0, 0, 0, 0}; if (forkserver_installed == 1) return; forkserver_installed = 1; diff --git a/src/afl-common.c b/src/afl-common.c index 825cd827..5216c7e0 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -59,6 +59,7 @@ char *afl_environment_variables[] = { "AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER", "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", + "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 56c3c9d5..d1037194 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -69,7 +69,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->mem_limit = MEM_LIMIT; fsrv->child_pid = -1; fsrv->out_dir_fd = -1; - + fsrv->map_size = MAP_SIZE; fsrv->use_fauxsrv = 0; fsrv->prev_timed_out = 0; @@ -82,7 +82,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { - unsigned char tmp[4] = {0}; + unsigned char tmp[4] = {0, 0, 0, 0}; pid_t child_pid = -1; /* Phone home and tell the parent that we're OK. If parent isn't there, @@ -167,9 +167,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, int status; s32 rlen; - if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:"); + if (!be_quiet) ACTF("Using Fauxserver:"); - if (!getenv("AFL_QUIET")) ACTF("Spinning up the fork server..."); + if (!be_quiet) ACTF("Spinning up the fork server..."); if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); @@ -340,7 +340,93 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (rlen == 4) { - if (!getenv("AFL_QUIET")) OKF("All right - fork server is up."); + if (!be_quiet) OKF("All right - fork server is up."); + + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { + + if (!be_quiet) + ACTF("Extended forkserver functions received (%08x).", status); + + if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + + fsrv->snapshot = 1; + if (!be_quiet) ACTF("Using SNAPSHOT feature."); + + } + + if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + + fsrv->map_size = FS_OPT_GET_MAPSIZE(status); + if (fsrv->map_size % 8) + fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); + if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); + + } + + if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + + // this is not afl-fuzz - we deny and return + status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT)); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + return; + + } + + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + + if (!be_quiet) ACTF("Using AUTODICT feature."); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) + FATAL("Reading from forkserver failed."); + + if (status < 2 || (u32)status > 0xffffff) + FATAL("Dictionary has an illegal size: %d", status); + + u32 len = status, offset = 0, count = 0; + u8 *dict = ck_alloc(len); + if (dict == NULL) + FATAL("Could not allocate %u bytes of autodictionary memmory", len); + + while (len != 0) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, len); + if (rlen > 0) { + + len -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, len); + + } + + } + + len = status; + offset = 0; + while (offset < status && (u8)dict[offset] + offset < status) { + + fsrv->function_ptr(fsrv->function_opt, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) ACTF("Loaded %u autodictionary entries", count); + ck_free(dict); + + } + + } + return; } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index c5347dcb..1c965532 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -78,16 +78,17 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { u64 *current = (u64 *)afl->fsrv.trace_bits; u64 *virgin = (u64 *)virgin_map; - u32 i = (MAP_SIZE >> 3); + u32 i = (afl->fsrv.map_size >> 3); #else u32 *current = (u32 *)afl->fsrv.trace_bits; u32 *virgin = (u32 *)virgin_map; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); #endif /* ^WORD_SIZE_64 */ + if (i == 0) i = 1; u8 ret = 0; @@ -148,12 +149,14 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { /* Count the number of bits set in the provided bitmap. Used for the status screen several times every second, does not have to be fast. */ -u32 count_bits(u8 *mem) { +u32 count_bits(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -182,12 +185,14 @@ u32 count_bits(u8 *mem) { mostly to update the status screen or calibrate and examine confirmed new paths. */ -u32 count_bytes(u8 *mem) { +u32 count_bytes(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -207,12 +212,14 @@ u32 count_bytes(u8 *mem) { /* Count the number of non-255 bytes set in the bitmap. Used strictly for the status screen, several calls per second or so. */ -u32 count_non_255_bytes(u8 *mem) { +u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -245,9 +252,11 @@ const u8 simplify_lookup[256] = { #ifdef WORD_SIZE_64 -void simplify_trace(u64 *mem) { +void simplify_trace(afl_state_t *afl, u64 *mem) { + + u32 i = (afl->fsrv.map_size >> 3); - u32 i = MAP_SIZE >> 3; + if (i == 0) i = 1; while (i--) { @@ -278,9 +287,11 @@ void simplify_trace(u64 *mem) { #else -void simplify_trace(u32 *mem) { +void simplify_trace(afl_state_t *afl, u32 *mem) { - u32 i = MAP_SIZE >> 2; + u32 i = (afl->fsrv.map_size >> 2); + + if (i == 0) i = 1; while (i--) { @@ -340,9 +351,11 @@ void init_count_class16(void) { #ifdef WORD_SIZE_64 -void classify_counts(u64 *mem) { +void classify_counts(afl_state_t *afl, u64 *mem) { + + u32 i = (afl->fsrv.map_size >> 3); - u32 i = MAP_SIZE >> 3; + if (i == 0) i = 1; while (i--) { @@ -367,9 +380,11 @@ void classify_counts(u64 *mem) { #else -void classify_counts(u32 *mem) { +void classify_counts(afl_state_t *afl, u32 *mem) { + + u32 i = (afl->fsrv.map_size >> 2); - u32 i = MAP_SIZE >> 2; + if (i == 0) i = 1; while (i--) { @@ -396,11 +411,11 @@ void classify_counts(u32 *mem) { count information here. This is called only sporadically, for some new paths. */ -void minimize_bits(u8 *dst, u8 *src) { +void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { u32 i = 0; - while (i < MAP_SIZE) { + while (i < afl->fsrv.map_size) { if (*(src++)) dst[i >> 3] |= 1 << (i & 7); ++i; @@ -527,7 +542,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 fn[PATH_MAX]; /* Update path frequency. */ - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); struct queue_entry *q = afl->queue; while (q) { @@ -611,9 +626,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (likely(!afl->dumb_mode)) { #ifdef WORD_SIZE_64 - simplify_trace((u64 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); #else - simplify_trace((u32 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ if (!has_new_bits(afl, afl->virgin_tmout)) return keeping; @@ -675,9 +690,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (likely(!afl->dumb_mode)) { #ifdef WORD_SIZE_64 - simplify_trace((u64 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); #else - simplify_trace((u32 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ if (!has_new_bits(afl, afl->virgin_crash)) return keeping; diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 5ad73539..ed4be6e4 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -389,7 +389,7 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { must prevent any earlier operations from venturing into that territory. */ - memset(afl->fsrv.trace_bits, 0, MAP_SIZE); + memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); MEM_BARRIER(); /* Since we always have a forkserver (or a fauxserver) running, we can simply @@ -469,9 +469,9 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { tb4 = *(u32 *)afl->fsrv.trace_bits; #ifdef WORD_SIZE_64 - classify_counts((u64 *)afl->fsrv.trace_bits); + classify_counts(afl, (u64 *)afl->fsrv.trace_bits); #else - classify_counts((u32 *)afl->fsrv.trace_bits); + classify_counts(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 16806934..55146dd9 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -305,10 +305,14 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } /* Maybe add automatic extra. */ +/* Ugly hack: afl state is transfered as u8* because we import data via + afl-forkserver.c - which is shared with other afl tools that do not + have the afl state struct */ -void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { +void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) { - u32 i; + afl_state_t *afl = (afl_state_t *)afl_tmp; + u32 i; /* Allow users to specify that they don't want auto dictionaries. */ @@ -469,7 +473,7 @@ void load_auto(afl_state_t *afl) { if (len < 0) PFATAL("Unable to read from '%s'", fn); if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, tmp, len); + maybe_add_auto((u8 *)afl, tmp, len); close(fd); ck_free(fn); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 6e0485e5..94ce9604 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -448,11 +448,13 @@ static void check_map_coverage(afl_state_t *afl) { u32 i; - if (count_bytes(afl->fsrv.trace_bits) < 100) return; + if (count_bytes(afl, afl->fsrv.trace_bits) < 100) return; for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i) if (afl->fsrv.trace_bits[i]) return; + if (afl->fsrv.map_size != MAP_SIZE) return; + WARNF("Recompile binary with newer version of afl to improve coverage!"); } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 754b2190..81504e29 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -244,7 +244,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; } - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (cksum == q->exec_cksum) { @@ -257,7 +257,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (!needs_write) { needs_write = 1; - memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, + afl->fsrv.map_size); } @@ -307,7 +308,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { ck_write(fd, in_buf, q->len, q->fname); close(fd); - memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, MAP_SIZE); + memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); update_bitmap_score(afl, q); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index b20bde90..80567160 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -601,7 +601,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) { @@ -613,7 +613,7 @@ u8 fuzz_one_original(afl_state_t *afl) { ++a_len; if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); } else if (cksum != prev_cksum) { @@ -621,7 +621,7 @@ u8 fuzz_one_original(afl_state_t *afl) { worthwhile queued up, and collect that if the answer is yes. */ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); a_len = 0; prev_cksum = cksum; @@ -761,7 +761,7 @@ u8 fuzz_one_original(afl_state_t *afl) { without wasting time on checksums. */ if (!afl->dumb_mode && len >= EFF_MIN_LEN) - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); else cksum = ~afl->queue_cur->exec_cksum; @@ -2615,7 +2615,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) { @@ -2627,7 +2627,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { ++a_len; if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); } else if (cksum != prev_cksum) { @@ -2635,7 +2635,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { worthwhile queued up, and collect that if the answer is yes. */ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); a_len = 0; prev_cksum = cksum; @@ -2775,7 +2775,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { without wasting time on checksums. */ if (!afl->dumb_mode && len >= EFF_MIN_LEN) - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); else cksum = ~afl->queue_cur->exec_cksum; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 174d7d92..346c2639 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -195,7 +195,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { /* For every byte set in afl->fsrv.trace_bits[], see if there is a previous winner, and how it compares to us. */ - for (i = 0; i < MAP_SIZE; ++i) + for (i = 0; i < afl->fsrv.map_size; ++i) if (afl->fsrv.trace_bits[i]) { @@ -248,8 +248,10 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { if (!q->trace_mini) { - q->trace_mini = ck_alloc(MAP_SIZE >> 3); - minimize_bits(q->trace_mini, afl->fsrv.trace_bits); + u32 len = (afl->fsrv.map_size >> 3); + if (len == 0) len = 1; + q->trace_mini = ck_alloc(len); + minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); } @@ -268,14 +270,17 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { void cull_queue(afl_state_t *afl) { struct queue_entry *q; - u8 temp_v[MAP_SIZE >> 3]; + u32 len = (afl->fsrv.map_size >> 3); u32 i; + u8 temp_v[MAP_SIZE >> 3]; + + if (len == 0) len = 1; if (afl->dumb_mode || !afl->score_changed) return; afl->score_changed = 0; - memset(temp_v, 255, MAP_SIZE >> 3); + memset(temp_v, 255, len); afl->queued_favored = 0; afl->pending_favored = 0; @@ -292,10 +297,10 @@ void cull_queue(afl_state_t *afl) { /* Let's see if anything in the bitmap isn't captured in temp_v. If yes, and if it has a afl->top_rated[] contender, let's use it. */ - for (i = 0; i < MAP_SIZE; ++i) + for (i = 0; i < afl->fsrv.map_size; ++i) if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) { - u32 j = MAP_SIZE >> 3; + u32 j = len; /* Remove all bits belonging to the current entry from temp_v. */ diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 4acc204b..517f8d7c 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -88,7 +88,7 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u32 *cksum) { if (unlikely(common_fuzz_stuff(afl, buf, len))) return 1; - *cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + *cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); return 0; } @@ -332,7 +332,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } - maybe_add_auto(afl, (u8 *)&v, shape); + maybe_add_auto((u8 *)afl, (u8 *)&v, shape); u64 rev; switch (shape) { @@ -340,15 +340,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { case 1: break; case 2: rev = SWAP16((u16)v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; case 4: rev = SWAP32((u32)v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; case 8: rev = SWAP64(v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; } @@ -486,8 +486,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { // If failed, add to dictionary if (fails == 8) { - maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape)); - maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape)); + maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape)); + maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape)); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 9bbdd23a..850a18bc 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -44,7 +44,7 @@ u8 run_target(afl_state_t *afl, u32 timeout) { must prevent any earlier operations from venturing into that territory. */ - memset(afl->fsrv.trace_bits, 0, MAP_SIZE); + memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); MEM_BARRIER(); @@ -122,9 +122,9 @@ u8 run_target(afl_state_t *afl, u32 timeout) { tb4 = *(u32 *)afl->fsrv.trace_bits; #ifdef WORD_SIZE_64 - classify_counts((u64 *)afl->fsrv.trace_bits); + classify_counts(afl, (u64 *)afl->fsrv.trace_bits); #else - classify_counts((u32 *)afl->fsrv.trace_bits); + classify_counts(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ afl->fsrv.prev_timed_out = afl->fsrv.child_timed_out; @@ -315,7 +315,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, afl->shm.cmplog_mode) init_cmplog_forkserver(afl); - if (q->exec_cksum) memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE); + if (q->exec_cksum) + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); start_us = get_cur_time_us(); @@ -336,14 +337,14 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (afl->stop_soon || fault != afl->crash_mode) goto abort_calibration; if (!afl->dumb_mode && !afl->stage_cur && - !count_bytes(afl->fsrv.trace_bits)) { + !count_bytes(afl, afl->fsrv.trace_bits)) { fault = FAULT_NOINST; goto abort_calibration; } - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (q->exec_cksum != cksum) { @@ -354,7 +355,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 i; - for (i = 0; i < MAP_SIZE; ++i) { + for (i = 0; i < afl->fsrv.map_size; ++i) { if (unlikely(!afl->var_bytes[i]) && unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i])) @@ -368,7 +369,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } else { q->exec_cksum = cksum; - memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } @@ -385,7 +386,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, This is used for fuzzing air time calculations in calculate_score(). */ q->exec_us = (stop_us - start_us) / afl->stage_max; - q->bitmap_size = count_bytes(afl->fsrv.trace_bits); + q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits); q->handicap = handicap; q->cal_failed = 0; @@ -413,7 +414,7 @@ abort_calibration: if (var_detected) { - afl->var_byte_count = count_bytes(afl->var_bytes); + afl->var_byte_count = count_bytes(afl, afl->var_bytes); if (!q->var_behavior) { @@ -640,7 +641,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); /* If the deletion had no impact on the trace, make it permanent. This isn't perfect for variable-path inputs, but we're just making a @@ -663,7 +664,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (!needs_write) { needs_write = 1; - memcpy(afl->clean_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } @@ -705,7 +706,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { ck_write(fd, in_buf, q->len, q->fname); close(fd); - memcpy(afl->fsrv.trace_bits, afl->clean_trace, MAP_SIZE); + memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); update_bitmap_score(afl, q); } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index a8c14c31..80039d6f 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,6 +99,10 @@ void afl_state_init(afl_state_t *afl) { afl->fsrv.use_stdin = 1; + afl->fsrv.map_size = MAP_SIZE; + afl->fsrv.function_opt = (u8 *)afl; + afl->fsrv.function_ptr = &maybe_add_auto; + afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index ab84bf3f..58a37298 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -37,7 +37,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, u8 fn[PATH_MAX]; s32 fd; FILE * f; - uint32_t t_bytes = count_non_255_bytes(afl->virgin_bits); + uint32_t t_bytes = count_non_255_bytes(afl, afl->virgin_bits); snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); @@ -258,8 +258,8 @@ void show_stats(afl_state_t *afl) { /* Do some bitmap stats. */ - t_bytes = count_non_255_bytes(afl->virgin_bits); - t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; + t_bytes = count_non_255_bytes(afl, afl->virgin_bits); + t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size; if (likely(t_bytes) && unlikely(afl->var_byte_count)) stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes); @@ -305,7 +305,7 @@ void show_stats(afl_state_t *afl) { /* Compute some mildly useful bitmap stats. */ - t_bits = (MAP_SIZE << 3) - count_bits(afl->virgin_bits); + t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits); /* Now, for the visuals... */ @@ -465,7 +465,8 @@ void show_stats(afl_state_t *afl) { SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp); sprintf(tmp, "%0.02f%% / %0.02f%%", - ((double)afl->queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio); + ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size, + t_byte_ratio); SAYF(" map density : %s%-21s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD diff --git a/src/afl-tmin.c b/src/afl-tmin.c index f899a6b5..53e8705d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -258,7 +258,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, fsrv->child_timed_out = 0; - memset(fsrv->trace_bits, 0, MAP_SIZE); + memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); write_to_testcase(fsrv, mem, len); @@ -393,7 +393,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, } - cksum = hash32(fsrv->trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST); if (first_run) orig_cksum = cksum; -- cgit 1.4.1 From 29ee3a1ffca2aa5a3939beb84d7c6a81621f3355 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 11 Apr 2020 01:09:07 +0200 Subject: refactored cmplog --- include/afl-fuzz.h | 6 +- include/cmplog.h | 6 + include/forkserver.h | 10 +- src/afl-analyze.c | 10 +- src/afl-common.c | 4 +- src/afl-forkserver.c | 32 ++-- src/afl-fuzz-bitmap.c | 2 +- src/afl-fuzz-cmplog.c | 477 +----------------------------------------------- src/afl-fuzz-init.c | 6 +- src/afl-fuzz-mutators.c | 2 +- src/afl-fuzz-run.c | 65 +++---- src/afl-fuzz-stats.c | 6 +- src/afl-fuzz.c | 29 ++- src/afl-showmap.c | 18 +- src/afl-tmin.c | 14 +- 15 files changed, 129 insertions(+), 558 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index edda81e1..97c1f31c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -439,7 +439,6 @@ typedef struct afl_state { no_arith, /* Skip most arithmetic ops */ shuffle_queue, /* Shuffle input queue? */ bitmap_changed, /* Time to update bitmap? */ - qemu_mode, /* Running in QEMU mode? */ unicorn_mode, /* Running in Unicorn mode? */ use_wine, /* Use WINE with QEMU mode */ skip_requested, /* Skip request, via SIGUSR1 */ @@ -560,7 +559,7 @@ typedef struct afl_state { /* CmpLog */ char *cmplog_binary; - s32 cmplog_child_pid, cmplog_fsrv_pid; + afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ /* Custom mutators */ struct custom_mutator *mutator; @@ -878,7 +877,7 @@ void show_init_stats(afl_state_t *); /* Run */ -u8 run_target(afl_state_t *, u32); +u8 run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); void write_to_testcase(afl_state_t *, void *, u32); u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8); void sync_fuzzers(afl_state_t *); @@ -922,7 +921,6 @@ void save_cmdline(afl_state_t *, u32, char **); /* CmpLog */ -void init_cmplog_forkserver(afl_state_t *afl); u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); /* RedQueen */ diff --git a/include/cmplog.h b/include/cmplog.h index 36f8f2c5..4731f779 100644 --- a/include/cmplog.h +++ b/include/cmplog.h @@ -29,6 +29,7 @@ #define _AFL_CMPLOG_H #include "config.h" +#include "forkserver.h" #define CMP_MAP_W 65536 #define CMP_MAP_H 256 @@ -74,5 +75,10 @@ struct cmp_map { }; +/* Execs the child */ + +void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv); + + #endif diff --git a/include/forkserver.h b/include/forkserver.h index 7470dbbc..24fa3e1b 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -66,15 +66,23 @@ typedef struct afl_forkserver { u32 prev_timed_out; /* if prev forkserver run timed out */ + u8 qemu_mode; /* if running in qemu mode or not */ + + char *cmplog_binary; /* the name of the cmplog binary */ + + /* Function to kick off the forkserver child */ + void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); + u8 *function_opt; /* for autodictionary: afl ptr */ void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len); + } afl_forkserver_t; void afl_fsrv_init(afl_forkserver_t *fsrv); void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, - volatile u8 *stop_soon_p); + volatile u8 *stop_soon_p, u8 debug_child_output); void afl_fsrv_deinit(afl_forkserver_t *fsrv); void afl_fsrv_killall(); diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 427fbe6d..b0e8afcb 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -36,6 +36,7 @@ #include "hash.h" #include "sharedmem.h" #include "common.h" +#include "forkserver.h" #include #include @@ -57,7 +58,7 @@ static s32 child_pid; /* PID of the tested program */ -u8 *trace_bits; /* SHM with instrumentation bitmap */ +static u8 *trace_bits; /* SHM with instrumentation bitmap */ static u8 *in_file, /* Analyzer input test case */ *prog_in; /* Targeted program input file */ @@ -74,16 +75,15 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static s32 dev_null_fd = -1; /* FD to /dev/null */ -u8 edges_only, /* Ignore hit counts? */ +static u8 edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ use_stdin = 1; /* Use stdin for program input? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ -static u8 qemu_mode; - static u8 *target_path; +static u8 qemu_mode; /* Constants used for describing byte behavior. */ @@ -639,7 +639,7 @@ 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() { u8 *x; diff --git a/src/afl-common.c b/src/afl-common.c index 5216c7e0..7eba6ae4 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -235,7 +235,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { "Oops, unable to find the 'afl-qemu-trace' binary. The binary must be " "built\n" " separately by following the instructions in " - "afl->qemu_mode/README.md. " + "qemu_mode/README.md. " "If you\n" " already have the binary installed, you may need to specify " "AFL_PATH in the\n" @@ -332,7 +332,7 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { "Oops, unable to find the '%s' binary. The binary must be " "built\n" " separately by following the instructions in " - "afl->qemu_mode/README.md. " + "qemu_mode/README.md. " "If you\n" " already have the binary installed, you may need to specify " "AFL_PATH in the\n" diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d1ff0e4d..7ab8a4b5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -51,6 +51,12 @@ list_t fsrv_list = {.element_prealloc_count = 0}; +static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { + + execv(fsrv->target_path, argv); + +} + /* Initializes the struct */ void afl_fsrv_init(afl_forkserver_t *fsrv) { @@ -73,6 +79,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->use_fauxsrv = 0; fsrv->prev_timed_out = 0; + fsrv->init_child_func = fsrv_exec_child; + list_append(&fsrv_list, fsrv); } @@ -163,7 +171,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, - volatile u8 *stop_soon_p) { + volatile u8 *stop_soon_p, u8 debug_child_output) { int st_pipe[2], ctl_pipe[2]; int status; @@ -171,6 +179,16 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) ACTF("Spinning up the fork server..."); + if (fsrv->use_fauxsrv) { + + /* TODO: Come up with sone nice way to initalize this all */ + + if (fsrv->init_child_func != fsrv_exec_child) + FATAL("Different forkserver not compatible with fauxserver"); + + fsrv->init_child_func = afl_fauxsrv_execv; + } + if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); fsrv->child_timed_out = 0; @@ -221,7 +239,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, setsid(); - if (!get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) { + if (!(debug_child_output)) { dup2(fsrv->dev_null_fd, 1); dup2(fsrv->dev_null_fd, 2); @@ -283,15 +301,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "msan_track_origins=0", 0); - if (fsrv->use_fauxsrv) { - - afl_fauxsrv_execv(fsrv, argv); - - } else { - - execv(fsrv->target_path, argv); - - } + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() falling through. */ diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 1c965532..b6a494db 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -645,7 +645,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 new_fault; write_to_testcase(afl, mem, len); - new_fault = run_target(afl, afl->hang_tmout); + new_fault = run_target(afl, &afl->fsrv, afl->hang_tmout); /* A corner case that one user reported bumping into: increasing the timeout actually uncovers a crash. Make sure we don't discard it if diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index ed4be6e4..f9480dc4 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -29,480 +29,21 @@ #include "afl-fuzz.h" #include "cmplog.h" -void init_cmplog_forkserver(afl_state_t *afl) { +typedef struct cmplog_data { +} cmplog_data_t; - int st_pipe[2], ctl_pipe[2]; - int status; - s32 rlen; +void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { - ACTF("Spinning up the cmplog fork server..."); + setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); + if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { - afl->fsrv.child_timed_out = 0; - afl->cmplog_fsrv_pid = fork(); - - if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed"); - - if (!afl->cmplog_fsrv_pid) { - - /* CHILD PROCESS */ - - struct rlimit r; - - /* Umpf. On OpenBSD, the default fd limit for root users is set to - soft 128. Let's try to fix that... */ - - if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { - - r.rlim_cur = FORKSRV_FD + 2; - setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ - - } - - if (afl->fsrv.mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20; - -#ifdef RLIMIT_AS - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ -#else - /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but - according to reliable sources, RLIMIT_DATA covers anonymous - maps - so we should be getting good protection against OOM bugs. */ - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ -#endif /* ^RLIMIT_AS */ - - } - - /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered - before the dump is complete. */ - - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - /* Isolate the process and configure standard descriptors. If - afl->fsrv.out_file is specified, stdin is /dev/null; otherwise, - afl->fsrv.out_fd is cloned instead. */ - - setsid(); - - if (!(afl->afl_env.afl_debug_child_output)) { - - dup2(afl->fsrv.dev_null_fd, 1); - dup2(afl->fsrv.dev_null_fd, 2); - - } - - if (!afl->fsrv.use_stdin) { - - dup2(afl->fsrv.dev_null_fd, 0); - - } else { - - dup2(afl->fsrv.out_fd, 0); - close(afl->fsrv.out_fd); - - } - - /* Set up control and status pipes, close the unneeded original fds. */ - - if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); - if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); - - close(ctl_pipe[0]); - close(ctl_pipe[1]); - close(st_pipe[0]); - close(st_pipe[1]); - - close(afl->fsrv.out_dir_fd); - close(afl->fsrv.dev_null_fd); -#ifndef HAVE_ARC4RANDOM - close(afl->fsrv.dev_urandom_fd); -#endif - if (afl->fsrv.plot_file != NULL) fclose(afl->fsrv.plot_file); - - /* This should improve performance a bit, since it stops the linker from - doing extra work post-fork(). */ - - if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); - - /* Set sane defaults for ASAN if nothing else specified. */ - - setenv("ASAN_OPTIONS", - "abort_on_error=1:" - "detect_leaks=0:" - "malloc_context_size=0:" - "symbolize=0:" - "allocator_may_return_null=1", - 0); - - /* MSAN is tricky, because it doesn't support abort_on_error=1 at this - point. So, we do this in a very hacky way. */ - - setenv("MSAN_OPTIONS", - "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" - "abort_on_error=1:" - "malloc_context_size=0:" - "allocator_may_return_null=1:" - "msan_track_origins=0", - 0); - - setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - - if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) { - - ck_free(afl->argv[0]); - afl->argv[0] = afl->cmplog_binary; - - } - - execv(afl->argv[0], afl->argv); - - /* Use a distinctive bitmap signature to tell the parent about execv() - falling through. */ - - *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - /* PARENT PROCESS */ - - /* Close the unneeded endpoints. */ - - close(ctl_pipe[0]); - close(st_pipe[1]); - - afl->cmplog_fsrv_ctl_fd = ctl_pipe[1]; - afl->cmplog_fsrv_st_fd = st_pipe[0]; - - /* Wait for the fork server to come up, but don't wait too long. */ - - rlen = 0; - if (afl->fsrv.exec_tmout) { - - rlen = 4; - u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT; - /* Reuse readfds as exceptfds to see when the child closed the pipe */ - u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms, - &afl->stop_soon); - - if (!exec_ms) { - - PFATAL("Error in timed read"); - - } else if (exec_ms > timeout_ms) { - - afl->fsrv.child_timed_out = 1; - kill(afl->cmplog_fsrv_pid, SIGKILL); - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - } else { - - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - /* If we have a four-byte "hello" message from the server, we're all set. - Otherwise, try to figure out what went wrong. */ - - if (afl->fsrv.child_timed_out) - FATAL( - "Timeout while initializing cmplog fork server (adjusting -t may " - "help)"); - - if (rlen == 4) { - - OKF("All right - fork server is up."); - return; - - } - - if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - if (WIFSIGNALED(status)) { - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && - afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! Since it seems to be built with ASAN and you " - "have a\n" - " restrictive memory limit configured, this is expected; please " - "read\n" - " %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n"); - - } else { - - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The current memory limit (%s) is too restrictive, causing " - "the\n" - " target to hit an OOM condition in the dynamic linker. Try " - "bumping up\n" - " the limit with the -m setting in the command line. A simple " - "way confirm\n" - " this diagnosis would be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to " - "quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n", - stringify_mem_size(val_buf, sizeof(val_buf), - afl->fsrv.mem_limit << 20), - afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status)); - - } - - if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute target application ('%s')", afl->argv[0]); - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Since it seems to be built " - "with ASAN and\n" - " you have a restrictive memory limit configured, this is " - "expected; please\n" - " read %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Perhaps there is a horrible " - "bug in the\n" - " fuzzer. Poke for troubleshooting " - "tips.\n"); - - } else { - - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - - SAYF( - "\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. There are %s probable " - "explanations:\n\n" - - "%s" - " - The current memory limit (%s) is too restrictive, causing an " - "OOM\n" - " fault in the dynamic linker. This can be fixed with the -m " - "option. A\n" - " simple way to confirm the diagnosis may be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n", - getenv(DEFER_ENV_VAR) ? "three" : "two", - getenv(DEFER_ENV_VAR) - ? " - You are using deferred forkserver, but __AFL_INIT() is " - "never\n" - " reached before the program terminates.\n\n" - : "", - stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), - afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server handshake failed"); - -} - -u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { - - int status = 0; - u32 exec_ms; - - u32 tb4; - s32 res; - - afl->fsrv.child_timed_out = 0; - - /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we - must prevent any earlier operations from venturing into that - territory. */ - - memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); - MEM_BARRIER(); - - /* Since we always have a forkserver (or a fauxserver) running, we can simply - tell them to have at it and read back the pid from it.*/ - - if ((res = write(afl->cmplog_fsrv_ctl_fd, &afl->cmplog_prev_timed_out, 4)) != - 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); + ck_free(argv[0]); + argv[0] = fsrv->cmplog_binary; } - if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if (afl->cmplog_child_pid <= 0) - FATAL("Cmplog fork server is misbehaving (OOM?)"); - - /* Configure timeout, as requested by user, then wait for child to terminate. - */ - exec_ms = - read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); - - if (exec_ms > timeout) { - - /* If there was no response from forkserver after timeout seconds, - we kill the child. The forkserver should inform us afterwards */ - - kill(afl->cmplog_child_pid, SIGKILL); - afl->fsrv.child_timed_out = 1; - - /* After killing the child, the forkserver should tell us */ - if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) exec_ms = 0; - - } - - if (!exec_ms) { // Something went wrong. - - if (afl->stop_soon) return 0; - SAYF("\n" cLRD "[-] " cRST - "Unable to communicate with fork server. Some possible reasons:\n\n" - " - You've run out of memory. Use -m to increase the the memory " - "limit\n" - " to something higher than %lld.\n" - " - The binary or one of the libraries it uses manages to create\n" - " threads before the forkserver initializes.\n" - " - The binary, at least in some circumstances, exits in a way " - "that\n" - " also kills the parent process - raise() could be the " - "culprit.\n\n" - "If all else fails you can disable the fork server via " - "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); - RPFATAL(res, "Unable to communicate with fork server"); - - } - - if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0; - - if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms; - - ++afl->total_execs; - - /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the - compiler below this point. Past this location, afl->fsrv.trace_bits[] - behave very normally and do not have to be treated as volatile. */ - - MEM_BARRIER(); - - tb4 = *(u32 *)afl->fsrv.trace_bits; - -#ifdef WORD_SIZE_64 - classify_counts(afl, (u64 *)afl->fsrv.trace_bits); -#else - classify_counts(afl, (u32 *)afl->fsrv.trace_bits); -#endif /* ^WORD_SIZE_64 */ - - afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out; - - /* Report outcome to caller. */ - - if (WIFSIGNALED(status) && !afl->stop_soon) { - - afl->kill_signal = WTERMSIG(status); - - if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) - return FAULT_TMOUT; - - return FAULT_CRASH; - - } - - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ - - if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { - - afl->kill_signal = 0; - return FAULT_CRASH; - - } - - if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG) - return FAULT_ERROR; - - return FAULT_NONE; + execv(argv[0], argv); } @@ -524,7 +65,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { write_to_testcase(afl, out_buf, len); - fault = run_cmplog_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) return 1; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 94ce9604..54cc81ef 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1853,8 +1853,6 @@ static void handle_stop_sig(int sig) { if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL); if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL); - if (el->cmplog_child_pid > 0) kill(el->cmplog_child_pid, SIGKILL); - if (el->cmplog_fsrv_pid > 0) kill(el->cmplog_fsrv_pid, SIGKILL); }); @@ -1988,7 +1986,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { #endif /* ^!__APPLE__ */ - if (!afl->qemu_mode && !afl->unicorn_mode && !afl->dumb_mode && + if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->dumb_mode && !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST @@ -2015,7 +2013,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if ((afl->qemu_mode) && + if ((afl->fsrv.qemu_mode) && memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 81504e29..a7d7ae18 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -239,7 +239,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { write_to_testcase(afl, retbuf, retlen); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 850a18bc..3a178e87 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -27,10 +27,12 @@ #include #include +#include "cmplog.h" + /* Execute target application, monitoring for timeouts. Return status - information. The called program will update afl->fsrv.trace_bits. */ + information. The called program will update afl->fsrv->trace_bits. */ -u8 run_target(afl_state_t *afl, u32 timeout) { +u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { s32 res; u32 exec_ms; @@ -38,46 +40,46 @@ u8 run_target(afl_state_t *afl, u32 timeout) { int status = 0; u32 tb4; - afl->fsrv.child_timed_out = 0; + fsrv->child_timed_out = 0; - /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we + /* After this memset, fsrv->trace_bits[] are effectively volatile, so we must prevent any earlier operations from venturing into that territory. */ - memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); + memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); /* we have the fork server (or faux server) up and running, so simply tell it to have at it, and then read back PID. */ - if ((res = write(afl->fsrv.fsrv_ctl_fd, &afl->fsrv.prev_timed_out, 4)) != 4) { + if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { if (afl->stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); } - if ((res = read(afl->fsrv.fsrv_st_fd, &afl->fsrv.child_pid, 4)) != 4) { + if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) { if (afl->stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); } - if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); + if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); exec_ms = - read_timed(afl->fsrv.fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); + read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); if (exec_ms > timeout) { /* If there was no response from forkserver after timeout seconds, we kill the child. The forkserver should inform us afterwards */ - kill(afl->fsrv.child_pid, SIGKILL); - afl->fsrv.child_timed_out = 1; - if (read(afl->fsrv.fsrv_st_fd, &status, 4) < 4) exec_ms = 0; + kill(fsrv->child_pid, SIGKILL); + fsrv->child_timed_out = 1; + if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0; } @@ -104,30 +106,30 @@ u8 run_target(afl_state_t *afl, u32 timeout) { "\n\n" "If all else fails you can disable the fork server via " "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); + fsrv->mem_limit); RPFATAL(res, "Unable to communicate with fork server"); } - if (!WIFSTOPPED(status)) afl->fsrv.child_pid = 0; + if (!WIFSTOPPED(status)) fsrv->child_pid = 0; ++afl->total_execs; - /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the - compiler below this point. Past this location, afl->fsrv.trace_bits[] + /* Any subsequent operations on fsrv->trace_bits must not be moved by the + compiler below this point. Past this location, fsrv->trace_bits[] behave very normally and do not have to be treated as volatile. */ MEM_BARRIER(); - tb4 = *(u32 *)afl->fsrv.trace_bits; + tb4 = *(u32 *)fsrv->trace_bits; #ifdef WORD_SIZE_64 - classify_counts(afl, (u64 *)afl->fsrv.trace_bits); + classify_counts(afl, (u64 *)fsrv->trace_bits); #else - classify_counts(afl, (u32 *)afl->fsrv.trace_bits); + classify_counts(afl, (u32 *)fsrv->trace_bits); #endif /* ^WORD_SIZE_64 */ - afl->fsrv.prev_timed_out = afl->fsrv.child_timed_out; + fsrv->prev_timed_out = fsrv->child_timed_out; /* Report outcome to caller. */ @@ -135,7 +137,7 @@ u8 run_target(afl_state_t *afl, u32 timeout) { afl->kill_signal = WTERMSIG(status); - if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) + if (fsrv->child_timed_out && afl->kill_signal == SIGKILL) return FAULT_TMOUT; return FAULT_CRASH; @@ -145,7 +147,7 @@ u8 run_target(afl_state_t *afl, u32 timeout) { /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and must use a special exit code. */ - if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { + if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { afl->kill_signal = 0; return FAULT_CRASH; @@ -309,11 +311,12 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ - if (!afl->fsrv.fsrv_pid) - afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon); - if (afl->dumb_mode != 1 && !afl->no_forkserver && !afl->cmplog_fsrv_pid && - afl->shm.cmplog_mode) - init_cmplog_forkserver(afl); + if (!afl->fsrv.fsrv_pid) { + if (afl->shm.cmplog_mode && afl->fsrv.init_child_func != cmplog_exec_child) { + FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly."); + } + afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + } if (q->exec_cksum) memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); @@ -329,7 +332,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, write_to_testcase(afl, use_mem, q->len); - fault = run_target(afl, use_tmout); + fault = run_target(afl, &afl->fsrv, use_tmout); /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ @@ -546,7 +549,7 @@ void sync_fuzzers(afl_state_t *afl) { write_to_testcase(afl, mem, st.st_size); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) goto close_sync; @@ -633,7 +636,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; if (afl->stop_soon || fault == FAULT_ERROR) goto abort_trimming; @@ -740,7 +743,7 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { write_to_testcase(afl, out_buf, len); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) return 1; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 58a37298..d83a747f 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -124,12 +124,12 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, (unsigned long int)(rus.ru_maxrss >> 10), #endif t_bytes, afl->var_byte_count, afl->use_banner, - afl->unicorn_mode ? "unicorn" : "", afl->qemu_mode ? "qemu " : "", + afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", afl->dumb_mode ? " dumb " : "", afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", afl->persistent_mode ? "persistent " : "", afl->deferred_mode ? "deferred " : "", - (afl->unicorn_mode || afl->qemu_mode || afl->dumb_mode || + (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->dumb_mode || afl->no_forkserver || afl->crash_mode || afl->persistent_mode || afl->deferred_mode) ? "" @@ -820,7 +820,7 @@ void show_init_stats(afl_state_t *afl) { SAYF("\n"); - if (avg_us > ((afl->qemu_mode || afl->unicorn_mode) ? 50000 : 10000)) + if (avg_us > ((afl->fsrv.qemu_mode || afl->unicorn_mode) ? 50000 : 10000)) WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.", doc_path); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 836393ac..44c48088 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -24,6 +24,7 @@ */ #include "afl-fuzz.h" +#include "cmplog.h" static u8 *get_libradamsa_path(u8 *own_loc) { @@ -213,6 +214,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { static int stricmp(char const *a, char const *b) { + if (!a || !b) FATAL("Null reference"); + for (;; ++a, ++b) { int d; @@ -498,8 +501,8 @@ int main(int argc, char **argv_orig, char **envp) { case 'Q': /* QEMU mode */ - if (afl->qemu_mode) FATAL("Multiple -Q options not supported"); - afl->qemu_mode = 1; + if (afl->fsrv.qemu_mode) FATAL("Multiple -Q options not supported"); + afl->fsrv.qemu_mode = 1; if (!mem_limit_given) afl->fsrv.mem_limit = MEM_LIMIT_QEMU; @@ -524,7 +527,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'W': /* Wine+QEMU mode */ if (afl->use_wine) FATAL("Multiple -W options not supported"); - afl->qemu_mode = 1; + afl->fsrv.qemu_mode = 1; afl->use_wine = 1; if (!mem_limit_given) afl->fsrv.mem_limit = 0; @@ -748,7 +751,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->dumb_mode) { if (afl->crash_mode) FATAL("-C and -n are mutually exclusive"); - if (afl->qemu_mode) FATAL("-Q 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"); } @@ -816,7 +819,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_preload) { - if (afl->qemu_mode) { + if (afl->fsrv.qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -991,7 +994,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->unicorn_mode) FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry"); - if (!afl->qemu_mode) check_binary(afl, afl->cmplog_binary); + if (!afl->fsrv.qemu_mode) check_binary(afl, afl->cmplog_binary); } @@ -999,7 +1002,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->start_time = get_cur_time(); - if (afl->qemu_mode) { + if (afl->fsrv.qemu_mode) { if (afl->use_wine) use_argv = get_wine_argv(argv[0], &afl->fsrv.target_path, argc - optind, @@ -1015,6 +1018,16 @@ int main(int argc, char **argv_orig, char **envp) { } afl->argv = use_argv; + + if (afl->cmplog_binary) { + + SAYF("Spawning cmplog forkserver"); + memcpy(&afl->cmplog_fsrv, &afl->fsrv, sizeof(afl->fsrv)); + afl->cmplog_fsrv.init_child_func = cmplog_exec_child; + afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + + } + perform_dry_run(afl); cull_queue(afl); @@ -1152,8 +1165,6 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.child_pid > 0) kill(afl->fsrv.child_pid, SIGKILL); if (afl->fsrv.fsrv_pid > 0) kill(afl->fsrv.fsrv_pid, SIGKILL); - if (afl->cmplog_child_pid > 0) kill(afl->cmplog_child_pid, SIGKILL); - if (afl->cmplog_fsrv_pid > 0) kill(afl->cmplog_fsrv_pid, SIGKILL); /* Now that we've killed the forkserver, we wait for it to be able to get * rusage stats. */ if (waitpid(afl->fsrv.fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 2fd17fb1..a8198f79 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -81,8 +81,6 @@ u8 quiet_mode, /* Hide non-essential messages? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ -static u8 qemu_mode; - /* Classify tuple counts. Instead of mapping to individual bits, as in afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */ @@ -482,7 +480,7 @@ 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(afl_forkserver_t *fsrv) { setenv("ASAN_OPTIONS", "abort_on_error=1:" @@ -499,7 +497,7 @@ static void set_up_environment(void) { if (get_afl_env("AFL_PRELOAD")) { - if (qemu_mode) { + if (fsrv->qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -798,10 +796,10 @@ int main(int argc, char **argv_orig, char **envp) { case 'Q': - if (qemu_mode) FATAL("Multiple -Q options not supported"); + if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported"); if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU; - qemu_mode = 1; + fsrv->qemu_mode = 1; break; case 'U': @@ -815,7 +813,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'W': /* Wine+QEMU mode */ if (use_wine) FATAL("Multiple -W options not supported"); - qemu_mode = 1; + fsrv->qemu_mode = 1; use_wine = 1; if (!mem_limit_given) fsrv->mem_limit = 0; @@ -860,7 +858,7 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0); setup_signal_handlers(); - set_up_environment(); + set_up_environment(fsrv); find_binary(fsrv, argv[optind]); @@ -885,7 +883,7 @@ int main(int argc, char **argv_orig, char **envp) { for (i = optind; i < argc; i++) if (strcmp(argv[i], "@@") == 0) arg_offset = i; - if (qemu_mode) { + if (fsrv->qemu_mode) { if (use_wine) use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, @@ -951,7 +949,7 @@ int main(int argc, char **argv_orig, char **envp) { } - afl_fsrv_start(fsrv, use_argv, &stop_soon); + afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT")? 1 :0); while (done == 0 && (dir_ent = readdir(dir_in))) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 53e8705d..8ad33814 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -80,8 +80,6 @@ u8 crash_mode, /* Crash-centric mode? */ static volatile u8 stop_soon; /* Ctrl-C pressed? */ -static u8 qemu_mode; - /* * forkserver section */ @@ -746,7 +744,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) { if (get_afl_env("AFL_PRELOAD")) { - if (qemu_mode) { + if (fsrv->qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -1029,10 +1027,10 @@ int main(int argc, char **argv_orig, char **envp) { case 'Q': - if (qemu_mode) FATAL("Multiple -Q options not supported"); + if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported"); if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU; - qemu_mode = 1; + fsrv->qemu_mode = 1; break; case 'U': @@ -1046,7 +1044,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'W': /* Wine+QEMU mode */ if (use_wine) FATAL("Multiple -W options not supported"); - qemu_mode = 1; + fsrv->qemu_mode = 1; use_wine = 1; if (!mem_limit_given) fsrv->mem_limit = 0; @@ -1107,7 +1105,7 @@ int main(int argc, char **argv_orig, char **envp) { find_binary(fsrv, argv[optind]); detect_file_args(argv + optind, fsrv->out_file, &fsrv->use_stdin); - if (qemu_mode) { + if (fsrv->qemu_mode) { if (use_wine) use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, @@ -1133,7 +1131,7 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv, &stop_soon); + afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT")? 1 :0); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : ""); -- cgit 1.4.1 From 68f269437d0f502a5a091a6ed62cf8d71d0148d6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 11 Apr 2020 07:32:42 +0200 Subject: Autodictionary (#309) * lto module clean-up * step 1/3 * step 1/3 completed * if tmp is ever made non-static * parts 2 and 3 - autodictionary is complete * variable map_size support * variable map size: changed overlooked functions * remove debug for autodict * 64 bit alignment of map size * fix review comments * force 64 bit alignment on both sides * typo * better map transfer, display snapshot in UI * update readme --- include/forkserver.h | 1 - llvm_mode/README.lto.md | 3 +- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 45 ++- llvm_mode/afl-llvm-rt.o.c | 4 +- src/afl-forkserver.c | 23 +- src/afl-fuzz-cmplog.c | 468 ++++++++++++++++++++++++++- src/afl-fuzz-stats.c | 26 +- 7 files changed, 528 insertions(+), 42 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/include/forkserver.h b/include/forkserver.h index 24fa3e1b..e1707429 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,7 +77,6 @@ typedef struct afl_forkserver { void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len); - } afl_forkserver_t; void afl_fsrv_init(afl_forkserver_t *fsrv); diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 48d0e36c..9fc444df 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -50,7 +50,8 @@ Example build output from a libtiff build: libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm afl-clang-lto++2.63d by Marc "vanHauser" Heuse in mode LTO afl-llvm-lto++2.63d by Marc "vanHauser" Heuse -[+] Instrumented 11836 locations with no collisions (on average 1007 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). +AUTODICTIONARY: 11 strings found +[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). ``` ## Building llvm 11 diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 28f6bf9e..5cdf0b70 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -468,15 +468,13 @@ bool AFLLTOPass::runOnModule(Module &M) { TmpConstStr.append("\0", 1); ConstStr = StringRef(TmpConstStr); - if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; } + if (isSizedcmp && constLen > sizedLen) constLen = sizedLen; - /* - if (!be_quiet) - errs() << callInst->getCalledFunction()->getName() << ": len " - << constLen << ": " << ConstStr << "\n"; - */ + if (debug) + errs() << callInst->getCalledFunction()->getName() << ": len " + << constLen << ": " << ConstStr << "\n"; - if (constLen && constLen < MAX_DICT_FILE) + if (constLen >= MIN_AUTO_EXTRA && constLen <= MAX_DICT_FILE) dictionary.push_back(ConstStr.str().substr(0, constLen)); } @@ -514,14 +512,22 @@ bool AFLLTOPass::runOnModule(Module &M) { if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) { - GlobalVariable *AFLFinalLoc = new GlobalVariable( - M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", - 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); - ConstantInt *const_loc = - ConstantInt::get(Int32Ty, (((afl_global_id + 8) >> 3) << 3)); - StoreInst *StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); - StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + uint32_t write_loc = afl_global_id; + + if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3); + + if (write_loc <= MAP_SIZE && write_loc <= 0x800000) { + + GlobalVariable *AFLFinalLoc = new GlobalVariable( + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, + "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, + false); + ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc); + StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } } @@ -537,7 +543,9 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (!be_quiet) printf("AUTODICTIONARY: %lu strings found\n", count); + if (!be_quiet) + printf("AUTODICTIONARY: %lu string%s found\n", count, + count == 1 ? "" : "s"); if (count) { @@ -549,13 +557,16 @@ bool AFLLTOPass::runOnModule(Module &M) { } + count = 0; + for (auto token : dictionary) { - if (offset + token.length() < 0xfffff0) { + if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) { ptr[offset++] = (uint8_t)token.length(); memcpy(ptr + offset, token.c_str(), token.length()); offset += token.length(); + count++; } diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index cbc4648d..3ad9eab4 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -208,7 +208,7 @@ static void __afl_start_snapshots(void) { assume we're not running in forkserver mode and just execute program. */ status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT); - if (map_size <= 0x1000000) + if (map_size <= 0x800000) status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; memcpy(tmp, &status, 4); @@ -373,7 +373,7 @@ static void __afl_start_forkserver(void) { void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); - if (map_size <= 0x1000000) + if (map_size <= 0x800000) status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; if (status) status |= (FS_OPT_ENABLED); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 7ab8a4b5..3c0ad4a2 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -367,23 +367,28 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { fsrv->map_size = FS_OPT_GET_MAPSIZE(status); - if (fsrv->map_size % 8) + if (fsrv->map_size % 8) // should not happen fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); + if (fsrv->map_size > MAP_SIZE) + FATAL( + "Target's coverage map size of %u is larger than the one this " + "afl++ is compiled with (%u)\n", + fsrv->map_size, MAP_SIZE); } - if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { - // this is not afl-fuzz - we deny and return - status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT)); - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) - FATAL("Writing to forkserver failed."); - return; + if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { - } + // this is not afl-fuzz - we deny and return + status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT)); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + return; - if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + } if (!be_quiet) ACTF("Using AUTODICT feature."); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index f9480dc4..4d8bb58f 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -38,12 +38,479 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { +#if 0 + afl->fsrv.child_timed_out = 0; + afl->cmplog_fsrv_pid = fork(); + + if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed"); + + if (!afl->cmplog_fsrv_pid) { + + /* CHILD PROCESS */ + + struct rlimit r; + + /* Umpf. On OpenBSD, the default fd limit for root users is set to + soft 128. Let's try to fix that... */ + + if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { + + r.rlim_cur = FORKSRV_FD + 2; + setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ + + } + + if (afl->fsrv.mem_limit) { + + r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20; + +#ifdef RLIMIT_AS + setrlimit(RLIMIT_AS, &r); /* Ignore errors */ +#else + /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but + according to reliable sources, RLIMIT_DATA covers anonymous + maps - so we should be getting good protection against OOM bugs. */ + + setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ +#endif /* ^RLIMIT_AS */ + + } + + /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered + before the dump is complete. */ + + // r.rlim_max = r.rlim_cur = 0; + // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + /* Isolate the process and configure standard descriptors. If + afl->fsrv.out_file is specified, stdin is /dev/null; otherwise, + afl->fsrv.out_fd is cloned instead. */ + + setsid(); + + if (!(afl->afl_env.afl_debug_child_output)) { + + dup2(afl->fsrv.dev_null_fd, 1); + dup2(afl->fsrv.dev_null_fd, 2); + + } + + if (!afl->fsrv.use_stdin) { + + dup2(afl->fsrv.dev_null_fd, 0); + + } else { + + dup2(afl->fsrv.out_fd, 0); + close(afl->fsrv.out_fd); + + } + + /* Set up control and status pipes, close the unneeded original fds. */ + + if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); + if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); + + close(ctl_pipe[0]); + close(ctl_pipe[1]); + close(st_pipe[0]); + close(st_pipe[1]); + + close(afl->fsrv.out_dir_fd); + close(afl->fsrv.dev_null_fd); +#ifndef HAVE_ARC4RANDOM + close(afl->fsrv.dev_urandom_fd); +#endif + if (afl->fsrv.plot_file != NULL) fclose(afl->fsrv.plot_file); + + /* This should improve performance a bit, since it stops the linker from + doing extra work post-fork(). */ + + if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); + + /* Set sane defaults for ASAN if nothing else specified. */ + + setenv("ASAN_OPTIONS", + "abort_on_error=1:" + "detect_leaks=0:" + "malloc_context_size=0:" + "symbolize=0:" + "allocator_may_return_null=1", + 0); + + /* MSAN is tricky, because it doesn't support abort_on_error=1 at this + point. So, we do this in a very hacky way. */ + + setenv("MSAN_OPTIONS", + "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "abort_on_error=1:" + "malloc_context_size=0:" + "allocator_may_return_null=1:" + "msan_track_origins=0", + 0); + + setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); + + if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) { + + ck_free(afl->argv[0]); + afl->argv[0] = afl->cmplog_binary; + + } + + execv(afl->argv[0], afl->argv); + + /* Use a distinctive bitmap signature to tell the parent about execv() + falling through. */ + + *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG; + exit(0); + + } + + /* PARENT PROCESS */ + + /* Close the unneeded endpoints. */ + + close(ctl_pipe[0]); + close(st_pipe[1]); + + afl->cmplog_fsrv_ctl_fd = ctl_pipe[1]; + afl->cmplog_fsrv_st_fd = st_pipe[0]; + + /* Wait for the fork server to come up, but don't wait too long. */ + + rlen = 0; + if (afl->fsrv.exec_tmout) { + + rlen = 4; + u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT; + /* Reuse readfds as exceptfds to see when the child closed the pipe */ + u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms, + &afl->stop_soon); + + if (!exec_ms) { + + PFATAL("Error in timed read"); + + } else if (exec_ms > timeout_ms) { + + afl->fsrv.child_timed_out = 1; + kill(afl->cmplog_fsrv_pid, SIGKILL); + rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); + + } + + } else { + + rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); + + } + + /* If we have a four-byte "hello" message from the server, we're all set. + Otherwise, try to figure out what went wrong. */ + + if (afl->fsrv.child_timed_out) + FATAL( + "Timeout while initializing cmplog fork server (adjusting -t may " + "help)"); + + if (rlen == 4) { + + OKF("All right - fork server is up."); + return; + + } + + if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0) + PFATAL("waitpid() failed"); + + if (WIFSIGNALED(status)) { + + if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && + afl->fsrv.uses_asan) { + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the target binary crashed suddenly, " + "before receiving any input\n" + " from the fuzzer! Since it seems to be built with ASAN and you " + "have a\n" + " restrictive memory limit configured, this is expected; please " + "read\n" + " %s/notes_for_asan.md for help.\n", + doc_path); + + } else if (!afl->fsrv.mem_limit) { + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the target binary crashed suddenly, " + "before receiving any input\n" + " from the fuzzer! There are several probable explanations:\n\n" + + " - The binary is just buggy and explodes entirely on its own. " + "If so, you\n" + " need to fix the underlying problem or find a better " + "replacement.\n\n" + + MSG_FORK_ON_APPLE + + " - Less likely, there is a horrible bug in the fuzzer. If other " + "options\n" + " fail, poke for troubleshooting " + "tips.\n"); + + } else { + + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the target binary crashed suddenly, " + "before receiving any input\n" + " from the fuzzer! There are several probable explanations:\n\n" + + " - The current memory limit (%s) is too restrictive, causing " + "the\n" + " target to hit an OOM condition in the dynamic linker. Try " + "bumping up\n" + " the limit with the -m setting in the command line. A simple " + "way confirm\n" + " this diagnosis would be:\n\n" + + MSG_ULIMIT_USAGE + " /path/to/fuzzed_app )\n\n" + + " Tip: you can use http://jwilk.net/software/recidivm to " + "quickly\n" + " estimate the required amount of virtual memory for the " + "binary.\n\n" + + " - The binary is just buggy and explodes entirely on its own. " + "If so, you\n" + " need to fix the underlying problem or find a better " + "replacement.\n\n" + + MSG_FORK_ON_APPLE + + " - Less likely, there is a horrible bug in the fuzzer. If other " + "options\n" + " fail, poke for troubleshooting " + "tips.\n", + stringify_mem_size(val_buf, sizeof(val_buf), + afl->fsrv.mem_limit << 20), + afl->fsrv.mem_limit - 1); + + } + + FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status)); + + } + + if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG) + FATAL("Unable to execute target application ('%s')", afl->argv[0]); + + if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) { + + SAYF("\n" cLRD "[-] " cRST + "Hmm, looks like the target binary terminated " + "before we could complete a\n" + " handshake with the injected code. Since it seems to be built " + "with ASAN and\n" + " you have a restrictive memory limit configured, this is " + "expected; please\n" + " read %s/notes_for_asan.md for help.\n", + doc_path); + + } else if (!afl->fsrv.mem_limit) { + + SAYF("\n" cLRD "[-] " cRST + "Hmm, looks like the target binary terminated " + "before we could complete a\n" + " handshake with the injected code. Perhaps there is a horrible " + "bug in the\n" + " fuzzer. Poke for troubleshooting " + "tips.\n"); + + } else { + + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + + SAYF( + "\n" cLRD "[-] " cRST + "Hmm, looks like the target binary terminated " + "before we could complete a\n" + " handshake with the injected code. There are %s probable " + "explanations:\n\n" + + "%s" + " - The current memory limit (%s) is too restrictive, causing an " + "OOM\n" + " fault in the dynamic linker. This can be fixed with the -m " + "option. A\n" + " simple way to confirm the diagnosis may be:\n\n" + + MSG_ULIMIT_USAGE + " /path/to/fuzzed_app )\n\n" + + " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" + " estimate the required amount of virtual memory for the " + "binary.\n\n" + + " - Less likely, there is a horrible bug in the fuzzer. If other " + "options\n" + " fail, poke for troubleshooting " + "tips.\n", + getenv(DEFER_ENV_VAR) ? "three" : "two", + getenv(DEFER_ENV_VAR) + ? " - You are using deferred forkserver, but __AFL_INIT() is " + "never\n" + " reached before the program terminates.\n\n" + : "", + stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), + afl->fsrv.mem_limit - 1); + + } + + FATAL("Cmplog fork server handshake failed"); + +} + +u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { + + int status = 0; + u32 exec_ms; + + u32 tb4; + s32 res; + + afl->fsrv.child_timed_out = 0; + + /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we + must prevent any earlier operations from venturing into that + territory. */ + + memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); + MEM_BARRIER(); + + /* Since we always have a forkserver (or a fauxserver) running, we can simply + tell them to have at it and read back the pid from it.*/ + + if ((res = write(afl->cmplog_fsrv_ctl_fd, &afl->cmplog_prev_timed_out, 4)) != + 4) { + + if (afl->stop_soon) return 0; + RPFATAL(res, + "Unable to request new process from cmplog fork server (OOM?)"); + + } + + if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) { + + if (afl->stop_soon) return 0; + RPFATAL(res, + "Unable to request new process from cmplog fork server (OOM?)"); + + } + + if (afl->cmplog_child_pid <= 0) + FATAL("Cmplog fork server is misbehaving (OOM?)"); + + /* Configure timeout, as requested by user, then wait for child to terminate. + */ + exec_ms = + read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); + + if (exec_ms > timeout) { + + /* If there was no response from forkserver after timeout seconds, + we kill the child. The forkserver should inform us afterwards */ + + kill(afl->cmplog_child_pid, SIGKILL); + afl->fsrv.child_timed_out = 1; + + /* After killing the child, the forkserver should tell us */ + if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) exec_ms = 0; + + } + + if (!exec_ms) { // Something went wrong. + + if (afl->stop_soon) return 0; + SAYF("\n" cLRD "[-] " cRST + "Unable to communicate with fork server. Some possible reasons:\n\n" + " - You've run out of memory. Use -m to increase the the memory " + "limit\n" + " to something higher than %lld.\n" + " - The binary or one of the libraries it uses manages to create\n" + " threads before the forkserver initializes.\n" + " - The binary, at least in some circumstances, exits in a way " + "that\n" + " also kills the parent process - raise() could be the " + "culprit.\n\n" + "If all else fails you can disable the fork server via " + "AFL_NO_FORKSRV=1.\n", + afl->fsrv.mem_limit); + RPFATAL(res, "Unable to communicate with fork server"); + + } + + if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0; + + if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms; + + ++afl->total_execs; + + /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the + compiler below this point. Past this location, afl->fsrv.trace_bits[] + behave very normally and do not have to be treated as volatile. */ + + MEM_BARRIER(); + + tb4 = *(u32 *)afl->fsrv.trace_bits; + +#ifdef WORD_SIZE_64 + classify_counts(afl, (u64 *)afl->fsrv.trace_bits); +#else + classify_counts(afl, (u32 *)afl->fsrv.trace_bits); +#endif /* ^WORD_SIZE_64 */ + + afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out; + + /* Report outcome to caller. */ + + if (WIFSIGNALED(status) && !afl->stop_soon) { + + afl->kill_signal = WTERMSIG(status); + + if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) + return FAULT_TMOUT; + + return FAULT_CRASH; + + } + + /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and + must use a special exit code. */ + + if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { + + afl->kill_signal = 0; + return FAULT_CRASH; + + } + + if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG) + return FAULT_ERROR; + + return FAULT_NONE; +#else ck_free(argv[0]); argv[0] = fsrv->cmplog_binary; } execv(argv[0], argv); +#endif } @@ -104,4 +571,3 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { return 0; } - diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d83a747f..65876f67 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -366,9 +366,9 @@ void show_stats(afl_state_t *afl) { /* Lord, forgive me this. */ - SAYF(SET_G1 bSTG bLT bH bSTOP cCYA + SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA - " overall results " bSTG bH2 bH2 bRT "\n"); + " overall results " bSTG bH2 bH2 bRT "\n"); if (afl->dumb_mode) { @@ -450,9 +450,9 @@ void show_stats(afl_state_t *afl) { " uniq hangs : " cRST "%-6s" bSTG bV "\n", time_tmp, tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA - " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); + " map coverage " bSTG bH 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 @@ -482,9 +482,9 @@ void show_stats(afl_state_t *afl) { SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA - " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); + " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored), ((double)afl->queued_favored) * 100 / afl->queued_paths); @@ -558,7 +558,7 @@ void show_stats(afl_state_t *afl) { /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); @@ -737,6 +737,8 @@ void show_stats(afl_state_t *afl) { if (afl->cpu_core_count) { + char *spacing = SP10, snap[24] = " " cLGN "snapshot" cRST " "; + double cur_runnable = get_runnable_processes(); u32 cur_utilization = cur_runnable * 100 / afl->cpu_core_count; @@ -751,23 +753,25 @@ void show_stats(afl_state_t *afl) { if (!afl->no_cpu_meter_red && cur_utilization >= 150) cpu_color = cLRD; + if (afl->fsrv.snapshot) spacing = snap; + #ifdef HAVE_AFFINITY if (afl->cpu_aff >= 0) { - SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, MIN(afl->cpu_aff, 999), - cpu_color, MIN(cur_utilization, 999)); + SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing, + MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, 999)); } else { - SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color, + SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color, MIN(cur_utilization, 999)); } #else - SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color, + SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color, MIN(cur_utilization, 999)); #endif /* ^HAVE_AFFINITY */ -- cgit 1.4.1 From 32ba60185eba8a3ae8eeba0b5830d1bb43e38473 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 11 Apr 2020 08:02:54 +0200 Subject: more refactoring and update changelog --- docs/Changelog.md | 11 +- include/afl-fuzz.h | 7 +- include/cmplog.h | 1 - include/forkserver.h | 2 +- src/afl-analyze.c | 6 +- src/afl-forkserver.c | 1 + src/afl-fuzz-cmplog.c | 469 +----------------------------------------------- src/afl-fuzz-mutators.c | 6 +- src/afl-fuzz-run.c | 14 +- src/afl-fuzz-state.c | 7 + src/afl-fuzz.c | 10 +- src/afl-showmap.c | 3 +- src/afl-tmin.c | 3 +- 13 files changed, 50 insertions(+), 490 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/docs/Changelog.md b/docs/Changelog.md index 0ec330a7..a1b55a69 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,7 +10,16 @@ sending a mail to . ### Version ++2.63d (development): - - LTO mode now requires llvm11 - but compiles all targets! :) + - llvm_mode LTO mode: + - now requires llvm11 - but compiles all targets! :) + - autodictionary feature added, enable with AFL_LLVM_LTO_AUTODICTIONARY + - variable map size usage + - afl-fuzz: + - variable map size support added (only LTO mode can use this) + - snapshot feature usage now visible in UI + - extended forkserver: map_size and more information is communicated to + afl-fuzz (and afl-fuzz acts accordingly) + - more refactoring - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 97c1f31c..1440b645 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -331,7 +331,8 @@ typedef struct afl_env_vars { u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check, 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_output, afl_autoresume; + afl_bench_until_crash, afl_debug_child_output, afl_autoresume, + afl_cal_fast; u8 *afl_tmpdir, *afl_post_library, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, @@ -558,7 +559,7 @@ typedef struct afl_state { /* CmpLog */ - char *cmplog_binary; + char * cmplog_binary; afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ /* Custom mutators */ @@ -921,7 +922,7 @@ void save_cmdline(afl_state_t *, u32, char **); /* CmpLog */ -u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); +u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); /* RedQueen */ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, diff --git a/include/cmplog.h b/include/cmplog.h index 4731f779..74e6a3bb 100644 --- a/include/cmplog.h +++ b/include/cmplog.h @@ -79,6 +79,5 @@ struct cmp_map { void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv); - #endif diff --git a/include/forkserver.h b/include/forkserver.h index e1707429..444f92df 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -68,7 +68,7 @@ typedef struct afl_forkserver { u8 qemu_mode; /* if running in qemu mode or not */ - char *cmplog_binary; /* the name of the cmplog binary */ + char *cmplog_binary; /* the name of the cmplog binary */ /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-analyze.c b/src/afl-analyze.c index b0e8afcb..66dbefab 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -58,7 +58,7 @@ static s32 child_pid; /* PID of the tested program */ -static u8 *trace_bits; /* SHM with instrumentation bitmap */ +static u8 *trace_bits; /* SHM with instrumentation bitmap */ static u8 *in_file, /* Analyzer input test case */ *prog_in; /* Targeted program input file */ @@ -75,7 +75,7 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static s32 dev_null_fd = -1; /* FD to /dev/null */ -static u8 edges_only, /* Ignore hit counts? */ +static u8 edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ use_stdin = 1; /* Use stdin for program input? */ @@ -83,7 +83,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ static u8 *target_path; -static u8 qemu_mode; +static u8 qemu_mode; /* Constants used for describing byte behavior. */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3c0ad4a2..a7067791 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -187,6 +187,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, FATAL("Different forkserver not compatible with fauxserver"); fsrv->init_child_func = afl_fauxsrv_execv; + } if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 4d8bb58f..6f201013 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -30,6 +30,7 @@ #include "cmplog.h" typedef struct cmplog_data { + } cmplog_data_t; void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { @@ -38,479 +39,12 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { -#if 0 - afl->fsrv.child_timed_out = 0; - afl->cmplog_fsrv_pid = fork(); - - if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed"); - - if (!afl->cmplog_fsrv_pid) { - - /* CHILD PROCESS */ - - struct rlimit r; - - /* Umpf. On OpenBSD, the default fd limit for root users is set to - soft 128. Let's try to fix that... */ - - if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { - - r.rlim_cur = FORKSRV_FD + 2; - setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ - - } - - if (afl->fsrv.mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20; - -#ifdef RLIMIT_AS - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ -#else - /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but - according to reliable sources, RLIMIT_DATA covers anonymous - maps - so we should be getting good protection against OOM bugs. */ - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ -#endif /* ^RLIMIT_AS */ - - } - - /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered - before the dump is complete. */ - - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - /* Isolate the process and configure standard descriptors. If - afl->fsrv.out_file is specified, stdin is /dev/null; otherwise, - afl->fsrv.out_fd is cloned instead. */ - - setsid(); - - if (!(afl->afl_env.afl_debug_child_output)) { - - dup2(afl->fsrv.dev_null_fd, 1); - dup2(afl->fsrv.dev_null_fd, 2); - - } - - if (!afl->fsrv.use_stdin) { - - dup2(afl->fsrv.dev_null_fd, 0); - - } else { - - dup2(afl->fsrv.out_fd, 0); - close(afl->fsrv.out_fd); - - } - - /* Set up control and status pipes, close the unneeded original fds. */ - - if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); - if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); - - close(ctl_pipe[0]); - close(ctl_pipe[1]); - close(st_pipe[0]); - close(st_pipe[1]); - - close(afl->fsrv.out_dir_fd); - close(afl->fsrv.dev_null_fd); -#ifndef HAVE_ARC4RANDOM - close(afl->fsrv.dev_urandom_fd); -#endif - if (afl->fsrv.plot_file != NULL) fclose(afl->fsrv.plot_file); - - /* This should improve performance a bit, since it stops the linker from - doing extra work post-fork(). */ - - if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); - - /* Set sane defaults for ASAN if nothing else specified. */ - - setenv("ASAN_OPTIONS", - "abort_on_error=1:" - "detect_leaks=0:" - "malloc_context_size=0:" - "symbolize=0:" - "allocator_may_return_null=1", - 0); - - /* MSAN is tricky, because it doesn't support abort_on_error=1 at this - point. So, we do this in a very hacky way. */ - - setenv("MSAN_OPTIONS", - "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" - "abort_on_error=1:" - "malloc_context_size=0:" - "allocator_may_return_null=1:" - "msan_track_origins=0", - 0); - - setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - - if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) { - - ck_free(afl->argv[0]); - afl->argv[0] = afl->cmplog_binary; - - } - - execv(afl->argv[0], afl->argv); - - /* Use a distinctive bitmap signature to tell the parent about execv() - falling through. */ - - *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - /* PARENT PROCESS */ - - /* Close the unneeded endpoints. */ - - close(ctl_pipe[0]); - close(st_pipe[1]); - - afl->cmplog_fsrv_ctl_fd = ctl_pipe[1]; - afl->cmplog_fsrv_st_fd = st_pipe[0]; - - /* Wait for the fork server to come up, but don't wait too long. */ - - rlen = 0; - if (afl->fsrv.exec_tmout) { - - rlen = 4; - u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT; - /* Reuse readfds as exceptfds to see when the child closed the pipe */ - u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms, - &afl->stop_soon); - - if (!exec_ms) { - - PFATAL("Error in timed read"); - - } else if (exec_ms > timeout_ms) { - - afl->fsrv.child_timed_out = 1; - kill(afl->cmplog_fsrv_pid, SIGKILL); - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - } else { - - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - /* If we have a four-byte "hello" message from the server, we're all set. - Otherwise, try to figure out what went wrong. */ - - if (afl->fsrv.child_timed_out) - FATAL( - "Timeout while initializing cmplog fork server (adjusting -t may " - "help)"); - - if (rlen == 4) { - - OKF("All right - fork server is up."); - return; - - } - - if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - if (WIFSIGNALED(status)) { - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && - afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! Since it seems to be built with ASAN and you " - "have a\n" - " restrictive memory limit configured, this is expected; please " - "read\n" - " %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n"); - - } else { - - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The current memory limit (%s) is too restrictive, causing " - "the\n" - " target to hit an OOM condition in the dynamic linker. Try " - "bumping up\n" - " the limit with the -m setting in the command line. A simple " - "way confirm\n" - " this diagnosis would be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to " - "quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n", - stringify_mem_size(val_buf, sizeof(val_buf), - afl->fsrv.mem_limit << 20), - afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status)); - - } - - if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute target application ('%s')", afl->argv[0]); - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Since it seems to be built " - "with ASAN and\n" - " you have a restrictive memory limit configured, this is " - "expected; please\n" - " read %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Perhaps there is a horrible " - "bug in the\n" - " fuzzer. Poke for troubleshooting " - "tips.\n"); - - } else { - - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - - SAYF( - "\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. There are %s probable " - "explanations:\n\n" - - "%s" - " - The current memory limit (%s) is too restrictive, causing an " - "OOM\n" - " fault in the dynamic linker. This can be fixed with the -m " - "option. A\n" - " simple way to confirm the diagnosis may be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n", - getenv(DEFER_ENV_VAR) ? "three" : "two", - getenv(DEFER_ENV_VAR) - ? " - You are using deferred forkserver, but __AFL_INIT() is " - "never\n" - " reached before the program terminates.\n\n" - : "", - stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), - afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server handshake failed"); - -} - -u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { - - int status = 0; - u32 exec_ms; - - u32 tb4; - s32 res; - - afl->fsrv.child_timed_out = 0; - - /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we - must prevent any earlier operations from venturing into that - territory. */ - - memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); - MEM_BARRIER(); - - /* Since we always have a forkserver (or a fauxserver) running, we can simply - tell them to have at it and read back the pid from it.*/ - - if ((res = write(afl->cmplog_fsrv_ctl_fd, &afl->cmplog_prev_timed_out, 4)) != - 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if (afl->cmplog_child_pid <= 0) - FATAL("Cmplog fork server is misbehaving (OOM?)"); - - /* Configure timeout, as requested by user, then wait for child to terminate. - */ - exec_ms = - read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); - - if (exec_ms > timeout) { - - /* If there was no response from forkserver after timeout seconds, - we kill the child. The forkserver should inform us afterwards */ - - kill(afl->cmplog_child_pid, SIGKILL); - afl->fsrv.child_timed_out = 1; - - /* After killing the child, the forkserver should tell us */ - if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) exec_ms = 0; - - } - - if (!exec_ms) { // Something went wrong. - - if (afl->stop_soon) return 0; - SAYF("\n" cLRD "[-] " cRST - "Unable to communicate with fork server. Some possible reasons:\n\n" - " - You've run out of memory. Use -m to increase the the memory " - "limit\n" - " to something higher than %lld.\n" - " - The binary or one of the libraries it uses manages to create\n" - " threads before the forkserver initializes.\n" - " - The binary, at least in some circumstances, exits in a way " - "that\n" - " also kills the parent process - raise() could be the " - "culprit.\n\n" - "If all else fails you can disable the fork server via " - "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); - RPFATAL(res, "Unable to communicate with fork server"); - - } - - if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0; - - if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms; - - ++afl->total_execs; - - /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the - compiler below this point. Past this location, afl->fsrv.trace_bits[] - behave very normally and do not have to be treated as volatile. */ - - MEM_BARRIER(); - - tb4 = *(u32 *)afl->fsrv.trace_bits; - -#ifdef WORD_SIZE_64 - classify_counts(afl, (u64 *)afl->fsrv.trace_bits); -#else - classify_counts(afl, (u32 *)afl->fsrv.trace_bits); -#endif /* ^WORD_SIZE_64 */ - - afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out; - - /* Report outcome to caller. */ - - if (WIFSIGNALED(status) && !afl->stop_soon) { - - afl->kill_signal = WTERMSIG(status); - - if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) - return FAULT_TMOUT; - - return FAULT_CRASH; - - } - - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ - - if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { - - afl->kill_signal = 0; - return FAULT_CRASH; - - } - - if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG) - return FAULT_ERROR; - - return FAULT_NONE; -#else ck_free(argv[0]); argv[0] = fsrv->cmplog_binary; } execv(argv[0], argv); -#endif } @@ -571,3 +105,4 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { return 0; } + diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index a7d7ae18..efb1c117 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -34,7 +34,7 @@ void load_custom_mutator_py(afl_state_t *, char *); void setup_custom_mutator(afl_state_t *afl) { /* Try mutator library first */ - u8 *fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + u8 *fn = afl->afl_env.afl_custom_mutator_library; if (fn) { @@ -52,7 +52,7 @@ void setup_custom_mutator(afl_state_t *afl) { /* Try Python module */ #ifdef USE_PYTHON - u8 *module_name = getenv("AFL_PYTHON_MODULE"); + u8 *module_name = afl->afl_env.afl_python_module; if (module_name) { @@ -67,7 +67,7 @@ void setup_custom_mutator(afl_state_t *afl) { } #else - if (getenv("AFL_PYTHON_MODULE")) + if (afl->afl_env.afl_python_module) FATAL("Your AFL binary was built without Python support"); #endif diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 3a178e87..4c98d788 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -69,8 +69,7 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - exec_ms = - read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); + exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); if (exec_ms > timeout) { @@ -312,10 +311,17 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, count its spin-up time toward binary calibration. */ if (!afl->fsrv.fsrv_pid) { - if (afl->shm.cmplog_mode && afl->fsrv.init_child_func != cmplog_exec_child) { + + if (afl->shm.cmplog_mode && + afl->fsrv.init_child_func != cmplog_exec_child) { + FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly."); + } - afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + + afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); + } if (q->exec_cksum) diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 80039d6f..f58345fb 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -284,6 +284,13 @@ 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_CAL_FAST", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cal_fast = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TMPDIR", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 44c48088..3341898c 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -248,6 +248,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_state_init(afl); afl_fsrv_init(&afl->fsrv); + if (get_afl_env("AFL_DEBUG")) afl->debug = 1; read_afl_environment(afl, envp); exit_1 = !!afl->afl_env.afl_bench_just_one; @@ -690,7 +691,7 @@ int main(int argc, char **argv_orig, char **envp) { OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->force_deterministic && - getenv("AFL_CUSTOM_MUTATOR_ONLY")) + afl->afl_env.afl_custom_mutator_only) WARNF( "Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will " "result in no deterministic mutations being done!"); @@ -865,7 +866,7 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) afl->not_on_tty = 0; - if (get_afl_env("AFL_CAL_FAST")) { + if (afl->afl_env.afl_cal_fast) { /* Use less calibration cycles, for slow applications */ afl->cal_cycles = 3; @@ -873,8 +874,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (get_afl_env("AFL_DEBUG")) afl->debug = 1; - if (afl->afl_env.afl_custom_mutator_only) { /* This ensures we don't proceed to havoc/splice */ @@ -1024,7 +1023,8 @@ int main(int argc, char **argv_orig, char **envp) { SAYF("Spawning cmplog forkserver"); memcpy(&afl->cmplog_fsrv, &afl->fsrv, sizeof(afl->fsrv)); afl->cmplog_fsrv.init_child_func = cmplog_exec_child; - afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index a8198f79..c84fa36c 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -949,7 +949,8 @@ int main(int argc, char **argv_orig, char **envp) { } - afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT")? 1 :0); + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); while (done == 0 && (dir_ent = readdir(dir_in))) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 8ad33814..3be6b2c0 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1131,7 +1131,8 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT")? 1 :0); + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : ""); -- cgit 1.4.1 From 033c743a417b208ee48218d59d8665823434ea67 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 13 Apr 2020 11:37:48 +0200 Subject: fix all cmplog errors --- src/afl-fuzz-cmplog.c | 6 +----- src/afl-fuzz-run.c | 14 +++++--------- src/afl-fuzz.c | 2 ++ 3 files changed, 8 insertions(+), 14 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 6f201013..e2747097 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -37,13 +37,9 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { - - ck_free(argv[0]); + if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) argv[0] = fsrv->cmplog_binary; - } - execv(argv[0], argv); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 9f79a5c9..1ddd7e1a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -46,10 +46,10 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { must prevent any earlier operations from venturing into that territory. */ - if (fsrv->trace_bits) memset(fsrv->trace_bits, 0, fsrv->map_size); + memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); - + /* we have the fork server (or faux server) up and running, so simply tell it to have at it, and then read back PID. */ @@ -120,18 +120,14 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { MEM_BARRIER(); - if (fsrv->trace_bits) { - - tb4 = *(u32 *)fsrv->trace_bits; + tb4 = *(u32 *)fsrv->trace_bits; #ifdef WORD_SIZE_64 - classify_counts(afl, (u64 *)fsrv->trace_bits); + classify_counts(afl, (u64 *)fsrv->trace_bits); #else - classify_counts(afl, (u32 *)fsrv->trace_bits); + classify_counts(afl, (u32 *)fsrv->trace_bits); #endif /* ^WORD_SIZE_64 */ - } - fsrv->prev_timed_out = fsrv->child_timed_out; /* Report outcome to caller. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a813906c..136a9519 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1022,6 +1022,8 @@ int main(int argc, char **argv_orig, char **envp) { ACTF("Spawning cmplog forkserver"); afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv); // TODO: this is semi-nice + afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; + afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.init_child_func = cmplog_exec_child; afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, -- cgit 1.4.1 From 6dc36f1e6e7d2d781cc6b14f2898b3f7021e1d06 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 14 Apr 2020 19:27:25 +0200 Subject: unified forkservered run_target, fixes #308 --- include/afl-fuzz.h | 16 +----- include/forkserver.h | 21 ++++++-- src/afl-analyze.c | 2 +- src/afl-forkserver.c | 132 +++++++++++++++++++++++++++++++++++++++++++++--- src/afl-fuzz-bitmap.c | 16 +++--- src/afl-fuzz-cmplog.c | 2 +- src/afl-fuzz-init.c | 14 ++--- src/afl-fuzz-mutators.c | 2 +- src/afl-fuzz-one.c | 12 ++--- src/afl-fuzz-queue.c | 2 +- src/afl-fuzz-redqueen.c | 4 +- src/afl-fuzz-run.c | 128 +++------------------------------------------- src/afl-fuzz-stats.c | 18 +++---- src/afl-fuzz.c | 2 +- src/afl-sharedmem.c | 1 - src/afl-showmap.c | 95 ++++------------------------------ src/afl-tmin.c | 109 ++++++++------------------------------- 17 files changed, 222 insertions(+), 354 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 3df99a58..abaa71b5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -195,18 +195,6 @@ enum { }; -/* Execution status fault codes */ - -enum { - - /* 00 */ FAULT_NONE, - /* 01 */ FAULT_TMOUT, - /* 02 */ FAULT_CRASH, - /* 03 */ FAULT_ERROR, - /* 04 */ FAULT_NOINST, - /* 05 */ FAULT_NOBITS - -}; #define operator_num 16 #define swarm_num 5 @@ -433,7 +421,6 @@ typedef struct afl_state { use_splicing, /* Recombine input files? */ dumb_mode, /* Run in non-instrumented mode? */ score_changed, /* Scoring for favorites changed? */ - kill_signal, /* Signal that killed the child */ resuming_fuzz, /* Resuming an older fuzzing job? */ timeout_given, /* Specific timeout given? */ not_on_tty, /* stdout is not a tty */ @@ -488,7 +475,6 @@ typedef struct afl_state { total_tmouts, /* Total number of timeouts */ unique_tmouts, /* Timeouts with unique signatures */ unique_hangs, /* Hangs with unique signatures */ - total_execs, /* Total execve() calls */ last_crash_execs, /* Exec counter at last crash */ queue_cycle, /* Queue round counter */ cycles_wo_finds, /* Cycles without any new paths */ @@ -888,7 +874,7 @@ void show_init_stats(afl_state_t *); /* Run */ -u8 run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); +fsrv_run_result_t run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); void write_to_testcase(afl_state_t *, void *, u32); u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8); void sync_fuzzers(afl_state_t *); diff --git a/include/forkserver.h b/include/forkserver.h index 6fbaf612..7559e785 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -29,6 +29,7 @@ #define __AFL_FORKSERVER_H #include +#include typedef struct afl_forkserver { @@ -55,16 +56,18 @@ typedef struct afl_forkserver { u32 snapshot; /* is snapshot feature used */ u64 mem_limit; /* Memory cap for child (MB) */ + u64 total_execs; /* How often run_target was called */ + u8 *out_file, /* File to fuzz, if any */ *target_path; /* Path of the target */ FILE *plot_file; /* Gnuplot output file */ - u8 child_timed_out; /* Traced process timed out? */ + u8 last_run_timed_out; /* Traced process timed out? */ - u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ + u8 last_kill_signal; /* Signal that killed the child */ - u32 prev_timed_out; /* if prev forkserver run timed out */ + u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ u8 qemu_mode; /* if running in qemu mode or not */ @@ -79,10 +82,22 @@ typedef struct afl_forkserver { } afl_forkserver_t; +typedef enum fsrv_run_result { + + /* 00 */ FSRV_RUN_OK = 0, + /* 01 */ FSRV_RUN_TMOUT, + /* 02 */ FSRV_RUN_CRASH, + /* 03 */ FSRV_RUN_ERROR, + /* 04 */ FSRV_RUN_NOINST, + /* 05 */ FSRV_RUN_NOBITS, + +} fsrv_run_result_t; + void afl_fsrv_init(afl_forkserver_t *fsrv); void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from); void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output); +fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, volatile u8 *stop_soon_p); void afl_fsrv_killall(void); void afl_fsrv_deinit(afl_forkserver_t *fsrv); diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 952786b0..8625cfda 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -80,7 +80,7 @@ static u8 edges_only, /* Ignore hit counts? */ use_stdin = 1; /* Use stdin for program input? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ - child_timed_out; /* Child timed out? */ + child_timed_out; /* Child timed out? */ static u8 *target_path; static u8 qemu_mode; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index f647ff5d..a7be8e8b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -76,7 +76,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->child_pid = -1; fsrv->map_size = MAP_SIZE; fsrv->use_fauxsrv = 0; - fsrv->prev_timed_out = 0; + fsrv->last_run_timed_out = 0; fsrv->init_child_func = fsrv_exec_child; @@ -102,7 +102,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->out_dir_fd = -1; fsrv_to->child_pid = -1; fsrv_to->use_fauxsrv = 0; - fsrv_to->prev_timed_out = 0; + fsrv_to->last_run_timed_out = 0; fsrv_to->init_child_func = fsrv_exec_child; @@ -217,7 +217,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); - fsrv->child_timed_out = 0; + fsrv->last_run_timed_out = 0; fsrv->fsrv_pid = fork(); if (fsrv->fsrv_pid < 0) PFATAL("fork() failed"); @@ -361,7 +361,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) { - fsrv->child_timed_out = 1; + fsrv->last_run_timed_out = 1; kill(fsrv->fsrv_pid, SIGKILL); } else { @@ -476,7 +476,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if (fsrv->child_timed_out) + if (fsrv->last_run_timed_out) FATAL("Timeout while initializing fork server (adjusting -t may help)"); if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) PFATAL("waitpid() failed"); @@ -640,6 +640,127 @@ static void afl_fsrv_kill(afl_forkserver_t *fsrv) { } +/* Execute target application, monitoring for timeouts. Return status + information. The called program will update afl->fsrv->trace_bits. */ + +fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, volatile u8 *stop_soon_p) { + + s32 res; + u32 exec_ms; + + int status = 0; + + u32 timeout = fsrv->exec_tmout; + + /* After this memset, fsrv->trace_bits[] are effectively volatile, so we + must prevent any earlier operations from venturing into that + territory. */ + + memset(fsrv->trace_bits, 0, fsrv->map_size); + + MEM_BARRIER(); + + /* we have the fork server (or faux server) up and running + First, tell it if the previous run timed out. */ + + if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->last_run_timed_out, 4)) != 4) { + + if (*stop_soon_p) return 0; + RPFATAL(res, "Unable to request new process from fork server (OOM?)"); + + } + + fsrv->last_run_timed_out = 0; + + if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) { + + if (stop_soon_p) return 0; + RPFATAL(res, "Unable to request new process from fork server (OOM?)"); + + } + + if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); + + exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, stop_soon_p); + + if (exec_ms > timeout) { + + /* If there was no response from forkserver after timeout seconds, + we kill the child. The forkserver should inform us afterwards */ + + kill(fsrv->child_pid, SIGKILL); + fsrv->last_run_timed_out = 1; + if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0; + + } + + if (!exec_ms) { + + if (*stop_soon_p) return 0; + SAYF("\n" cLRD "[-] " cRST + "Unable to communicate with fork server. Some possible reasons:\n\n" + " - You've run out of memory. Use -m to increase the the memory " + "limit\n" + " to something higher than %lld.\n" + " - The binary or one of the libraries it uses manages to " + "create\n" + " threads before the forkserver initializes.\n" + " - The binary, at least in some circumstances, exits in a way " + "that\n" + " also kills the parent process - raise() could be the " + "culprit.\n" + " - If using persistent mode with QEMU, " + "AFL_QEMU_PERSISTENT_ADDR " + "is\n" + " probably not valid (hint: add the base address in case of " + "PIE)" + "\n\n" + "If all else fails you can disable the fork server via " + "AFL_NO_FORKSRV=1.\n", + fsrv->mem_limit); + RPFATAL(res, "Unable to communicate with fork server"); + + } + + if (!WIFSTOPPED(status)) fsrv->child_pid = 0; + + fsrv->total_execs++; + + /* Any subsequent operations on fsrv->trace_bits must not be moved by the + compiler below this point. Past this location, fsrv->trace_bits[] + behave very normally and do not have to be treated as volatile. */ + + MEM_BARRIER(); + + /* Report outcome to caller. */ + + if (WIFSIGNALED(status) && !*stop_soon_p) { + + fsrv->last_kill_signal = WTERMSIG(status); + + if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL) + return FSRV_RUN_TMOUT; + + return FSRV_RUN_CRASH; + + } + + /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and + must use a special exit code. */ + + if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { + + fsrv->last_kill_signal = 0; + return FSRV_RUN_CRASH; + + } + + if ((*(u32 *)fsrv->trace_bits) == EXEC_FAIL_SIG) return FSRV_RUN_NOINST; + + return FSRV_RUN_OK; + +} + void afl_fsrv_killall() { LIST_FOREACH(&fsrv_list, afl_forkserver_t, { @@ -656,4 +777,3 @@ void afl_fsrv_deinit(afl_forkserver_t *fsrv) { list_remove(&fsrv_list, fsrv); } - diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index a0a720fa..66b1e60d 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -598,7 +598,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0); - if (unlikely(res == FAULT_ERROR)) + if (unlikely(res == FSRV_RUN_ERROR)) FATAL("Unable to execute target application"); fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600); @@ -612,7 +612,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { switch (fault) { - case FAULT_TMOUT: + case FSRV_RUN_TMOUT: /* Timeouts are not very interesting, but we're still obliged to keep a handful of samples. We use the presence of new bits in the @@ -651,9 +651,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { timeout actually uncovers a crash. Make sure we don't discard it if so. */ - if (!afl->stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash; + if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) goto keep_as_crash; - if (afl->stop_soon || new_fault != FAULT_TMOUT) return keeping; + if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) return keeping; } @@ -675,7 +675,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { break; - case FAULT_CRASH: + case FSRV_RUN_CRASH: keep_as_crash: @@ -704,7 +704,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, - afl->unique_crashes, afl->kill_signal, describe_op(afl, 0)); + afl->unique_crashes, afl->fsrv.last_kill_signal, describe_op(afl, 0)); #else @@ -730,11 +730,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { } afl->last_crash_time = get_cur_time(); - afl->last_crash_execs = afl->total_execs; + afl->last_crash_execs = afl->fsrv.total_execs; break; - case FAULT_ERROR: FATAL("Unable to execute target application"); + case FSRV_RUN_ERROR: FATAL("Unable to execute target application"); default: return keeping; diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index e2747097..ab93d838 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -66,7 +66,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (afl->stop_soon) return 1; - if (fault == FAULT_TMOUT) { + if (fault == FSRV_RUN_TMOUT) { if (afl->subseq_tmouts++ > TMOUT_LIMIT) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 10417da6..55f7ce53 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -493,13 +493,13 @@ void perform_dry_run(afl_state_t *afl) { if (afl->stop_soon) return; - if (res == afl->crash_mode || res == FAULT_NOBITS) + if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST, q->len, q->bitmap_size, q->exec_us); switch (res) { - case FAULT_NONE: + case FSRV_RUN_OK: if (q == afl->queue) check_map_coverage(afl); @@ -507,7 +507,7 @@ void perform_dry_run(afl_state_t *afl) { break; - case FAULT_TMOUT: + case FSRV_RUN_TMOUT: if (afl->timeout_given) { @@ -556,7 +556,7 @@ void perform_dry_run(afl_state_t *afl) { } - case FAULT_CRASH: + case FSRV_RUN_CRASH: if (afl->crash_mode) break; @@ -650,13 +650,13 @@ void perform_dry_run(afl_state_t *afl) { FATAL("Test case '%s' results in a crash", fn); - case FAULT_ERROR: + case FSRV_RUN_ERROR: FATAL("Unable to execute target application ('%s')", afl->argv[0]); - case FAULT_NOINST: FATAL("No instrumentation detected"); + case FSRV_RUN_NOINST: FATAL("No instrumentation detected"); - case FAULT_NOBITS: + case FSRV_RUN_NOBITS: ++afl->useless_at_start; diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index efb1c117..7bf23e84 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -242,7 +242,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; - if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; } + if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 961a29d6..cc97654a 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -442,14 +442,14 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(afl->queue_cur->cal_failed)) { - u8 res = FAULT_TMOUT; + u8 res = FSRV_RUN_TMOUT; if (afl->queue_cur->cal_failed < CAL_CHANCES) { res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0); - if (unlikely(res == FAULT_ERROR)) + if (unlikely(res == FSRV_RUN_ERROR)) FATAL("Unable to execute target application"); } @@ -471,7 +471,7 @@ u8 fuzz_one_original(afl_state_t *afl) { u8 res = trim_case(afl, afl->queue_cur, in_buf); - if (unlikely(res == FAULT_ERROR)) + if (unlikely(res == FSRV_RUN_ERROR)) FATAL("Unable to execute target application"); if (unlikely(afl->stop_soon)) { @@ -2469,14 +2469,14 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->queue_cur->cal_failed) { - u8 res = FAULT_TMOUT; + u8 res = FSRV_RUN_TMOUT; if (afl->queue_cur->cal_failed < CAL_CHANCES) { res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0); - if (res == FAULT_ERROR) FATAL("Unable to execute target application"); + if (res == FSRV_RUN_ERROR) FATAL("Unable to execute target application"); } @@ -2497,7 +2497,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u8 res = trim_case(afl, afl->queue_cur, in_buf); - if (res == FAULT_ERROR) FATAL("Unable to execute target application"); + if (res == FSRV_RUN_ERROR) FATAL("Unable to execute target application"); if (afl->stop_soon) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 5eb110d0..d05eee08 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -492,7 +492,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { // the more often fuzz result paths are equal to this queue entry, // reduce its value perf_score *= - (1 - (double)((double)q->n_fuzz / (double)afl->total_execs)); + (1 - (double)((double)q->n_fuzz / (double)afl->fsrv.total_execs)); break; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 6a01ec89..8cea01e8 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -622,7 +622,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) return 1; u64 orig_hit_cnt, new_hit_cnt; - u64 orig_execs = afl->total_execs; + u64 orig_execs = afl->fsrv.total_execs; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_name = "input-to-state"; @@ -670,7 +670,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, exit_its: new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_ITS] += afl->total_execs - orig_execs; + afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs; memcpy(orig_buf, buf, len); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 514ba9ef..b20c5436 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -32,95 +32,9 @@ /* Execute target application, monitoring for timeouts. Return status information. The called program will update afl->fsrv->trace_bits. */ -u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { +fsrv_run_result_t run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { - s32 res; - u32 exec_ms; - - int status = 0; - u32 tb4; - - fsrv->child_timed_out = 0; - - /* After this memset, fsrv->trace_bits[] are effectively volatile, so we - must prevent any earlier operations from venturing into that - territory. */ - - memset(fsrv->trace_bits, 0, fsrv->map_size); - - MEM_BARRIER(); - - /* we have the fork server (or faux server) up and running, so simply - tell it to have at it, and then read back PID. */ - - if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - - } - - if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - - } - - if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - - exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); - - if (exec_ms > timeout) { - - /* If there was no response from forkserver after timeout seconds, - we kill the child. The forkserver should inform us afterwards */ - - kill(fsrv->child_pid, SIGKILL); - fsrv->child_timed_out = 1; - if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0; - - } - - if (!exec_ms) { - - if (afl->stop_soon) return 0; - SAYF("\n" cLRD "[-] " cRST - "Unable to communicate with fork server. Some possible reasons:\n\n" - " - You've run out of memory. Use -m to increase the the memory " - "limit\n" - " to something higher than %lld.\n" - " - The binary or one of the libraries it uses manages to " - "create\n" - " threads before the forkserver initializes.\n" - " - The binary, at least in some circumstances, exits in a way " - "that\n" - " also kills the parent process - raise() could be the " - "culprit.\n" - " - If using persistent mode with QEMU, " - "AFL_QEMU_PERSISTENT_ADDR " - "is\n" - " probably not valid (hint: add the base address in case of " - "PIE)" - "\n\n" - "If all else fails you can disable the fork server via " - "AFL_NO_FORKSRV=1.\n", - fsrv->mem_limit); - RPFATAL(res, "Unable to communicate with fork server"); - - } - - if (!WIFSTOPPED(status)) fsrv->child_pid = 0; - - ++afl->total_execs; - - /* Any subsequent operations on fsrv->trace_bits must not be moved by the - compiler below this point. Past this location, fsrv->trace_bits[] - behave very normally and do not have to be treated as volatile. */ - - MEM_BARRIER(); - - tb4 = *(u32 *)fsrv->trace_bits; + fsrv_run_result_t res = afl_fsrv_run_target(&afl->fsrv, &afl->stop_soon); #ifdef WORD_SIZE_64 classify_counts(afl, (u64 *)fsrv->trace_bits); @@ -128,35 +42,7 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { classify_counts(afl, (u32 *)fsrv->trace_bits); #endif /* ^WORD_SIZE_64 */ - fsrv->prev_timed_out = fsrv->child_timed_out; - - /* Report outcome to caller. */ - - if (WIFSIGNALED(status) && !afl->stop_soon) { - - afl->kill_signal = WTERMSIG(status); - - if (fsrv->child_timed_out && afl->kill_signal == SIGKILL) - return FAULT_TMOUT; - - return FAULT_CRASH; - - } - - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ - - if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { - - afl->kill_signal = 0; - return FAULT_CRASH; - - } - - if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG) - return FAULT_ERROR; - - return FAULT_NONE; + return res; } @@ -348,7 +234,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (!afl->dumb_mode && !afl->stage_cur && !count_bytes(afl, afl->fsrv.trace_bits)) { - fault = FAULT_NOINST; + fault = FSRV_RUN_NOINST; goto abort_calibration; } @@ -408,7 +294,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, parent. This is a non-critical problem, but something to warn the user about. */ - if (!afl->dumb_mode && first_run && !fault && !new_bits) fault = FAULT_NOBITS; + if (!afl->dumb_mode && first_run && !fault && !new_bits) fault = FSRV_RUN_NOBITS; abort_calibration: @@ -645,7 +531,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; - if (afl->stop_soon || fault == FAULT_ERROR) goto abort_trimming; + if (afl->stop_soon || fault == FSRV_RUN_ERROR) goto abort_trimming; /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ @@ -753,7 +639,7 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (afl->stop_soon) return 1; - if (fault == FAULT_TMOUT) { + if (fault == FSRV_RUN_TMOUT) { if (afl->subseq_tmouts++ > TMOUT_LIMIT) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d48dd5e3..52148dc2 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -108,14 +108,14 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, afl->start_time / 1000, cur_time / 1000, (cur_time - afl->start_time) / 1000, getpid(), afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, - afl->total_execs, - afl->total_execs / ((double)(get_cur_time() - afl->start_time) / 1000), + afl->fsrv.total_execs, + afl->fsrv.total_execs / ((double)(get_cur_time() - afl->start_time) / 1000), afl->queued_paths, afl->queued_favored, afl->queued_discovered, afl->queued_imported, afl->max_depth, afl->current_entry, afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable, stability, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->last_path_time / 1000, afl->last_crash_time / 1000, - afl->last_hang_time / 1000, afl->total_execs - afl->last_crash_execs, + afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout, afl->slowest_exec_ms, #ifdef __APPLE__ (unsigned long int)(rus.ru_maxrss >> 20), @@ -227,7 +227,7 @@ void show_stats(afl_state_t *afl) { if (afl->most_execs_key == 1) { - if (afl->most_execs <= afl->total_execs) { + if (afl->most_execs <= afl->fsrv.total_execs) { afl->most_execs_key = 2; afl->stop_soon = 2; @@ -251,11 +251,11 @@ void show_stats(afl_state_t *afl) { if (!afl->stats_last_execs) { afl->stats_avg_exec = - ((double)afl->total_execs) * 1000 / (cur_ms - afl->start_time); + ((double)afl->fsrv.total_execs) * 1000 / (cur_ms - afl->start_time); } else { - double cur_avg = ((double)(afl->total_execs - afl->stats_last_execs)) * + double cur_avg = ((double)(afl->fsrv.total_execs - afl->stats_last_execs)) * 1000 / (cur_ms - afl->stats_last_ms); /* If there is a dramatic (5x+) jump in speed, reset the indicator @@ -270,7 +270,7 @@ void show_stats(afl_state_t *afl) { } afl->stats_last_ms = cur_ms; - afl->stats_last_execs = afl->total_execs; + afl->stats_last_execs = afl->fsrv.total_execs; /* Tell the callers when to contact us (as measured in execs). */ @@ -543,14 +543,14 @@ void show_stats(afl_state_t *afl) { SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP " new crashes : %s%-22s" bSTG bV "\n", - u_stringify_int(IB(0), afl->total_execs), + u_stringify_int(IB(0), afl->fsrv.total_execs), afl->unique_crashes ? cLRD : cRST, tmp); } else { SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP " total crashes : %s%-22s" bSTG bV "\n", - u_stringify_int(IB(0), afl->total_execs), + u_stringify_int(IB(0), afl->fsrv.total_execs), afl->unique_crashes ? cLRD : cRST, tmp); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 07067691..9f17b61b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -480,7 +480,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'C': /* crash mode */ if (afl->crash_mode) FATAL("Multiple -C options not supported"); - afl->crash_mode = FAULT_CRASH; + afl->crash_mode = FSRV_RUN_CRASH; break; case 'n': /* dumb mode */ diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c index eea1cc95..16d6fe41 100644 --- a/src/afl-sharedmem.c +++ b/src/afl-sharedmem.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 3fcc1d2b..5f622c25 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -69,7 +69,7 @@ static u8 *in_data; /* Input data */ static u32 total, highest; /* tuple content information */ static u32 in_len, /* Input data length */ - arg_offset, total_execs; /* Total number of execs */ + arg_offset; /* Total number of execs */ static u8 quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ @@ -193,7 +193,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (cmin_mode) { - if (fsrv->child_timed_out) break; + if (fsrv->last_run_timed_out) break; if (!caa && child_crashed != cco) break; fprintf(f, "%u%u\n", fsrv->trace_bits[i], i); @@ -233,75 +233,18 @@ static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) { } -/* Execute target application. Returns 0 if the changes are a dud, or - 1 if they should be kept. */ +/* Execute target application. */ -static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, +void run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len) { - struct itimerval it; - int status = 0; - - memset(fsrv->trace_bits, 0, MAP_SIZE); - MEM_BARRIER(); - write_to_testcase(fsrv, mem, len); - s32 res; - - /* we have the fork server up and running, so simply - tell it to have at it, and then read back PID. */ - - if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { - - if (stop_soon) return 0; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - - } - - if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) { - - if (stop_soon) return 0; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - - } - - if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - - /* Configure timeout, wait for child, cancel timeout. */ - - if (fsrv->exec_tmout) { - - it.it_value.tv_sec = (fsrv->exec_tmout / 1000); - it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000; - - } - - setitimer(ITIMER_REAL, &it, NULL); - - if ((res = read(fsrv->fsrv_st_fd, &status, 4)) != 4) { - - if (stop_soon) return 0; - RPFATAL(res, "Unable to communicate with fork server (OOM?)"); - - } - - fsrv->child_pid = 0; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &it, NULL); - - MEM_BARRIER(); - - /* Clean up bitmap, analyze exit condition, etc. */ - - if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute '%s'", argv[0]); + fsrv_run_result_t res = afl_fsrv_run_target(fsrv, &stop_soon); + if (res == FSRV_RUN_NOINST || res == FSRV_RUN_ERROR) FATAL("Error running target"); classify_counts(fsrv->trace_bits, binary_mode ? count_class_binary : count_class_human); - total_execs++; if (stop_soon) { @@ -310,22 +253,6 @@ static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, } - /* Always discard inputs that time out. */ - - if (fsrv->child_timed_out) { return 0; } - - /* Handle crashing inputs depending on current mode. */ - - if (WIFSIGNALED(status) || - (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) || - (WIFEXITED(status) && WEXITSTATUS(status))) { - - return 0; - - } - - return 0; - } /* Read initial file. */ @@ -425,7 +352,7 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) { if (fsrv->exec_tmout) { - fsrv->child_timed_out = 0; + fsrv->last_run_timed_out = 0; it.it_value.tv_sec = (fsrv->exec_tmout / 1000); it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000; @@ -452,12 +379,12 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) { if (!quiet_mode) SAYF(cRST "-- Program output ends --\n"); - if (!fsrv->child_timed_out && !stop_soon && WIFSIGNALED(status)) + if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) child_crashed = 1; if (!quiet_mode) { - if (fsrv->child_timed_out) + if (fsrv->last_run_timed_out) SAYF(cLRD "\n+++ Program timed off +++\n" cRST); else if (stop_soon) SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST); @@ -980,7 +907,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (!quiet_mode) OKF("Processed %u input files.", total_execs); + if (!quiet_mode) OKF("Processed %llu input files.", fsrv->total_execs); closedir(dir_in); if (dir_out) closedir(dir_out); @@ -1010,7 +937,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_deinit(&shm); - u32 ret = child_crashed * 2 + fsrv->child_timed_out; + u32 ret = child_crashed * 2 + fsrv->last_run_timed_out; if (fsrv->target_path) ck_free(fsrv->target_path); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 31fad1df..999d5f65 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -67,7 +67,6 @@ static u8 *in_data; /* Input data for trimming */ static u32 in_len, /* Input data length */ orig_cksum, /* Original checksum */ - total_execs, /* Total number of execs */ missed_hangs, /* Misses due to hangs */ missed_crashes, /* Misses due to crashes */ missed_paths; /* Misses due to exec path diffs */ @@ -249,69 +248,11 @@ static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) { static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, u8 first_run) { - struct itimerval it; - int status = 0; - - u32 cksum; - - fsrv->child_timed_out = 0; - - memset(fsrv->trace_bits, 0, fsrv->map_size); - MEM_BARRIER(); - write_to_testcase(fsrv, mem, len); - s32 res; - - /* we have the fork server up and running, so simply - tell it to have at it, and then read back PID. */ - - if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { - - if (stop_soon) return 0; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - - } - - if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) { - - if (stop_soon) return 0; - RPFATAL(res, "Unable to request new process from fork server (OOM?)"); - - } - - if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - - /* Configure timeout, wait for child, cancel timeout. */ - - if (fsrv->exec_tmout) { - - it.it_value.tv_sec = (fsrv->exec_tmout / 1000); - it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000; - - } - - setitimer(ITIMER_REAL, &it, NULL); + fsrv_run_result_t ret = afl_fsrv_run_target(fsrv, &stop_soon); - if ((res = read(fsrv->fsrv_st_fd, &status, 4)) != 4) { - - if (stop_soon) return 0; - RPFATAL(res, "Unable to communicate with fork server (OOM?)"); - - } - - fsrv->child_pid = 0; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &it, NULL); - - MEM_BARRIER(); - - /* Clean up bitmap, analyze exit condition, etc. */ - - if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute '%s'", argv[0]); + if (ret == FSRV_RUN_ERROR) FATAL("Couldn't run child"); if (!hang_mode) { @@ -320,8 +261,6 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, } - total_execs++; - if (stop_soon) { SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST); @@ -334,25 +273,21 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, if (hang_mode) { - if (fsrv->child_timed_out) return 1; - - if (WIFSIGNALED(status) || - (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) || - (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) { - + switch (ret) + { + case FSRV_RUN_TMOUT: + return 1; + case FSRV_RUN_CRASH: missed_crashes++; - - } else { - + return 0; + default: missed_hangs++; - + return 0; } - return 0; - } - if (fsrv->child_timed_out) { + if (ret == FSRV_RUN_TMOUT) { missed_hangs++; return 0; @@ -361,9 +296,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, /* Handle crashing inputs depending on current mode. */ - if (WIFSIGNALED(status) || - (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) || - (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) { + if (ret == FSRV_RUN_CRASH) { if (first_run) crash_mode = 1; @@ -391,7 +324,9 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, } - cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST); + if (ret == FSRV_RUN_NOINST) FATAL("Binary not instrumented?"); + + u32 cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST); if (first_run) orig_cksum = cksum; @@ -640,11 +575,11 @@ finalize_all: SAYF("\n" cGRA " File size reduced by : " cRST "%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST - "%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA + "%0.02f%%\n" cGRA " Number of execs done : " cRST "%llu\n" cGRA " Fruitless execs : " cRST "termination=%u crash=%u\n\n", 100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s", - ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs, + ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), fsrv->total_execs, missed_paths, missed_crashes); return; @@ -652,13 +587,13 @@ finalize_all: SAYF("\n" cGRA " File size reduced by : " cRST "%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST - "%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA + "%0.02f%%\n" cGRA " Number of execs done : " cRST "%llu\n" cGRA " Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n", 100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s", - ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs, + ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), fsrv->total_execs, missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_hangs); - if (total_execs > 50 && missed_hangs * 10 > total_execs && !hang_mode) + if (fsrv->total_execs > 50 && missed_hangs * 10 > fsrv->total_execs && !hang_mode) WARNF(cLRD "Frequent timeouts - results may be skewed." cRST); } @@ -1139,13 +1074,13 @@ int main(int argc, char **argv_orig, char **envp) { run_target(fsrv, use_argv, in_data, in_len, 1); - if (hang_mode && !fsrv->child_timed_out) + if (hang_mode && !fsrv->last_run_timed_out) FATAL( "Target binary did not time out but hang minimization mode " "(-H) was set (-t %u).", fsrv->exec_tmout); - if (fsrv->child_timed_out && !hang_mode) + if (fsrv->last_run_timed_out && !hang_mode) FATAL( "Target binary times out (adjusting -t may help). Use -H to minimize a " "hang."); -- cgit 1.4.1 From b10007a7b5bcc231c98f9150b073daf3f1b18c95 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 16 Apr 2020 15:32:04 +0200 Subject: renamed duplicated func names --- include/afl-fuzz.h | 2 +- include/debug.h | 1 - src/afl-analyze.c | 12 ++++++------ src/afl-fuzz-bitmap.c | 2 +- src/afl-fuzz-cmplog.c | 2 +- src/afl-fuzz-mutators.c | 2 +- src/afl-fuzz-run.c | 10 +++++----- src/afl-showmap.c | 10 +++++----- src/afl-tmin.c | 12 ++++++------ 9 files changed, 26 insertions(+), 27 deletions(-) (limited to 'src/afl-fuzz-cmplog.c') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 7c6019e6..c92b002e 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -873,7 +873,7 @@ void show_init_stats(afl_state_t *); /* Run */ -fsrv_run_result_t run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); +fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); void write_to_testcase(afl_state_t *, void *, u32); u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8); void sync_fuzzers(afl_state_t *); diff --git a/include/debug.h b/include/debug.h index 890e8d70..4cce56b5 100644 --- a/include/debug.h +++ b/include/debug.h @@ -31,7 +31,6 @@ /* __FUNCTION__ is non-iso */ #ifdef __func__ #define __FUNCTION__ __func__ -#else #endif /******************* diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 952786b0..f2a54a20 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -209,7 +209,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) { /* Execute target application. Returns exec checksum, or 0 if program times out. */ -static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) { +static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { static struct itimerval it; int status = 0; @@ -560,16 +560,16 @@ static void analyze(char **argv) { code. */ in_data[i] ^= 0xff; - xor_ff = run_target(argv, in_data, in_len, 0); + xor_ff = analyze_run_target(argv, in_data, in_len, 0); in_data[i] ^= 0xfe; - xor_01 = run_target(argv, in_data, in_len, 0); + xor_01 = analyze_run_target(argv, in_data, in_len, 0); in_data[i] = (in_data[i] ^ 0x01) - 0x10; - sub_10 = run_target(argv, in_data, in_len, 0); + sub_10 = analyze_run_target(argv, in_data, in_len, 0); in_data[i] += 0x20; - add_10 = run_target(argv, in_data, in_len, 0); + add_10 = analyze_run_target(argv, in_data, in_len, 0); in_data[i] -= 0x10; /* Classify current behavior. */ @@ -1020,7 +1020,7 @@ int main(int argc, char **argv, char **envp) { ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", mem_limit, exec_tmout, edges_only ? ", edges only" : ""); - run_target(use_argv, in_data, in_len, 1); + analyze_run_target(use_argv, in_data, in_len, 1); if (child_timed_out) FATAL("Target binary times out (adjusting -t may help)."); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 92966c8c..6042b4b8 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -653,7 +653,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 new_fault; write_to_testcase(afl, mem, len); - new_fault = run_target(afl, &afl->fsrv, afl->hang_tmout); + new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout); /* A corner case that one user reported bumping into: increasing the timeout actually uncovers a crash. Make sure we don't discard it if diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index ab93d838..12c814ba 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -62,7 +62,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { write_to_testcase(afl, out_buf, len); - fault = run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout); + fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) return 1; diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 7bf23e84..a7d67569 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -239,7 +239,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { write_to_testcase(afl, retbuf, retlen); - fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 594a9390..6ad6444a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -33,7 +33,7 @@ /* Execute target application, monitoring for timeouts. Return status information. The called program will update afl->fsrv->trace_bits. */ -fsrv_run_result_t run_target(afl_state_t *afl, afl_forkserver_t *fsrv, +fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon); @@ -191,7 +191,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, write_to_testcase(afl, use_mem, q->len); - fault = run_target(afl, &afl->fsrv, use_tmout); + fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ @@ -409,7 +409,7 @@ void sync_fuzzers(afl_state_t *afl) { write_to_testcase(afl, mem, st.st_size); - fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) goto close_sync; @@ -496,7 +496,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); - fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; if (afl->stop_soon || fault == FSRV_RUN_ERROR) goto abort_trimming; @@ -603,7 +603,7 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { write_to_testcase(afl, out_buf, len); - fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) return 1; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 97f377f3..55f7d438 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -218,7 +218,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { /* Execute target application. */ -void run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, +static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len) { afl_fsrv_write_to_testcase(fsrv, mem, len); @@ -243,7 +243,7 @@ void run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, /* Read initial file. */ -u32 read_file(u8 *in_file) { +static u32 read_file(u8 *in_file) { struct stat st; s32 fd = open(in_file, O_RDONLY); @@ -268,7 +268,7 @@ u32 read_file(u8 *in_file) { /* Execute target application. */ -static void run_target(afl_forkserver_t *fsrv, char **argv) { +static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { static struct itimerval it; int status = 0; @@ -883,7 +883,7 @@ int main(int argc, char **argv_orig, char **envp) { if (read_file(infile)) { - run_target_forkserver(fsrv, use_argv, in_data, in_len); + showmap_run_target_forkserver(fsrv, use_argv, in_data, in_len); ck_free(in_data); tcnt = write_results_to_file(fsrv, outfile); @@ -898,7 +898,7 @@ int main(int argc, char **argv_orig, char **envp) { } else { - run_target(fsrv, use_argv); + showmap_run_target(fsrv, use_argv); tcnt = write_results_to_file(fsrv, out_file); } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 3330561b..409bf01d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -214,7 +214,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) { /* Execute target application. Returns 0 if the changes are a dud, or 1 if they should be kept. */ -static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, +static u8 tmin_run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, u8 first_run) { afl_fsrv_write_to_testcase(fsrv, mem, len); @@ -336,7 +336,7 @@ static void minimize(afl_forkserver_t *fsrv, char **argv) { memset(tmp_buf + set_pos, '0', use_len); u8 res; - res = run_target(fsrv, argv, tmp_buf, in_len, 0); + res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0); if (res) { @@ -409,7 +409,7 @@ next_del_blksize: /* Tail */ memcpy(tmp_buf + del_pos, in_data + del_pos + del_len, tail_len); - res = run_target(fsrv, argv, tmp_buf, del_pos + tail_len, 0); + res = tmin_run_target(fsrv, argv, tmp_buf, del_pos + tail_len, 0); if (res) { @@ -472,7 +472,7 @@ next_del_blksize: for (r = 0; r < in_len; r++) if (tmp_buf[r] == i) tmp_buf[r] = '0'; - res = run_target(fsrv, argv, tmp_buf, in_len, 0); + res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0); if (res) { @@ -508,7 +508,7 @@ next_del_blksize: if (orig == '0') continue; tmp_buf[i] = '0'; - res = run_target(fsrv, argv, tmp_buf, in_len, 0); + res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0); if (res) { @@ -1036,7 +1036,7 @@ int main(int argc, char **argv_orig, char **envp) { ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : ""); - run_target(fsrv, use_argv, in_data, in_len, 1); + tmin_run_target(fsrv, use_argv, in_data, in_len, 1); if (hang_mode && !fsrv->last_run_timed_out) FATAL( -- cgit 1.4.1