From 00abb999e3c051c5c7c6349c385d77d25dea8e7f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 1 Jul 2020 18:24:00 +0200 Subject: v2.66d init --- include/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/config.h b/include/config.h index e8f52f45..7de74009 100644 --- a/include/config.h +++ b/include/config.h @@ -28,7 +28,7 @@ /* Version string: */ // c = release, d = volatile github dev, e = experimental branch -#define VERSION "++2.66c" +#define VERSION "++2.66d" /****************************************************** * * -- cgit 1.4.1 From 83790d65afb52a055d093451a50ce55690a25002 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 8 Jul 2020 11:16:39 +0200 Subject: eliminate race condition for cpu affinity on -M/-S --- docs/Changelog.md | 4 ++- include/config.h | 4 +++ src/afl-fuzz-init.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++------- src/afl-fuzz.c | 24 +++++++------ 4 files changed, 105 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/docs/Changelog.md b/docs/Changelog.md index 57b2b4a2..18e4e97e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,7 +10,9 @@ sending a mail to . ### Version ++2.66d (devel) - - ... ? + - afl-fuzz: + - eliminated CPU affinity race condition for -S/-M runs + - small fixes to afl-plot, afl-whatsup and man page creation ### Version ++2.66c (release) diff --git a/include/config.h b/include/config.h index 7de74009..4503c3e9 100644 --- a/include/config.h +++ b/include/config.h @@ -380,6 +380,10 @@ #define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID" +/* CPU Affinity lockfile env var */ + +#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE" + /* Uncomment this to use inferior block-coverage-based instrumentation. Note that you need to recompile the target binary for this to have any effect: */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index a2e849dc..e51b4729 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//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,7 +391,9 @@ 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) @@ -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.c b/src/afl-fuzz.c index e4e2669c..f7f247f3 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 @@ -1011,17 +1013,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 +1042,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); } -- cgit 1.4.1 From c2b04bdf6c596f5d220f27caead20d09452ed42d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 16 Jul 2020 14:32:41 +0200 Subject: queue buffer and new splice havoc mutation --- include/afl-fuzz.h | 4 ++ src/afl-fuzz-one.c | 111 +++++++++++++++++++++++++++++++++++++++++++-------- src/afl-fuzz-queue.c | 5 +++ src/afl-fuzz-state.c | 1 + 4 files changed, 104 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c9f84c61..adab8155 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -546,6 +546,10 @@ typedef struct afl_state { *queue_top, /* Top of the list */ *q_prev100; /* Previous 100 marker */ + // growing buf + struct queue_entry **queue_buf; + size_t queue_size; + struct queue_entry **top_rated; /* Top entries for bitmap bytes */ struct extra_data *extras; /* Extra tokens to fuzz with */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 72383727..399bfcab 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1897,7 +1897,7 @@ havoc_stage: } switch (rand_below( - afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { + afl, 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { case 0: @@ -2190,12 +2190,102 @@ havoc_stage: break; + } + + case 15: { + + /* Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ + + if (afl->queued_paths < 2) break; + + /* Pick a random queue entry and seek to it. */ + + u32 tid; + do + tid = rand_below(afl, afl->queued_paths); + while (tid == afl->current_entry); + + struct queue_entry* target = afl->queue_buf[tid]; + + /* Make sure that the target has a reasonable length. */ + + while (target && (target->len < 2 || target == afl->queue_cur)) + target = target->next; + + if (!target) break; + + /* Read the testcase into a new buffer. */ + + fd = open(target->fname, O_RDONLY); + + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } + + u32 new_len = target->len; + u8 * new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + + ck_read(fd, new_buf, new_len, target->fname); + + 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; + } + + if (overwrite) { + + u32 copy_from, copy_to, copy_len; + + copy_len = choose_block_len(afl, new_len - 1); + if (copy_len > temp_len) copy_len = temp_len; + + copy_from = rand_below(afl, new_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); + + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); + + } 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); + + /* Head */ + + memcpy(temp_buf, out_buf, clone_to); + + /* Inserted part */ + + memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + + /* Tail */ + memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); + + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + out_buf = temp_buf; + temp_len += clone_len; + + } + + break; + } /* Values 15 and 16 can be selected only if there are any extras present in the dictionaries. */ - case 15: { + case 16: { /* Overwrite bytes with an extra. */ @@ -2233,7 +2323,7 @@ havoc_stage: } - case 16: { + case 17: { u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); u8 *ptr; @@ -2357,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 7afdd9f1..a96995e5 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -25,6 +25,8 @@ #include "afl-fuzz.h" #include +#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 scans. */ @@ -137,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(); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index e0e43f54..e56d122a 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -405,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); } -- cgit 1.4.1 From ce9b4698fec5222e0af1b62d68c4105e6364771e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 21 Jul 2020 20:53:51 +0200 Subject: added andrea's splicing, added cycle_schedules --- GNUmakefile | 2 +- include/afl-fuzz.h | 11 +- include/config.h | 24 ++ include/envs.h | 1 + src/afl-fuzz-one.c | 719 +++++++++++++++++++++++++++++++++++++++++++-------- src/afl-fuzz-queue.c | 112 +++++++- src/afl-fuzz-state.c | 7 + src/afl-fuzz.c | 80 +++++- 8 files changed, 834 insertions(+), 122 deletions(-) (limited to 'include') diff --git a/GNUmakefile b/GNUmakefile index f44ef95e..86d6a947 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -455,7 +455,7 @@ code-format: ./.custom-format.py -i llvm_mode/*.h ./.custom-format.py -i llvm_mode/*.cc ./.custom-format.py -i gcc_plugin/*.c - #./.custom-format.py -i gcc_plugin/*.h + @#./.custom-format.py -i gcc_plugin/*.h ./.custom-format.py -i gcc_plugin/*.cc ./.custom-format.py -i custom_mutators/*/*.c ./.custom-format.py -i custom_mutators/*/*.h diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index adab8155..96d3d9f4 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -139,7 +139,8 @@ struct queue_entry { var_behavior, /* Variable behavior? */ favored, /* Currently favored? */ fs_redundant, /* Marked as redundant in the fs? */ - fully_colorized; /* Do not run redqueen stage again */ + fully_colorized, /* Do not run redqueen stage again */ + is_ascii; /* Is the input just ascii text? */ u32 bitmap_size, /* Number of bits set in bitmap */ fuzz_level; /* Number of fuzzing iterations */ @@ -333,7 +334,7 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child_output, afl_autoresume, - afl_cal_fast; + afl_cal_fast, afl_cycle_schedules; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, *afl_preload; @@ -454,7 +455,9 @@ typedef struct afl_state { fixed_seed, /* do not reseed */ fast_cal, /* Try to calibrate faster? */ disable_trim, /* Never trim in fuzz_one */ - shmem_testcase_mode; /* If sharedmem testcases are used */ + shmem_testcase_mode, /* If sharedmem testcases are used */ + expand_havoc, /* perform expensive havoc after no find */ + cycle_schedules; /* cycle power schedules ? */ u8 *virgin_bits, /* Regions yet untouched by fuzzing */ *virgin_tmout, /* Bits we haven't seen in tmouts */ @@ -548,7 +551,7 @@ typedef struct afl_state { // growing buf struct queue_entry **queue_buf; - size_t queue_size; + size_t queue_size; struct queue_entry **top_rated; /* Top entries for bitmap bytes */ diff --git a/include/config.h b/include/config.h index 4503c3e9..9710cd1f 100644 --- a/include/config.h +++ b/include/config.h @@ -401,5 +401,29 @@ // #define IGNORE_FINDS +/* Text mutations */ + +/* What is the minimum length of a queue input to be evaluated for "is_ascii"? ++ */ + +#define AFL_TXT_MIN_LEN 12 + +/* What is the minimum percentage of ascii characters present to be classifed + as "is_ascii"? */ + +#define AFL_TXT_MIN_PERCENT 95 + +/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */ + +#define AFL_TXT_BIAS 6 + +/* Maximum length of a string to tamper with */ + +#define AFL_TXT_STRING_MAX_LEN 1024 + +/* Maximum mutations on a string */ + +#define AFL_TXT_STRING_MAX_MUTATIONS 8 + #endif /* ! _HAVE_CONFIG_H */ diff --git a/include/envs.h b/include/envs.h index 86222418..cb3c183e 100644 --- a/include/envs.h +++ b/include/envs.h @@ -34,6 +34,7 @@ static char *afl_environment_variables[] = { "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CXX", + "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", "AFL_DEBUG_CHILD_OUTPUT", "AFL_DEBUG_GDB", diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 399bfcab..250409da 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -24,6 +24,11 @@ */ #include "afl-fuzz.h" +#include + +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 */ @@ -362,6 +367,450 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { #endif /* !IGNORE_FINDS */ +#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size + +/* search a string */ + +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; + +} + +/* replace a string */ + +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) { return 0; } + + pos = rand_below(afl, temp_len - 1); + int choice = rand_below(afl, 72); + switch (choice) { + + case 0: /* Semantic statement deletion */ + yes += string_replace(out_buf, &temp_len, pos, "\n", "#"); + 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, " ", "`"); + break; + case 39: + yes += string_replace(out_buf, &temp_len, pos, " ", "\""); + 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: /* Remove a semicolon delimited statement after a semicolon */ + yes += delim_replace(out_buf, &temp_len, pos, ";", ";", ";"); + break; + case 54: /* Remove a semicolon delimited statement after a left curly + brace */ + yes += delim_replace(out_buf, &temp_len, pos, "}", ";", "}"); + break; + case 55: /* Remove a curly brace construct */ + yes += delim_replace(out_buf, &temp_len, pos, "{", "}", ""); + break; + case 56: /* Replace a curly brace construct with an empty one */ + yes += delim_replace(out_buf, &temp_len, pos, "{", "}", "{}"); + break; + case 57: + yes += delim_swap(out_buf, &temp_len, pos, ";", ";", ";"); + break; + case 58: + yes += delim_swap(out_buf, &temp_len, pos, "}", ";", ";"); + break; + case 59: /* Swap comma delimited things case 1 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ")"); + break; + case 60: /* Swap comma delimited things case 2 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ","); + break; + case 61: /* Swap comma delimited things case 3 */ + yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ","); + break; + case 62: /* Swap comma delimited things case 4 */ + yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ")"); + break; + case 63: /* Just delete a line */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", ""); + break; + case 64: /* Delete something like "const" case 1 */ + yes += delim_replace(out_buf, &temp_len, pos, " ", " ", ""); + break; + case 65: /* Delete something like "const" case 2 */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", " ", ""); + break; + case 66: /* Delete something like "const" case 3 */ + yes += delim_replace(out_buf, &temp_len, pos, "(", " ", ""); + break; + case 67: /* Swap space delimited things case 1 */ + yes += delim_swap(out_buf, &temp_len, pos, " ", " ", " "); + break; + case 68: /* Swap space delimited things case 2 */ + yes += delim_swap(out_buf, &temp_len, pos, " ", " ", ")"); + break; + case 69: /* Swap space delimited things case 3 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", " ", " "); + break; + case 70: /* Swap space delimited things case 4 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", " ", ")"); + break; + case 71: /* Duplicate a single line of code */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", NULL); + break; + case 72: /* 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. */ @@ -1854,6 +2303,22 @@ 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, r; + + if (unlikely(afl->expand_havoc)) { + + /* add expensive havoc cases here, they are activated after a full + cycle without finds happened */ + + r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0) + + (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 0); + + } else { + + r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + + } + for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { u32 use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2)); @@ -1896,8 +2361,9 @@ havoc_stage: } - switch (rand_below( - afl, 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { + retry_havoc: + + switch ((r = rand_below(afl, r_max))) { case 0: @@ -2191,176 +2657,203 @@ havoc_stage: break; } - - case 15: { - /* Overwrite bytes with a randomly selected chunk from another - testcase or insert that chunk. */ + default: - if (afl->queued_paths < 2) break; + if (likely(r <= 16 && (afl->extras_cnt || afl->a_extras_cnt))) { - /* Pick a random queue entry and seek to it. */ + /* Values 15 and 16 can be selected only if there are any extras + present in the dictionaries. */ - u32 tid; - do - tid = rand_below(afl, afl->queued_paths); - while (tid == afl->current_entry); + if (r == 15) { - struct queue_entry* target = afl->queue_buf[tid]; + /* Overwrite bytes with an extra. */ - /* Make sure that the target has a reasonable length. */ + if (!afl->extras_cnt || + (afl->a_extras_cnt && rand_below(afl, 2))) { - while (target && (target->len < 2 || target == afl->queue_cur)) - target = target->next; + /* No user-specified extras or odds in our favor. Let's use an + auto-detected one. */ - if (!target) break; + u32 use_extra = rand_below(afl, afl->a_extras_cnt); + u32 extra_len = afl->a_extras[use_extra].len; + u32 insert_at; - /* Read the testcase into a new buffer. */ + if (extra_len > temp_len) { break; } - fd = open(target->fname, O_RDONLY); + insert_at = rand_below(afl, temp_len - extra_len + 1); + memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, + extra_len); - if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } + } else { - u32 new_len = target->len; - u8 * new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + /* No auto extras or odds in our favor. Use the dictionary. */ - ck_read(fd, new_buf, new_len, target->fname); + u32 use_extra = rand_below(afl, afl->extras_cnt); + u32 extra_len = afl->extras[use_extra].len; + u32 insert_at; - close(fd); + if (extra_len > temp_len) { break; } - 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; - } + insert_at = rand_below(afl, temp_len - extra_len + 1); + memcpy(out_buf + insert_at, afl->extras[use_extra].data, + extra_len); - if (overwrite) { + } - u32 copy_from, copy_to, copy_len; + break; - copy_len = choose_block_len(afl, new_len - 1); - if (copy_len > temp_len) copy_len = temp_len; + } else { // case 16 - copy_from = rand_below(afl, new_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); + u32 use_extra, extra_len, + insert_at = rand_below(afl, temp_len + 1); + u8 *ptr; - memmove(out_buf + copy_to, new_buf + copy_from, copy_len); + /* Insert an extra. Do the same dice-rolling stuff as for the + previous case. */ - } 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); + if (!afl->extras_cnt || + (afl->a_extras_cnt && rand_below(afl, 2))) { - u8 * temp_buf = - ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); + use_extra = rand_below(afl, afl->a_extras_cnt); + extra_len = afl->a_extras[use_extra].len; + ptr = afl->a_extras[use_extra].data; - /* Head */ + } else { - memcpy(temp_buf, out_buf, clone_to); + use_extra = rand_below(afl, afl->extras_cnt); + extra_len = afl->extras[use_extra].len; + ptr = afl->extras[use_extra].data; - /* Inserted part */ + } - memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + if (temp_len + extra_len >= MAX_FILE) { break; } - /* Tail */ - memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); + out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); - out_buf = temp_buf; - temp_len += clone_len; - - } + /* Tail */ + memmove(out_buf + insert_at + extra_len, out_buf + insert_at, + temp_len - insert_at); - break; + /* Inserted part */ + memcpy(out_buf + insert_at, ptr, extra_len); - } + temp_len += extra_len; - /* Values 15 and 16 can be selected only if there are any extras - present in the dictionaries. */ + break; - case 16: { + } - /* Overwrite bytes with an extra. */ + } else - if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + switch (r) { - /* No user-specified extras or odds in our favor. Let's use an - auto-detected one. */ + case 15: // fall through + case 17: { - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; - u32 insert_at; + /* Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ - if (extra_len > temp_len) { break; } + if (afl->queued_paths < 2) break; - insert_at = rand_below(afl, temp_len - extra_len + 1); - memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, - extra_len); + /* Pick a random queue entry and seek to it. */ - } else { + u32 tid; + do + tid = rand_below(afl, afl->queued_paths); + while (tid == afl->current_entry); - /* No auto extras or odds in our favor. Use the dictionary. */ + struct queue_entry *target = afl->queue_buf[tid]; - u32 use_extra = rand_below(afl, afl->extras_cnt); - u32 extra_len = afl->extras[use_extra].len; - u32 insert_at; + /* Make sure that the target has a reasonable length. */ - if (extra_len > temp_len) { break; } + while (target && (target->len < 2 || target == afl->queue_cur)) + target = target->next; - insert_at = rand_below(afl, temp_len - extra_len + 1); - memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); + if (!target) break; - } + /* Read the testcase into a new buffer. */ - break; + fd = open(target->fname, O_RDONLY); - } + if (unlikely(fd < 0)) { + + PFATAL("Unable to open '%s'", target->fname); - case 17: { + } - u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); - u8 *ptr; + u32 new_len = target->len; + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); - /* Insert an extra. Do the same dice-rolling stuff as for the - previous case. */ + ck_read(fd, new_buf, new_len, target->fname); - if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + close(fd); - use_extra = rand_below(afl, afl->a_extras_cnt); - extra_len = afl->a_extras[use_extra].len; - ptr = afl->a_extras[use_extra].data; + u8 overwrite = 0; + if (temp_len >= 2 && rand_below(afl, 2)) + overwrite = 1; + else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { - } else { + if (temp_len >= 2) + overwrite = 1; + else + break; - use_extra = rand_below(afl, afl->extras_cnt); - extra_len = afl->extras[use_extra].len; - ptr = afl->extras[use_extra].data; + } - } + if (overwrite) { - if (temp_len + extra_len >= MAX_FILE) { break; } + u32 copy_from, copy_to, copy_len; - out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); + copy_len = choose_block_len(afl, new_len - 1); + if (copy_len > temp_len) copy_len = temp_len; - /* Tail */ - memmove(out_buf + insert_at + extra_len, out_buf + insert_at, - temp_len - insert_at); + copy_from = rand_below(afl, new_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); - /* Inserted part */ - memcpy(out_buf + insert_at, ptr, extra_len); + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - temp_len += extra_len; + } else { - break; + 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); + + /* Head */ + + memcpy(temp_buf, out_buf, clone_to); + + /* Inserted part */ + + memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + + /* Tail */ + memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); + + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + out_buf = temp_buf; + temp_len += clone_len; + + } + + break; + + } + + default: + + // perform ascii mutations + if (text_mutation(afl, &out_buf, &temp_len) == 0) + goto retry_havoc; + + } // end default: switch(r) } @@ -4827,7 +5320,7 @@ u8 fuzz_one(afl_state_t *afl) { return (key_val_lv_1 | key_val_lv_2); -#undef BUF_PARAMS - } +#undef BUF_PARAMS + diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index a96995e5..56073b0a 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -24,6 +24,7 @@ #include "afl-fuzz.h" #include +#include #define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size @@ -102,6 +103,108 @@ 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]; + 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; + + } + + 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) { @@ -139,9 +242,10 @@ 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; + + 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(); @@ -164,6 +268,8 @@ 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-state.c b/src/afl-fuzz-state.c index e56d122a..f68a79e8 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -293,6 +293,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_autoresume = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES", + + afl_environment_variable_len)) { + + afl->cycle_schedules = afl->afl_env.afl_cycle_schedules = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CAL_FAST", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index df2896d2..88f8e902 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1252,11 +1252,42 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (afl->queued_paths == prev_queued) { + if (afl->queued_paths == prev_queued && + (get_cur_time() - afl->start_time) >= 3600) { if (afl->use_splicing) { ++afl->cycles_wo_finds; + switch (afl->expand_havoc) { + + case 0: + afl->expand_havoc = 1; + break; + case 1: + if (afl->limit_time_sig == 0) { + + afl->limit_time_sig = -1; + afl->limit_time_puppet = 0; + + } + + afl->expand_havoc = 2; + break; + case 2: + afl->cycle_schedules = 1; + afl->expand_havoc = 3; + break; + case 3: + // nothing else currently + break; + + } + + if (afl->expand_havoc) { + + } else + + afl->expand_havoc = 1; } else { @@ -1270,6 +1301,53 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->cycle_schedules) { + + /* we cannot mix non-AFLfast schedules with others */ + + switch (afl->schedule) { + + case EXPLORE: + afl->schedule = EXPLOIT; + break; + case EXPLOIT: + afl->schedule = MMOPT; + break; + case MMOPT: + afl->schedule = SEEK; + break; + case SEEK: + afl->schedule = EXPLORE; + break; + case FAST: + afl->schedule = COE; + break; + case COE: + afl->schedule = LIN; + break; + case LIN: + afl->schedule = QUAD; + break; + case QUAD: + afl->schedule = RARE; + break; + case RARE: + afl->schedule = FAST; + break; + + } + + struct queue_entry *q = afl->queue; + // we must recalculate the scores of all queue entries + while (q) { + + update_bitmap_score(afl, q); + q = q->next; + + } + + } + prev_queued = afl->queued_paths; if (afl->sync_id && afl->queue_cycle == 1 && -- cgit 1.4.1 From b015e4f07aabb39e1683406704f2aae1f7dcde4a Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 22 Jul 2020 16:15:16 +0200 Subject: epand havoc now env --- include/envs.h | 1 + src/afl-fuzz-one.c | 211 ++++++++++++++++++++++++++++++++++------------------- src/afl-fuzz.c | 1 + 3 files changed, 138 insertions(+), 75 deletions(-) (limited to 'include') diff --git a/include/envs.h b/include/envs.h index cb3c183e..c1c7d387 100644 --- a/include/envs.h +++ b/include/envs.h @@ -130,6 +130,7 @@ static char *afl_environment_variables[] = { "AFL_USE_CFISAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", + "AFL_EXPAND_HAVOC_NOW", NULL }; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 250409da..a0ecb7a9 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -564,238 +564,299 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_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); + *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS +1); temp_len = *orig_temp_len; memcpy(new_buf, *out_buf, temp_len); + new_buf[temp_len] = 0; for (u32 i = 0; i < mutations; i++) { if (temp_len < AFL_TXT_MIN_LEN) { return 0; } pos = rand_below(afl, temp_len - 1); - int choice = rand_below(afl, 72); + int choice = rand_below(afl, 80); switch (choice) { case 0: /* Semantic statement deletion */ - yes += string_replace(out_buf, &temp_len, pos, "\n", "#"); + yes += string_replace(&new_buf, &temp_len, pos, "\n", "#"); break; case 1: - yes += string_replace(out_buf, &temp_len, pos, "(", "(!"); + yes += string_replace(&new_buf, &temp_len, pos, "(", "(!"); break; case 2: - yes += string_replace(out_buf, &temp_len, pos, "==", "!="); + yes += string_replace(&new_buf, &temp_len, pos, "==", "!="); break; case 3: - yes += string_replace(out_buf, &temp_len, pos, "!=", "=="); + yes += string_replace(&new_buf, &temp_len, pos, "!=", "=="); break; case 4: - yes += string_replace(out_buf, &temp_len, pos, "==", "<"); + yes += string_replace(&new_buf, &temp_len, pos, "==", "<"); break; case 5: - yes += string_replace(out_buf, &temp_len, pos, "<", "=="); + yes += string_replace(&new_buf, &temp_len, pos, "<", "=="); break; case 6: - yes += string_replace(out_buf, &temp_len, pos, "==", ">"); + yes += string_replace(&new_buf, &temp_len, pos, "==", ">"); break; case 7: - yes += string_replace(out_buf, &temp_len, pos, ">", "=="); + yes += string_replace(&new_buf, &temp_len, pos, ">", "=="); break; case 8: - yes += string_replace(out_buf, &temp_len, pos, "=", "<"); + yes += string_replace(&new_buf, &temp_len, pos, "=", "<"); break; case 9: - yes += string_replace(out_buf, &temp_len, pos, "=", ">"); + yes += string_replace(&new_buf, &temp_len, pos, "=", ">"); break; case 10: - yes += string_replace(out_buf, &temp_len, pos, "<", ">"); + yes += string_replace(&new_buf, &temp_len, pos, "<", ">"); break; case 11: - yes += string_replace(out_buf, &temp_len, pos, ">", "<"); + yes += string_replace(&new_buf, &temp_len, pos, ">", "<"); break; case 12: - yes += string_replace(out_buf, &temp_len, pos, "++", "--"); + yes += string_replace(&new_buf, &temp_len, pos, "++", "--"); break; case 13: - yes += string_replace(out_buf, &temp_len, pos, "--", "++"); + yes += string_replace(&new_buf, &temp_len, pos, "--", "++"); break; case 14: - yes += string_replace(out_buf, &temp_len, pos, "+", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "-"); break; case 15: - yes += string_replace(out_buf, &temp_len, pos, "+", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "*"); break; case 16: - yes += string_replace(out_buf, &temp_len, pos, "+", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "/"); break; case 17: - yes += string_replace(out_buf, &temp_len, pos, "+", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "%"); break; case 18: - yes += string_replace(out_buf, &temp_len, pos, "*", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "-"); break; case 19: - yes += string_replace(out_buf, &temp_len, pos, "*", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "+"); break; case 20: - yes += string_replace(out_buf, &temp_len, pos, "*", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "/"); break; case 21: - yes += string_replace(out_buf, &temp_len, pos, "*", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "%"); break; case 22: - yes += string_replace(out_buf, &temp_len, pos, "-", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); break; case 23: - yes += string_replace(out_buf, &temp_len, pos, "-", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "*"); break; case 24: - yes += string_replace(out_buf, &temp_len, pos, "-", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "/"); break; case 25: - yes += string_replace(out_buf, &temp_len, pos, "-", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "%"); break; case 26: - yes += string_replace(out_buf, &temp_len, pos, "/", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "-"); break; case 27: - yes += string_replace(out_buf, &temp_len, pos, "/", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "*"); break; case 28: - yes += string_replace(out_buf, &temp_len, pos, "/", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "+"); break; case 29: - yes += string_replace(out_buf, &temp_len, pos, "/", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "%"); break; case 30: - yes += string_replace(out_buf, &temp_len, pos, "%", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "-"); break; case 31: - yes += string_replace(out_buf, &temp_len, pos, "%", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "*"); break; case 32: - yes += string_replace(out_buf, &temp_len, pos, "%", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "/"); break; case 33: - yes += string_replace(out_buf, &temp_len, pos, "%", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "+"); break; case 34: - yes += string_replace(out_buf, &temp_len, pos, " ", "|"); + yes += string_replace(&new_buf, &temp_len, pos, " ", "|"); break; case 35: - yes += string_replace(out_buf, &temp_len, pos, " ", "$"); + yes += string_replace(&new_buf, &temp_len, pos, " ", "$"); break; case 36: - yes += string_replace(out_buf, &temp_len, pos, "0", "1"); + yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); break; case 37: - yes += string_replace(out_buf, &temp_len, pos, "1", "0"); + yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); break; case 38: - yes += string_replace(out_buf, &temp_len, pos, " ", "`"); + yes += string_replace(&new_buf, &temp_len, pos, " ", "`"); break; case 39: - yes += string_replace(out_buf, &temp_len, pos, " ", "\""); + yes += string_replace(&new_buf, &temp_len, pos, " ", "\""); break; case 40: - yes += string_replace(out_buf, &temp_len, pos, ";", " "); + yes += string_replace(&new_buf, &temp_len, pos, ";", " "); break; case 41: - yes += string_replace(out_buf, &temp_len, pos, "&&", "||"); + yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); break; case 42: - yes += string_replace(out_buf, &temp_len, pos, "||", "&&"); + yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); break; case 43: - yes += string_replace(out_buf, &temp_len, pos, "!", ""); + yes += string_replace(&new_buf, &temp_len, pos, "!", ""); break; case 44: - yes += string_replace(out_buf, &temp_len, pos, "==", "="); + yes += string_replace(&new_buf, &temp_len, pos, "==", "="); break; case 45: - yes += string_replace(out_buf, &temp_len, pos, "--", ""); + yes += string_replace(&new_buf, &temp_len, pos, "--", ""); break; case 46: - yes += string_replace(out_buf, &temp_len, pos, "<<", "<"); + yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); break; case 47: - yes += string_replace(out_buf, &temp_len, pos, ">>", ">"); + yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); break; case 48: - yes += string_replace(out_buf, &temp_len, pos, "<", "<<"); + yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); break; case 49: - yes += string_replace(out_buf, &temp_len, pos, ">", ">>"); + yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); break; case 50: - yes += string_replace(out_buf, &temp_len, pos, "\"", "'"); + yes += string_replace(&new_buf, &temp_len, pos, "\"", "'"); break; case 51: - yes += string_replace(out_buf, &temp_len, pos, "'", "\""); + yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); break; case 52: - yes += string_replace(out_buf, &temp_len, pos, "(", "\""); + yes += string_replace(&new_buf, &temp_len, pos, "(", "\""); break; case 53: /* Remove a semicolon delimited statement after a semicolon */ - yes += delim_replace(out_buf, &temp_len, pos, ";", ";", ";"); + yes += delim_replace(&new_buf, &temp_len, pos, ";", ";", ";"); break; case 54: /* Remove a semicolon delimited statement after a left curly brace */ - yes += delim_replace(out_buf, &temp_len, pos, "}", ";", "}"); + yes += delim_replace(&new_buf, &temp_len, pos, "}", ";", "}"); break; case 55: /* Remove a curly brace construct */ - yes += delim_replace(out_buf, &temp_len, pos, "{", "}", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", ""); break; case 56: /* Replace a curly brace construct with an empty one */ - yes += delim_replace(out_buf, &temp_len, pos, "{", "}", "{}"); + yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "{}"); break; case 57: - yes += delim_swap(out_buf, &temp_len, pos, ";", ";", ";"); + yes += delim_swap(&new_buf, &temp_len, pos, ";", ";", ";"); break; case 58: - yes += delim_swap(out_buf, &temp_len, pos, "}", ";", ";"); + yes += delim_swap(&new_buf, &temp_len, pos, "}", ";", ";"); break; case 59: /* Swap comma delimited things case 1 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ")"); break; case 60: /* Swap comma delimited things case 2 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ","); + yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ","); break; case 61: /* Swap comma delimited things case 3 */ - yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ","); + yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ","); break; case 62: /* Swap comma delimited things case 4 */ - yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ")"); break; case 63: /* Just delete a line */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", ""); break; case 64: /* Delete something like "const" case 1 */ - yes += delim_replace(out_buf, &temp_len, pos, " ", " ", ""); + yes += delim_replace(&new_buf, &temp_len, pos, " ", " ", ""); break; case 65: /* Delete something like "const" case 2 */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", " ", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", " ", ""); break; case 66: /* Delete something like "const" case 3 */ - yes += delim_replace(out_buf, &temp_len, pos, "(", " ", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "(", " ", ""); break; case 67: /* Swap space delimited things case 1 */ - yes += delim_swap(out_buf, &temp_len, pos, " ", " ", " "); + yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", " "); break; case 68: /* Swap space delimited things case 2 */ - yes += delim_swap(out_buf, &temp_len, pos, " ", " ", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", ")"); break; case 69: /* Swap space delimited things case 3 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", " ", " "); + yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", " "); break; case 70: /* Swap space delimited things case 4 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", " ", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", ")"); break; case 71: /* Duplicate a single line of code */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", NULL); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", NULL); break; case 72: /* Duplicate a construct (most often, a non-nested for loop */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "}", NULL); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", "}", NULL); break; + default: { + + for (u32 j = pos; j < temp_len; ++j) { + if (isdigit(new_buf[j])) { + + u8* endptr; + unsigned long long num = strtoull(new_buf +j, (char**)&endptr, 0); + + switch (rand_below(afl, 8)) { + case 0: + num = rand_below(afl, INT_MAX); + break; + case 1: + num = rand_next(afl); + break; + case 2: + num += 1 + rand_below(afl, 255); + break; + case 3: + num -= 1 + rand_below(afl, 255); + break; + case 4: + num *= 1 + rand_below(afl, 255); + break; + case 5: + num /= 1 + rand_below(afl, 255); + break; + case 6: + num /= 1 + rand_below(afl, 255); + break; + case 7: + num = ~num; + break; + } + + const char* fmt = "%llu"; + if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability + fmt = "-%llu"; + + size_t num_len = snprintf(NULL, 0, fmt, num); + size_t old_len = endptr - (new_buf +j); + if (num_len < old_len) { + memmove(new_buf +j +num_len, endptr, temp_len - (endptr - new_buf)); + snprintf(new_buf +j, num_len, fmt, num); + temp_len -= old_len - num_len; + } else if (num_len == old_len) { + snprintf(new_buf +j, num_len, fmt, num); + } else { + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + (num_len - old_len)); + memmove(new_buf +j +num_len, endptr, temp_len - (endptr - new_buf)); + snprintf(new_buf +j, num_len, fmt, num); + temp_len += num_len - old_len; + } + + yes += 1; + + } + } + + } } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 88f8e902..8220b41b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -900,6 +900,7 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; } if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; } if (get_afl_env("AFL_FAST_CAL")) { afl->fast_cal = 1; } + if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; } if (afl->afl_env.afl_autoresume) { -- cgit 1.4.1 From 9cddbc04206bd8d1399e5a5311c98fff5be80731 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 24 Jul 2020 12:26:52 +0200 Subject: add -F option to sync to foreign fuzzer queues --- GNUmakefile | 4 +- README.md | 20 +++--- TODO.md | 2 - docs/Changelog.md | 2 + docs/parallel_fuzzing.md | 14 ++++- include/afl-fuzz.h | 13 ++++ src/afl-fuzz-init.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++ src/afl-fuzz-run.c | 2 + src/afl-fuzz.c | 22 ++++++- 9 files changed, 211 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/GNUmakefile b/GNUmakefile index f44ef95e..ab9144b8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -455,10 +455,10 @@ code-format: ./.custom-format.py -i llvm_mode/*.h ./.custom-format.py -i llvm_mode/*.cc ./.custom-format.py -i gcc_plugin/*.c - #./.custom-format.py -i gcc_plugin/*.h + @#./.custom-format.py -i gcc_plugin/*.h ./.custom-format.py -i gcc_plugin/*.cc ./.custom-format.py -i custom_mutators/*/*.c - ./.custom-format.py -i custom_mutators/*/*.h + @#./.custom-format.py -i custom_mutators/*/*.h # destroys input.h :-( ./.custom-format.py -i examples/*/*.c ./.custom-format.py -i examples/*/*.h ./.custom-format.py -i test/*.c diff --git a/README.md b/README.md index 4e83021d..b2f41315 100644 --- a/README.md +++ b/README.md @@ -366,9 +366,9 @@ If you find other good ones, please send them to us :-) ## Power schedules -The power schedules were copied from Marcel Böhme's excellent AFLfast -implementation and expand on the ability to discover new paths and -therefore may increase the code coverage. +The power schedules were copied from Marcel Böhme's AFLfast implementation and +measure differently which queue entries to prefer and therefore may find +different paths faster for large queues. The available schedules are: @@ -382,16 +382,10 @@ The available schedules are: - mmopt (afl++ experimental) - seek (afl++ experimental) -In parallel mode (-M/-S, several instances with the shared queue), we suggest to -run the main node using the explore or fast schedule (-p explore) and the secondary -nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast), -explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does -not perform well for a target, restart the secondary nodes with a different schedule. - -In single mode, using -p fast is usually slightly more beneficial than the -default explore mode. -(We don't want to change the default behavior of afl, so "fast" has not been -made the default mode). +In parallel mode (-M/-S, several instances with the shared queue), we suggest +to run the main node using the default explore schedule (`-p explore`) and the +secondary nodes with different schedules. If a schedule does not perform well +for a target, restart the secondary nodes with a different schedule. More details can be found in the paper published at the 23rd ACM Conference on Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/) diff --git a/TODO.md b/TODO.md index ad3ef83e..ad743b6b 100644 --- a/TODO.md +++ b/TODO.md @@ -3,9 +3,7 @@ ## Roadmap 2.67+ - -i - + foreign fuzzer sync support: scandir with time sort - - pre_save custom module example to save away test cases - expand on AFL_LLVM_INSTRUMENT_FILE to also support sancov allowlist format - - allow to sync against honggfuzz and libfuzzer - AFL_MAP_SIZE for qemu_mode and unicorn_mode - namespace for targets? e.g. network - learn from honggfuzz (mutations, maybe ptrace?) diff --git a/docs/Changelog.md b/docs/Changelog.md index a25cc43c..bec87d65 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,8 @@ sending a mail to . ### Version ++2.66d (devel) - afl-fuzz: + - added -F option to allow -M main fuzzers to sync to foreign fuzzers, + e.g. honggfuzz or libfuzzer - eliminated CPU affinity race condition for -S/-M runs - llvm_mode: - fixes for laf-intel float splitting (thanks to mark-griffin for diff --git a/docs/parallel_fuzzing.md b/docs/parallel_fuzzing.md index 271f8369..2ab1466c 100644 --- a/docs/parallel_fuzzing.md +++ b/docs/parallel_fuzzing.md @@ -99,7 +99,15 @@ example may be: This is not a concern if you use @@ without -f and let afl-fuzz come up with the file name. -## 3) Multi-system parallelization +## 3) Syncing with non-afl fuzzers or independant instances + +A -M main node can be told with the `-F other_fuzzer_queue_directory` option +to sync results from other fuzzers, e.g. libfuzzer or honggfuzz. + +Only the specified directory will by synced into afl, not subdirectories. +The specified directories do not need to exist yet at the start of afl. + +## 4) Multi-system parallelization The basic operating principle for multi-system parallelization is similar to the mechanism explained in section 2. The key difference is that you need to @@ -176,7 +184,7 @@ It is *not* advisable to skip the synchronization script and run the fuzzers directly on a network filesystem; unexpected latency and unkillable processes in I/O wait state can mess things up. -## 4) Remote monitoring and data collection +## 5) Remote monitoring and data collection You can use screen, nohup, tmux, or something equivalent to run remote instances of afl-fuzz. If you redirect the program's output to a file, it will @@ -200,7 +208,7 @@ Keep in mind that crashing inputs are *not* automatically propagated to the main instance, so you may still want to monitor for crashes fleet-wide from within your synchronization or health checking scripts (see afl-whatsup). -## 5) Asymmetric setups +## 6) Asymmetric setups It is perhaps worth noting that all of the following is permitted: diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c9f84c61..cf4254ac 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -347,6 +347,13 @@ struct afl_pass_stat { }; +struct foreign_sync { + + u8 * dir; + time_t ctime; + +}; + typedef struct afl_state { /* Position of this state in the global states list */ @@ -574,6 +581,11 @@ typedef struct afl_state { u8 describe_op_buf_256[256]; /* describe_op will use this to return a string up to 256 */ +/* foreign sync */ +#define FOREIGN_SYNCS_MAX 32 + u8 foreign_sync_cnt; + struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX]; + #ifdef _AFL_DOCUMENT_MUTATIONS u8 do_document; u32 document_counter; @@ -937,6 +949,7 @@ void fix_up_banner(afl_state_t *, u8 *); void check_if_tty(afl_state_t *); void setup_signal_handlers(void); void save_cmdline(afl_state_t *, u32, char **); +void read_foreign_testcases(afl_state_t *, int); /* CmpLog */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 609e16ba..65ad0c9f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -438,6 +438,159 @@ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) { } +/* Read all testcases from foreign input directories, then queue them for + testing. Called at startup and at sync intervals. + Does not descend into subdirectories! */ + +void read_foreign_testcases(afl_state_t *afl, int first) { + + if (!afl->foreign_sync_cnt) return; + + struct dirent **nl; + s32 nl_cnt; + u32 i, iter; + + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + + for (iter = 0; iter < afl->foreign_sync_cnt; iter++) { + + if (afl->foreign_syncs[iter].dir != NULL && + afl->foreign_syncs[iter].dir[0] != 0) { + + if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir); + time_t ctime_max = 0; + + /* We use scandir() + alphasort() rather than readdir() because otherwise, + the ordering of test cases would vary somewhat randomly and would be + difficult to control. */ + + 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 */ + + snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "foreign sync %u", iter); + + afl->stage_name = afl->stage_name_buf; + afl->stage_cur = 0; + afl->stage_max = 0; + + for (i = 0; i < 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 */ + + if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) { + + if (first) PFATAL("Unable to access '%s'", fn2); + continue; + + } + + /* we detect new files by their ctime */ + if (likely(st.st_ctime <= afl->foreign_syncs[iter].ctime)) { + + 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); + // as this could add duplicates of the startup input corpus + + 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; + + } + + write_to_testcase(afl, mem, st.st_size); + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + afl->syncing_party = "foreign"; + afl->queued_imported += + save_if_interesting(afl, mem, st.st_size, fault); + afl->syncing_party = 0; + munmap(mem, st.st_size); + close(fd); + + if (st.st_ctime > ctime_max) ctime_max = st.st_ctime; + + } + + afl->foreign_syncs[iter].ctime = ctime_max; + free(nl); /* not tracked */ + + } + + } + + if (first) { + + afl->last_path_time = 0; + afl->queued_at_start = afl->queued_paths; + + } + +} + /* Read all testcases from the input directory, then queue them for testing. Called at startup. */ @@ -530,6 +683,7 @@ void read_testcases(afl_state_t *afl) { 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; } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 2a1664e2..6e3be72b 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -612,6 +612,8 @@ void sync_fuzzers(afl_state_t *afl) { } + if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); + } /* Trim all new test cases to save cycles when doing deterministic checks. The diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index df2896d2..f03c545d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -131,10 +131,13 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { "executions.\n\n" "Other stuff:\n" - " -T text - text banner to show on the screen\n" " -M/-S id - distributed mode (see docs/parallel_fuzzing.md)\n" " use -D to force -S secondary to perform deterministic " "fuzzing\n" + " -F path - sync to a foreign fuzzer queue directory (requires " + "-M, can\n" + " be specified up to %u times)\n" + " -T text - text banner to show on the screen\n" " -I command - execute this command/script when a new crash is " "found\n" //" -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap @@ -142,7 +145,7 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { " -C - crash exploration mode (the peruvian rabbit thing)\n" " -e ext - file extension for the fuzz test input file (if " "needed)\n\n", - argv0, EXEC_TIMEOUT, MEM_LIMIT); + argv0, EXEC_TIMEOUT, MEM_LIMIT, FOREIGN_SYNCS_MAX); if (more_help > 1) { @@ -403,6 +406,19 @@ int main(int argc, char **argv_orig, char **envp) { afl->use_splicing = 1; break; + case 'F': /* foreign sync dir */ + + if (!afl->is_main_node) + FATAL( + "Option -F can only be specified after the -M option for the " + "main fuzzer of a fuzzing campaign"); + if (afl->foreign_sync_cnt >= FOREIGN_SYNCS_MAX) + FATAL("Maximum %u entried of -F option can be specified", + FOREIGN_SYNCS_MAX); + afl->foreign_syncs[afl->foreign_sync_cnt].dir = optarg; + afl->foreign_sync_cnt++; + break; + case 'f': /* target file */ if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); } @@ -1059,6 +1075,8 @@ int main(int argc, char **argv_orig, char **envp) { setup_cmdline_file(afl, argv + optind); read_testcases(afl); + // read_foreign_testcases(afl, 1); for the moment dont do this + load_auto(afl); pivot_inputs(afl); -- cgit 1.4.1 From 30c09915432af7a9e98f9b4d8b09566731e0cca9 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 24 Jul 2020 13:26:07 +0200 Subject: better text mutation --- include/afl-fuzz.h | 2 +- include/config.h | 7 +- src/afl-fuzz-one.c | 341 +++++++++++++++++++++++++----------------------- src/afl-fuzz-redqueen.c | 142 ++++++++++---------- src/afl-fuzz-state.c | 7 + src/afl-fuzz.c | 2 +- 6 files changed, 261 insertions(+), 240 deletions(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 96d3d9f4..0e2b7458 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -334,7 +334,7 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child_output, afl_autoresume, - afl_cal_fast, afl_cycle_schedules; + afl_cal_fast, afl_cycle_schedules, afl_expand_havoc; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, *afl_preload; diff --git a/include/config.h b/include/config.h index 9710cd1f..344a368f 100644 --- a/include/config.h +++ b/include/config.h @@ -403,15 +403,14 @@ /* Text mutations */ -/* What is the minimum length of a queue input to be evaluated for "is_ascii"? -+ */ +/* Minimum length of a queue input to be evaluated for "is_ascii"? */ #define AFL_TXT_MIN_LEN 12 /* What is the minimum percentage of ascii characters present to be classifed as "is_ascii"? */ -#define AFL_TXT_MIN_PERCENT 95 +#define AFL_TXT_MIN_PERCENT 94 /* How often to perform ASCII mutations 0 = disable, 1-8 are good values */ @@ -423,7 +422,7 @@ /* Maximum mutations on a string */ -#define AFL_TXT_STRING_MAX_MUTATIONS 8 +#define AFL_TXT_STRING_MAX_MUTATIONS 6 #endif /* ! _HAVE_CONFIG_H */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 7f96c2c6..dc19150d 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -559,13 +559,25 @@ static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, /* Returns 1 if a mutant was generated and placed in out_buf, 0 if none * generated. */ +static const uint8_t text_mutation_special_chars[] = { + + '\t', '\n', '\r', ' ', '!', '"', '$', '%', '&', '\'', '(', ')', '*', + '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', + '\\', ']', '^', '_', '`', '{', '|', '}', '~', ' ' // space is here twice + +}; + static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { + if (*orig_temp_len < AFL_TXT_MIN_LEN) { return 0; } + 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 +1); + mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 16; + u8 *new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), + *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS + 16); + u8 fromc[2] = {0, 0}, toc[2] = {0, 0}; temp_len = *orig_temp_len; memcpy(new_buf, *out_buf, temp_len); new_buf[temp_len] = 0; @@ -575,9 +587,12 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { if (temp_len < AFL_TXT_MIN_LEN) { return 0; } pos = rand_below(afl, temp_len - 1); - int choice = rand_below(afl, 80); + int choice = rand_below(afl, 100); + switch (choice) { + /* 50% -> fixed replacements */ + case 0: /* Semantic statement deletion */ yes += string_replace(&new_buf, &temp_len, pos, "\n", "#"); break; @@ -624,246 +639,240 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { yes += string_replace(&new_buf, &temp_len, pos, "+", "-"); break; case 15: - yes += string_replace(&new_buf, &temp_len, pos, "+", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); break; case 16: - yes += string_replace(&new_buf, &temp_len, pos, "+", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); break; case 17: - yes += string_replace(&new_buf, &temp_len, pos, "+", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); break; case 18: - yes += string_replace(&new_buf, &temp_len, pos, "*", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); break; case 19: - yes += string_replace(&new_buf, &temp_len, pos, "*", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); break; case 20: - yes += string_replace(&new_buf, &temp_len, pos, "*", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "!", ""); break; case 21: - yes += string_replace(&new_buf, &temp_len, pos, "*", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "==", "="); break; case 22: - yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "=", "=="); break; case 23: - yes += string_replace(&new_buf, &temp_len, pos, "-", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "--", ""); break; case 24: - yes += string_replace(&new_buf, &temp_len, pos, "-", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); break; case 25: - yes += string_replace(&new_buf, &temp_len, pos, "-", "%"); + yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); break; case 26: - yes += string_replace(&new_buf, &temp_len, pos, "/", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); break; case 27: - yes += string_replace(&new_buf, &temp_len, pos, "/", "*"); + yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); break; case 28: - yes += string_replace(&new_buf, &temp_len, pos, "/", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); break; case 29: - yes += string_replace(&new_buf, &temp_len, pos, "/", "%"); - break; - case 30: - yes += string_replace(&new_buf, &temp_len, pos, "%", "-"); - break; - case 31: - yes += string_replace(&new_buf, &temp_len, pos, "%", "*"); - break; - case 32: - yes += string_replace(&new_buf, &temp_len, pos, "%", "/"); - break; - case 33: - yes += string_replace(&new_buf, &temp_len, pos, "%", "+"); - break; - case 34: - yes += string_replace(&new_buf, &temp_len, pos, " ", "|"); - break; - case 35: - yes += string_replace(&new_buf, &temp_len, pos, " ", "$"); - break; - case 36: - yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); - break; - case 37: - yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); - break; - case 38: - yes += string_replace(&new_buf, &temp_len, pos, " ", "`"); - break; - case 39: - yes += string_replace(&new_buf, &temp_len, pos, " ", "\""); - break; - case 40: - yes += string_replace(&new_buf, &temp_len, pos, ";", " "); - break; - case 41: - yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); - break; - case 42: - yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); - break; - case 43: - yes += string_replace(&new_buf, &temp_len, pos, "!", ""); - break; - case 44: - yes += string_replace(&new_buf, &temp_len, pos, "==", "="); - break; - case 45: - yes += string_replace(&new_buf, &temp_len, pos, "--", ""); - break; - case 46: - yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); - break; - case 47: - yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); - break; - case 48: - yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); - break; - case 49: - yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); - break; - case 50: yes += string_replace(&new_buf, &temp_len, pos, "\"", "'"); break; - case 51: - yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); - break; - case 52: - yes += string_replace(&new_buf, &temp_len, pos, "(", "\""); - break; - case 53: /* Remove a semicolon delimited statement after a semicolon */ + case 30: /* Remove a semicolon delimited statement after a semicolon */ yes += delim_replace(&new_buf, &temp_len, pos, ";", ";", ";"); break; - case 54: /* Remove a semicolon delimited statement after a left curly + case 31: /* Remove a semicolon delimited statement after a left curly brace */ yes += delim_replace(&new_buf, &temp_len, pos, "}", ";", "}"); break; - case 55: /* Remove a curly brace construct */ + case 32: /* Remove a curly brace construct */ yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", ""); break; - case 56: /* Replace a curly brace construct with an empty one */ + case 33: /* Replace a curly brace construct with an empty one */ yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "{}"); break; - case 57: + case 34: yes += delim_swap(&new_buf, &temp_len, pos, ";", ";", ";"); break; - case 58: + case 35: yes += delim_swap(&new_buf, &temp_len, pos, "}", ";", ";"); break; - case 59: /* Swap comma delimited things case 1 */ + case 36: /* Swap comma delimited things case 1 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ")"); break; - case 60: /* Swap comma delimited things case 2 */ + case 37: /* Swap comma delimited things case 2 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ","); break; - case 61: /* Swap comma delimited things case 3 */ + case 38: /* Swap comma delimited things case 3 */ yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ","); break; - case 62: /* Swap comma delimited things case 4 */ + case 39: /* Swap comma delimited things case 4 */ yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ")"); break; - case 63: /* Just delete a line */ + case 40: /* Just delete a line */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", ""); break; - case 64: /* Delete something like "const" case 1 */ + case 41: /* Delete something like "const" case 1 */ yes += delim_replace(&new_buf, &temp_len, pos, " ", " ", ""); break; - case 65: /* Delete something like "const" case 2 */ + case 42: /* Delete something like "const" case 2 */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", " ", ""); break; - case 66: /* Delete something like "const" case 3 */ + case 43: /* Delete something like "const" case 3 */ yes += delim_replace(&new_buf, &temp_len, pos, "(", " ", ""); break; - case 67: /* Swap space delimited things case 1 */ + case 44: /* Swap space delimited things case 1 */ yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", " "); break; - case 68: /* Swap space delimited things case 2 */ + case 45: /* Swap space delimited things case 2 */ yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", ")"); break; - case 69: /* Swap space delimited things case 3 */ + case 46: /* Swap space delimited things case 3 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", " "); break; - case 70: /* Swap space delimited things case 4 */ + case 47: /* Swap space delimited things case 4 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", ")"); break; - case 71: /* Duplicate a single line of code */ + case 48: /* Duplicate a single line of code */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", NULL); break; - case 72: /* Duplicate a construct (most often, a non-nested for loop */ + case 49: /* Duplicate a construct (most often, a non-nested for loop */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", "}", NULL); break; default: { - - for (u32 j = pos; j < temp_len; ++j) { - if (isdigit(new_buf[j])) { - - new_buf[temp_len] = 0; // should be safe thanks to the initial grow - - u8* endptr; - unsigned long long num = strtoull(new_buf +j, (char**)&endptr, 0); - - switch (rand_below(afl, 8)) { - case 0: - num = rand_below(afl, INT_MAX); - break; - case 1: - num = rand_next(afl); - break; - case 2: - num += 1 + rand_below(afl, 255); - break; - case 3: - num -= 1 + rand_below(afl, 255); - break; - case 4: - num *= 1 + rand_below(afl, 255); - break; - case 5: - num /= 1 + rand_below(afl, 255); - break; - case 6: - num /= 1 + rand_below(afl, 255); - break; - case 7: - num = ~num; - break; - } - - const char* fmt = "%llu"; - if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability - fmt = "-%llu"; - - size_t num_len = snprintf(NULL, 0, fmt, num); - size_t old_len = endptr - (new_buf +j); - if (num_len < old_len) { - memmove(new_buf +j +num_len, new_buf +j +old_len, temp_len - (j + old_len)); - snprintf(new_buf +j, num_len, fmt, num); - temp_len -= old_len - num_len; - } else if (num_len == old_len) { - snprintf(new_buf +j, num_len, fmt, num); - } else { - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + (num_len - old_len) + AFL_TXT_STRING_MAX_MUTATIONS +1); - memmove(new_buf +j +num_len, new_buf +j +old_len, temp_len - (j + old_len)); - snprintf(new_buf +j, num_len, fmt, num); - temp_len += num_len - old_len; + + /* 10% is transforming ascii numbers */ + + if (choice < 60) { + + for (u32 j = pos; j < temp_len; ++j) { + + if (isdigit(new_buf[j])) { + + new_buf[temp_len] = + 0; // should be safe thanks to the initial grow + + u8 * endptr; + unsigned long long num = + strtoull(new_buf + j, (char **)&endptr, 0); + + switch (rand_below(afl, 8)) { + + case 0: + num = rand_below(afl, INT_MAX); + break; + case 1: + num = rand_next(afl); + break; + case 2: + num += 1 + rand_below(afl, 255); + break; + case 3: + num -= 1 + rand_below(afl, 255); + break; + case 4: + num *= 1 + rand_below(afl, 255); + break; + case 5: + num /= 1 + rand_below(afl, 255); + break; + case 6: + num /= 1 + rand_below(afl, 255); + break; + case 7: + num = ~num; + break; + + } + + const char *fmt = "%llu"; + if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability + fmt = "-%llu"; + + size_t num_len = snprintf(NULL, 0, fmt, num); + size_t old_len = endptr - (new_buf + j); + if (num_len < old_len) { + + memmove(new_buf + j + num_len, new_buf + j + old_len, + temp_len - (j + old_len)); + snprintf(new_buf + j, num_len, fmt, num); + temp_len -= old_len - num_len; + + } else if (num_len == old_len) { + + snprintf(new_buf + j, num_len, fmt, num); + + } else { + + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), + temp_len + (num_len - old_len) + + AFL_TXT_STRING_MAX_MUTATIONS + 1); + memmove(new_buf + j + num_len, new_buf + j + old_len, + temp_len - (j + old_len)); + snprintf(new_buf + j, num_len, fmt, num); + temp_len += num_len - old_len; + + } + + yes += 1; + break; + } - yes += 1; - break; - } + + } else if (choice < 90) { + + /* 30% is special character transform */ + + fromc[0] = text_mutation_special_chars[rand_below( + afl, sizeof(text_mutation_special_chars))]; + + do { + + toc[0] = text_mutation_special_chars[rand_below( + afl, sizeof(text_mutation_special_chars))]; + + } while (toc[0] == fromc[0]); + + yes += string_replace(&new_buf, &temp_len, pos, fromc, toc); + break; + + } else { + + /* 10% is random text character transform */ + + u32 iter, cnt, loc, prev_loc = temp_len; + if (temp_len > 32) { + + cnt = 1 + rand_below(afl, 5); + + } else { + + cnt = rand_below(afl, 2); + + } + + for (iter = 0; iter <= cnt; iter++) { + + while ((loc = rand_below(afl, temp_len)) == prev_loc) + ; + new_buf[loc] = 32 + rand_below(afl, 'z' - ' ' + 1); + prev_loc = loc; + + } + } - + } } - + } if (yes == 0 || temp_len <= 0) { return 0; } @@ -871,7 +880,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); *out_buf = new_buf; *orig_temp_len = temp_len; - + return 1; } diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index de3adb2d..57e60c3d 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -264,49 +264,53 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { } static long long strntoll(const char *str, size_t sz, char **end, int base) { - char buf[64]; - long long ret; - const char *beg = str; - - for (; beg && sz && *beg == ' '; beg++, sz--) - ; - - if (!sz || sz >= sizeof(buf)) { - if (end) - *end = (char *)str; - return 0; - } - - memcpy(buf, beg, sz); - buf[sz] = '\0'; - ret = strtoll(buf, end, base); - if (ret == LLONG_MIN || ret == LLONG_MAX) - return ret; - if (end) - *end = (char *)beg + (*end - buf); - return ret; + + char buf[64]; + long long ret; + const char *beg = str; + + for (; beg && sz && *beg == ' '; beg++, sz--) + ; + + if (!sz || sz >= sizeof(buf)) { + + if (end) *end = (char *)str; + return 0; + + } + + memcpy(buf, beg, sz); + buf[sz] = '\0'; + ret = strtoll(buf, end, base); + if (ret == LLONG_MIN || ret == LLONG_MAX) return ret; + if (end) *end = (char *)beg + (*end - buf); + return ret; + } -static unsigned long long strntoull(const char *str, size_t sz, char **end, int base) { - char buf[64]; - unsigned long long ret; - const char *beg = str; - - for (; beg && sz && *beg == ' '; beg++, sz--) - ; - - if (!sz || sz >= sizeof(buf)) { - if (end) - *end = (char *)str; - return 0; - } - - memcpy(buf, beg, sz); - buf[sz] = '\0'; - ret = strtoull(buf, end, base); - if (end) - *end = (char *)beg + (*end - buf); - return ret; +static unsigned long long strntoull(const char *str, size_t sz, char **end, + int base) { + + char buf[64]; + unsigned long long ret; + const char * beg = str; + + for (; beg && sz && *beg == ' '; beg++, sz--) + ; + + if (!sz || sz >= sizeof(buf)) { + + if (end) *end = (char *)str; + return 0; + + } + + memcpy(buf, beg, sz); + buf[sz] = '\0'; + ret = strtoull(buf, end, base); + if (end) *end = (char *)beg + (*end - buf); + return ret; + } #define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size @@ -328,49 +332,51 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u32 its_len = len - idx; // *status = 0; - u8 *endptr; - u8 use_num = 0, use_unum = 0; + u8 * endptr; + u8 use_num = 0, use_unum = 0; unsigned long long unum; - long long num; + long long num; if (afl->queue_cur->is_ascii) { - + endptr = buf_8; - num = strntoll(buf_8, len - idx, (char**)&endptr, 0); + num = strntoll(buf_8, len - idx, (char **)&endptr, 0); if (endptr == buf_8) { - unum = strntoull(buf_8, len - idx, (char**)&endptr, 0); - if (endptr == buf_8) - use_unum = 1; + + unum = strntoull(buf_8, len - idx, (char **)&endptr, 0); + if (endptr == buf_8) use_unum = 1; + } else + use_num = 1; - + } - + if (use_num && num == pattern) { - + size_t old_len = endptr - buf_8; size_t num_len = snprintf(NULL, 0, "%lld", num); - - u8* new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len); + + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len); memcpy(new_buf, buf, idx); - - snprintf(new_buf +idx, num_len, "%lld", num); - memcpy(new_buf +idx +num_len, buf_8 + old_len, len - idx - old_len); - + + snprintf(new_buf + idx, num_len, "%lld", num); + memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } - + } else if (use_unum && unum == pattern) { - + size_t old_len = endptr - buf_8; size_t num_len = snprintf(NULL, 0, "%llu", unum); - - u8* new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len); + + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len); memcpy(new_buf, buf, idx); - - snprintf(new_buf +idx, num_len, "%llu", unum); - memcpy(new_buf +idx +num_len, buf_8 + old_len, len - idx - old_len); - + + snprintf(new_buf + idx, num_len, "%llu", unum); + memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } - + } if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) { @@ -382,7 +388,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, *buf_64 = pattern; } - + // reverse encoding if (do_reverse && *status != 1) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f68a79e8..66280ed1 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -300,6 +300,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->cycle_schedules = afl->afl_env.afl_cycle_schedules = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW", + + afl_environment_variable_len)) { + + afl->expand_havoc = afl->afl_env.afl_expand_havoc = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CAL_FAST", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 553300e9..c014035e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1275,7 +1275,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->expand_havoc = 2; break; case 2: - //afl->cycle_schedules = 1; + // afl->cycle_schedules = 1; afl->expand_havoc = 3; break; case 3: -- cgit 1.4.1 From 16e362d2b93a60d6c50fca6abfabd9976ca6142d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 26 Jul 2020 15:55:03 +0200 Subject: add last 60s exec/s stat --- include/afl-fuzz.h | 4 ++ src/afl-fuzz-mutators.c | 3 +- src/afl-fuzz-stats.c | 154 +++++++++++++++++++++++++--------------------- test/test-floatingpoint.c | 8 +-- 4 files changed, 93 insertions(+), 76 deletions(-) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index cf4254ac..c0c4cfd5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -581,6 +581,10 @@ typedef struct afl_state { u8 describe_op_buf_256[256]; /* describe_op will use this to return a string up to 256 */ + unsigned long long int last_avg_exec_update; + u32 last_avg_execs; + float last_avg_execs_saved; + /* foreign sync */ #define FOREIGN_SYNCS_MAX 32 u8 foreign_sync_cnt; diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index ed777811..850266c2 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -168,7 +168,8 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { /* "afl_custom_deinit", optional for backward compatibility */ mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit"); - if (!mutator->afl_custom_deinit) FATAL("Symbol 'afl_custom_deinit' not found."); + if (!mutator->afl_custom_deinit) + FATAL("Symbol 'afl_custom_deinit' not found."); /* "afl_custom_post_process", optional */ mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process"); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index fc93011b..995f298e 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -39,7 +39,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, u8 fn[PATH_MAX]; s32 fd; FILE * f; - uint32_t t_bytes = count_non_255_bytes(afl, afl->virgin_bits); + u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); @@ -67,89 +67,101 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, } + if ((unlikely(!afl->last_avg_exec_update || + cur_time - afl->last_avg_exec_update >= 60000))) { + + afl->last_avg_execs_saved = + (float)(1000*(afl->fsrv.total_execs - afl->last_avg_execs)) / + (float)(cur_time - afl->last_avg_exec_update); + afl->last_avg_execs = afl->fsrv.total_execs; + afl->last_avg_exec_update = cur_time; + + } + #ifndef __HAIKU__ if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; } #endif - fprintf( - f, - "start_time : %llu\n" - "last_update : %llu\n" - "run_time : %llu\n" - "fuzzer_pid : %u\n" - "cycles_done : %llu\n" - "cycles_wo_finds : %llu\n" - "execs_done : %llu\n" - "execs_per_sec : %0.02f\n" - // "real_execs_per_sec: %0.02f\n" // damn the name is too long - "paths_total : %u\n" - "paths_favored : %u\n" - "paths_found : %u\n" - "paths_imported : %u\n" - "max_depth : %u\n" - "cur_path : %u\n" /* Must match find_start_position() */ - "pending_favs : %u\n" - "pending_total : %u\n" - "variable_paths : %u\n" - "stability : %0.02f%%\n" - "bitmap_cvg : %0.02f%%\n" - "unique_crashes : %llu\n" - "unique_hangs : %llu\n" - "last_path : %llu\n" - "last_crash : %llu\n" - "last_hang : %llu\n" - "execs_since_crash : %llu\n" - "exec_timeout : %u\n" - "slowest_exec_ms : %u\n" - "peak_rss_mb : %lu\n" - "cpu_affinity : %d\n" - "edges_found : %u\n" - "var_byte_count : %u\n" - "afl_banner : %s\n" - "afl_version : " VERSION - "\n" - "target_mode : %s%s%s%s%s%s%s%s%s\n" - "command_line : %s\n", - afl->start_time / 1000, cur_time / 1000, - (cur_time - afl->start_time) / 1000, (u32)getpid(), - afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, - afl->fsrv.total_execs, - afl->fsrv.total_execs / - ((double)(get_cur_time() - afl->start_time) / 1000), - afl->queued_paths, afl->queued_favored, afl->queued_discovered, - afl->queued_imported, afl->max_depth, afl->current_entry, - afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable, - stability, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, - afl->last_path_time / 1000, afl->last_crash_time / 1000, - afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs, - afl->fsrv.exec_tmout, afl->slowest_exec_ms, + fprintf(f, + "start_time : %llu\n" + "last_update : %llu\n" + "run_time : %llu\n" + "fuzzer_pid : %u\n" + "cycles_done : %llu\n" + "cycles_wo_finds : %llu\n" + "execs_done : %llu\n" + "execs_per_sec : %0.02f\n" + "execs_ps_last_min : %0.02f\n" + "paths_total : %u\n" + "paths_favored : %u\n" + "paths_found : %u\n" + "paths_imported : %u\n" + "max_depth : %u\n" + "cur_path : %u\n" /* Must match find_start_position() */ + "pending_favs : %u\n" + "pending_total : %u\n" + "variable_paths : %u\n" + "stability : %0.02f%%\n" + "bitmap_cvg : %0.02f%%\n" + "unique_crashes : %llu\n" + "unique_hangs : %llu\n" + "last_path : %llu\n" + "last_crash : %llu\n" + "last_hang : %llu\n" + "execs_since_crash : %llu\n" + "exec_timeout : %u\n" + "slowest_exec_ms : %u\n" + "peak_rss_mb : %lu\n" + "cpu_affinity : %d\n" + "edges_found : %u\n" + "var_byte_count : %u\n" + "afl_banner : %s\n" + "afl_version : " VERSION + "\n" + "target_mode : %s%s%s%s%s%s%s%s%s\n" + "command_line : %s\n", + afl->start_time / 1000, cur_time / 1000, + (cur_time - afl->start_time) / 1000, (u32)getpid(), + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, + afl->fsrv.total_execs, + afl->fsrv.total_execs / + ((double)(get_cur_time() - afl->start_time) / 1000), + afl->last_avg_execs_saved, afl->queued_paths, afl->queued_favored, + afl->queued_discovered, afl->queued_imported, afl->max_depth, + afl->current_entry, afl->pending_favored, afl->pending_not_fuzzed, + afl->queued_variable, stability, bitmap_cvg, afl->unique_crashes, + afl->unique_hangs, afl->last_path_time / 1000, + afl->last_crash_time / 1000, afl->last_hang_time / 1000, + afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout, + afl->slowest_exec_ms, #ifndef __HAIKU__ #ifdef __APPLE__ - (unsigned long int)(rus.ru_maxrss >> 20), + (unsigned long int)(rus.ru_maxrss >> 20), #else - (unsigned long int)(rus.ru_maxrss >> 10), + (unsigned long int)(rus.ru_maxrss >> 10), #endif #else - -1UL, + -1UL, #endif #ifdef HAVE_AFFINITY - afl->cpu_aff, + afl->cpu_aff, #else - -1, + -1, #endif - t_bytes, afl->var_byte_count, afl->use_banner, - afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", - afl->non_instrumented_mode ? " non_instrumented " : "", - afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", - afl->persistent_mode ? "persistent " : "", - afl->shmem_testcase_mode ? "shmem_testcase " : "", - afl->deferred_mode ? "deferred " : "", - (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->non_instrumented_mode || - afl->no_forkserver || afl->crash_mode || afl->persistent_mode || - afl->deferred_mode) - ? "" - : "default", - afl->orig_cmdline); + t_bytes, afl->var_byte_count, afl->use_banner, + afl->unicorn_mode ? "unicorn" : "", + afl->fsrv.qemu_mode ? "qemu " : "", + afl->non_instrumented_mode ? " non_instrumented " : "", + afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", + afl->persistent_mode ? "persistent " : "", + afl->shmem_testcase_mode ? "shmem_testcase " : "", + afl->deferred_mode ? "deferred " : "", + (afl->unicorn_mode || afl->fsrv.qemu_mode || + afl->non_instrumented_mode || afl->no_forkserver || + afl->crash_mode || afl->persistent_mode || afl->deferred_mode) + ? "" + : "default", + afl->orig_cmdline); /* ignore errors */ if (afl->debug) { diff --git a/test/test-floatingpoint.c b/test/test-floatingpoint.c index 083f0df5..acecd55a 100644 --- a/test/test-floatingpoint.c +++ b/test/test-floatingpoint.c @@ -8,16 +8,16 @@ __AFL_FUZZ_INIT(); int main(void) { ssize_t bytes_read; - + __AFL_INIT(); - float *magic = (float*)__AFL_FUZZ_TESTCASE_BUF; - + float *magic = (float *)__AFL_FUZZ_TESTCASE_BUF; + while (__AFL_LOOP(INT_MAX)) { if (__AFL_FUZZ_TESTCASE_LEN != sizeof(float)) return 1; /* 15 + 1/2 + 1/8 + 1/32 + 1/128 */ if ((-*magic == 15.0 + 0.5 + 0.125 + 0.03125 + 0.0078125)) abort(); - + } return 0; -- cgit 1.4.1 From a22f4dd1ac1fe12bc5b81c3311524bc175a2eed0 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 28 Jul 2020 16:13:32 +0200 Subject: new snapshot api --- include/snapshot-inl.h | 63 ++++++++++++++++++++++++++++++++++++++++------- llvm_mode/afl-llvm-rt.o.c | 2 +- 2 files changed, 55 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/snapshot-inl.h b/include/snapshot-inl.h index b73a001e..55251db5 100644 --- a/include/snapshot-inl.h +++ b/include/snapshot-inl.h @@ -25,35 +25,80 @@ // From AFL-Snapshot-LKM/include/afl_snapshot.h (must be kept synced) #include -#include -#include +#include #include #define AFL_SNAPSHOT_FILE_NAME "/dev/afl_snapshot" #define AFL_SNAPSHOT_IOCTL_MAGIC 44313 -#define AFL_SNAPSHOT_IOCTL_DO _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 1) -#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 2) +#define AFL_SNAPSHOT_EXCLUDE_VMRANGE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 1, struct afl_snapshot_vmrange_args*) +#define AFL_SNAPSHOT_INCLUDE_VMRANGE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 2, struct afl_snapshot_vmrange_args*) +#define AFL_SNAPSHOT_IOCTL_TAKE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 3, int) +#define AFL_SNAPSHOT_IOCTL_RESTORE _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 4) +#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 5) + +// Trace new mmaped ares and unmap them on restore. +#define AFL_SNAPSHOT_MMAP 1 +// Do not snapshot any page (by default all writeable not-shared pages +// are shanpshotted. +#define AFL_SNAPSHOT_BLOCK 2 +// Snapshot file descriptor state, close newly opened descriptors +#define AFL_SNAPSHOT_FDS 4 +// Snapshot registers state +#define AFL_SNAPSHOT_REGS 8 +// Perform a restore when exit_group is invoked +#define AFL_SNAPSHOT_EXIT 16 +// TODO(andrea) allow not COW snapshots (high perf on small processes) +// Disable COW, restore all the snapshotted pages +#define AFL_SNAPSHOT_NOCOW 32 +// Do not snapshot Stack pages +#define AFL_SNAPSHOT_NOSTACK 64 + +struct afl_snapshot_vmrange_args { + + unsigned long start, end; + +}; static int afl_snapshot_dev_fd; -static int afl_snapshot_init(void) { +static int afl_snapshot_init() { afl_snapshot_dev_fd = open(AFL_SNAPSHOT_FILE_NAME, 0); return afl_snapshot_dev_fd; } -static int afl_snapshot_do() { +static void afl_snapshot_exclude_vmrange(void* start, void* end) { - return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO); + struct afl_snapshot_vmrange_args args = {(unsigned long)start, (unsigned long)end}; + ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_EXCLUDE_VMRANGE, &args); } -static int afl_snapshot_clean(void) { +static void afl_snapshot_include_vmrange(void* start, void* end) { - return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN); + struct afl_snapshot_vmrange_args args = {(unsigned long)start, (unsigned long)end}; + ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_INCLUDE_VMRANGE, &args); + +} + +static int afl_snapshot_take(int config) { + + return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_TAKE, config); + +} + +static void afl_snapshot_restore(void) { + + ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_RESTORE); + +} + +static void afl_snapshot_clean(void) { + + ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_CLEAN); } diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index a2038188..25be0d5a 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -521,7 +521,7 @@ static void __afl_start_snapshots(void) { close(FORKSRV_FD); close(FORKSRV_FD + 1); - if (!afl_snapshot_do()) { raise(SIGSTOP); } + if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS | AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) { raise(SIGSTOP); } __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); -- cgit 1.4.1 From d64c0e888751a3747d945702bc3e732c94db0cc9 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 28 Jul 2020 16:31:07 +0200 Subject: lkm new api --- include/snapshot-inl.h | 37 ++++++++++++++++++++++++------------- llvm_mode/afl-llvm-rt.o.c | 7 ++++++- 2 files changed, 30 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/snapshot-inl.h b/include/snapshot-inl.h index 55251db5..263a4b63 100644 --- a/include/snapshot-inl.h +++ b/include/snapshot-inl.h @@ -32,23 +32,26 @@ #define AFL_SNAPSHOT_IOCTL_MAGIC 44313 -#define AFL_SNAPSHOT_EXCLUDE_VMRANGE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 1, struct afl_snapshot_vmrange_args*) -#define AFL_SNAPSHOT_INCLUDE_VMRANGE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 2, struct afl_snapshot_vmrange_args*) -#define AFL_SNAPSHOT_IOCTL_TAKE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 3, int) -#define AFL_SNAPSHOT_IOCTL_RESTORE _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 4) -#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 5) +#define AFL_SNAPSHOT_IOCTL_DO _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 1) +#define AFL_SNAPSHOT_IOCTL_CLEAN _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 2) +#define AFL_SNAPSHOT_EXCLUDE_VMRANGE \ + _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 3, struct afl_snapshot_vmrange_args *) +#define AFL_SNAPSHOT_INCLUDE_VMRANGE \ + _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 4, struct afl_snapshot_vmrange_args *) +#define AFL_SNAPSHOT_IOCTL_TAKE _IOR(AFL_SNAPSHOT_IOCTL_MAGIC, 5, int) +#define AFL_SNAPSHOT_IOCTL_RESTORE _IO(AFL_SNAPSHOT_IOCTL_MAGIC, 6) // Trace new mmaped ares and unmap them on restore. -#define AFL_SNAPSHOT_MMAP 1 +#define AFL_SNAPSHOT_MMAP 1 // Do not snapshot any page (by default all writeable not-shared pages // are shanpshotted. #define AFL_SNAPSHOT_BLOCK 2 // Snapshot file descriptor state, close newly opened descriptors -#define AFL_SNAPSHOT_FDS 4 +#define AFL_SNAPSHOT_FDS 4 // Snapshot registers state -#define AFL_SNAPSHOT_REGS 8 +#define AFL_SNAPSHOT_REGS 8 // Perform a restore when exit_group is invoked -#define AFL_SNAPSHOT_EXIT 16 +#define AFL_SNAPSHOT_EXIT 16 // TODO(andrea) allow not COW snapshots (high perf on small processes) // Disable COW, restore all the snapshotted pages #define AFL_SNAPSHOT_NOCOW 32 @@ -70,16 +73,18 @@ static int afl_snapshot_init() { } -static void afl_snapshot_exclude_vmrange(void* start, void* end) { +static void afl_snapshot_exclude_vmrange(void *start, void *end) { - struct afl_snapshot_vmrange_args args = {(unsigned long)start, (unsigned long)end}; + struct afl_snapshot_vmrange_args args = {(unsigned long)start, + (unsigned long)end}; ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_EXCLUDE_VMRANGE, &args); } -static void afl_snapshot_include_vmrange(void* start, void* end) { +static void afl_snapshot_include_vmrange(void *start, void *end) { - struct afl_snapshot_vmrange_args args = {(unsigned long)start, (unsigned long)end}; + struct afl_snapshot_vmrange_args args = {(unsigned long)start, + (unsigned long)end}; ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_INCLUDE_VMRANGE, &args); } @@ -90,6 +95,12 @@ static int afl_snapshot_take(int config) { } +static int afl_snapshot_take(void) { + + return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO); + +} + static void afl_snapshot_restore(void) { ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_RESTORE); diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 25be0d5a..c0ed1bcf 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -521,7 +521,12 @@ static void __afl_start_snapshots(void) { close(FORKSRV_FD); close(FORKSRV_FD + 1); - if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS | AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) { raise(SIGSTOP); } + if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS | + AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) { + + raise(SIGSTOP); + + } __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); -- cgit 1.4.1 From ffe5619a9d0934f9088ef32ddbd507a0ddbde321 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Jul 2020 14:30:22 +0200 Subject: fix snapshot include --- README.md | 11 ++++++----- docs/Changelog.md | 2 ++ include/snapshot-inl.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/README.md b/README.md index c6893fa0..d747ea00 100644 --- a/README.md +++ b/README.md @@ -272,11 +272,12 @@ afl-clang-lto: To use this set the following environment variable before compiling the target: `export AFL_LLVM_LAF_ALL=1` You can read more about this in [llvm/README.laf-intel.md](llvm/README.laf-intel.md) - * A different technique is to instrument the target so that any compare values - in the target are sent to afl++ which then tries to put this value into the - fuzzing data at different locations. This technique is very fast and good - - if the target does not transform input data before comparison. Therefore - technique is called `input to state` or `redqueen`. + * A different technique (and usually a bit better than laf-intel) is to + instrument the target so that any compare values in the target are sent to + afl++ which then tries to put this value into the fuzzing data at different + locations. This technique is very fast and good - if the target does not + transform input data before comparison. Therefore this technique is called + `input to state` or `redqueen`. If you want to use this technique, then you have to compile the target twice, once specifically with/for this mode. You can read more about this in [llvm_mode/README.cmplog.md](llvm_mode/README.cmplog.md) diff --git a/docs/Changelog.md b/docs/Changelog.md index 7efab1e6..1e7a1c1d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,8 @@ sending a mail to . ### Version ++2.66d (devel) + - Support for improved afl++ snapshot module: + https://github.com/AFLplusplus/AFL-Snapshot-LKM - afl-fuzz: - added -F option to allow -M main fuzzers to sync to foreign fuzzers, e.g. honggfuzz or libfuzzer diff --git a/include/snapshot-inl.h b/include/snapshot-inl.h index 263a4b63..a75d69c0 100644 --- a/include/snapshot-inl.h +++ b/include/snapshot-inl.h @@ -95,7 +95,7 @@ static int afl_snapshot_take(int config) { } -static int afl_snapshot_take(void) { +static int afl_snapshot_do(void) { return ioctl(afl_snapshot_dev_fd, AFL_SNAPSHOT_IOCTL_DO); -- cgit 1.4.1 From c661587128fd84847e88bb1b66e8403b81d0d296 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 30 Jul 2020 18:06:25 +0200 Subject: cdecl void --- examples/afl_untracer/afl-untracer.c | 10 +++++----- include/snapshot-inl.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 68658bfd..77b15eb8 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -115,10 +115,10 @@ static library_list_t liblist[MAX_LIB_COUNT]; static u32 liblist_cnt; static void sigtrap_handler(int signum, siginfo_t *si, void *context); -static void fuzz(); +static void fuzz(void); /* read the library information */ -void read_library_information() { +void read_library_information(void) { #if defined(__linux__) FILE *f; @@ -284,7 +284,7 @@ library_list_t *find_library(char *name) { // this seems to work for clang too. nice :) requires gcc 4.4+ #pragma GCC push_options #pragma GCC optimize("O0") -void breakpoint() { +void breakpoint(void) { if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); @@ -461,7 +461,7 @@ inline static void __afl_end_testcase(int status) { ((uintptr_t)addr & 0x3) * 0x10000000000)) #endif -void setup_trap_instrumentation() { +void setup_trap_instrumentation(void) { library_list_t *lib_base = NULL; size_t lib_size = 0; @@ -748,7 +748,7 @@ int main(int argc, char *argv[]) { inline #endif static void - fuzz() { + fuzz(void) { // STEP 3: call the function to fuzz, also the functions you might // need to call to prepare the function and - important! - diff --git a/include/snapshot-inl.h b/include/snapshot-inl.h index a75d69c0..a18187ef 100644 --- a/include/snapshot-inl.h +++ b/include/snapshot-inl.h @@ -66,7 +66,7 @@ struct afl_snapshot_vmrange_args { static int afl_snapshot_dev_fd; -static int afl_snapshot_init() { +static int afl_snapshot_init(void) { afl_snapshot_dev_fd = open(AFL_SNAPSHOT_FILE_NAME, 0); return afl_snapshot_dev_fd; -- cgit 1.4.1 From 320f26d26f7e0cbe093e6f5af5f27f180bc31a1b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 30 Jul 2020 19:00:41 +0200 Subject: add -b option to afl-fuzz --- docs/Changelog.md | 1 + include/afl-fuzz.h | 3 ++- src/afl-fuzz-init.c | 22 +++++++++++++++++----- src/afl-fuzz-state.c | 1 + src/afl-fuzz.c | 19 ++++++++++++++++--- 5 files changed, 37 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/docs/Changelog.md b/docs/Changelog.md index 1e7a1c1d..dcaf64a7 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ sending a mail to . - afl-fuzz: - added -F option to allow -M main fuzzers to sync to foreign fuzzers, e.g. honggfuzz or libfuzzer + - added -b option to bind to a specific CPU - eliminated CPU affinity race condition for -S/-M runs - expanded havoc mode added, on no cycle finds add extra splicing and MOpt into the mix diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1c1be711..bc3f65b6 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -545,7 +545,8 @@ typedef struct afl_state { u64 total_bitmap_size, /* Total bit count for all bitmaps */ total_bitmap_entries; /* Number of bitmaps counted */ - s32 cpu_core_count; /* CPU core count */ + s32 cpu_core_count, /* CPU core count */ + cpu_to_bind; /* bind to specific CPU */ #ifdef HAVE_AFFINITY s32 cpu_aff; /* Selected CPU core */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 65ad0c9f..ad92dff6 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -53,6 +53,13 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 cpu_used[4096] = {0}, lockfile[PATH_MAX] = ""; u32 i; + if (afl->cpu_to_bind != -1) { + + i = afl->cpu_to_bind; + goto set_cpu; + + } + if (afl->sync_id) { s32 lockfd, first = 1; @@ -295,20 +302,23 @@ void bind_to_free_cpu(afl_state_t *afl) { try: + if (afl->cpu_to_bind != -1) + FATAL("bind to CPU #%d failed!", afl->cpu_to_bind); + #if !defined(__ANDROID__) - for (i = cpu_start; i < afl->cpu_core_count; i++) { + for (i = cpu_start; i < afl->cpu_core_count; i++) { - if (!cpu_used[i]) { break; } + if (!cpu_used[i]) { break; } - } + } if (i == afl->cpu_core_count) { #else - for (i = afl->cpu_core_count - cpu_start - 1; i > -1; i--) - if (!cpu_used[i]) break; + for (i = afl->cpu_core_count - cpu_start - 1; i > -1; i--) + if (!cpu_used[i]) break; if (i == -1) { #endif @@ -327,6 +337,8 @@ void bind_to_free_cpu(afl_state_t *afl) { OKF("Found a free CPU core, try binding to #%u.", i); +set_cpu: + afl->cpu_aff = i; #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 66280ed1..e2d62bc6 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -94,6 +94,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->havoc_div = 1; /* Cycle count divisor for havoc */ afl->stage_name = "init"; /* Name of the current fuzz stage */ afl->splicing_with = -1; /* Splicing with which test case? */ + afl->cpu_to_bind = -1; #ifdef HAVE_AFFINITY afl->cpu_aff = -1; /* Selected CPU core */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 5bedf6e1..e33a4bbd 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -143,6 +143,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { //" -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap //" "file\n" " -C - crash exploration mode (the peruvian rabbit thing)\n" + " -b cpu_id - bind the fuzzing process to the specified CPU core " + "(0-...)\n" " -e ext - file extension for the fuzz test input file (if " "needed)\n\n", argv0, EXEC_TIMEOUT, MEM_LIMIT, FOREIGN_SYNCS_MAX); @@ -271,9 +273,9 @@ int main(int argc, char **argv_orig, char **envp) { afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing - while ((opt = getopt(argc, argv, - "+c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > - 0) { + while ((opt = getopt( + argc, argv, + "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > 0) { switch (opt) { @@ -281,6 +283,17 @@ int main(int argc, char **argv_orig, char **envp) { afl->infoexec = optarg; break; + case 'b': { /* bind CPU core */ + + if (afl->cpu_to_bind != -1) FATAL("Multiple -b options not supported"); + + if (sscanf(optarg, "%u", &afl->cpu_to_bind) < 0 || optarg[0] == '-') + FATAL("Bad syntax used for -b"); + + break; + + } + case 'c': { afl->shm.cmplog_mode = 1; -- cgit 1.4.1 From 185f4436598aacb3f25736ce6eb53309d1d9472f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 31 Jul 2020 17:53:01 +0200 Subject: add LTO AFL_LLVM_DOCUMENT_IDS feature --- docs/Changelog.md | 2 ++ docs/FAQ.md | 12 +++++----- docs/env_variables.md | 35 ++++++++++++++++------------ include/envs.h | 1 + llvm_mode/README.lto.md | 6 +++++ llvm_mode/afl-clang-fast.c | 2 ++ llvm_mode/afl-llvm-lto-instrumentation.so.cc | 18 ++++++++++++++ 7 files changed, 55 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/docs/Changelog.md b/docs/Changelog.md index dcaf64a7..14d00a43 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,6 +26,8 @@ sending a mail to . - LTO: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used as it is always better + - LTO: env var AFL_LLVM_DOCUMENT_IDS=file will document which edge ID + was given to which function during compilation - setting AFL_LLVM_LAF_SPLIT_FLOATS now activates AFL_LLVM_LAF_SPLIT_COMPARES - added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz diff --git a/docs/FAQ.md b/docs/FAQ.md index e09385a8..b09a16ae 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -95,12 +95,13 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! 2. Second step: Find the responsible function. - a) For LTO instrumented binaries just disassemble or decompile the target - and look which edge is writing to that edge ID. Ghidra is a good tool - for this: [https://ghidra-sre.org/](https://ghidra-sre.org/) + a) For LTO instrumented binaries this can be documented during compile + time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/afile`. + This file will have one assigned edge ID and the corresponding function + per line. - b) For PCGUARD instrumented binaries it is more difficult. Here you can - either modify the __sanitizer_cov_trace_pc_guard function in + b) For PCGUARD instrumented binaries it is much more difficult. Here you + can either modify the __sanitizer_cov_trace_pc_guard function in llvm_mode/afl-llvm-rt.o.c to write a backtrace to a file if the ID in __afl_area_ptr[*guard] is one of the unstable edge IDs. Then recompile and reinstall llvm_mode and rebuild your target. Run the recompiled @@ -121,4 +122,3 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! 4. Fourth step: recompile the target Recompile, fuzz it, be happy :) - diff --git a/docs/env_variables.md b/docs/env_variables.md index 87344331..4c0d2db7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -121,18 +121,16 @@ Then there are a few specific features that are only available in llvm_mode: built if LLVM 11 or newer is used. - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation. - (recommended) - - - AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target - binary based on string compare and memory compare functions. - afl-fuzz will automatically get these transmitted when starting to - fuzz. + (not recommended!) None of the following options are necessary to be used and are rather for manual use (which only ever the author of this LTO implementation will use). These are used if several seperated instrumentation are performed which are then later combined. + - AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given + to which function. This helps to identify functions with variable bytes + or which functions were touched by an input. - AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than the default 0x10000. A value of 0 or empty sets the map address to be dynamic (the original afl way, which is slower) @@ -254,15 +252,6 @@ checks or alter some of the more exotic semantics of the tool: useful if you can't change the defaults (e.g., no root access to the system) and are OK with some performance loss. - - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to - fork + execve() call for every tested input. This is useful mostly when - working with unruly libraries that create threads or do other crazy - things when initializing (before the instrumentation has a chance to run). - - Note that this setting inhibits some of the user-friendly diagnostics - normally done when starting up the forkserver and causes a pretty - significant performance drop. - - AFL_EXIT_WHEN_DONE causes afl-fuzz to terminate when all existing paths have been fuzzed and there were no new finds for a while. This would be normally indicated by the cycle counter in the UI turning green. May be @@ -338,6 +327,13 @@ checks or alter some of the more exotic semantics of the tool: - In QEMU mode (-Q), AFL_PATH will be searched for afl-qemu-trace. + - Setting AFL_CYCLE_SCHEDULES will switch to a different schedule everytime + a cycle is finished. + + - Setting AFL_EXPAND_HAVOC_NOW will start in the extended havoc mode that + includes costly mutations. afl-fuzz automatically enables this mode when + deemed useful otherwise. + - Setting AFL_PRELOAD causes AFL to set LD_PRELOAD for the target binary without disrupting the afl-fuzz process itself. This is useful, among other things, for bootstrapping libdislocator.so. @@ -365,6 +361,15 @@ checks or alter some of the more exotic semantics of the tool: for an existing out folder, even if a different `-i` was provided. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. + - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to + fork + execve() call for every tested input. This is useful mostly when + working with unruly libraries that create threads or do other crazy + things when initializing (before the instrumentation has a chance to run). + + Note that this setting inhibits some of the user-friendly diagnostics + normally done when starting up the forkserver and causes a pretty + significant performance drop. + - Outdated environment variables that are that not supported anymore: AFL_DEFER_FORKSRV AFL_PERSISTENT diff --git a/include/envs.h b/include/envs.h index c1c7d387..7153ed47 100644 --- a/include/envs.h +++ b/include/envs.h @@ -65,6 +65,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", + "AFL_LLVM_DOCUMENT_IDS", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", "AFL_LLVM_LTO_AUTODICTIONARY", diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index a4c969b9..e521ac82 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -140,6 +140,12 @@ to be dynamic - the original afl way, which is slower). AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which is safer but also slower). +## Document edge IDs + +Setting `export AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge +ID was given to which function. This helps to identify functions with variable +bytes or which functions were touched by an input. + ## Solving difficult targets Some targets are difficult because the configure script does unusual stuff that diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index dca11bf3..a2550d2c 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -890,6 +890,8 @@ int main(int argc, char **argv, char **envp) { "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" "AFL_PATH: path to instrumenting pass and runtime " "(afl-llvm-rt.*o)\n" + "AFL_LLVM_DOCUMENT_IDS: document edge IDs given to which function (LTO " + "only)\n" "AFL_QUIET: suppress verbose output\n" "AFL_USE_ASAN: activate address sanitizer\n" "AFL_USE_CFISAN: activate control flow sanitizer\n" diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 3c1d3565..46a97e54 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -103,6 +103,7 @@ bool AFLLTOPass::runOnModule(Module &M) { std::vector calls; DenseMap valueMap; char * ptr; + FILE * documentFile = NULL; IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); @@ -120,6 +121,13 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; + if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) { + + if ((documentFile = fopen(ptr, "a")) == NULL) + WARNF("Cannot access document file %s", ptr); + + } + if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || @@ -579,6 +587,14 @@ bool AFLLTOPass::runOnModule(Module &M) { } + if (documentFile) { + + fprintf(documentFile, "%s %u\n", + origBB->getParent()->getName().str().c_str(), + afl_global_id); + + } + BasicBlock::iterator IP = newBB->getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); @@ -632,6 +648,8 @@ bool AFLLTOPass::runOnModule(Module &M) { } + if (documentFile) fclose(documentFile); + } // save highest location ID to global variable -- cgit 1.4.1 From 54d96685808bd7b47de30f5028727d94b5369962 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 31 Jul 2020 17:21:17 +0000 Subject: Haiku set explicitly to performance. No command line to set through afl-system-config (the only one is a GUI). --- include/afl-fuzz.h | 5 +++++ src/afl-fuzz.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'include') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index bc3f65b6..b82ddb4a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -82,6 +82,11 @@ #include #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ +#if defined(__HAIKU__) + #include + #include +#endif + /* For systems that have sched_setaffinity; right now just Linux, but one can hope... */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 54db1efb..326ccc1c 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1057,6 +1057,11 @@ int main(int argc, char **argv_orig, char **envp) { bind_to_free_cpu(afl); #endif /* HAVE_AFFINITY */ + #ifdef __HAIKU__ + /* Prioritizes performance over power saving */ + set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY); + #endif + afl->fsrv.trace_bits = afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); -- cgit 1.4.1