diff options
author | van Hauser <vh@thc.org> | 2020-07-21 13:15:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-21 13:15:59 +0200 |
commit | b6e65f98827470745d7df5cf1e38b506b9e839b0 (patch) | |
tree | 602abd8c1a1929aebda3f80665ffe02b435fdd00 /src | |
parent | fc5cfc6cb309b072a45b991be117c17396e46a89 (diff) | |
parent | c2b04bdf6c596f5d220f27caead20d09452ed42d (diff) | |
download | afl++-b6e65f98827470745d7df5cf1e38b506b9e839b0.tar.gz |
Merge pull request #461 from AFLplusplus/new_splicing
New splicing
Diffstat (limited to 'src')
-rw-r--r-- | src/afl-analyze.c | 29 | ||||
-rw-r--r-- | src/afl-common.c | 74 | ||||
-rw-r--r-- | src/afl-forkserver.c | 29 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 99 | ||||
-rw-r--r-- | src/afl-fuzz-one.c | 681 | ||||
-rw-r--r-- | src/afl-fuzz-queue.c | 121 | ||||
-rw-r--r-- | src/afl-fuzz-redqueen.c | 28 | ||||
-rw-r--r-- | src/afl-fuzz-state.c | 56 | ||||
-rw-r--r-- | src/afl-fuzz.c | 35 | ||||
-rw-r--r-- | src/afl-gcc.c | 5 | ||||
-rw-r--r-- | src/afl-performance.c | 10 | ||||
-rw-r--r-- | src/afl-showmap.c | 29 | ||||
-rw-r--r-- | src/afl-tmin.c | 29 |
13 files changed, 448 insertions, 777 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 56284f6f..e6dd0fca 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -772,15 +772,38 @@ static void set_up_environment(void) { setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "allocator_may_return_null=1:" "symbolize=0:" - "allocator_may_return_null=1", + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", + 0); + + setenv("UBSAN_OPTIONS", + "halt_on_error=1:" + "abort_on_error=1:" + "malloc_context_size=0:" + "allocator_may_return_null=1:" + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" "abort_on_error=1:" + "msan_track_origins=0" "allocator_may_return_null=1:" - "msan_track_origins=0", 0); + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); if (get_afl_env("AFL_PRELOAD")) { diff --git a/src/afl-common.c b/src/afl-common.c index 79d419cd..c023789b 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -46,50 +46,6 @@ u8 be_quiet = 0; u8 *doc_path = ""; u8 last_intr = 0; -char *afl_environment_variables[] = { - - "AFL_ALIGNED_ALLOC", "AFL_ALLOW_TMP", "AFL_ANALYZE_HEX", "AFL_AS", - "AFL_AUTORESUME", "AFL_AS_FORCE_INSTRUMENT", "AFL_BENCH_JUST_ONE", - "AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CMIN_ALLOW_ANY", - "AFL_CMIN_CRASHES_ONLY", "AFL_CODE_END", "AFL_CODE_START", - "AFL_COMPCOV_BINNAME", "AFL_COMPCOV_LEVEL", "AFL_CUSTOM_MUTATOR_LIBRARY", - "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CXX", "AFL_DEBUG", "AFL_DEBUG_CHILD_OUTPUT", - "AFL_DEBUG_GDB", - //"AFL_DEFER_FORKSRV", // not implemented anymore, so warn additionally - "AFL_DISABLE_TRIM", "AFL_DONT_OPTIMIZE", "AFL_DUMB_FORKSRV", - "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", "AFL_FAST_CAL", "AFL_FORCE_UI", - "AFL_GCC_WHITELIST", "AFL_GCJ", "AFL_HANG_TMOUT", "AFL_HARDEN", - "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IMPORT_FIRST", - "AFL_INST_LIBS", "AFL_INST_RATIO", "AFL_KEEP_TRACES", "AFL_KEEP_ASSEMBLY", - "AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER", - "AFL_LD_PASSTHROUGH", "AFL_REAL_LD", "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_SKIPSINGLEBLOCK", "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_ALL", "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR", - "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", - "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_LLVM_SKIP_NEVERZERO", - "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", - "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", - "AFL_NO_UI", "AFL_NO_PYTHON", "AFL_UNTRACER_FILE", "AFL_LLVM_USE_TRACE_PC", - "AFL_NO_X86", // not really an env but we dont want to warn on it - "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE", - //"AFL_PERSISTENT", // not implemented anymore, so warn additionally - "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV", - "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", "AFL_QEMU_DISABLE_CACHE", - "AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT", - "AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_HOOK", - "AFL_QEMU_PERSISTENT_RET", "AFL_QEMU_PERSISTENT_RETADDR_OFFSET", - "AFL_QUIET", "AFL_RANDOM_ALLOC_CANARY", "AFL_REAL_PATH", - "AFL_SHUFFLE_QUEUE", "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", - "AFL_SKIP_CRASHES", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", - "AFL_TRACE_PC", "AFL_USE_ASAN", "AFL_USE_MSAN", "AFL_USE_TRACE_PC", - "AFL_USE_UBSAN", "AFL_USE_CFISAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", - NULL}; - void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { u32 i = 0; @@ -449,14 +405,14 @@ void check_environment_vars(char **envp) { if (be_quiet) { return; } - int index = 0, found = 0; + int index = 0, issue_detected = 0; char *env, *val; while ((env = envp[index++]) != NULL) { if (strncmp(env, "ALF_", 4) == 0) { WARNF("Potentially mistyped AFL environment variable: %s", env); - found++; + issue_detected = 1; } else if (strncmp(env, "AFL_", 4) == 0) { @@ -474,6 +430,7 @@ void check_environment_vars(char **envp) { "AFL environment variable %s defined but is empty, this can " "lead to unexpected consequences", afl_environment_variables[i]); + issue_detected = 1; } @@ -485,10 +442,31 @@ void check_environment_vars(char **envp) { } + i = 0; + while (match == 0 && afl_environment_deprecated[i] != NULL) { + + if (strncmp(env, afl_environment_deprecated[i], + strlen(afl_environment_deprecated[i])) == 0 && + env[strlen(afl_environment_deprecated[i])] == '=') { + + match = 1; + + WARNF("AFL environment variable %s is deprecated!", + afl_environment_deprecated[i]); + issue_detected = 1; + + } else { + + i++; + + } + + } + if (match == 0) { WARNF("Mistyped AFL environment variable: %s", env); - found++; + issue_detected = 1; } @@ -496,7 +474,7 @@ void check_environment_vars(char **envp) { } - if (found) { sleep(2); } + if (issue_detected) { sleep(2); } } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 419ce28e..47493eba 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -434,7 +434,27 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "detect_leaks=0:" "malloc_context_size=0:" "symbolize=0:" - "allocator_may_return_null=1", + "allocator_may_return_null=1:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", + 0); + + /* Set sane defaults for UBSAN if nothing else specified. */ + + setenv("UBSAN_OPTIONS", + "halt_on_error=1:" + "abort_on_error=1:" + "malloc_context_size=0:" + "allocator_may_return_null=1:" + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); /* MSAN is tricky, because it doesn't support abort_on_error=1 at this @@ -446,7 +466,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "abort_on_error=1:" "malloc_context_size=0:" "allocator_may_return_null=1:" - "msan_track_origins=0", + "msan_track_origins=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); fsrv->init_child_func(fsrv, argv); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index a2e849dc..e95ae95f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -36,14 +36,11 @@ void bind_to_free_cpu(afl_state_t *afl) { #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) cpu_set_t c; #elif defined(__NetBSD__) - cpuset_t * c; + cpuset_t *c; #elif defined(__sun) - psetid_t c; + psetid_t c; #endif - u8 cpu_used[4096] = {0}; - u32 i; - if (afl->cpu_core_count < 2) { return; } if (afl->afl_env.afl_no_affinity) { @@ -53,13 +50,46 @@ void bind_to_free_cpu(afl_state_t *afl) { } + u8 cpu_used[4096] = {0}, lockfile[PATH_MAX] = ""; + u32 i; + + 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, 0600)) < 0) { + + if (first) { + + WARNF("CPU affinity lock file present, waiting ..."); + first = 0; + + } + + usleep(1000); + + } + + } while (lockfd < 0); + + close(lockfd); + + } + #if defined(__linux__) + DIR * d; struct dirent *de; d = opendir("/proc"); if (!d) { + if (lockfile[0]) unlink(lockfile); WARNF("Unable to access /proc - can't scan for free CPU cores."); return; @@ -67,11 +97,6 @@ void bind_to_free_cpu(afl_state_t *afl) { ACTF("Checking CPU core loadout..."); - /* Introduce some jitter, in case multiple AFL tasks are doing the same - thing at the same time... */ - - usleep(R(1000) * 250); - /* Scan all /proc/<pid>/status entries, checking for Cpus_allowed_list. Flag all processes bound to a specific CPU using cpu_used[]. This will fail for some exotic binding setups, but is likely good enough in almost @@ -114,20 +139,29 @@ void bind_to_free_cpu(afl_state_t *afl) { } closedir(d); + #elif defined(__FreeBSD__) || defined(__DragonFly__) + struct kinfo_proc *procs; size_t nprocs; size_t proccount; int s_name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]); - if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) return; + if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) { + + if (lockfile[0]) unlink(lockfile); + return; + + } + proccount = nprocs / sizeof(*procs); nprocs = nprocs * 4 / 3; 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; @@ -136,6 +170,7 @@ 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; // fix when ki_oncpu = -1 @@ -145,16 +180,21 @@ void bind_to_free_cpu(afl_state_t *afl) { if (oncpu != -1 && oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60) cpu_used[oncpu] = 1; + #elif defined(__DragonFly__) + if (procs[i].kp_lwp.kl_cpuid < sizeof(cpu_used) && procs[i].kp_lwp.kl_pctcpu > 10) cpu_used[procs[i].kp_lwp.kl_cpuid] = 1; + #endif } ck_free(procs); + #elif defined(__NetBSD__) + struct kinfo_proc2 *procs; size_t nprocs; size_t proccount; @@ -163,13 +203,20 @@ void bind_to_free_cpu(afl_state_t *afl) { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 0}; size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]); - if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) return; + if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) { + + if (lockfile[0]) unlink(lockfile); + return; + + } + proccount = nprocs / sizeof(struct kinfo_proc2); procs = ck_alloc(nprocs * sizeof(struct kinfo_proc2)); 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; @@ -183,7 +230,9 @@ void bind_to_free_cpu(afl_state_t *afl) { } ck_free(procs); + #elif defined(__sun) + kstat_named_t *n; kstat_ctl_t * m; kstat_t * k; @@ -198,6 +247,7 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!k) { + if (lockfile[0]) unlink(lockfile); kstat_close(m); return; @@ -205,6 +255,7 @@ void bind_to_free_cpu(afl_state_t *afl) { if (kstat_read(m, k, NULL)) { + if (lockfile[0]) unlink(lockfile); kstat_close(m); return; @@ -220,6 +271,7 @@ void bind_to_free_cpu(afl_state_t *afl) { k = kstat_lookup(m, "cpu_stat", i, NULL); if (kstat_read(m, k, &cs)) { + if (lockfile[0]) unlink(lockfile); kstat_close(m); return; @@ -233,6 +285,7 @@ void bind_to_free_cpu(afl_state_t *afl) { } kstat_close(m); + #else #warning \ "For this platform we do not have free CPU binding code yet. If possible, please supply a PR to https://github.com/AFLplusplus/AFLplusplus" @@ -241,7 +294,9 @@ void bind_to_free_cpu(afl_state_t *afl) { size_t cpu_start = 0; try: + #if !defined(__ANDROID__) + for (i = cpu_start; i < afl->cpu_core_count; i++) { if (!cpu_used[i]) { break; } @@ -251,6 +306,7 @@ void bind_to_free_cpu(afl_state_t *afl) { if (i == afl->cpu_core_count) { #else + for (i = afl->cpu_core_count - cpu_start - 1; i > -1; i--) if (!cpu_used[i]) break; if (i == -1) { @@ -274,18 +330,25 @@ void bind_to_free_cpu(afl_state_t *afl) { afl->cpu_aff = i; #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) + CPU_ZERO(&c); CPU_SET(i, &c); + #elif defined(__NetBSD__) + c = cpuset_create(); if (c == NULL) PFATAL("cpuset_create failed"); cpuset_set(i, c); + #elif defined(__sun) + pset_create(&c); if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed"); + #endif #if defined(__linux__) + if (sched_setaffinity(0, sizeof(c), &c)) { if (cpu_start == afl->cpu_core_count) { @@ -302,6 +365,7 @@ if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed"); } #elif defined(__FreeBSD__) || defined(__DragonFly__) + if (pthread_setaffinity_np(pthread_self(), sizeof(c), &c)) { if (cpu_start == afl->cpu_core_count) @@ -314,6 +378,7 @@ if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed"); } #elif defined(__NetBSD__) + if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) { if (cpu_start == afl->cpu_core_count) @@ -326,12 +391,14 @@ if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) { } cpuset_destroy(c); + #elif defined(__sun) + if (pset_bind(c, P_PID, getpid(), NULL)) { if (cpu_start == afl->cpu_core_count) PFATAL("pset_bind failed for cpu %d, exit", i); - WARNF("pthread_setaffinity failed to CPU %d, trying next CPU", i); + WARNF("pset_bind failed to CPU %d, trying next CPU", i); cpu_start++; goto try ; @@ -339,11 +406,17 @@ if (pset_bind(c, P_PID, getpid(), NULL)) { } pset_destroy(c); + #else + // this will need something for other platforms // TODO: Solaris/Illumos has processor_bind ... might worth a try + #endif + if (lockfile[0]) unlink(lockfile); + // we leave the environment variable to ensure a cleanup for other processes + } #endif /* HAVE_AFFINITY */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 9e54815c..399bfcab 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -24,11 +24,6 @@ */ #include "afl-fuzz.h" -#include <string.h> - -static u8 *strnstr(const u8 *s, const u8 *find, size_t slen); -static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, - u8 *to); /* MOpt */ @@ -367,463 +362,6 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { #endif /* !IGNORE_FINDS */ -/* Not pretty, but saves a lot of writing */ -#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size - -static u8 *strnstr(const u8 *s, const u8 *find, size_t slen) { - - char c, sc; - size_t len; - - if ((c = *find++) != '\0') { - - len = strlen(find); - do { - - do { - - if (slen-- < 1 || (sc = *s++) == '\0') return (NULL); - - } while (sc != c); - - if (len > slen) return (NULL); - - } while (strncmp(s, find, len) != 0); - - s--; - - } - - return ((u8 *)s); - -} - -/* replace between deliminators, if rep == NULL, then we will duplicate the - * target */ - -static u32 delim_replace(u8 **out_buf, s32 *temp_len, size_t pos, - const u8 *ldelim, const u8 *rdelim, u8 *rep) { - - u8 *end_buf = *out_buf + *temp_len; - u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, *temp_len - pos); - - if (ldelim_start != NULL) { - - u32 max = (end_buf - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN - ? AFL_TXT_STRING_MAX_LEN - : end_buf - ldelim_start - 1); - - if (max > 0) { - - u8 *rdelim_end = strnstr(ldelim_start + 1, rdelim, max); - - if (rdelim_end != NULL) { - - u32 rep_len, delim_space_len = rdelim_end - ldelim_start - 1, xtra = 0; - - if (rep != NULL) { - - rep_len = (u32)strlen(rep); - - } else { // NULL? then we copy the value in between the delimiters - - rep_len = delim_space_len; - delim_space_len = 0; - rep = ldelim_start + 1; - xtra = rep_len; - - } - - if (rep_len != delim_space_len) { - - memmove(ldelim_start + rep_len + xtra + 1, rdelim_end, - *temp_len - (rdelim_end - *out_buf)); - - } - - memcpy(ldelim_start + 1, rep, rep_len); - *temp_len = (*temp_len - delim_space_len + rep_len); - - return 1; - - } - - } - - } - - return 0; - -} - -static u32 delim_swap(u8 **out_buf, s32 *temp_len, size_t pos, const u8 *ldelim, - const u8 *mdelim, const u8 *rdelim) { - - u8 *out_buf_end = *out_buf + *temp_len; - u32 max = (*temp_len - pos > AFL_TXT_STRING_MAX_LEN ? AFL_TXT_STRING_MAX_LEN - : *temp_len - pos); - u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, max); - - if (ldelim_start != NULL) { - - max = (out_buf_end - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN - ? AFL_TXT_STRING_MAX_LEN - : out_buf_end - ldelim_start - 1); - if (max > 1) { - - u8 *mdelim_pos = strnstr(ldelim_start + 1, mdelim, max); - - if (mdelim_pos != NULL) { - - max = (out_buf_end - mdelim_pos - 1 > AFL_TXT_STRING_MAX_LEN - ? AFL_TXT_STRING_MAX_LEN - : out_buf_end - mdelim_pos - 1); - if (max > 0) { - - u8 *rdelim_end = strnstr(mdelim + 1, rdelim, max); - - if (rdelim_end != NULL) { - - u32 first_len = mdelim_pos - ldelim_start - 1; - u32 second_len = rdelim_end - mdelim_pos - 1; - u8 scratch[AFL_TXT_STRING_MAX_LEN]; - - memcpy(scratch, ldelim_start + 1, first_len); - - if (first_len != second_len) { - - memmove(ldelim_start + second_len + 1, mdelim_pos, - out_buf_end - mdelim_pos); - - } - - memcpy(ldelim_start + 1, mdelim_pos + 1, second_len); - - if (first_len != second_len) { - - memmove(mdelim_pos + first_len + 1, rdelim_end, - out_buf_end - rdelim_end); - - } - - memcpy(mdelim_pos + 1, scratch, first_len); - - return 1; - - } - - } - - } - - } - - } - - return 0; - -} - -static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, - u8 *to) { - - u8 *start = strnstr(*out_buf + pos, from, *temp_len - pos); - - if (start) { - - u32 from_len = strlen(from); - u32 to_len = strlen(to); - - if (from_len != to_len) { - - memmove(start + to_len, start + from_len, - *temp_len - from_len - (start - *out_buf)); - - } - - memcpy(start, to, to_len); - *temp_len = (*temp_len - from_len + to_len); - - return 1; - - } - - return 0; - -} - -/* Returns 1 if a mutant was generated and placed in out_buf, 0 if none - * generated. */ - -static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { - - s32 temp_len; - u32 pos, yes = 0, - mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 1; - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS); - temp_len = *orig_temp_len; - memcpy(new_buf, *out_buf, temp_len); - - for (u32 i = 0; i < mutations; i++) { - - if (temp_len < AFL_TXT_MIN_LEN) { - - if (yes) - return 1; - else - return 0; - - } - - pos = rand_below(afl, temp_len - 1); - int choice = rand_below(afl, 76); - switch (choice) { - - case 0: - yes += string_replace(out_buf, &temp_len, pos, "*", " "); - break; - case 1: - yes += string_replace(out_buf, &temp_len, pos, "(", "(!"); - break; - case 2: - yes += string_replace(out_buf, &temp_len, pos, "==", "!="); - break; - case 3: - yes += string_replace(out_buf, &temp_len, pos, "!=", "=="); - break; - case 4: - yes += string_replace(out_buf, &temp_len, pos, "==", "<"); - break; - case 5: - yes += string_replace(out_buf, &temp_len, pos, "<", "=="); - break; - case 6: - yes += string_replace(out_buf, &temp_len, pos, "==", ">"); - break; - case 7: - yes += string_replace(out_buf, &temp_len, pos, ">", "=="); - break; - case 8: - yes += string_replace(out_buf, &temp_len, pos, "=", "<"); - break; - case 9: - yes += string_replace(out_buf, &temp_len, pos, "=", ">"); - break; - case 10: - yes += string_replace(out_buf, &temp_len, pos, "<", ">"); - break; - case 11: - yes += string_replace(out_buf, &temp_len, pos, ">", "<"); - break; - case 12: - yes += string_replace(out_buf, &temp_len, pos, "++", "--"); - break; - case 13: - yes += string_replace(out_buf, &temp_len, pos, "--", "++"); - break; - case 14: - yes += string_replace(out_buf, &temp_len, pos, "+", "-"); - break; - case 15: - yes += string_replace(out_buf, &temp_len, pos, "+", "*"); - break; - case 16: - yes += string_replace(out_buf, &temp_len, pos, "+", "/"); - break; - case 17: - yes += string_replace(out_buf, &temp_len, pos, "+", "%"); - break; - case 18: - yes += string_replace(out_buf, &temp_len, pos, "*", "-"); - break; - case 19: - yes += string_replace(out_buf, &temp_len, pos, "*", "+"); - break; - case 20: - yes += string_replace(out_buf, &temp_len, pos, "*", "/"); - break; - case 21: - yes += string_replace(out_buf, &temp_len, pos, "*", "%"); - break; - case 22: - yes += string_replace(out_buf, &temp_len, pos, "-", "+"); - break; - case 23: - yes += string_replace(out_buf, &temp_len, pos, "-", "*"); - break; - case 24: - yes += string_replace(out_buf, &temp_len, pos, "-", "/"); - break; - case 25: - yes += string_replace(out_buf, &temp_len, pos, "-", "%"); - break; - case 26: - yes += string_replace(out_buf, &temp_len, pos, "/", "-"); - break; - case 27: - yes += string_replace(out_buf, &temp_len, pos, "/", "*"); - break; - case 28: - yes += string_replace(out_buf, &temp_len, pos, "/", "+"); - break; - case 29: - yes += string_replace(out_buf, &temp_len, pos, "/", "%"); - break; - case 30: - yes += string_replace(out_buf, &temp_len, pos, "%", "-"); - break; - case 31: - yes += string_replace(out_buf, &temp_len, pos, "%", "*"); - break; - case 32: - yes += string_replace(out_buf, &temp_len, pos, "%", "/"); - break; - case 33: - yes += string_replace(out_buf, &temp_len, pos, "%", "+"); - break; - case 34: - yes += string_replace(out_buf, &temp_len, pos, "->", "."); - break; - case 35: - yes += string_replace(out_buf, &temp_len, pos, ".", "->"); - break; - case 36: - yes += string_replace(out_buf, &temp_len, pos, "0", "1"); - break; - case 37: - yes += string_replace(out_buf, &temp_len, pos, "1", "0"); - break; - case 38: - yes += string_replace(out_buf, &temp_len, pos, "if", "while"); - break; - case 39: - yes += string_replace(out_buf, &temp_len, pos, "while", "if"); - break; - case 40: - yes += string_replace(out_buf, &temp_len, pos, "!", " "); - break; - case 41: - yes += string_replace(out_buf, &temp_len, pos, "&&", "||"); - break; - case 42: - yes += string_replace(out_buf, &temp_len, pos, "||", "&&"); - break; - case 43: - yes += string_replace(out_buf, &temp_len, pos, "!", ""); - break; - case 44: - yes += string_replace(out_buf, &temp_len, pos, "==", "="); - break; - case 45: - yes += string_replace(out_buf, &temp_len, pos, "--", ""); - break; - case 46: - yes += string_replace(out_buf, &temp_len, pos, "<<", "<"); - break; - case 47: - yes += string_replace(out_buf, &temp_len, pos, ">>", ">"); - break; - case 48: - yes += string_replace(out_buf, &temp_len, pos, "<", "<<"); - break; - case 49: - yes += string_replace(out_buf, &temp_len, pos, ">", ">>"); - break; - case 50: - yes += string_replace(out_buf, &temp_len, pos, "\"", "'"); - break; - case 51: - yes += string_replace(out_buf, &temp_len, pos, "'", "\""); - break; - case 52: - yes += string_replace(out_buf, &temp_len, pos, "(", "\""); - break; - case 53: - yes += string_replace(out_buf, &temp_len, pos, "\n", " "); - break; - case 54: - yes += string_replace(out_buf, &temp_len, pos, "\n", ";"); - break; - case 55: - yes += string_replace(out_buf, &temp_len, pos, "\n", "<"); - break; - case 56: /* Remove a semicolon delimited statement after a semicolon */ - yes += delim_replace(out_buf, &temp_len, pos, ";", ";", ";"); - break; - case 57: /* Remove a semicolon delimited statement after a left curly - brace */ - yes += delim_replace(out_buf, &temp_len, pos, "}", ";", "}"); - break; - case 58: /* Remove a curly brace construct */ - yes += delim_replace(out_buf, &temp_len, pos, "{", "}", ""); - break; - case 59: /* Replace a curly brace construct with an empty one */ - yes += delim_replace(out_buf, &temp_len, pos, "{", "}", "{}"); - break; - case 60: - yes += delim_swap(out_buf, &temp_len, pos, ";", ";", ";"); - break; - case 61: - yes += delim_swap(out_buf, &temp_len, pos, "}", ";", ";"); - break; - case 62: /* Swap comma delimited things case 1 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ")"); - break; - case 63: /* Swap comma delimited things case 2 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ","); - break; - case 64: /* Swap comma delimited things case 3 */ - yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ","); - break; - case 65: /* Swap comma delimited things case 4 */ - yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ")"); - break; - case 66: /* Just delete a line */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", ""); - break; - case 67: /* Delete something like "const" case 1 */ - yes += delim_replace(out_buf, &temp_len, pos, " ", " ", ""); - break; - case 68: /* Delete something like "const" case 2 */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", " ", ""); - break; - case 69: /* Delete something like "const" case 3 */ - yes += delim_replace(out_buf, &temp_len, pos, "(", " ", ""); - break; - case 70: /* Swap space delimited things case 1 */ - yes += delim_swap(out_buf, &temp_len, pos, " ", " ", " "); - break; - case 71: /* Swap space delimited things case 2 */ - yes += delim_swap(out_buf, &temp_len, pos, " ", " ", ")"); - break; - case 72: /* Swap space delimited things case 3 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", " ", " "); - break; - case 73: /* Swap space delimited things case 4 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", " ", ")"); - break; - case 74: /* Duplicate a single line of code */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", NULL); - break; - case 75: /* Duplicate a construct (most often, a non-nested for loop */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "}", NULL); - break; - - } - - } - - if (yes == 0 || temp_len <= 0) { return 0; } - - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); - *out_buf = new_buf; - *orig_temp_len = temp_len; - - return 1; - -} - /* Take the current entry from the queue, fuzz it for a while. This function is a tad too long... returns 0 if fuzzed successfully, 1 if skipped or bailed out. */ @@ -840,6 +378,9 @@ u8 fuzz_one_original(afl_state_t *afl) { u8 a_collect[MAX_AUTO_EXTRA]; u32 a_len = 0; +/* Not pretty, but saves a lot of writing */ +#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size + #ifdef IGNORE_FINDS /* In IGNORE_FINDS mode, skip any entries that weren't in the @@ -2313,12 +1854,9 @@ havoc_stage: /* We essentially just do several thousand runs (depending on perf_score) where we take the input file and make random stacked tweaks. */ - u32 r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0) + - (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 0); - for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - u32 r, use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2)); + u32 use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2)); afl->stage_cur_val = use_stacking; @@ -2358,9 +1896,8 @@ havoc_stage: } - retry_havoc: - - switch ((r = rand_below(afl, r_max))) { + switch (rand_below( + afl, 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { case 0: @@ -2654,98 +2191,177 @@ havoc_stage: break; } + + case 15: { - // TODO: add splicing mutation here. - // 15: - // break; + /* Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ - default: - if (r == 15 && (afl->extras_cnt || afl->a_extras_cnt)) { + if (afl->queued_paths < 2) break; - /* Values 15 and 16 can be selected only if there are any extras - present in the dictionaries. */ + /* Pick a random queue entry and seek to it. */ - /* Overwrite bytes with an extra. */ + u32 tid; + do + tid = rand_below(afl, afl->queued_paths); + while (tid == afl->current_entry); - if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + struct queue_entry* target = afl->queue_buf[tid]; - /* No user-specified extras or odds in our favor. Let's use an - auto-detected one. */ + /* Make sure that the target has a reasonable length. */ - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; - u32 insert_at; + while (target && (target->len < 2 || target == afl->queue_cur)) + target = target->next; - if (extra_len > temp_len) { break; } + if (!target) break; - insert_at = rand_below(afl, temp_len - extra_len + 1); - memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, - extra_len); + /* Read the testcase into a new buffer. */ - } else { + fd = open(target->fname, O_RDONLY); - /* No auto extras or odds in our favor. Use the dictionary. */ + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } - u32 use_extra = rand_below(afl, afl->extras_cnt); - u32 extra_len = afl->extras[use_extra].len; - u32 insert_at; + u32 new_len = target->len; + u8 * new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); - if (extra_len > temp_len) { break; } + ck_read(fd, new_buf, new_len, target->fname); - insert_at = rand_below(afl, temp_len - extra_len + 1); - memcpy(out_buf + insert_at, afl->extras[use_extra].data, - extra_len); + close(fd); - } + u8 overwrite = 0; + if (temp_len >= 2 && rand_below(afl, 2)) + overwrite = 1; + else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { + if (temp_len >= 2) overwrite = 1; + else break; + } - } else if (r == 16 && (afl->extras_cnt || afl->a_extras_cnt)) { + if (overwrite) { - u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); - u8 *ptr; + u32 copy_from, copy_to, copy_len; - /* Insert an extra. Do the same dice-rolling stuff as for the - previous case. */ + copy_len = choose_block_len(afl, new_len - 1); + if (copy_len > temp_len) copy_len = temp_len; - if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + copy_from = rand_below(afl, new_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); - use_extra = rand_below(afl, afl->a_extras_cnt); - extra_len = afl->a_extras[use_extra].len; - ptr = afl->a_extras[use_extra].data; + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - } else { + } else { + + u32 clone_from, clone_to, clone_len; + + clone_len = choose_block_len(afl, new_len); + clone_from = rand_below(afl, new_len - clone_len + 1); + + clone_to = rand_below(afl, temp_len); + + u8 * temp_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); - use_extra = rand_below(afl, afl->extras_cnt); - extra_len = afl->extras[use_extra].len; - ptr = afl->extras[use_extra].data; + /* Head */ - } + memcpy(temp_buf, out_buf, clone_to); - if (temp_len + extra_len >= MAX_FILE) { break; } + /* Inserted part */ - out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); + memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); /* Tail */ - memmove(out_buf + insert_at + extra_len, out_buf + insert_at, - temp_len - insert_at); + memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); - /* Inserted part */ - memcpy(out_buf + insert_at, ptr, extra_len); + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + out_buf = temp_buf; + temp_len += clone_len; + + } + + break; + + } - temp_len += extra_len; + /* Values 15 and 16 can be selected only if there are any extras + present in the dictionaries. */ + + case 16: { + + /* Overwrite bytes with an extra. */ + + if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + + /* No user-specified extras or odds in our favor. Let's use an + auto-detected one. */ + + u32 use_extra = rand_below(afl, afl->a_extras_cnt); + u32 extra_len = afl->a_extras[use_extra].len; + u32 insert_at; + + if (extra_len > temp_len) { break; } + + insert_at = rand_below(afl, temp_len - extra_len + 1); + memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, + extra_len); } else { - // ascii mutations - if (text_mutation(afl, &out_buf, &temp_len) == 0) goto retry_havoc; + /* No auto extras or odds in our favor. Use the dictionary. */ + + u32 use_extra = rand_below(afl, afl->extras_cnt); + u32 extra_len = afl->extras[use_extra].len; + u32 insert_at; - //#ifdef _AFL_DOCUMENT_MUTATIONS - // fprintf(stderr, "MUTATED: %s/mutations/%09u:*\n", - // afl->out_dir, - // afl->document_counter); - //#endif + if (extra_len > temp_len) { break; } + + insert_at = rand_below(afl, temp_len - extra_len + 1); + memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); } + break; + + } + + case 17: { + + u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); + u8 *ptr; + + /* Insert an extra. Do the same dice-rolling stuff as for the + previous case. */ + + if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + + use_extra = rand_below(afl, afl->a_extras_cnt); + extra_len = afl->a_extras[use_extra].len; + ptr = afl->a_extras[use_extra].data; + + } else { + + use_extra = rand_below(afl, afl->extras_cnt); + extra_len = afl->extras[use_extra].len; + ptr = afl->extras[use_extra].data; + + } + + if (temp_len + extra_len >= MAX_FILE) { break; } + + out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); + + /* Tail */ + memmove(out_buf + insert_at + extra_len, out_buf + insert_at, + temp_len - insert_at); + + /* Inserted part */ + memcpy(out_buf + insert_at, ptr, extra_len); + + temp_len += extra_len; + + break; + + } + } } @@ -2831,20 +2447,7 @@ retry_splicing: } while (tid == afl->current_entry); afl->splicing_with = tid; - target = afl->queue; - - while (tid >= 100) { - - target = target->next_100; - tid -= 100; - - } - - while (tid--) { - - target = target->next; - - } + target = afl->queue_buf[tid]; /* Make sure that the target has a reasonable length. */ diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index da6b1eee..a96995e5 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -24,7 +24,8 @@ #include "afl-fuzz.h" #include <limits.h> -#include <ctype.h> + +#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size /* Mark deterministic checks as done for a particular queue entry. We use the .state file to avoid repeating deterministic fuzzing when resuming aborted @@ -101,119 +102,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { } -/* check if ascii or UTF-8 */ - -static u8 check_if_text(struct queue_entry *q) { - - if (q->len < AFL_TXT_MIN_LEN) return 0; - - u8 buf[MAX_FILE], bom[3] = {0xef, 0xbb, 0xbf}; - s32 fd, len = q->len, offset = 0, ascii = 0, utf8 = 0, comp; - - if ((fd = open(q->fname, O_RDONLY)) < 0) return 0; - if ((comp = read(fd, buf, len)) != len) return 0; - close(fd); - - 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 (((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && - (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) { - - offset += 2; - utf8++; - comp--; - continue; - - } - - // excluding overlongs - if ((buf[offset + 0] == 0xE0 && - (0xA0 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) && - (0x80 <= buf[offset + 2] && - buf[offset + 2] <= 0xBF)) || // straight 3-byte - (((0xE1 <= buf[offset + 0] && buf[offset + 0] <= 0xEC) || - buf[offset + 0] == 0xEE || buf[offset + 0] == 0xEF) && - (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) && - (0x80 <= buf[offset + 2] && - buf[offset + 2] <= 0xBF)) || // excluding surrogates - (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 - if ((buf[offset + 0] == 0xF0 && - (0x90 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) && - (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) && - (0x80 <= buf[offset + 3] && - buf[offset + 3] <= 0xBF)) || // planes 4-15 - ((0xF1 <= buf[offset + 0] && buf[offset + 0] <= 0xF3) && - (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) && - (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) && - (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)) || // plane 16 - (buf[offset + 0] == 0xF4 && - (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; - - } - - // handle utf8 bom - if (buf[offset + 0] == bom[0] && buf[offset + 1] == bom[1] && - buf[offset + 2] == bom[2]) { - - offset += 3; - utf8++; - comp -= 2; - continue; - - } - - offset++; - - } - - u32 percent_utf8 = (utf8 * 100) / comp; - u32 percent_ascii = (ascii * 100) / len; - - if (percent_utf8 >= percent_ascii && percent_utf8 >= AFL_TXT_MIN_PERCENT) - 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) { @@ -251,6 +139,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { afl->q_prev100 = q; } + + struct queue_entry** queue_buf = ck_maybe_grow(BUF_PARAMS(queue), afl->queued_paths * sizeof(struct queue_entry*)); + queue_buf[afl->queued_paths -1] = q; afl->last_path_time = get_cur_time(); @@ -273,8 +164,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } - q->is_ascii = check_if_text(q); - } /* Destroy the entire queue. */ diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 43850eb5..c53e0e06 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -177,6 +177,9 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur; ck_free(backup); + ck_free(rng); + rng = NULL; + while (ranges) { rng = ranges; @@ -186,9 +189,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { } - ck_free(rng); - rng = NULL; - // save the input with the high entropy if (needs_write) { @@ -277,9 +277,9 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u8 * o_buf_8 = &orig_buf[idx]; u32 its_len = len - idx; - *status = 0; + // *status = 0; - if (SHAPE_BYTES(h->shape) == 8) { + if (SHAPE_BYTES(h->shape) >= 8) { if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) { @@ -290,7 +290,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } // reverse encoding - if (do_reverse) { + if (do_reverse && *status != 1) { if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), SWAP64(o_pattern), idx, orig_buf, buf, @@ -304,7 +304,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - if (SHAPE_BYTES(h->shape) == 4 || *status == 2) { + if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) { if (its_len >= 4 && *buf_32 == (u32)pattern && *o_buf_32 == (u32)o_pattern) { @@ -316,7 +316,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } // reverse encoding - if (do_reverse) { + if (do_reverse && *status != 1) { if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), SWAP32(o_pattern), idx, orig_buf, buf, @@ -330,7 +330,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - if (SHAPE_BYTES(h->shape) == 2 || *status == 2) { + if (SHAPE_BYTES(h->shape) >= 2 && *status != 1) { if (its_len >= 2 && *buf_16 == (u16)pattern && *o_buf_16 == (u16)o_pattern) { @@ -342,7 +342,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } // reverse encoding - if (do_reverse) { + if (do_reverse && *status != 1) { if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), SWAP16(o_pattern), idx, orig_buf, buf, @@ -356,7 +356,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - if (SHAPE_BYTES(h->shape) == 1 || *status == 2) { + if (SHAPE_BYTES(h->shape) >= 1 && *status != 1) { if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) { @@ -435,7 +435,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { u32 fails; u8 found_one = 0; - /* loop cmps are useless, detect and blacklist them */ + /* loop cmps are useless, detect and ignore them */ u64 s_v0, s_v1; u8 s_v0_fixed = 1, s_v1_fixed = 1; u8 s_v0_inc = 1, s_v1_inc = 1; @@ -482,6 +482,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { for (idx = 0; idx < len && fails < 8; ++idx) { + status = 0; if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, orig_buf, buf, len, 1, &status))) { @@ -499,6 +500,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } + status = 0; if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, orig_buf, buf, len, 1, &status))) { @@ -743,7 +745,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, afl->pass_stats[k].faileds || afl->pass_stats[k].total == 0xff)) { - afl->shm.cmp_map->headers[k].hits = 0; // blacklist this cmp + afl->shm.cmp_map->headers[k].hits = 0; // ignore this cmp } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index ece2d170..e56d122a 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -164,14 +164,14 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { void read_afl_environment(afl_state_t *afl, char **envp) { - int index = 0, found = 0; + int index = 0, issue_detected = 0; char *env; while ((env = envp[index++]) != NULL) { if (strncmp(env, "ALF_", 4) == 0) { WARNF("Potentially mistyped AFL environment variable: %s", env); - found++; + issue_detected = 1; } else if (strncmp(env, "AFL_", 4) == 0) { @@ -307,15 +307,6 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_tmpdir = (u8 *)get_afl_env(afl_environment_variables[i]); - } else if (!strncmp(env, "AFL_POST_LIBRARY", - - afl_environment_variable_len)) { - - FATAL( - "AFL_POST_LIBRARY is deprecated, use " - "AFL_CUSTOM_MUTATOR_LIBRARY instead, see " - "docs/custom_mutators.md"); - } else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_LIBRARY", afl_environment_variable_len)) { @@ -352,10 +343,48 @@ void read_afl_environment(afl_state_t *afl, char **envp) { } + i = 0; + while (match == 0 && afl_environment_variables[i] != NULL) { + + if (strncmp(env, afl_environment_variables[i], + strlen(afl_environment_variables[i])) == 0 && + env[strlen(afl_environment_variables[i])] == '=') { + + match = 1; + + } else { + + i++; + + } + + } + + i = 0; + while (match == 0 && afl_environment_deprecated[i] != NULL) { + + if (strncmp(env, afl_environment_deprecated[i], + strlen(afl_environment_deprecated[i])) == 0 && + env[strlen(afl_environment_deprecated[i])] == '=') { + + match = 1; + + WARNF("AFL environment variable %s is deprecated!", + afl_environment_deprecated[i]); + issue_detected = 1; + + } else { + + i++; + + } + + } + if (match == 0) { WARNF("Mistyped AFL environment variable: %s", env); - found++; + issue_detected = 1; } @@ -363,7 +392,7 @@ void read_afl_environment(afl_state_t *afl, char **envp) { } - if (found) { sleep(2); } + if (issue_detected) { sleep(2); } } @@ -376,6 +405,7 @@ void afl_state_deinit(afl_state_t *afl) { if (afl->pass_stats) { ck_free(afl->pass_stats); } if (afl->orig_cmp_map) { ck_free(afl->orig_cmp_map); } + if (afl->queue_buf) { free(afl->queue_buf); } if (afl->out_buf) { free(afl->out_buf); } if (afl->out_scratch_buf) { free(afl->out_scratch_buf); } if (afl->eff_buf) { free(afl->eff_buf); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f25f8bb6..872ed9ae 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -42,19 +42,21 @@ static void at_exit() { int i; char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL}; - char *ptr = getenv("__AFL_TARGET_PID1"); + char *ptr; + ptr = getenv(CPU_AFFINITY_ENV_VAR); + if (ptr && *ptr) unlink(ptr); + + ptr = getenv("__AFL_TARGET_PID1"); if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); ptr = getenv("__AFL_TARGET_PID2"); - if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); i = 0; while (list[i] != NULL) { ptr = getenv(list[i]); - if (ptr && *ptr) { #ifdef USEMMAP @@ -264,6 +266,8 @@ int main(int argc, char **argv_orig, char **envp) { gettimeofday(&tv, &tz); rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid()); + afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing + while ((opt = getopt(argc, argv, "+c:i:I:o:f:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > 0) { @@ -561,7 +565,6 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); } afl->fsrv.qemu_mode = 1; - afl->shmem_testcase_mode = 1; if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; } @@ -578,7 +581,6 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); } afl->unicorn_mode = 1; - afl->shmem_testcase_mode = 1; if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; } @@ -589,7 +591,6 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->use_wine) { FATAL("Multiple -W options not supported"); } afl->fsrv.qemu_mode = 1; afl->use_wine = 1; - afl->shmem_testcase_mode = 1; if (!mem_limit_given) { afl->fsrv.mem_limit = 0; } @@ -790,8 +791,8 @@ int main(int argc, char **argv_orig, char **envp) { OKF("afl++ is open source, get it at " "https://github.com/AFLplusplus/AFLplusplus"); OKF("Power schedules from github.com/mboehme/aflfast"); - OKF("Python Mutator and llvm_mode whitelisting from github.com/choller/afl"); - OKF("afl-tmin fork server patch from github.com/nccgroup/TriforceAFL"); + OKF("Python Mutator and llvm_mode instrument file list from " + "github.com/choller/afl"); OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->is_main_node && @@ -1011,17 +1012,19 @@ int main(int argc, char **argv_orig, char **envp) { } + check_crash_handling(); + check_cpu_governor(afl); + get_core_count(afl); + atexit(at_exit); + + setup_dirs_fds(afl); + #ifdef HAVE_AFFINITY bind_to_free_cpu(afl); #endif /* HAVE_AFFINITY */ - check_crash_handling(); - check_cpu_governor(afl); - - atexit(at_exit); - afl->fsrv.trace_bits = afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); @@ -1038,12 +1041,10 @@ int main(int argc, char **argv_orig, char **envp) { } - setup_dirs_fds(afl); - if (afl->is_secondary_node && check_main_node_exists(afl) == 0) { WARNF("no -M main node found. You need to run one main instance!"); - sleep(5); + sleep(3); } @@ -1280,7 +1281,7 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->is_main_node)) { - if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 2))) { sync_fuzzers(afl); } + if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { sync_fuzzers(afl); } } else { diff --git a/src/afl-gcc.c b/src/afl-gcc.c index b8ff7e77..22e6be8e 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -132,6 +132,9 @@ static void edit_params(u32 argc, char **argv) { name = argv[0]; + /* This should never happen but fixes a scan-build warning */ + if (!name) { FATAL("Empty argv set"); } + } else { ++name; @@ -465,7 +468,7 @@ int main(int argc, char **argv) { u32 map_size = atoi(ptr); if (map_size != MAP_SIZE) { - FATAL("AFL_MAP_SIZE is not supported by afl-gcc"); + WARNF("AFL_MAP_SIZE is not supported by afl-gcc"); } diff --git a/src/afl-performance.c b/src/afl-performance.c index 6631f148..0c1697a8 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -44,12 +44,10 @@ void rand_set_seed(afl_state_t *afl, s64 init_seed) { } -uint32_t rand_next(afl_state_t *afl) { +uint64_t rand_next(afl_state_t *afl) { - const uint32_t result = - (uint32_t)rotl(afl->rand_seed[0] + afl->rand_seed[3], 23) + - afl->rand_seed[0]; - // const uint32_t result = (uint32_t) rotl(afl->rand_seed[1] * 5, 7) * 9; + const uint64_t result = + rotl(afl->rand_seed[0] + afl->rand_seed[3], 23) + afl->rand_seed[0]; const uint64_t t = afl->rand_seed[1] << 17; @@ -62,7 +60,7 @@ uint32_t rand_next(afl_state_t *afl) { afl->rand_seed[3] = rotl(afl->rand_seed[3], 45); - return (uint32_t)result; + return result; } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 883398ff..71e975a1 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -456,15 +456,38 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "allocator_may_return_null=1:" "symbolize=0:" - "allocator_may_return_null=1", + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", + 0); + + setenv("UBSAN_OPTIONS", + "halt_on_error=1:" + "abort_on_error=1:" + "malloc_context_size=0:" + "allocator_may_return_null=1:" + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" "abort_on_error=1:" + "msan_track_origins=0" "allocator_may_return_null=1:" - "msan_track_origins=0", 0); + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); if (get_afl_env("AFL_PRELOAD")) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 2db1eae7..68fcdd14 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -701,15 +701,38 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" + "allocator_may_return_null=1:" "symbolize=0:" - "allocator_may_return_null=1", + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", + 0); + + setenv("UBSAN_OPTIONS", + "halt_on_error=1:" + "abort_on_error=1:" + "malloc_context_size=0:" + "allocator_may_return_null=1:" + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" "abort_on_error=1:" + "msan_track_origins=0" "allocator_may_return_null=1:" - "msan_track_origins=0", 0); + "symbolize=0:" + "handle_segv=0:" + "handle_sigbus=0:" + "handle_abort=0:" + "handle_sigfpe=0:" + "handle_sigill=0", 0); if (get_afl_env("AFL_PRELOAD")) { |