From 271a27cde0eb99c3ede7d2d8dcc58b0b6ed7bb47 Mon Sep 17 00:00:00 2001 From: lahiri-phdworks Date: Tue, 24 Oct 2023 19:34:25 +0530 Subject: [PATCH] [init] Generation impl clean-up --- GNUmakefile | 5 - GNUmakefile.gcc_plugin | 12 +- GNUmakefile.llvm | 5 - src/afl-fuzz-bitmap.c | 156 +----------- src/afl-fuzz-init.c | 545 +++-------------------------------------- src/afl-fuzz-queue.c | 285 --------------------- 6 files changed, 39 insertions(+), 969 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 9f3ada0ebf..88816e8585 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -41,11 +41,6 @@ ARCH = $(shell uname -m) $(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH)) -ifdef STABLE_DEBUG - CFLAGS += -DSTABLE_DEBUG - CXXFLAGS += -DSTABLE_DEBUG -endif - ifdef NO_SPLICING override CFLAGS_OPT += -DNO_SPLICING endif diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index f89754cbff..9a1e6d279e 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -28,11 +28,7 @@ MAN_PATH ?= $(PREFIX)/share/man/man8 VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) -ifdef STABLE_DEBUG - CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1 -DSTABLE_DEBUG -else - CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1 -endif +CFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1 CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ @@ -40,11 +36,7 @@ CFLAGS_SAFE := -Wall -Iinclude -Wno-pointer-sign \ -Wno-unused-function override CFLAGS += $(CFLAGS_SAFE) -ifdef STABLE_DEBUG - CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1 -DSTABLE_DEBUG -else - CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1 -endif +CXXFLAGS ?= -O3 -g -funroll-loops -D_FORTIFY_SOURCE=1 CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11 diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index d2da7d0b94..65786d8b0e 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -32,11 +32,6 @@ VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2 SYS = $(shell uname -s) -ifdef STABLE_DEBUG - CFLAGS += -DSTABLE_DEBUG - CXXFLAGS += -DSTABLE_DEBUG -endif - ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index a6ff3dc7ec..362c61a9c4 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -34,7 +34,6 @@ interesting input without rediscovering all the others. */ void write_bitmap(afl_state_t *afl) { - u8 fname[PATH_MAX]; s32 fd; @@ -49,40 +48,33 @@ void write_bitmap(afl_state_t *afl) { ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname); close(fd); - } /* 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(afl_state_t *afl, u8 *mem) { - u32 *ptr = (u32 *)mem; u32 i = ((afl->fsrv.real_map_size + 3) >> 2); u32 ret = 0; while (i--) { - u32 v = *(ptr++); /* This gets called on the inverse, virgin bitmap; optimize for sparse data. */ if (likely(v == 0xffffffff)) { - ret += 32; continue; - } v -= ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24; - } return ret; - } /* Count the number of bytes set in the bitmap. Called fairly sporadically, @@ -90,13 +82,11 @@ u32 count_bits(afl_state_t *afl, u8 *mem) { new paths. */ u32 count_bytes(afl_state_t *afl, u8 *mem) { - u32 *ptr = (u32 *)mem; u32 i = ((afl->fsrv.real_map_size + 3) >> 2); u32 ret = 0; while (i--) { - u32 v = *(ptr++); if (likely(!v)) { continue; } @@ -104,24 +94,20 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) { if (v & 0x0000ff00U) { ++ret; } if (v & 0x00ff0000U) { ++ret; } if (v & 0xff000000U) { ++ret; } - } return ret; - } /* 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(afl_state_t *afl, u8 *mem) { - u32 *ptr = (u32 *)mem; u32 i = ((afl->fsrv.real_map_size + 3) >> 2); u32 ret = 0; while (i--) { - u32 v = *(ptr++); /* This is called on the virgin bitmap, so optimize for the most likely @@ -132,11 +118,9 @@ u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) { if ((v & 0x0000ff00U) != 0x0000ff00U) { ++ret; } if ((v & 0x00ff0000U) != 0x00ff0000U) { ++ret; } if ((v & 0xff000000U) != 0xff000000U) { ++ret; } - } return ret; - } /* Destructively simplify trace by eliminating hit count information @@ -170,20 +154,14 @@ const u8 count_class_lookup8[256] = { u16 count_class_lookup16[65536]; void init_count_class16(void) { - u32 b1, b2; for (b1 = 0; b1 < 256; b1++) { - for (b2 = 0; b2 < 256; b2++) { - count_class_lookup16[(b1 << 8) + b2] = (count_class_lookup8[b1] << 8) | count_class_lookup8[b2]; - } - } - } /* Import coverage processing routines. */ @@ -203,7 +181,6 @@ void init_count_class16(void) { it needs to be fast. We do this in 32-bit and 64-bit flavors. */ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { - #ifdef WORD_SIZE_64 u64 *current = (u64 *)afl->fsrv.trace_bits; @@ -218,23 +195,20 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { u32 i = ((afl->fsrv.real_map_size + 3) >> 2); -#endif /* ^WORD_SIZE_64 */ +#endif /* ^WORD_SIZE_64 */ u8 ret = 0; while (i--) { - if (unlikely(*current)) discover_word(&ret, current, virgin); current++; virgin++; - } if (unlikely(ret) && likely(virgin_map == afl->virgin_bits)) afl->bitmap_changed = 1; return ret; - } /* A combination of classify_counts and has_new_bits. If 0 is returned, then the @@ -248,7 +222,6 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { * return has_new_bits(). */ inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) { - /* Handle the hot path first: no new coverage */ u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size; @@ -262,10 +235,9 @@ inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) { if (!skim((u32 *)virgin_map, (u32 *)afl->fsrv.trace_bits, (u32 *)end)) return 0; -#endif /* ^WORD_SIZE_64 */ +#endif /* ^WORD_SIZE_64 */ classify_counts(&afl->fsrv); return has_new_bits(afl, virgin_map); - } /* Compact trace bytes into a smaller bitmap. We effectively just drop the @@ -273,16 +245,12 @@ inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) { new paths. */ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { - u32 i = 0; while (i < afl->fsrv.map_size) { - if (*(src++)) { dst[i >> 3] |= 1 << (i & 7); } ++i; - } - } #ifndef SIMPLE_FILES @@ -291,14 +259,11 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { - u8 is_timeout = 0; if (new_bits & 0xf0) { - new_bits -= 0x80; is_timeout = 1; - } size_t real_max_len = @@ -306,17 +271,13 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { u8 *ret = afl->describe_op_buf_256; if (unlikely(afl->syncing_party)) { - sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case); } else { - sprintf(ret, "src:%06u", afl->current_entry); if (afl->splicing_with >= 0) { - sprintf(ret + strlen(ret), "+%06d", afl->splicing_with); - } sprintf(ret + strlen(ret), ",time:%llu,execs:%llu", @@ -325,7 +286,6 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { if (afl->current_custom_fuzz && afl->current_custom_fuzz->afl_custom_describe) { - /* We are currently in a custom mutator that supports afl_custom_describe, * use it! */ @@ -341,43 +301,32 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { afl->current_custom_fuzz->afl_custom_describe( afl->current_custom_fuzz->data, size_left); if (!custom_description || !custom_description[0]) { - DEBUGF("Error getting a description from afl_custom_describe"); /* Take the stage name as description fallback */ sprintf(ret + len_current, "op:%s", afl->stage_short); } else { - /* We got a proper custom description, use it */ strncat(ret + len_current, custom_description, size_left); - } } else { - /* Normal testcase descriptions start here */ sprintf(ret + strlen(ret), ",op:%s", afl->stage_short); if (afl->stage_cur_byte >= 0) { - sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte); if (afl->stage_val_type != STAGE_VAL_NONE) { - sprintf(ret + strlen(ret), ",val:%s%+d", (afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "", afl->stage_cur_val); - } } else { - sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val); - } - } - } if (is_timeout) { strcat(ret, ",+tout"); } @@ -388,15 +337,13 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { FATAL("describe string is too long"); return ret; - } -#endif /* !SIMPLE_FILES */ +#endif /* !SIMPLE_FILES */ /* Write a message accompanying the crash directory :-) */ void write_crash_readme(afl_state_t *afl) { - u8 fn[PATH_MAX]; s32 fd; FILE *f; @@ -414,10 +361,8 @@ void write_crash_readme(afl_state_t *afl) { f = fdopen(fd, "w"); if (unlikely(!f)) { - close(fd); return; - } fprintf( @@ -442,10 +387,9 @@ void write_crash_readme(afl_state_t *afl) { afl->orig_cmdline, stringify_mem_size(val_buf, sizeof(val_buf), - afl->fsrv.mem_limit << 20)); /* ignore errors */ + afl->fsrv.mem_limit << 20)); /* ignore errors */ fclose(f); - } /* Check if the result of an execve() during routine fuzzing is interesting, @@ -454,13 +398,10 @@ void write_crash_readme(afl_state_t *afl) { u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { - if (unlikely(len == 0)) { return 0; } if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) { - return 0; - } u8 fn[PATH_MAX]; @@ -475,7 +416,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { /* Generating a hash on every input is super expensive. Bad idea and should only be used for special schedules */ if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) { - classify_counts(&afl->fsrv); classified = 1; need_hash = 0; @@ -485,31 +425,24 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { /* Saturated increment */ if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)) afl->n_fuzz[cksum % N_FUZZ_SIZE]++; - } if (likely(fault == afl->crash_mode)) { - /* Keep only if there are new bits in the map, add to queue for future fuzzing, etc. */ if (likely(classified)) { - new_bits = has_new_bits(afl, afl->virgin_bits); } else { - new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); if (unlikely(new_bits)) { classified = 1; } - } if (likely(!new_bits)) { - if (unlikely(afl->crash_mode)) { ++afl->total_crashes; } return 0; - } save_to_queue: @@ -526,80 +459,58 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { queue_fn = alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_items); -#endif /* ^!SIMPLE_FILES */ +#endif /* ^!SIMPLE_FILES */ fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); } ck_write(fd, mem, len, queue_fn); close(fd); -#ifdef STABLE_DEBUG - DEBUGF("[add_to_queue] AFL added this (save_if_interesting)\n"); -#endif add_to_queue(afl, queue_fn, len, 0); if (unlikely(afl->fuzz_mode) && likely(afl->switch_fuzz_mode && !afl->non_instrumented_mode)) { - if (afl->afl_env.afl_no_ui) { - ACTF("New coverage found, switching back to exploration mode."); - } afl->fuzz_mode = 0; - } #ifdef INTROSPECTION if (afl->custom_mutators_count && afl->current_custom_fuzz) { - LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - if (afl->current_custom_fuzz == el && el->afl_custom_introspection) { - const char *ptr = el->afl_custom_introspection(el->data); if (ptr != NULL && *ptr != 0) { - fprintf(afl->introspection_file, "QUEUE CUSTOM %s = %s\n", ptr, afl->queue_top->fname); - } - } - }); } else if (afl->mutation[0] != 0) { - fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation, afl->queue_top->fname); - } #endif if (new_bits == 2) { - afl->queue_top->has_new_cov = 1; ++afl->queued_with_cov; - } if (unlikely(need_hash && new_bits)) { - /* due to classify counts we have to recalculate the checksum */ afl->queue_top->exec_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); need_hash = 0; - } /* For AFLFast schedules we update the new queue entry */ if (likely(cksum)) { - afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; - } /* Try to calibrate inline; this also calls update_bitmap_score() when @@ -607,23 +518,17 @@ 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 == FSRV_RUN_ERROR)) { - FATAL("Unable to execute target application"); - } if (likely(afl->q_testcase_max_cache_size)) { - queue_testcase_store_mem(afl, afl->queue_top, mem); - } keeping = 1; - } switch (fault) { - case FSRV_RUN_TMOUT: /* Timeouts are not very interesting, but we're still obliged to keep @@ -636,46 +541,33 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (afl->saved_hangs >= KEEP_UNIQUE_HANG) { return keeping; } if (likely(!afl->non_instrumented_mode)) { - if (unlikely(!classified)) { - classify_counts(&afl->fsrv); classified = 1; - } simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_tmout)) { return keeping; } - } is_timeout = 0x80; #ifdef INTROSPECTION if (afl->custom_mutators_count && afl->current_custom_fuzz) { - LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - if (afl->current_custom_fuzz == el && el->afl_custom_introspection) { - const char *ptr = el->afl_custom_introspection(el->data); if (ptr != NULL && *ptr != 0) { - fprintf(afl->introspection_file, "UNIQUE_TIMEOUT CUSTOM %s = %s\n", ptr, afl->queue_top->fname); - } - } - }); } else if (afl->mutation[0] != 0) { - fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation); - } #endif @@ -685,18 +577,14 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { is already generous). */ if (afl->fsrv.exec_tmout < afl->hang_tmout) { - u8 new_fault; u32 tmp_len = write_to_testcase(afl, &mem, len, 0); if (likely(tmp_len)) { - len = tmp_len; } else { - len = write_to_testcase(afl, &mem, len, 1); - } new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout); @@ -707,26 +595,18 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { so. */ if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) { - goto keep_as_crash; - } if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) { - if (afl->afl_env.afl_keep_timeouts) { - ++afl->saved_tmouts; goto save_to_queue; } else { - return keeping; - } - } - } #ifndef SIMPLE_FILES @@ -740,7 +620,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir, afl->saved_hangs); -#endif /* ^!SIMPLE_FILES */ +#endif /* ^!SIMPLE_FILES */ ++afl->saved_hangs; @@ -761,25 +641,19 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (afl->saved_crashes >= KEEP_UNIQUE_CRASH) { return keeping; } if (likely(!afl->non_instrumented_mode)) { - if (unlikely(!classified)) { - classify_counts(&afl->fsrv); classified = 1; - } simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; } - } if (unlikely(!afl->saved_crashes) && (afl->afl_env.afl_no_crash_readme != 1)) { - write_crash_readme(afl); - } #ifndef SIMPLE_FILES @@ -793,38 +667,28 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal); -#endif /* ^!SIMPLE_FILES */ +#endif /* ^!SIMPLE_FILES */ ++afl->saved_crashes; #ifdef INTROSPECTION if (afl->custom_mutators_count && afl->current_custom_fuzz) { - LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - if (afl->current_custom_fuzz == el && el->afl_custom_introspection) { - const char *ptr = el->afl_custom_introspection(el->data); if (ptr != NULL && *ptr != 0) { - fprintf(afl->introspection_file, "UNIQUE_CRASH CUSTOM %s = %s\n", ptr, afl->queue_top->fname); - } - } - }); } else if (afl->mutation[0] != 0) { - fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation); - } #endif if (unlikely(afl->infoexec)) { - // if the user wants to be informed on new crashes - do that #if !TARGET_OS_IPHONE // we dont care if system errors, but we dont want a @@ -835,7 +699,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #else WARNF("command execution unsupported"); #endif - } afl->last_crash_time = get_cur_time(); @@ -848,7 +711,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { default: return keeping; - } /* If we're here, we apparently want to save the crash or hang @@ -861,7 +723,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifdef __linux__ if (afl->fsrv.nyx_mode && fault == FSRV_RUN_CRASH) { - u8 fn_log[PATH_MAX]; (void)(snprintf(fn_log, PATH_MAX, "%s.log", fn) + 1); @@ -873,12 +734,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len, fn_log); close(fd); - } #endif return keeping; - } - diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 1b7f865023..df4476f459 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -34,7 +34,6 @@ /* bind process to a specific cpu. Returns 0 on failure. */ static u8 bind_cpu(afl_state_t *afl, s32 cpuid) { - #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) cpu_set_t c; #elif defined(__NetBSD__) @@ -74,10 +73,8 @@ static u8 bind_cpu(afl_state_t *afl, s32 cpuid) { #elif defined(__NetBSD__) if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) { - cpuset_destroy(c); return 0; - } cpuset_destroy(c); @@ -86,10 +83,8 @@ static u8 bind_cpu(afl_state_t *afl, s32 cpuid) { #elif defined(__sun) if (pset_bind(c, P_PID, getpid(), NULL)) { - pset_destroy(c); return 0; - } pset_destroy(c); @@ -103,90 +98,69 @@ static u8 bind_cpu(afl_state_t *afl, s32 cpuid) { return 1; #endif - } /* Build a list of processes bound to specific cores. Returns -1 if nothing can be found. Assumes an upper bound of 4k CPUs. */ void bind_to_free_cpu(afl_state_t *afl) { - u8 cpu_used[4096] = {0}; u8 lockfile[PATH_MAX] = ""; s32 i; if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) { - if (afl->cpu_to_bind != -1) { - FATAL("-b and AFL_NO_AFFINITY are mututally exclusive."); - } WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set)."); return; - } if (afl->cpu_to_bind != -1) { - if (!bind_cpu(afl, afl->cpu_to_bind)) { - if (afl->afl_env.afl_try_affinity) { - WARNF( "Could not bind to requested CPU %d! Make sure you passed a valid " "-b.", afl->cpu_to_bind); } else { - FATAL( "Could not bind to requested CPU %d! Make sure you passed a valid " "-b.", afl->cpu_to_bind); - } } else { - OKF("CPU binding request using -b %d successful.", afl->cpu_to_bind); - } return; - } if (afl->cpu_core_count < 2) { return; } if (afl->sync_id) { - s32 lockfd, first = 1; snprintf(lockfile, sizeof(lockfile), "%s/.affinity_lock", afl->sync_dir); setenv(CPU_AFFINITY_ENV_VAR, lockfile, 1); do { - if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION)) < 0) { - if (first) { - WARNF("CPU affinity lock file present, waiting ..."); first = 0; - } usleep(1000); - } } while (lockfd < 0); close(lockfd); - } #if defined(__linux__) @@ -196,11 +170,9 @@ void bind_to_free_cpu(afl_state_t *afl) { d = opendir("/proc"); if (!d) { - if (lockfile[0]) unlink(lockfile); WARNF("Unable to access /proc - can't scan for free CPU cores."); return; - } ACTF("Checking CPU core loadout..."); @@ -211,7 +183,6 @@ void bind_to_free_cpu(afl_state_t *afl) { all real-world use cases. */ while ((de = readdir(d))) { - u8 fn[PATH_MAX]; FILE *f; u8 tmp[MAX_LINE]; @@ -224,7 +195,6 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!(f = fopen(fn, "r"))) { continue; } while (fgets(tmp, MAX_LINE, f)) { - u32 hval; /* Processes without VmSize are probably kernel tasks. */ @@ -234,16 +204,12 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!strncmp(tmp, "Cpus_allowed_list:\t", 19) && !strchr(tmp, '-') && !strchr(tmp, ',') && sscanf(tmp + 19, "%u", &hval) == 1 && hval < sizeof(cpu_used) && has_vmsize) { - cpu_used[hval] = 1; break; - } - } fclose(f); - } closedir(d); @@ -257,10 +223,8 @@ void bind_to_free_cpu(afl_state_t *afl) { size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]); if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) { - if (lockfile[0]) unlink(lockfile); return; - } proccount = nprocs / sizeof(*procs); @@ -268,11 +232,9 @@ void bind_to_free_cpu(afl_state_t *afl) { procs = ck_alloc(nprocs); if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) { - if (lockfile[0]) unlink(lockfile); ck_free(procs); return; - } for (i = 0; i < (s32)proccount; i++) { @@ -296,7 +258,6 @@ void bind_to_free_cpu(afl_state_t *afl) { cpu_used[procs[i].kp_lwp.kl_cpuid] = 1; #endif - } ck_free(procs); @@ -312,10 +273,8 @@ void bind_to_free_cpu(afl_state_t *afl) { size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]); if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) { - if (lockfile[0]) unlink(lockfile); return; - } proccount = nprocs / sizeof(struct kinfo_proc2); @@ -323,18 +282,14 @@ void bind_to_free_cpu(afl_state_t *afl) { s_name[5] = proccount; if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) { - if (lockfile[0]) unlink(lockfile); ck_free(procs); return; - } for (i = 0; i < (s32)proccount; i++) { - if (procs[i].p_cpuid < sizeof(cpu_used) && procs[i].p_pctcpu > 0) cpu_used[procs[i].p_cpuid] = 1; - } ck_free(procs); @@ -354,19 +309,15 @@ void bind_to_free_cpu(afl_state_t *afl) { k = kstat_lookup(m, "unix", 0, "system_misc"); if (!k) { - if (lockfile[0]) unlink(lockfile); kstat_close(m); return; - } if (kstat_read(m, k, NULL)) { - if (lockfile[0]) unlink(lockfile); kstat_close(m); return; - } n = kstat_data_lookup(k, "ncpus"); @@ -375,21 +326,17 @@ void bind_to_free_cpu(afl_state_t *afl) { if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used); for (i = 0; i < (s32)ncpus; i++) { - k = kstat_lookup(m, "cpu_stat", i, NULL); if (kstat_read(m, k, &cs)) { - if (lockfile[0]) unlink(lockfile); kstat_close(m); return; - } if (cs.cpu_sysinfo.cpu[CPU_IDLE] > 0) continue; if (cs.cpu_sysinfo.cpu[CPU_USER] > 0 || cs.cpu_sysinfo.cpu[CPU_KERNEL] > 0) cpu_used[i] = 1; - } kstat_close(m); @@ -402,7 +349,6 @@ void bind_to_free_cpu(afl_state_t *afl) { #if !defined(__aarch64__) && !defined(__arm__) && !defined(__arm64__) for (i = 0; i < afl->cpu_core_count; i++) { - #else /* many ARM devices have performance and efficiency cores, the slower @@ -417,23 +363,19 @@ void bind_to_free_cpu(afl_state_t *afl) { OKF("Found a free CPU core, try binding to #%u.", i); if (bind_cpu(afl, i)) { - #ifdef __linux__ if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = i; } #endif /* Success :) */ break; - } WARNF("setaffinity failed to CPU %d, trying next CPU", i); - } if (lockfile[0]) unlink(lockfile); if (i == afl->cpu_core_count || i == -1) { - SAYF("\n" cLRD "[-] " cRST "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). " @@ -446,28 +388,22 @@ void bind_to_free_cpu(afl_state_t *afl) { "AFL_NO_AFFINITY and try again.\n"); if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); } - } - } -#endif /* HAVE_AFFINITY */ +#endif /* HAVE_AFFINITY */ /* Shuffle an array of pointers. Might be slightly biased. */ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) { - u32 i; for (i = 0; i < cnt - 2; ++i) { - u32 j = i + rand_below(afl, cnt - i); void *s = ptrs[i]; ptrs[i] = ptrs[j]; ptrs[j] = s; - } - } /* Read all testcases from foreign input directories, then queue them for @@ -475,7 +411,6 @@ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) { Does not descend into subdirectories! */ void read_foreign_testcases(afl_state_t *afl, int first) { - if (!afl->foreign_sync_cnt) return; struct dirent **nl; @@ -486,32 +421,24 @@ void read_foreign_testcases(afl_state_t *afl, int first) { u8 foreign_name[16]; for (iter = 0; iter < afl->foreign_sync_cnt; iter++) { - if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) { - if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir); time_t mtime_max = 0; u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/'); if (!name) { - name = afl->foreign_syncs[iter].dir; } else { - ++name; - } if (!strcmp(name, "queue") || !strcmp(name, "out") || !strcmp(name, "default")) { - snprintf(foreign_name, sizeof(foreign_name), "foreign_%u", iter); } else { - snprintf(foreign_name, sizeof(foreign_name), "%s_%u", name, iter); - } /* We do not use sorting yet and do a more expensive mtime check instead. @@ -520,29 +447,21 @@ void read_foreign_testcases(afl_state_t *afl, int first) { nl_cnt = scandir(afl->foreign_syncs[iter].dir, &nl, NULL, NULL); if (nl_cnt < 0) { - if (first) { - WARNF("Unable to open directory '%s'", afl->foreign_syncs[iter].dir); sleep(1); - } continue; - } if (nl_cnt == 0) { - if (first) { - WARNF("directory %s is currently empty", afl->foreign_syncs[iter].dir); - } continue; - } /* Show stats */ @@ -554,52 +473,41 @@ void read_foreign_testcases(afl_state_t *afl, int first) { afl->stage_max = 0; for (i = 0; i < (u32)nl_cnt; ++i) { - struct stat st; u8 *fn2 = alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name); - free(nl[i]); /* not tracked */ + free(nl[i]); /* not tracked */ if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) { - if (first) PFATAL("Unable to access '%s'", fn2); continue; - } /* we detect new files by their mtime */ if (likely(st.st_mtime <= afl->foreign_syncs[iter].mtime)) { - ck_free(fn2); continue; - } /* This also takes care of . and .. */ if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { - ck_free(fn2); continue; - } if (st.st_size > MAX_FILE) { - if (first) { - WARNF( "Test case '%s' is too big (%s, limit is %s), skipping", fn2, stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); - } ck_free(fn2); continue; - } // lets do not use add_to_queue(afl, fn2, st.st_size, 0); @@ -607,20 +515,16 @@ void read_foreign_testcases(afl_state_t *afl, int first) { int fd = open(fn2, O_RDONLY); if (fd < 0) { - ck_free(fn2); continue; - } u8 fault; u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mem == MAP_FAILED) { - ck_free(fn2); continue; - } u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1); @@ -632,30 +536,23 @@ void read_foreign_testcases(afl_state_t *afl, int first) { close(fd); if (st.st_mtime > mtime_max) mtime_max = st.st_mtime; - } afl->foreign_syncs[iter].mtime = mtime_max; - free(nl); /* not tracked */ - + free(nl); /* not tracked */ } - } if (first) { - afl->last_find_time = 0; afl->queued_at_start = afl->queued_items; - } - } /* Read all testcases from the input directory, then queue them for testing. Called at startup. */ void read_testcases(afl_state_t *afl, u8 *directory) { - struct dirent **nl; s32 nl_cnt, subdirs = 1; u32 i; @@ -665,21 +562,16 @@ void read_testcases(afl_state_t *afl, u8 *directory) { /* Auto-detect non-in-place resumption attempts. */ if (dir == NULL) { - fn1 = alloc_printf("%s/queue", afl->in_dir); if (!access(fn1, F_OK)) { - afl->in_dir = fn1; subdirs = 0; } else { - ck_free(fn1); - } dir = afl->in_dir; - } ACTF("Scanning '%s'...", dir); @@ -691,9 +583,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { nl_cnt = scandir(dir, &nl, NULL, alphasort); if (nl_cnt < 0 && directory == NULL) { - if (errno == ENOENT || errno == ENOTDIR) { - SAYF("\n" cLRD "[-] " cRST "The input directory does not seem to be valid - try again. The " "fuzzer needs\n" @@ -702,38 +592,29 @@ void read_testcases(afl_state_t *afl, u8 *directory) { " or so. The cases must be stored as regular files directly in " "the input\n" " directory.\n"); - } PFATAL("Unable to open '%s'", dir); - } if (unlikely(afl->old_seed_selection && afl->shuffle_queue && nl_cnt > 1)) { - ACTF("Shuffling queue..."); shuffle_ptrs(afl, (void **)nl, nl_cnt); - } // if (getenv("MYTEST")) afl->in_place_resume = 1; if (nl_cnt) { - u32 done = 0; if (unlikely(afl->in_place_resume)) { - i = nl_cnt; } else { - i = 0; - } do { - if (unlikely(afl->in_place_resume)) { --i; } struct stat st; @@ -745,39 +626,31 @@ void read_testcases(afl_state_t *afl, u8 *directory) { u8 passed_det = 0; if (lstat(fn2, &st) || access(fn2, R_OK)) { - PFATAL("Unable to access '%s'", fn2); - } /* obviously we want to skip "descending" into . and .. directories, however it is a good idea to skip also directories that start with a dot */ if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { - - free(nl[i]); /* not tracked */ + free(nl[i]); /* not tracked */ read_testcases(afl, fn2); ck_free(fn2); goto next_entry; - } free(nl[i]); if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { - ck_free(fn2); goto next_entry; - } if (st.st_size > MAX_FILE) { - WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); - } /* Check for metadata that indicates that deterministic fuzzing @@ -787,58 +660,40 @@ void read_testcases(afl_state_t *afl, u8 *directory) { if (!access(dfn, F_OK)) { passed_det = 1; } -#ifdef STABLE_DEBUG - DEBUGF("[add_to_queue] AFL queued it for inital testing (read_testcases)\n"); -#endif - add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size, passed_det); if (unlikely(afl->shm.cmplog_mode)) { - if (afl->cmplog_lvl == 1) { - if (!afl->cmplog_max_filesize || afl->cmplog_max_filesize < st.st_size) { - afl->cmplog_max_filesize = st.st_size; - } } else if (afl->cmplog_lvl == 2) { - if (!afl->cmplog_max_filesize || afl->cmplog_max_filesize > st.st_size) { - afl->cmplog_max_filesize = st.st_size; - } - } - } next_entry: if (unlikely(afl->in_place_resume)) { - if (unlikely(i == 0)) { done = 1; } } else { - if (unlikely(++i >= (u32)nl_cnt)) { done = 1; } - } } while (!done); - } // if (getenv("MYTEST")) afl->in_place_resume = 0; - free(nl); /* not tracked */ + free(nl); /* not tracked */ if (!afl->queued_items && directory == NULL) { - SAYF("\n" cLRD "[-] " cRST "Looks like there are no valid test cases in the input directory! The " "fuzzer\n" @@ -849,39 +704,30 @@ void read_testcases(afl_state_t *afl, u8 *directory) { " input directory.\n"); FATAL("No usable test cases in '%s'", afl->in_dir); - } if (unlikely(afl->shm.cmplog_mode)) { - if (afl->cmplog_max_filesize < 1024) { - afl->cmplog_max_filesize = 1024; } else { - afl->cmplog_max_filesize = (((afl->cmplog_max_filesize >> 10) + 1) << 10); - } - } afl->last_find_time = 0; afl->queued_at_start = afl->queued_items; - } /* Perform dry run of all test cases to confirm that the app is working as expected. This is done only for the initial inputs, and only once. */ void perform_dry_run(afl_state_t *afl) { - struct queue_entry *q; u32 cal_failures = 0, idx; u8 *use_mem; for (idx = 0; idx < afl->queued_items; idx++) { - q = afl->queue_buf[idx]; if (unlikely(!q || q->disabled)) { continue; } @@ -889,10 +735,8 @@ void perform_dry_run(afl_state_t *afl) { s32 fd; if (unlikely(!q->len)) { - WARNF("Skipping 0-sized entry in queue (%s)", q->fname); continue; - } if (afl->afl_env.afl_cmplog_only_new) { q->colorized = CMPLOG_LVL_MAX; } @@ -915,16 +759,13 @@ void perform_dry_run(afl_state_t *afl) { if (afl->stop_soon) { return; } if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) { - SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us, hash = " "%016llx\n" cRST, q->len, q->bitmap_size, q->exec_us, q->exec_cksum); - } switch (res) { - case FSRV_RUN_OK: if (afl->crash_mode) { FATAL("Test case '%s' does *NOT* crash", fn); } @@ -934,7 +775,6 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_TMOUT: if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) { - /* if we have a timeout but a timeout value was given then always skip. The '+' meaning has been changed! */ WARNF("Test case results in a timeout (skipping)"); @@ -944,22 +784,18 @@ void perform_dry_run(afl_state_t *afl) { q->perf_score = 0; if (!q->was_fuzzed) { - q->was_fuzzed = 1; afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; - } break; } else { - static int say_once = 0; if (!say_once) { - SAYF( "\n" cLRD "[-] " cRST "The program took more than %u ms to process one of the " @@ -975,22 +811,17 @@ void perform_dry_run(afl_state_t *afl) { afl->fsrv.exec_tmout); if (!afl->afl_env.afl_ignore_seed_problems) { - FATAL("Test case '%s' results in a timeout", fn); - } say_once = 1; - } if (!q->was_fuzzed) { - q->was_fuzzed = 1; afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; - } q->disabled = 1; @@ -998,7 +829,6 @@ void perform_dry_run(afl_state_t *afl) { WARNF("Test case '%s' results in a timeout, skipping", fn); break; - } case FSRV_RUN_CRASH: @@ -1006,7 +836,6 @@ void perform_dry_run(afl_state_t *afl) { if (afl->crash_mode) { break; } if (afl->fsrv.mem_limit) { - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; SAYF("\n" cLRD "[-] " cRST @@ -1053,7 +882,6 @@ void perform_dry_run(afl_state_t *afl) { afl->fsrv.mem_limit - 1); } else { - SAYF("\n" cLRD "[-] " cRST "Oops, the program crashed with one of the test cases provided. " "There are\n" @@ -1077,23 +905,19 @@ void perform_dry_run(afl_state_t *afl) { "other options\n" " fail, poke the Awesome Fuzzing Discord for " "troubleshooting tips.\n"); - } #undef MSG_ULIMIT_USAGE #undef MSG_FORK_ON_APPLE if (afl->fsrv.uses_crash_exitcode) { - WARNF( "Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, " "skipping", fn, (int)(s8)afl->fsrv.crash_exitcode); } else { - if (afl->afl_env.afl_crashing_seeds_as_new_crash) { - WARNF( "Test case '%s' results in a crash, " "as AFL_CRASHING_SEEDS_AS_NEW_CRASH is set, " @@ -1101,50 +925,38 @@ void perform_dry_run(afl_state_t *afl) { fn); } else { - WARNF("Test case '%s' results in a crash, skipping", fn); - } - } if (afl->afl_env.afl_exit_on_seed_issues) { - FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits."); - } /* Remove from fuzzing queue but keep for splicing */ if (!q->was_fuzzed) { - q->was_fuzzed = 1; afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; - } /* Crashing seeds will be regarded as new crashes on startup */ if (afl->afl_env.afl_crashing_seeds_as_new_crash) { - ++afl->total_crashes; if (likely(!afl->non_instrumented_mode)) { - classify_counts(&afl->fsrv); simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_crash)) { break; } - } if (unlikely(!afl->saved_crashes) && (afl->afl_env.afl_no_crash_readme != 1)) { - write_crash_readme(afl); - } u8 crash_fn[PATH_MAX]; @@ -1181,34 +993,25 @@ void perform_dry_run(afl_state_t *afl) { afl->last_crash_execs = afl->fsrv.total_execs; } else { - u32 i = 0; while (unlikely(i < afl->queued_items && afl->queue_buf[i] && afl->queue_buf[i]->disabled)) { - ++i; - } if (i < afl->queued_items && afl->queue_buf[i]) { - afl->queue = afl->queue_buf[i]; } else { - afl->queue = afl->queue_buf[0]; - } afl->max_depth = 0; for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) { - if (!afl->queue_buf[i]->disabled && afl->queue_buf[i]->depth > afl->max_depth) afl->max_depth = afl->queue_buf[i]->depth; - } - } q->disabled = 1; @@ -1223,9 +1026,7 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_NOINST: #ifdef __linux__ if (afl->fsrv.nyx_mode && afl->fsrv.nyx_runner != NULL) { - afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner); - } #endif @@ -1236,40 +1037,28 @@ void perform_dry_run(afl_state_t *afl) { ++afl->useless_at_start; if (!afl->in_bitmap && !afl->shuffle_queue) { - WARNF("No new instrumentation output, test case may be useless."); - } break; - } if (unlikely(q->var_behavior && !afl->afl_env.afl_no_warn_instability)) { - WARNF("Instrumentation output varies across runs."); - } - } if (cal_failures) { - if (cal_failures == afl->queued_items) { - FATAL("All test cases time out or crash, giving up!"); - } WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.", cal_failures, ((double)cal_failures) * 100 / afl->queued_items); if (cal_failures * 5 > afl->queued_items) { - WARNF(cLRD "High percentage of rejected test cases, check settings!"); - } - } /* Now we remove all entries from the queue that have a duplicate trace map */ @@ -1277,98 +1066,75 @@ void perform_dry_run(afl_state_t *afl) { u32 duplicates = 0, i; for (idx = 0; idx < afl->queued_items - 1; idx++) { - q = afl->queue_buf[idx]; if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; } u32 done = 0; for (i = idx + 1; likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) { - struct queue_entry *p = afl->queue_buf[i]; if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; } if (p->exec_cksum == q->exec_cksum) { - duplicates = 1; // we keep the shorter file if (p->len >= q->len) { - if (!p->was_fuzzed) { - p->was_fuzzed = 1; afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; - } p->disabled = 1; p->perf_score = 0; if (afl->debug) { - WARNF("Same coverage - %s is kept active, %s is disabled.", q->fname, p->fname); - } } else { - if (!q->was_fuzzed) { - q->was_fuzzed = 1; afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; - } q->disabled = 1; q->perf_score = 0; if (afl->debug) { - WARNF("Same coverage - %s is kept active, %s is disabled.", p->fname, q->fname); - } done = 1; // end inner loop because outer loop entry is disabled now - } - } - } - } if (duplicates) { - afl->max_depth = 0; for (idx = 0; idx < afl->queued_items; idx++) { - if (afl->queue_buf[idx] && !afl->queue_buf[idx]->disabled && afl->queue_buf[idx]->depth > afl->max_depth) afl->max_depth = afl->queue_buf[idx]->depth; - } afl->queue_top = afl->queue; - } OKF("All test cases processed."); - } /* Helper function: link() if possible, copy otherwise. */ static void link_or_copy(u8 *old_path, u8 *new_path) { - s32 i = link(old_path, new_path); s32 sfd, dfd; u8 *tmp; @@ -1384,9 +1150,7 @@ static void link_or_copy(u8 *old_path, u8 *new_path) { tmp = ck_alloc(64 * 1024); while ((i = read(sfd, tmp, 64 * 1024)) > 0) { - ck_write(dfd, tmp, i, new_path); - } if (i < 0) { PFATAL("read() failed"); } @@ -1394,21 +1158,18 @@ static void link_or_copy(u8 *old_path, u8 *new_path) { ck_free(tmp); close(sfd); close(dfd); - } /* Create hard links for input test cases in the output directory, choosing good names and pivoting accordingly. */ void pivot_inputs(afl_state_t *afl) { - struct queue_entry *q; u32 id = 0, i; ACTF("Creating hard links for all input files..."); for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) { - q = afl->queue_buf[i]; if (unlikely(q->disabled)) { continue; } @@ -1417,13 +1178,10 @@ void pivot_inputs(afl_state_t *afl) { u32 orig_id; if (!rsl) { - rsl = q->fname; } else { - ++rsl; - } /* If the original file name conforms to the syntax and the recorded @@ -1432,7 +1190,6 @@ void pivot_inputs(afl_state_t *afl) { if (!strncmp(rsl, CASE_PREFIX, 3) && sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) { - u8 *src_str; u32 src_id; @@ -1445,21 +1202,16 @@ void pivot_inputs(afl_state_t *afl) { src_str = strchr(rsl + 3, ':'); if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { - if (src_id < afl->queued_items) { - struct queue_entry *s = afl->queue_buf[src_id]; if (s) { q->depth = s->depth + 1; } - } if (afl->max_depth < q->depth) { afl->max_depth = q->depth; } - } } else { - /* No dice - invent a new name, capturing the original one as a substring. */ @@ -1468,13 +1220,10 @@ void pivot_inputs(afl_state_t *afl) { u8 *use_name = strstr(rsl, ",orig:"); if (use_name) { - use_name += 6; } else { - use_name = rsl; - } nfn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s", @@ -1484,8 +1233,7 @@ void pivot_inputs(afl_state_t *afl) { nfn = alloc_printf("%s/queue/id_%06u", afl->out_dir, id); -#endif /* ^!SIMPLE_FILES */ - +#endif /* ^!SIMPLE_FILES */ } /* Pivot to the new queue entry. */ @@ -1499,25 +1247,20 @@ void pivot_inputs(afl_state_t *afl) { if (q->passed_det) { mark_as_det_done(afl, q); } if (afl->custom_mutators_count) { - run_afl_custom_queue_new_entry(afl, q, q->fname, NULL); - } ++id; - } if (afl->in_place_resume) { nuke_resume_dir(afl); } - } /* When resuming, try to find the queue position to start from. This makes sense only when resuming, and when we can find the original fuzzer_stats. */ u32 find_start_position(afl_state_t *afl) { - - u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */ + u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */ u8 *fn, *off; s32 fd, i; @@ -1526,13 +1269,10 @@ u32 find_start_position(afl_state_t *afl) { if (!afl->resuming_fuzz) { return 0; } if (afl->in_place_resume) { - fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); } else { - fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir); - } fd = open(fn, O_RDONLY); @@ -1541,7 +1281,7 @@ u32 find_start_position(afl_state_t *afl) { if (fd < 0) { return 0; } i = read(fd, tmp, sizeof(tmp) - 1); - (void)i; /* Ignore errors */ + (void)i; /* Ignore errors */ close(fd); off = strstr(tmp, "cur_item : "); @@ -1550,7 +1290,6 @@ u32 find_start_position(afl_state_t *afl) { ret = atoi(off + 20); if (ret >= afl->queued_items) { ret = 0; } return ret; - } /* The same, but for timeouts. The idea is that when resuming sessions without @@ -1558,8 +1297,7 @@ u32 find_start_position(afl_state_t *afl) { again to prevent it from growing due to random flukes. */ void find_timeout(afl_state_t *afl) { - - u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */ + u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */ u8 *fn, *off; s32 fd, i; @@ -1568,13 +1306,10 @@ void find_timeout(afl_state_t *afl) { if (!afl->resuming_fuzz) { return; } if (afl->in_place_resume) { - fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); } else { - fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir); - } fd = open(fn, O_RDONLY); @@ -1583,7 +1318,7 @@ void find_timeout(afl_state_t *afl) { if (fd < 0) { return; } i = read(fd, tmp, sizeof(tmp) - 1); - (void)i; /* Ignore errors */ + (void)i; /* Ignore errors */ close(fd); off = strstr(tmp, "exec_timeout : "); @@ -1594,14 +1329,12 @@ void find_timeout(afl_state_t *afl) { afl->fsrv.exec_tmout = ret; afl->timeout_given = 3; - } /* A helper function for handle_existing_out_dir(), deleting all prefixed files in a directory. */ static u8 delete_files(u8 *path, u8 *prefix) { - DIR *d; struct dirent *d_ent; @@ -1610,28 +1343,22 @@ static u8 delete_files(u8 *path, u8 *prefix) { if (!d) { return 0; } while ((d_ent = readdir(d))) { - if (d_ent->d_name[0] != '.' && (!prefix || !strncmp(d_ent->d_name, prefix, strlen(prefix)))) { - u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name); if (unlink(fname)) { PFATAL("Unable to delete '%s'", fname); } ck_free(fname); - } - } closedir(d); return !!rmdir(path); - } /* Get the number of runnable processes, with some simple smoothing. */ double get_runnable_processes(void) { - double res = 0; #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ @@ -1650,45 +1377,36 @@ double get_runnable_processes(void) { processes well. */ FILE *f = fopen("/proc/stat", "r"); - u8 tmp[1024]; - u32 val = 0; + u8 tmp[1024]; + u32 val = 0; if (!f) { return 0; } while (fgets(tmp, sizeof(tmp), f)) { - if (!strncmp(tmp, "procs_running ", 14) || !strncmp(tmp, "procs_blocked ", 14)) { - val += atoi(tmp + 14); - } - } fclose(f); if (!res) { - res = val; } else { - res = res * (1.0 - 1.0 / AVG_SMOOTHING) + ((double)val) * (1.0 / AVG_SMOOTHING); - } -#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__) */ +#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__) */ return res; - } /* Delete the temporary directory used for in-place session resume. */ void nuke_resume_dir(afl_state_t *afl) { - u8 *fn; fn = alloc_printf("%s/_resume/.state/deterministic_done", afl->out_dir); @@ -1720,7 +1438,6 @@ void nuke_resume_dir(afl_state_t *afl) { dir_cleanup_failed: FATAL("_resume directory cleanup failed"); - } /* Delete fuzzer output directory if we recognize it as ours, if the fuzzer @@ -1728,7 +1445,6 @@ void nuke_resume_dir(afl_state_t *afl) { Resume fuzzing if `-` is set as in_dir or if AFL_AUTORESUME is set */ static void handle_existing_out_dir(afl_state_t *afl) { - FILE *f; u8 *fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); @@ -1742,7 +1458,6 @@ static void handle_existing_out_dir(afl_state_t *afl) { #ifndef __sun if (flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB) && errno == EWOULDBLOCK) { - SAYF("\n" cLRD "[-] " cRST "Looks like the job output directory is being actively used by " "another\n" @@ -1751,24 +1466,20 @@ static void handle_existing_out_dir(afl_state_t *afl) { afl->sync_id ? "fuzzer ID" : "output location"); FATAL("Directory '%s' is in use", afl->out_dir); - } -#endif /* !__sun */ +#endif /* !__sun */ f = fopen(fn, "r"); if (f) { - u64 start_time2, last_update; if (fscanf(f, "start_time : %llu\n" "last_update : %llu\n", &start_time2, &last_update) != 2) { - FATAL("Malformed data in '%s'", fn); - } fclose(f); @@ -1777,17 +1488,14 @@ static void handle_existing_out_dir(afl_state_t *afl) { * already exists */ if (!afl->in_place_resume && afl->autoresume) { - OKF("Detected prior run with AFL_AUTORESUME set. Resuming."); afl->in_place_resume = 1; - } /* Let's see how much work is at stake. */ if (!afl->in_place_resume && last_update > start_time2 && last_update - start_time2 > OUTPUT_GRACE * 60) { - SAYF("\n" cLRD "[-] " cRST "The job output directory already exists and contains the results " "of more\n" @@ -1805,9 +1513,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { OUTPUT_GRACE); FATAL("At-risk data found in '%s'", afl->out_dir); - } - } ck_free(fn); @@ -1819,21 +1525,18 @@ static void handle_existing_out_dir(afl_state_t *afl) { dir instead, and we let rename() fail silently. */ if (afl->in_place_resume) { - u8 *orig_q = alloc_printf("%s/queue", afl->out_dir); afl->in_dir = alloc_printf("%s/_resume", afl->out_dir); - rename(orig_q, afl->in_dir); /* Ignore errors */ + rename(orig_q, afl->in_dir); /* Ignore errors */ OKF("Output directory exists, will attempt session resume."); ck_free(orig_q); } else { - OKF("Output directory exists but deemed OK to reuse."); - } ACTF("Deleting old session data..."); @@ -1842,11 +1545,9 @@ static void handle_existing_out_dir(afl_state_t *afl) { in out_dir>/.synced/.../id:*, if any are present. */ if (!afl->in_place_resume) { - fn = alloc_printf("%s/.synced", afl->out_dir); if (delete_files(fn, NULL)) { goto dir_cleanup_failed; } ck_free(fn); - } /* Next, we need to clean up out_dir>/queue/.state/ subdirectories: */ @@ -1882,11 +1583,9 @@ static void handle_existing_out_dir(afl_state_t *afl) { * out_dir>/hangs/id:*. */ if (!afl->in_place_resume) { - fn = alloc_printf("%s/crashes/README.txt", afl->out_dir); - unlink(fn); /* Ignore errors */ + unlink(fn); /* Ignore errors */ ck_free(fn); - } fn = alloc_printf("%s/crashes", afl->out_dir); @@ -1895,7 +1594,6 @@ static void handle_existing_out_dir(afl_state_t *afl) { doing in-place resume. */ if (afl->in_place_resume && rmdir(fn)) { - time_t cur_t = time(0); struct tm t; localtime_r(&cur_t, &t); @@ -1912,11 +1610,10 @@ static void handle_existing_out_dir(afl_state_t *afl) { alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); -#endif /* ^!SIMPLE_FILES */ +#endif /* ^!SIMPLE_FILES */ - rename(fn, nfn); /* Ignore errors. */ + rename(fn, nfn); /* Ignore errors. */ ck_free(nfn); - } if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } @@ -1927,7 +1624,6 @@ static void handle_existing_out_dir(afl_state_t *afl) { /* Backup hangs, too. */ if (afl->in_place_resume && rmdir(fn)) { - time_t cur_t = time(0); struct tm t; localtime_r(&cur_t, &t); @@ -1944,11 +1640,10 @@ static void handle_existing_out_dir(afl_state_t *afl) { alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); -#endif /* ^!SIMPLE_FILES */ +#endif /* ^!SIMPLE_FILES */ - rename(fn, nfn); /* Ignore errors. */ + rename(fn, nfn); /* Ignore errors. */ ck_free(nfn); - } if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } @@ -1957,34 +1652,26 @@ static void handle_existing_out_dir(afl_state_t *afl) { /* And now, for some finishing touches. */ if (afl->file_extension) { - fn = alloc_printf("%s/.cur_input.%s", afl->out_dir, afl->file_extension); } else { - fn = alloc_printf("%s/.cur_input", afl->out_dir); - } if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); if (afl->afl_env.afl_tmpdir) { - if (afl->file_extension) { - fn = alloc_printf("%s/.cur_input.%s", afl->afl_env.afl_tmpdir, afl->file_extension); } else { - fn = alloc_printf("%s/.cur_input", afl->afl_env.afl_tmpdir); - } if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); - } fn = alloc_printf("%s/fuzz_bitmap", afl->out_dir); @@ -1992,19 +1679,15 @@ static void handle_existing_out_dir(afl_state_t *afl) { ck_free(fn); if (!afl->in_place_resume) { - fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); - } if (!afl->in_place_resume) { - fn = alloc_printf("%s/plot_data", afl->out_dir); if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); - } fn = alloc_printf("%s/queue_data", afl->out_dir); @@ -2037,14 +1720,12 @@ static void handle_existing_out_dir(afl_state_t *afl) { fn); FATAL("Output directory cleanup failed"); - } /* If this is a -S secondary node, ensure a -M main node is running, if a main node is running when another main is started, then warn */ int check_main_node_exists(afl_state_t *afl) { - DIR *sd; struct dirent *sd_ent; u8 *fn; @@ -2053,52 +1734,40 @@ int check_main_node_exists(afl_state_t *afl) { if (!sd) { return 0; } while ((sd_ent = readdir(sd))) { - /* Skip dot files and our own output directory. */ if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) { - continue; - } fn = alloc_printf("%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name); int res = access(fn, F_OK); free(fn); if (res == 0) return 1; - } return 0; - } /* Prepare output directories and fds. */ void setup_dirs_fds(afl_state_t *afl) { - u8 *tmp; ACTF("Setting up output directories..."); if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) { - PFATAL("Unable to create '%s'", afl->sync_dir); - } if (mkdir(afl->out_dir, 0700)) { - if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); } handle_existing_out_dir(afl); } else { - if (afl->in_place_resume) { - FATAL("Resume attempted but old output directory not found"); - } afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY); @@ -2107,23 +1776,18 @@ void setup_dirs_fds(afl_state_t *afl) { if (afl->fsrv.out_dir_fd < 0 || flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB)) { - PFATAL("Unable to flock() output directory."); - } -#endif /* !__sun */ - +#endif /* !__sun */ } if (afl->is_main_node) { - u8 *x = alloc_printf("%s/is_main_node", afl->out_dir); int fd = open(x, O_CREAT | O_RDWR, 0644); if (fd < 0) FATAL("cannot create %s", x); free(x); close(fd); - } /* Queue directory for any starting & discovered paths. */ @@ -2167,17 +1831,13 @@ void setup_dirs_fds(afl_state_t *afl) { /* Sync directory for keeping track of cooperating fuzzers. */ if (afl->sync_id) { - tmp = alloc_printf("%s/.synced/", afl->out_dir); if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) { - PFATAL("Unable to create '%s'", tmp); - } ck_free(tmp); - } /* All recorded crashes. */ @@ -2205,7 +1865,6 @@ void setup_dirs_fds(afl_state_t *afl) { tmp = alloc_printf("%s/plot_data", afl->out_dir); if (!afl->in_place_resume) { - int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); @@ -2220,7 +1879,6 @@ void setup_dirs_fds(afl_state_t *afl) { "saved_hangs, max_depth, execs_per_sec, total_execs, edges_found\n"); } else { - int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION); if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); @@ -2229,17 +1887,14 @@ void setup_dirs_fds(afl_state_t *afl) { if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); } fseek(afl->fsrv.plot_file, 0, SEEK_END); - } fflush(afl->fsrv.plot_file); /* ignore errors */ - } void setup_cmdline_file(afl_state_t *afl, char **argv) { - u8 *tmp; s32 fd; u32 i = 0; @@ -2256,48 +1911,37 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) { if (!cmdline_file) { PFATAL("fdopen() failed"); } while (argv[i]) { - fprintf(cmdline_file, "%s\n", argv[i]); ++i; - } fclose(cmdline_file); - } /* Setup the output file for fuzzed data, if not using -f. */ void setup_stdio_file(afl_state_t *afl) { - if (afl->file_extension) { - afl->fsrv.out_file = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension); } else { - afl->fsrv.out_file = alloc_printf("%s/.cur_input", afl->tmp_dir); - } - unlink(afl->fsrv.out_file); /* Ignore errors */ + unlink(afl->fsrv.out_file); /* Ignore errors */ afl->fsrv.out_fd = open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (afl->fsrv.out_fd < 0) { - PFATAL("Unable to create '%s'", afl->fsrv.out_file); - } - } /* Make sure that core dumps don't go to a program. */ void check_crash_handling(void) { - #ifdef __APPLE__ /* Yuck! There appears to be no simple C API to query for the state of @@ -2335,14 +1979,13 @@ void check_crash_handling(void) { *BSD, so we can just let it slide for now. */ s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY); - u8 fchar; + u8 fchar; if (fd < 0) { return; } ACTF("Checking core_pattern..."); if (read(fd, &fchar, 1) == 1 && fchar == '|') { - SAYF( "\n" cLRD "[-] " cRST "Hmm, your system is configured to send core dump notifications to an\n" @@ -2361,23 +2004,18 @@ void check_crash_handling(void) { " echo core >/proc/sys/kernel/core_pattern\n"); if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) { - FATAL("Pipe at the beginning of 'core_pattern'"); - } - } close(fd); -#endif /* ^__APPLE__ */ - +#endif /* ^__APPLE__ */ } /* Check CPU governor. */ void check_cpu_governor(afl_state_t *afl) { - #ifdef __linux__ FILE *f; u8 tmp[128]; @@ -2386,42 +2024,32 @@ void check_cpu_governor(afl_state_t *afl) { if (afl->afl_env.afl_skip_cpufreq) { return; } if (afl->cpu_aff > 0) { - snprintf(tmp, sizeof(tmp), "%s%d%s", "/sys/devices/system/cpu/cpu", afl->cpu_aff, "/cpufreq/scaling_governor"); } else { - snprintf(tmp, sizeof(tmp), "%s", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"); - } f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r"); if (!f) { - if (afl->cpu_aff > 0) { - snprintf(tmp, sizeof(tmp), "%s%d%s", "/sys/devices/system/cpu/cpufreq/policy", afl->cpu_aff, "/scaling_governor"); } else { - snprintf(tmp, sizeof(tmp), "%s", "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"); - } f = fopen(tmp, "r"); - } if (!f) { - WARNF("Could not check CPU scaling governor"); return; - } ACTF("Checking CPU scaling governor..."); @@ -2435,19 +2063,15 @@ void check_cpu_governor(afl_state_t *afl) { f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r"); if (f) { - if (fscanf(f, "%llu", &min) != 1) { min = 0; } fclose(f); - } f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r"); if (f) { - if (fscanf(f, "%llu", &max) != 1) { max = 0; } fclose(f); - } if (min == max) { return; } @@ -2474,24 +2098,20 @@ void check_cpu_governor(afl_state_t *afl) { FATAL("Suboptimal CPU scaling governor"); #elif defined __APPLE__ - u64 min = 0, max = 0; + u64 min = 0, max = 0; size_t mlen = sizeof(min); if (afl->afl_env.afl_skip_cpufreq) return; ACTF("Checking CPU scaling governor..."); if (sysctlbyname("hw.cpufrequency_min", &min, &mlen, NULL, 0) == -1) { - WARNF("Could not check CPU min frequency"); return; - } if (sysctlbyname("hw.cpufrequency_max", &max, &mlen, NULL, 0) == -1) { - WARNF("Could not check CPU max frequency"); return; - } if (min == max) return; @@ -2508,13 +2128,11 @@ void check_cpu_governor(afl_state_t *afl) { #else (void)afl; #endif - } /* Count the number of logical CPU cores. */ void get_core_count(afl_state_t *afl) { - #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__DragonFly__) @@ -2533,7 +2151,7 @@ void get_core_count(afl_state_t *afl) { if (sysctl(s_name, 2, &afl->cpu_core_count, &s, NULL, 0) < 0) return; - #endif /* ^__APPLE__ */ + #endif /* ^__APPLE__ */ #else @@ -2553,12 +2171,11 @@ void get_core_count(afl_state_t *afl) { fclose(f); - #endif /* ^HAVE_AFFINITY */ + #endif /* ^HAVE_AFFINITY */ -#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */ +#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */ if (afl->cpu_core_count > 0) { - u32 cur_runnable = 0; cur_runnable = (u32)get_runnable_processes(); @@ -2570,53 +2187,40 @@ void get_core_count(afl_state_t *afl) { ++cur_runnable; -#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ +#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ OKF("You have %d CPU core%s and %u runnable tasks (utilization: %0.0f%%).", afl->cpu_core_count, afl->cpu_core_count > 1 ? "s" : "", cur_runnable, cur_runnable * 100.0 / afl->cpu_core_count); if (afl->cpu_core_count > 1) { - if (cur_runnable > afl->cpu_core_count * 1.5) { - WARNF("System under apparent load, performance may be spotty."); } else if ((s64)cur_runnable + 1 <= (s64)afl->cpu_core_count) { - OKF("Try parallel jobs - see " "%s/fuzzing_in_depth.md#c-using-multiple-cores", doc_path); - } - } } else { - afl->cpu_core_count = 0; WARNF("Unable to figure out the number of CPU cores."); - } - } /* Validate and fix up afl->out_dir and sync_dir when using -S. */ void fix_up_sync(afl_state_t *afl) { - u8 *x = afl->sync_id; while (*x) { - if (!isalnum(*x) && *x != '_' && *x != '-') { - FATAL("Non-alphanumeric fuzzer ID specified via -S or -M"); - } ++x; - } if (strlen(afl->sync_id) > 32) { FATAL("Fuzzer ID too long"); } @@ -2628,100 +2232,74 @@ void fix_up_sync(afl_state_t *afl) { #endif afl->sync_dir = afl->out_dir; afl->out_dir = x; - } /* Handle screen resize (SIGWINCH). */ static void handle_resize(int sig) { - (void)sig; afl_states_clear_screen(); - } /* Check ASAN options. */ void check_asan_opts(afl_state_t *afl) { - u8 *x = get_afl_env("ASAN_OPTIONS"); (void)(afl); if (x) { - if (!strstr(x, "abort_on_error=1")) { - FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); - } #ifndef ASAN_BUILD if (!afl->debug && !strstr(x, "symbolize=0")) { - FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); - } #endif - } x = get_afl_env("MSAN_OPTIONS"); if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) { - FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY( MSAN_ERROR) " - please fix!"); - } if (!afl->debug && !strstr(x, "symbolize=0")) { - FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); - } - } x = get_afl_env("LSAN_OPTIONS"); if (x) { - if (!strstr(x, "symbolize=0")) { - FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!"); - } - } - } /* Handle stop signal (Ctrl-C, etc). */ static void handle_stop_sig(int sig) { - (void)sig; afl_states_stop(); - } /* Handle skip request (SIGUSR1). */ static void handle_skipreq(int sig) { - (void)sig; afl_states_request_skip(); - } /* Setup shared map for fuzzing with input via sharedmem */ void setup_testcase_shmem(afl_state_t *afl) { - afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t)); // we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR @@ -2740,7 +2318,6 @@ void setup_testcase_shmem(afl_state_t *afl) { afl->fsrv.support_shmem_fuzz = 1; afl->fsrv.shmem_fuzz_len = (u32 *)map; afl->fsrv.shmem_fuzz = map + sizeof(u32); - } /* Do a PATH search and find target binary to see that it exists and @@ -2748,7 +2325,6 @@ void setup_testcase_shmem(afl_state_t *afl) { a valid ELF header and for evidence of AFL instrumentation. */ void check_binary(afl_state_t *afl, u8 *fname) { - if (unlikely(!fname)) { FATAL("BUG: Binary name is NULL"); } u8 *env_path = 0; @@ -2761,97 +2337,72 @@ void check_binary(afl_state_t *afl, u8 *fname) { ACTF("Validating target binary..."); if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { - afl->fsrv.target_path = ck_strdup(fname); #ifdef __linux__ if (afl->fsrv.nyx_mode) { - /* check if target_path is a nyx sharedir */ if (stat(afl->fsrv.target_path, &st) || S_ISDIR(st.st_mode)) { - char *tmp = alloc_printf("%s/config.ron", afl->fsrv.target_path); if (stat(tmp, &st) || S_ISREG(st.st_mode)) { - free(tmp); return; - } - } FATAL("Directory '%s' not found or is not a nyx share directory", afl->fsrv.target_path); - } #endif if (stat(afl->fsrv.target_path, &st) || !S_ISREG(st.st_mode) || !(st.st_mode & 0111) || (f_len = st.st_size) < 4) { - FATAL("Program '%s' not found or not executable", fname); - } } else { - while (env_path) { - u8 *cur_elem, *delim = strchr(env_path, ':'); if (delim) { - cur_elem = ck_alloc(delim - env_path + 1); if (unlikely(!cur_elem)) { FATAL("Unexpected large PATH"); } memcpy(cur_elem, env_path, delim - env_path); ++delim; } else { - cur_elem = ck_strdup(env_path); - } env_path = delim; if (cur_elem[0]) { - afl->fsrv.target_path = alloc_printf("%s/%s", cur_elem, fname); } else { - afl->fsrv.target_path = ck_strdup(fname); - } ck_free(cur_elem); if (!stat(afl->fsrv.target_path, &st) && S_ISREG(st.st_mode) && (st.st_mode & 0111) && (f_len = st.st_size) >= 4) { - break; - } ck_free(afl->fsrv.target_path); afl->fsrv.target_path = 0; - } if (!afl->fsrv.target_path) { - FATAL("Program '%s' not found or not executable", fname); - } - } if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode || (afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) || (afl->fsrv.cs_mode && getenv("AFL_CS_CUSTOM_BIN")) || afl->non_instrumented_mode) { - return; - } /* Check for blatant user errors. */ @@ -2875,15 +2426,12 @@ void check_binary(afl_state_t *afl, u8 *fname) { f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0); if (f_data == MAP_FAILED) { - PFATAL("Unable to mmap file '%s'", afl->fsrv.target_path); - } close(fd); if (f_data[0] == '#' && f_data[1] == '!') { - SAYF("\n" cLRD "[-] " cRST "Oops, the target binary looks like a shell script. Some build " "systems will\n" @@ -2901,15 +2449,12 @@ void check_binary(afl_state_t *afl, u8 *fname) { " in a compiled language instead.\n"); FATAL("Program '%s' is a shell script", afl->fsrv.target_path); - } #ifndef __APPLE__ if (f_data[0] != 0x7f || memcmp(f_data + 1, "ELF", 3)) { - FATAL("Program '%s' is not an ELF binary", afl->fsrv.target_path); - } #else @@ -2921,7 +2466,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { afl->fsrv.target_path); #endif -#endif /* ^!__APPLE__ */ +#endif /* ^!__APPLE__ */ if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode && #ifdef __linux__ @@ -2955,12 +2500,10 @@ void check_binary(afl_state_t *afl, u8 *fname) { doc_path); FATAL("No instrumentation detected"); - } if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) && afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { - SAYF("\n" cLRD "[-] " cRST "This program appears to be instrumented with afl-gcc, but is being " "run in\n" @@ -2969,21 +2512,17 @@ void check_binary(afl_state_t *afl, u8 *fname) { " this setup will be slow and offer no practical benefits.\n"); FATAL("Instrumentation found in -Q mode"); - } if (afl_memmem(f_data, f_len, "__asan_init", 11) || afl_memmem(f_data, f_len, "__msan_init", 11) || afl_memmem(f_data, f_len, "__lsan_init", 11)) { - afl->fsrv.uses_asan = 1; - } /* Detect persistent & deferred init signatures in the binary. */ if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) { - OKF(cPIN "Persistent mode binary detected."); setenv(PERSIST_ENV_VAR, "1", 1); afl->persistent_mode = 1; @@ -2991,7 +2530,6 @@ void check_binary(afl_state_t *afl, u8 *fname) { afl->shmem_testcase_mode = 1; } else if (getenv("AFL_PERSISTENT")) { - OKF(cPIN "Persistent mode enforced."); setenv(PERSIST_ENV_VAR, "1", 1); afl->persistent_mode = 1; @@ -2999,62 +2537,48 @@ void check_binary(afl_state_t *afl, u8 *fname) { afl->shmem_testcase_mode = 1; } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) { - OKF("FRIDA Persistent mode configuration options detected."); setenv(PERSIST_ENV_VAR, "1", 1); afl->persistent_mode = 1; afl->fsrv.persistent_mode = 1; afl->shmem_testcase_mode = 1; - } if (afl->fsrv.frida_mode || afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) { - OKF(cPIN "Deferred forkserver binary detected."); setenv(DEFER_ENV_VAR, "1", 1); afl->deferred_mode = 1; } else if (getenv("AFL_DEFER_FORKSRV")) { - OKF(cPIN "Deferred forkserver enforced."); setenv(DEFER_ENV_VAR, "1", 1); afl->deferred_mode = 1; - } if (munmap(f_data, f_len)) { PFATAL("unmap() failed"); } - } /* Check if we're on TTY. */ void check_if_tty(afl_state_t *afl) { - struct winsize ws; if (afl->afl_env.afl_no_ui) { - OKF("Disabling the UI because AFL_NO_UI is set."); afl->not_on_tty = 1; return; - } if (ioctl(1, TIOCGWINSZ, &ws)) { - if (errno == ENOTTY) { - OKF("Looks like we're not running on a tty, so I'll be a bit less " "verbose."); afl->not_on_tty = 1; - } return; - } - } /* Set up signal handlers. More complicated that needs to be, because libc on @@ -3062,7 +2586,6 @@ void check_if_tty(afl_state_t *afl) { siginterrupt(), and does other stupid things. */ void setup_signal_handlers(void) { - struct sigaction sa; memset((void *)&sa, 0, sizeof(sa)); @@ -3096,26 +2619,21 @@ void setup_signal_handlers(void) { sa.sa_handler = SIG_IGN; sigaction(SIGTSTP, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); - } /* Make a copy of the current command line. */ void save_cmdline(afl_state_t *afl, u32 argc, char **argv) { - u32 len = 1, i; u8 *buf; for (i = 0; i < argc; ++i) { - len += strlen(argv[i]) + 1; - } buf = afl->orig_cmdline = ck_alloc(len); for (i = 0; i < argc; ++i) { - u32 l = strlen(argv[i]); if (!argv[i] || !buf) { FATAL("null deref detected"); } @@ -3124,10 +2642,7 @@ void save_cmdline(afl_state_t *afl, u32 argc, char **argv) { buf += l; if (i != argc - 1) { *(buf++) = ' '; } - } *buf = 0; - } - diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 7ce6cb355d..2d8ce53aa0 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -29,16 +29,12 @@ #ifdef _STANDALONE_MODULE void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { - return; - } void run_afl_custom_queue_new_entry(afl_state_t *afl, struct queue_entry *q, u8 *a, u8 *b) { - return; - } #endif @@ -46,7 +42,6 @@ void run_afl_custom_queue_new_entry(afl_state_t *afl, struct queue_entry *q, /* select next queue entry based on alias algo - fast! */ inline u32 select_next_queue_entry(afl_state_t *afl) { - u32 s = rand_below(afl, afl->queued_items); double p = rand_next_percent(afl); @@ -57,20 +52,16 @@ inline u32 select_next_queue_entry(afl_state_t *afl) { */ return (p < afl->alias_probability[s] ? s : afl->alias_table[s]); - } double compute_weight(afl_state_t *afl, struct queue_entry *q, double avg_exec_us, double avg_bitmap_size, double avg_top_size) { - double weight = 1.0; if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) { - u32 hits = afl->n_fuzz[q->n_fuzz_entry]; if (likely(hits)) { weight /= (log10(hits) + 1); } - } if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); } @@ -83,13 +74,11 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, if (unlikely(q->fs_redundant)) { weight *= 0.8; } return weight; - } /* create the alias table that allows weighted random selection - expensive */ void create_alias_table(afl_state_t *afl) { - u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1; double sum = 0; @@ -103,9 +92,7 @@ void create_alias_table(afl_state_t *afl) { (void **)&afl->alias_probability, n * sizeof(double)); if (!P || !Small || !Large || !afl->alias_table || !afl->alias_probability) { - FATAL("could not acquire memory for alias table"); - } memset((void *)afl->alias_probability, 0, n * sizeof(double)); @@ -114,26 +101,21 @@ void create_alias_table(afl_state_t *afl) { memset((void *)Large, 0, n * sizeof(u32)); if (likely(afl->schedule < RARE)) { - double avg_exec_us = 0.0; double avg_bitmap_size = 0.0; double avg_top_size = 0.0; u32 active = 0; for (i = 0; i < n; i++) { - struct queue_entry *q = afl->queue_buf[i]; // disabled entries might have timings and bitmap values if (likely(!q->disabled)) { - avg_exec_us += q->exec_us; avg_bitmap_size += log(q->bitmap_size); avg_top_size += q->tc_ref; ++active; - } - } avg_exec_us /= active; @@ -141,99 +123,69 @@ void create_alias_table(afl_state_t *afl) { avg_top_size /= active; for (i = 0; i < n; i++) { - struct queue_entry *q = afl->queue_buf[i]; if (likely(!q->disabled)) { - q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size, avg_top_size); q->perf_score = calculate_score(afl, q); sum += q->weight; - } - } if (unlikely(afl->schedule == MMOPT) && afl->queued_discovered) { - u32 cnt = afl->queued_discovered >= 5 ? 5 : afl->queued_discovered; for (i = n - cnt; i < n; i++) { - struct queue_entry *q = afl->queue_buf[i]; if (likely(!q->disabled)) { q->weight *= 2.0; } - } - } for (i = 0; i < n; i++) { - // weight is always 0 for disabled entries if (unlikely(afl->queue_buf[i]->disabled)) { - P[i] = 0; } else { - P[i] = (afl->queue_buf[i]->weight * n) / sum; - } - } } else { - for (i = 0; i < n; i++) { - struct queue_entry *q = afl->queue_buf[i]; if (likely(!q->disabled)) { - q->perf_score = calculate_score(afl, q); sum += q->perf_score; - } - } for (i = 0; i < n; i++) { - // perf_score is always 0 for disabled entries if (unlikely(afl->queue_buf[i]->disabled)) { - P[i] = 0; } else { - P[i] = (afl->queue_buf[i]->perf_score * n) / sum; - } - } - } // Done collecting weightings in P, now create the arrays. for (s32 j = (s32)(n - 1); j >= 0; j--) { - if (P[j] < 1) { - Small[nSmall++] = (u32)j; } else { - Large[nLarge--] = (u32)j; - } - } while (nSmall && nLarge != n - 1) { - u32 small = Small[--nSmall]; u32 large = Large[++nLarge]; @@ -243,27 +195,19 @@ void create_alias_table(afl_state_t *afl) { P[large] = P[large] - (1 - P[small]); if (P[large] < 1) { - Small[nSmall++] = large; } else { - Large[nLarge--] = large; - } - } while (nSmall) { - afl->alias_probability[Small[--nSmall]] = 1; - } while (nLarge != n - 1) { - afl->alias_probability[Large[++nLarge]] = 1; - } afl->reinit_table = 0; @@ -304,7 +248,6 @@ void create_alias_table(afl_state_t *afl) { afl->queue_buf[i]->perf_score, afl->queue_buf[i]->weight, afl->queue_buf[i]->fname); */ - } /* Mark deterministic checks as done for a particular queue entry. We use the @@ -312,7 +255,6 @@ void create_alias_table(afl_state_t *afl) { scans. */ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { - char fn[PATH_MAX]; s32 fd; @@ -324,14 +266,12 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { close(fd); q->passed_det = 1; - } /* Mark as variable. Create symlinks if possible to make it easier to examine the files. */ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { - char fn[PATH_MAX]; char ldest[PATH_MAX]; @@ -341,22 +281,18 @@ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { sprintf(fn, "%s/queue/.state/variable_behavior/%s", afl->out_dir, fn_name); if (symlink(ldest, fn)) { - s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (fd < 0) { PFATAL("Unable to create '%s'", fn); } close(fd); - } q->var_behavior = 1; - } /* Mark / unmark as redundant (edge-only). This is not used for restoring state, but may be useful for post-processing datasets. */ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { - if (likely(state == q->fs_redundant)) { return; } char fn[PATH_MAX]; @@ -367,7 +303,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { strrchr((char *)q->fname, '/') + 1); if (state) { - s32 fd; fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); @@ -375,49 +310,38 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { close(fd); } else { - if (unlink(fn)) { PFATAL("Unable to remove '%s'", fn); } - } - } /* check if pointer is ascii or UTF-8 */ u8 check_if_text_buf(u8 *buf, u32 len) { - u32 offset = 0, ascii = 0, utf8 = 0; while (offset < len) { - // ASCII: <= 0x7F to allow ASCII control characters if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A || buf[offset + 0] == 0x0D || (0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) { - offset++; utf8++; ascii++; continue; - } if (isascii((int)buf[offset]) || isprint((int)buf[offset])) { - ascii++; // we continue though as it can also be a valid utf8 - } // non-overlong 2-byte if (len - offset > 1 && ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) { - offset += 2; utf8++; continue; - } // excluding overlongs @@ -434,11 +358,9 @@ u8 check_if_text_buf(u8 *buf, u32 len) { (buf[offset + 0] == 0xED && (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) && (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF)))) { - offset += 3; utf8++; continue; - } // planes 1-3 @@ -456,25 +378,20 @@ u8 check_if_text_buf(u8 *buf, u32 len) { (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) && (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) && (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)))) { - offset += 4; utf8++; continue; - } offset++; - } return (utf8 > ascii ? utf8 : ascii); - } /* check if queue entry is ascii or UTF-8 */ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) { - if (q->len < AFL_TXT_MIN_LEN || q->len < AFL_TXT_MAX_LEN) return 0; u8 *buf; @@ -491,36 +408,29 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) { buf[len] = 0; while (offset < len) { - // ASCII: <= 0x7F to allow ASCII control characters if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A || buf[offset + 0] == 0x0D || (0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) { - offset++; utf8++; ascii++; continue; - } if (isascii((int)buf[offset]) || isprint((int)buf[offset])) { - ascii++; // we continue though as it can also be a valid utf8 - } // non-overlong 2-byte if (len - offset > 1 && ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) { - offset += 2; utf8++; comp--; continue; - } // excluding overlongs @@ -537,12 +447,10 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) { (buf[offset + 0] == 0xED && (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) && (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF)))) { - offset += 3; utf8++; comp -= 2; continue; - } // planes 1-3 @@ -560,16 +468,13 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) { (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) && (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) && (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)))) { - offset += 4; utf8++; comp -= 3; continue; - } offset++; - } u32 percent_utf8 = (utf8 * 100) / comp; @@ -579,13 +484,11 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) { return 2; if (percent_ascii >= AFL_TXT_MIN_PERCENT) return 1; return 0; - } /* Append new test case to the queue. */ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { - struct queue_entry *q = (struct queue_entry *)ck_alloc(sizeof(struct queue_entry)); @@ -597,18 +500,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->testcase_buf = NULL; q->mother = afl->queue_cur; -#ifdef STABLE_DEBUG - if (q->mother != NULL) { - DEBUGF("[add_to_queue] Entry: %u, cur_depth: %u, CurrEntry: %u, " cGRN " %s" cRST "\n", - q->id, afl->cur_depth, afl->current_entry, q->fname); - DEBUGF("[add_to_queue] Mother_id: %u," cBRI " %s" cRST "\n", - q->mother->id, q->mother->fname); - } else { - DEBUGF("[add_to_queue] Entry: %u, cur_depth: %u, CurrEntry: %u, name: %s\n", - q->id, afl->cur_depth, afl->current_entry, q->fname); - } -#endif - #ifdef INTROSPECTION q->bitsmap_size = afl->bitsmap_size; #endif @@ -616,13 +507,10 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { if (q->depth > afl->max_depth) { afl->max_depth = q->depth; } if (afl->queue_top) { - afl->queue_top = q; } else { - afl->queue = afl->queue_top = q; - } if (likely(q->len > 4)) { ++afl->ready_for_splicing_count; } @@ -643,58 +531,42 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { if (likely(afl->start_time) && unlikely(afl->longest_find_time < cur_time - afl->last_find_time)) { - if (unlikely(!afl->last_find_time)) { - afl->longest_find_time = cur_time - afl->start_time; } else { - afl->longest_find_time = cur_time - afl->last_find_time; - } - } afl->last_find_time = cur_time; if (afl->custom_mutators_count) { - /* At the initialization stage, queue_cur is NULL */ if (afl->queue_cur && !afl->syncing_party) { - run_afl_custom_queue_new_entry(afl, q, fname, afl->queue_cur->fname); - } - } /* only redqueen currently uses is_ascii */ if (unlikely(afl->shm.cmplog_mode && !q->is_ascii)) { - q->is_ascii = check_if_text(afl, q); - } - } /* Destroy the entire queue. */ void destroy_queue(afl_state_t *afl) { - u32 i; for (i = 0; i < afl->queued_items; i++) { - struct queue_entry *q; q = afl->queue_buf[i]; ck_free(q->fname); ck_free(q->trace_mini); ck_free(q); - } - } /* When we bump into a new path, we call this to see if the path appears @@ -709,71 +581,53 @@ void destroy_queue(afl_state_t *afl) { factor. */ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { - u32 i; u64 fav_factor; u64 fuzz_p2; if (likely(afl->schedule >= FAST && afl->schedule < RARE)) { - fuzz_p2 = 0; // Skip the fuzz_p2 comparison } else if (unlikely(afl->schedule == RARE)) { - fuzz_p2 = next_pow2(afl->n_fuzz[q->n_fuzz_entry]); } else { - fuzz_p2 = q->fuzz_level; - } if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) { - fav_factor = q->len << 2; } else { - fav_factor = q->exec_us * q->len; - } /* 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 < afl->fsrv.map_size; ++i) { - if (afl->fsrv.trace_bits[i]) { - if (afl->top_rated[i]) { - /* Faster-executing or smaller test cases are favored. */ u64 top_rated_fav_factor; u64 top_rated_fuzz_p2; if (likely(afl->schedule >= FAST && afl->schedule < RARE)) { - top_rated_fuzz_p2 = 0; // Skip the fuzz_p2 comparison } else if (unlikely(afl->schedule == RARE)) { - top_rated_fuzz_p2 = next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]); } else { - top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level; - } if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) { - top_rated_fav_factor = afl->top_rated[i]->len << 2; } else { - top_rated_fav_factor = afl->top_rated[i]->exec_us * afl->top_rated[i]->len; - } if (likely(fuzz_p2 > top_rated_fuzz_p2)) { continue; } @@ -784,12 +638,9 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { previous winner, discard its afl->fsrv.trace_bits[] if necessary. */ if (!--afl->top_rated[i]->tc_ref) { - ck_free(afl->top_rated[i]->trace_mini); afl->top_rated[i]->trace_mini = 0; - } - } /* Insert ourselves as the new winner. */ @@ -798,19 +649,14 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { ++q->tc_ref; if (!q->trace_mini) { - u32 len = (afl->fsrv.map_size >> 3); q->trace_mini = (u8 *)ck_alloc(len); minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); - } afl->score_changed = 1; - } - } - } /* The second part of the mechanism discussed above is a routine that @@ -820,7 +666,6 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { all fuzzing steps. */ void cull_queue(afl_state_t *afl) { - if (likely(!afl->score_changed || afl->non_instrumented_mode)) { return; } u32 len = (afl->fsrv.map_size >> 3); @@ -835,9 +680,7 @@ void cull_queue(afl_state_t *afl) { afl->pending_favored = 0; for (i = 0; i < afl->queued_items; i++) { - afl->queue_buf[i]->favored = 0; - } /* Let's see if anything in the bitmap isn't captured in temp_v. @@ -846,57 +689,38 @@ void cull_queue(afl_state_t *afl) { afl->smallest_favored = -1; for (i = 0; i < afl->fsrv.map_size; ++i) { - if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) { - u32 j = len; /* Remove all bits belonging to the current entry from temp_v. */ while (j--) { - if (afl->top_rated[i]->trace_mini[j]) { - temp_v[j] &= ~afl->top_rated[i]->trace_mini[j]; - } - } if (!afl->top_rated[i]->favored) { - afl->top_rated[i]->favored = 1; ++afl->queued_favored; if (!afl->top_rated[i]->was_fuzzed) { - ++afl->pending_favored; if (unlikely(afl->smallest_favored < 0)) { - afl->smallest_favored = (s64)afl->top_rated[i]->id; - } - } - } - } - } for (i = 0; i < afl->queued_items; i++) { - if (likely(!afl->queue_buf[i]->disabled)) { - mark_as_redundant(afl, afl->queue_buf[i], !afl->queue_buf[i]->favored); - } - } afl->reinit_table = 1; - } /* Calculate case desirability score to adjust the length of havoc fuzzing. @@ -904,7 +728,6 @@ void cull_queue(afl_state_t *afl) { go into config.h. */ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { - u32 cal_cycles = afl->total_cal_cycles; u32 bitmap_entries = afl->total_bitmap_entries; @@ -926,66 +749,49 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { // coverage, the better the fuzzing, right? -mh if (likely(afl->schedule < RARE) && likely(!afl->fixed_seed)) { - if (q->exec_us * 0.1 > avg_exec_us) { - perf_score = 10; } else if (q->exec_us * 0.25 > avg_exec_us) { - perf_score = 25; } else if (q->exec_us * 0.5 > avg_exec_us) { - perf_score = 50; } else if (q->exec_us * 0.75 > avg_exec_us) { - perf_score = 75; } else if (q->exec_us * 4 < avg_exec_us) { - perf_score = 300; } else if (q->exec_us * 3 < avg_exec_us) { - perf_score = 200; } else if (q->exec_us * 2 < avg_exec_us) { - perf_score = 150; - } - } /* Adjust score based on bitmap size. The working theory is that better coverage translates to better targets. Multiplier from 0.25x to 3x. */ if (q->bitmap_size * 0.3 > avg_bitmap_size) { - perf_score *= 3; } else if (q->bitmap_size * 0.5 > avg_bitmap_size) { - perf_score *= 2; } else if (q->bitmap_size * 0.75 > avg_bitmap_size) { - perf_score *= 1.5; } else if (q->bitmap_size * 3 < avg_bitmap_size) { - perf_score *= 0.25; } else if (q->bitmap_size * 2 < avg_bitmap_size) { - perf_score *= 0.5; } else if (q->bitmap_size * 1.5 < avg_bitmap_size) { - perf_score *= 0.75; - } /* Adjust score based on handicap. Handicap is proportional to how late @@ -993,15 +799,12 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { for a bit longer until they catch up with the rest. */ if (q->handicap >= 4) { - perf_score *= 4; q->handicap -= 4; } else if (q->handicap) { - perf_score *= 2; --q->handicap; - } /* Final adjustment based on input depth, under the assumption that fuzzing @@ -1009,7 +812,6 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { discovered with traditional fuzzers. */ switch (q->depth) { - case 0 ... 3: break; case 4 ... 7: @@ -1023,7 +825,6 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { break; default: perf_score *= 5; - } u32 n_items; @@ -1031,7 +832,6 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { long double fuzz_mu; switch (afl->schedule) { - case EXPLORE: break; @@ -1051,14 +851,10 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { u32 i; for (i = 0; i < afl->queued_items; i++) { - if (likely(!afl->queue_buf[i]->disabled)) { - fuzz_mu += log2(afl->n_fuzz[afl->queue_buf[i]->n_fuzz_entry]); n_items++; - } - } if (unlikely(!n_items)) { FATAL("Queue state corrupt"); } @@ -1066,12 +862,10 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { fuzz_mu = fuzz_mu / n_items; if (log2(afl->n_fuzz[q->n_fuzz_entry]) > fuzz_mu) { - /* Never skip favourites */ if (!q->favored) factor = 0; break; - } // Fall through @@ -1081,7 +875,6 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { if (!q->fuzz_level) break; switch ((u32)log2(afl->n_fuzz[q->n_fuzz_entry])) { - case 0 ... 1: factor = 4; break; @@ -1108,7 +901,6 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { default: if (!q->favored) factor = 0.4; break; - } if (q->favored) factor *= 1.15; @@ -1159,73 +951,45 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { default: PFATAL("Unknown Power Schedule"); - } if (unlikely(afl->schedule >= EXPLOIT && afl->schedule <= QUAD)) { - if (factor > MAX_FACTOR) { factor = MAX_FACTOR; } perf_score *= factor / POWER_BETA; - } // MOpt mode if (afl->limit_time_sig != 0 && afl->max_depth - q->depth < 3) { - perf_score *= 2; } else if (afl->schedule != COE && perf_score < 1) { - // Add a lower bound to AFLFast's energy assignment strategies perf_score = 1; - } /* Make sure that we don't go over limit. */ if (perf_score > afl->havoc_max_mult * 100) { - perf_score = afl->havoc_max_mult * 100; - } -#ifdef STABLE_DEBUG - if (q->mother != NULL) { - DEBUGF("[fuzzsat] TEST ID: %u, CurrEntry: %u, perf_score: %u, | tf: %lf\n", - q->id, afl->current_entry, perf_score, factor); - fprintf(stderr, "[fuzzsat] TEST ID: %u, " cBRI "%s -> " cGRN "%s" cRST "\n", - q->id, q->mother->fname, q->fname); - fprintf(stderr, cRST ""); - } else { - DEBUGF("[fuzzsat] TEST ID: %u, CurrEntry: %u, perf_score: %u, | tf: %lf\n", - q->id, afl->current_entry, perf_score, factor); - DEBUGF("[fuzzsat] TEST ID: %u, Curr file: %s\n", q->id, q->fname); - } -#endif return perf_score; - } /* after a custom trim we need to reload the testcase from disk */ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, u32 old_len) { - if (likely(q->testcase_buf)) { - u32 len = q->len; if (len != old_len) { - afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len; q->testcase_buf = (u8 *)realloc(q->testcase_buf, len); if (unlikely(!q->testcase_buf)) { - PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len); - } - } int fd = open((char *)q->fname, O_RDONLY); @@ -1234,66 +998,49 @@ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, ck_read(fd, q->testcase_buf, len, q->fname); close(fd); - } - } /* after a normal trim we need to replace the testcase with the new data */ inline void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q, u8 *in, u32 len, u32 old_len) { - if (likely(q->testcase_buf)) { - u32 is_same = in == q->testcase_buf; if (likely(len != old_len)) { - u8 *ptr = (u8 *)realloc(q->testcase_buf, len); if (likely(ptr)) { - q->testcase_buf = ptr; afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len; - } - } if (unlikely(!is_same)) { memcpy(q->testcase_buf, in, len); } - } - } /* Returns the testcase buf from the file behind this queue entry. Increases the refcount. */ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { - u32 len = q->len; /* first handle if no testcase cache is configured */ if (unlikely(!afl->q_testcase_max_cache_size)) { - u8 *buf; if (unlikely(q == afl->queue_cur)) { - buf = (u8 *)afl_realloc((void **)&afl->testcase_buf, len); } else { - buf = (u8 *)afl_realloc((void **)&afl->splicecase_buf, len); - } if (unlikely(!buf)) { - PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len); - } int fd = open((char *)q->fname, O_RDONLY); @@ -1303,13 +1050,11 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { ck_read(fd, buf, len, q->fname); close(fd); return buf; - } /* now handle the testcase cache */ if (unlikely(!q->testcase_buf)) { - /* Buf not cached, let's load it */ u32 tid = afl->q_testcase_max_cache_count; static u32 do_once = 0; // because even threaded we would want this. WIP @@ -1317,7 +1062,6 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { while (unlikely( afl->q_testcase_cache_size + len >= afl->q_testcase_max_cache_size || afl->q_testcase_cache_count >= afl->q_testcase_max_cache_entries - 1)) { - /* We want a max number of entries to the cache that we learn. Very simple: once the cache is filled by size - that is the max. */ @@ -1328,16 +1072,12 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { afl->q_testcase_max_cache_count < afl->q_testcase_max_cache_entries) && !do_once)) { - if (afl->q_testcase_max_cache_count > afl->q_testcase_cache_count) { - afl->q_testcase_max_cache_entries = afl->q_testcase_max_cache_count + 1; } else { - afl->q_testcase_max_cache_entries = afl->q_testcase_cache_count + 1; - } do_once = 1; @@ -1345,14 +1085,12 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { afl->q_testcase_cache = (struct queue_entry **)ck_realloc( afl->q_testcase_cache, (afl->q_testcase_max_cache_entries + 1) * sizeof(size_t)); - } /* Cache full. We neet to evict one or more to map one. Get a random one which is not in use */ do { - // if the cache (MB) is not enough for the queue then this gets // undesirable because q_testcase_max_cache_count grows sometimes // although the number of items in the cache will not change hence @@ -1372,14 +1110,11 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { ++afl->q_testcase_evictions; if (tid < afl->q_testcase_smallest_free) afl->q_testcase_smallest_free = tid; - } if (unlikely(tid >= afl->q_testcase_max_cache_entries)) { - // uh we were full, so now we have to search from start tid = afl->q_testcase_smallest_free; - } // we need this while loop in case there were ever previous evictions but @@ -1396,9 +1131,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { q->testcase_buf = (u8 *)malloc(len); if (unlikely(!q->testcase_buf)) { - PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len); - } ck_read(fd, q->testcase_buf, len, q->fname); @@ -1409,50 +1142,39 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { afl->q_testcase_cache_size += len; ++afl->q_testcase_cache_count; if (likely(tid >= afl->q_testcase_max_cache_count)) { - afl->q_testcase_max_cache_count = tid + 1; } else if (unlikely(tid == afl->q_testcase_smallest_free)) { - afl->q_testcase_smallest_free = tid + 1; - } - } return q->testcase_buf; - } /* Adds the new queue entry to the cache. */ inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, u8 *mem) { - u32 len = q->len; if (unlikely(afl->q_testcase_cache_size + len >= afl->q_testcase_max_cache_size || afl->q_testcase_cache_count >= afl->q_testcase_max_cache_entries - 1)) { - // no space? will be loaded regularly later. return; - } u32 tid; if (unlikely(afl->q_testcase_max_cache_count >= afl->q_testcase_max_cache_entries)) { - // uh we were full, so now we have to search from start tid = afl->q_testcase_smallest_free; } else { - tid = afl->q_testcase_max_cache_count; - } while (unlikely(afl->q_testcase_cache[tid] != NULL)) @@ -1463,9 +1185,7 @@ inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, q->testcase_buf = (u8 *)malloc(len); if (unlikely(!q->testcase_buf)) { - PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len); - } memcpy(q->testcase_buf, mem, len); @@ -1476,14 +1196,9 @@ inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, ++afl->q_testcase_cache_count; if (likely(tid >= afl->q_testcase_max_cache_count)) { - afl->q_testcase_max_cache_count = tid + 1; } else if (unlikely(tid == afl->q_testcase_smallest_free)) { - afl->q_testcase_smallest_free = tid + 1; - } - } -