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 --- include/afl-fuzz.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/afl-fuzz.h') 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 */ -- 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/afl-fuzz.h') 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 From c8354d751606e0f7a0364685958036bb7031e35a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 4 Aug 2020 23:22:42 +0200 Subject: new rand mode for data offsets that prefer low offset values --- include/afl-fuzz.h | 24 ++++++++++++++++++ src/afl-fuzz-one.c | 73 +++++++++++++++++++++++++++++------------------------- 2 files changed, 63 insertions(+), 34 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index b82ddb4a..dac99a76 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1001,6 +1001,30 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { } +/* we prefer lower range values here */ +/* this is only called with normal havoc, not MOpt, to have an equalizer for + expand havoc mode */ +static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) { + + switch (rand_below(afl, 3)) { + + case 2: + return (rand_below(afl, limit) % rand_below(afl, limit)) % + rand_below(afl, limit); + break; + case 1: + return rand_below(afl, limit) % rand_below(afl, limit); + break; + case 0: + return rand_below(afl, limit); + break; + + } + + return 1; // cannot be reached + +} + static inline s64 rand_get_seed(afl_state_t *afl) { if (unlikely(afl->fixed_seed)) { return afl->init_seed; } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 1f0bf30e..77bce7d0 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1921,14 +1921,14 @@ havoc_stage: /* Flip a single bit somewhere. Spooky! */ - FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); + FLIP_BIT(out_buf, rand_below_datalen(afl, temp_len << 3)); break; case 1: /* Set byte to interesting value. */ - out_buf[rand_below(afl, temp_len)] = + out_buf[rand_below_datalen(afl, temp_len)] = interesting_8[rand_below(afl, sizeof(interesting_8))]; break; @@ -1940,12 +1940,12 @@ havoc_stage: if (rand_below(afl, 2)) { - *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = + *(u16 *)(out_buf + rand_below_datalen(afl, temp_len - 1)) = interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; } else { - *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( + *(u16 *)(out_buf + rand_below_datalen(afl, temp_len - 1)) = SWAP16( interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); } @@ -1960,12 +1960,12 @@ havoc_stage: if (rand_below(afl, 2)) { - *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = + *(u32 *)(out_buf + rand_below_datalen(afl, temp_len - 3)) = interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; } else { - *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32( + *(u32 *)(out_buf + rand_below_datalen(afl, temp_len - 3)) = SWAP32( interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]); } @@ -1976,14 +1976,16 @@ havoc_stage: /* Randomly subtract from byte. */ - out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX); + out_buf[rand_below_datalen(afl, temp_len)] -= + 1 + rand_below(afl, ARITH_MAX); break; case 5: /* Randomly add to byte. */ - out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); + out_buf[rand_below_datalen(afl, temp_len)] += + 1 + rand_below(afl, ARITH_MAX); break; case 6: @@ -1994,13 +1996,13 @@ havoc_stage: if (rand_below(afl, 2)) { - u32 pos = rand_below(afl, temp_len - 1); + u32 pos = rand_below_datalen(afl, temp_len - 1); *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = rand_below(afl, temp_len - 1); + u32 pos = rand_below_datalen(afl, temp_len - 1); u16 num = 1 + rand_below(afl, ARITH_MAX); *(u16 *)(out_buf + pos) = @@ -2018,13 +2020,13 @@ havoc_stage: if (rand_below(afl, 2)) { - u32 pos = rand_below(afl, temp_len - 1); + u32 pos = rand_below_datalen(afl, temp_len - 1); *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = rand_below(afl, temp_len - 1); + u32 pos = rand_below_datalen(afl, temp_len - 1); u16 num = 1 + rand_below(afl, ARITH_MAX); *(u16 *)(out_buf + pos) = @@ -2042,13 +2044,13 @@ havoc_stage: if (rand_below(afl, 2)) { - u32 pos = rand_below(afl, temp_len - 3); + u32 pos = rand_below_datalen(afl, temp_len - 3); *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = rand_below(afl, temp_len - 3); + u32 pos = rand_below_datalen(afl, temp_len - 3); u32 num = 1 + rand_below(afl, ARITH_MAX); *(u32 *)(out_buf + pos) = @@ -2066,13 +2068,13 @@ havoc_stage: if (rand_below(afl, 2)) { - u32 pos = rand_below(afl, temp_len - 3); + u32 pos = rand_below_datalen(afl, temp_len - 3); *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = rand_below(afl, temp_len - 3); + u32 pos = rand_below_datalen(afl, temp_len - 3); u32 num = 1 + rand_below(afl, ARITH_MAX); *(u32 *)(out_buf + pos) = @@ -2088,7 +2090,8 @@ havoc_stage: why not. We use XOR with 1-255 to eliminate the possibility of a no-op. */ - out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); + out_buf[rand_below_datalen(afl, temp_len)] ^= + 1 + rand_below(afl, 255); break; case 11 ... 12: { @@ -2105,7 +2108,7 @@ havoc_stage: del_len = choose_block_len(afl, temp_len - 1); - del_from = rand_below(afl, temp_len - del_len + 1); + del_from = rand_below_datalen(afl, temp_len - del_len + 1); memmove(out_buf + del_from, out_buf + del_from + del_len, temp_len - del_from - del_len); @@ -2129,7 +2132,7 @@ havoc_stage: if (actually_clone) { clone_len = choose_block_len(afl, temp_len); - clone_from = rand_below(afl, temp_len - clone_len + 1); + clone_from = rand_below_datalen(afl, temp_len - clone_len + 1); } else { @@ -2138,7 +2141,7 @@ havoc_stage: } - clone_to = rand_below(afl, temp_len); + clone_to = rand_below_datalen(afl, temp_len); new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); @@ -2156,8 +2159,9 @@ havoc_stage: } else { memset(new_buf + clone_to, - rand_below(afl, 2) ? rand_below(afl, 256) - : out_buf[rand_below(afl, temp_len)], + rand_below(afl, 2) + ? rand_below(afl, 256) + : out_buf[rand_below_datalen(afl, temp_len)], clone_len); } @@ -2186,8 +2190,8 @@ havoc_stage: copy_len = choose_block_len(afl, temp_len - 1); - copy_from = rand_below(afl, temp_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); + copy_from = rand_below_datalen(afl, temp_len - copy_len + 1); + copy_to = rand_below_datalen(afl, temp_len - copy_len + 1); if (rand_below(afl, 4)) { @@ -2200,8 +2204,9 @@ havoc_stage: } else { memset(out_buf + copy_to, - rand_below(afl, 2) ? rand_below(afl, 256) - : out_buf[rand_below(afl, temp_len)], + rand_below(afl, 2) + ? rand_below(afl, 256) + : out_buf[rand_below_datalen(afl, temp_len)], copy_len); } @@ -2233,7 +2238,7 @@ havoc_stage: if (extra_len > temp_len) { break; } - insert_at = rand_below(afl, temp_len - extra_len + 1); + insert_at = rand_below_datalen(afl, temp_len - extra_len + 1); memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, extra_len); @@ -2247,7 +2252,7 @@ havoc_stage: if (extra_len > temp_len) { break; } - insert_at = rand_below(afl, temp_len - extra_len + 1); + insert_at = rand_below_datalen(afl, temp_len - extra_len + 1); memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); @@ -2258,7 +2263,7 @@ havoc_stage: } else { // case 16 u32 use_extra, extra_len, - insert_at = rand_below(afl, temp_len + 1); + insert_at = rand_below_datalen(afl, temp_len + 1); u8 *ptr; /* Insert an extra. Do the same dice-rolling stuff as for the @@ -2362,8 +2367,8 @@ havoc_stage: 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); + copy_from = rand_below_datalen(afl, new_len - copy_len + 1); + copy_to = rand_below_datalen(afl, temp_len - copy_len + 1); memmove(out_buf + copy_to, new_buf + copy_from, copy_len); @@ -2372,9 +2377,9 @@ havoc_stage: 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_from = rand_below_datalen(afl, new_len - clone_len + 1); - clone_to = rand_below(afl, temp_len); + clone_to = rand_below_datalen(afl, temp_len); u8 *temp_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); @@ -2523,7 +2528,7 @@ retry_splicing: /* Split somewhere between the first and last differing byte. */ - split_at = f_diff + rand_below(afl, l_diff - f_diff); + split_at = f_diff + rand_below_datalen(afl, l_diff - f_diff); /* Do the thing. */ -- cgit 1.4.1 From 585ec0450331ec7fd8b9a79737cba6b6937422bf Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 5 Aug 2020 09:21:39 +0200 Subject: silly rand_below_datalen fix --- include/afl-fuzz.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index dac99a76..2324efa5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -986,6 +986,8 @@ uint64_t rand_next(afl_state_t *afl); static inline u32 rand_below(afl_state_t *afl, u32 limit) { + if (limit <= 1) return 0; + /* The boundary not being necessarily a power of 2, we need to ensure the result uniformity. */ if (unlikely(!afl->rand_cnt--) && likely(!afl->fixed_seed)) { @@ -1006,14 +1008,16 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { expand havoc mode */ static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) { + if (limit <= 1) return 0; + switch (rand_below(afl, 3)) { case 2: - return (rand_below(afl, limit) % rand_below(afl, limit)) % - rand_below(afl, limit); + return (rand_below(afl, limit) % (1 + rand_below(afl, limit - 1))) % + (1 + rand_below(afl, limit - 1)); break; case 1: - return rand_below(afl, limit) % rand_below(afl, limit); + return rand_below(afl, limit) % (1 + rand_below(afl, limit - 1)); break; case 0: return rand_below(afl, limit); -- cgit 1.4.1 From f30ca1476c2d4d08d46fe9657ad4aa1d828eb578 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 5 Aug 2020 11:17:15 +0200 Subject: fix short write --- include/afl-fuzz.h | 4 ++-- llvm_mode/afl-clang-fast.c | 10 ++++++---- src/afl-fuzz-queue.c | 2 ++ src/afl-fuzz-run.c | 17 ++++++++++++++--- 4 files changed, 24 insertions(+), 9 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 2324efa5..bb1bb314 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -986,7 +986,7 @@ uint64_t rand_next(afl_state_t *afl); static inline u32 rand_below(afl_state_t *afl, u32 limit) { - if (limit <= 1) return 0; + if (limit <= 1) return 0; /* The boundary not being necessarily a power of 2, we need to ensure the result uniformity. */ @@ -1008,7 +1008,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { expand havoc mode */ static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) { - if (limit <= 1) return 0; + if (limit <= 1) return 0; switch (rand_below(afl, 3)) { diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 16f2c9c0..3038df30 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -161,8 +161,8 @@ static void find_obj(u8 *argv0) { static void edit_params(u32 argc, char **argv, char **envp) { - u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, - preprocessor_only = 0; + u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, + preprocessor_only = 0; u8 have_pic = 0; u8 *name; @@ -400,7 +400,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue; - + if (!strcmp(cur, "-E")) preprocessor_only = 1; cc_params[cc_par_cnt++] = cur; @@ -566,8 +566,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "none"; } - + if (preprocessor_only) { + /* In the preprocessor_only case (-E), we are not actually compiling at all but requesting the compiler to output preprocessed sources only. We must not add the runtime in this case because the compiler will @@ -575,6 +576,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { systems that rely on a separate source preprocessing step. */ cc_params[cc_par_cnt] = NULL; return; + } #ifndef __ANDROID__ diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 71874283..f35df914 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -112,8 +112,10 @@ static u8 check_if_text(struct queue_entry *q) { u8 buf[MAX_FILE]; s32 fd, len = q->len, offset = 0, ascii = 0, utf8 = 0, comp; + if (len >= MAX_FILE) len = MAX_FILE - 1; if ((fd = open(q->fname, O_RDONLY)) < 0) return 0; if ((comp = read(fd, buf, len)) != len) return 0; + buf[len] = 0; close(fd); while (offset < len) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 44d3c522..ed4a1081 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -819,16 +819,27 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fd = open(q->fname, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } + + u32 written = 0; + while (written < q->len) { + + ssize_t result = write(fd, in_buf, q->len - written); + if (result > 0) written += result; + + } + } else { unlink(q->fname); /* ignore errors */ fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); - } + if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } - if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } + ck_write(fd, in_buf, q->len, q->fname); + + } - ck_write(fd, in_buf, q->len, q->fname); close(fd); memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); -- cgit 1.4.1 From 9a1d526ed408cbd7d681be15c5512032f7632887 Mon Sep 17 00:00:00 2001 From: murx- Date: Sat, 8 Aug 2020 18:34:54 +0200 Subject: Add support for specific custom mutator name --- include/afl-fuzz.h | 1 + src/afl-fuzz-mutators.c | 1 + src/afl-fuzz-one.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index bb1bb314..51ab0e85 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -656,6 +656,7 @@ typedef struct afl_state { struct custom_mutator { const char *name; + char * name_short; void * dh; u8 * post_process_buf; size_t post_process_size; diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index b30106a0..0fa646f9 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -142,6 +142,7 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); mutator->name = fn; + mutator->name_short = strrchr(fn, '/') + 1; ACTF("Loading custom mutator library from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 74e09ee3..452c5298 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1683,6 +1683,8 @@ custom_mutator_stage: has_custom_fuzz = true; + afl->stage_short = el->name_short; + for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { -- cgit 1.4.1 From e4a0237cbc745552a5b21a2450d7ab55ee98759d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 00:35:12 +0200 Subject: step 1 --- GNUmakefile | 2 +- include/afl-fuzz.h | 6 ++++++ include/forkserver.h | 2 ++ qemu_taint/README.md | 2 +- src/afl-common.c | 1 + src/afl-forkserver.c | 15 +++++++++++++-- src/afl-fuzz-bitmap.c | 32 ++++++++++++++++++++++++++++++++ src/afl-fuzz-run.c | 13 +++++++++++++ src/afl-fuzz.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 9 files changed, 116 insertions(+), 8 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index 9b064eb6..4d0c434e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -98,7 +98,7 @@ ifneq "$(shell uname -m)" "x86_64" endif CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) -override CFLAGS += -Wall -Wextra -Werror -g -Wno-pointer-sign \ +override CFLAGS += -g -Wno-pointer-sign \ -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index bb1bb314..eb7f8ca5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -371,6 +371,8 @@ typedef struct afl_state { afl_env_vars_t afl_env; char **argv; /* argv if needed */ + + char **argv_taint; /* argv for taint mode */ /* MOpt: Lots of globals, but mostly for the status UI and other things where it @@ -581,6 +583,9 @@ typedef struct afl_state { char * cmplog_binary; afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ + /* Taint mode */ + afl_forkserver_t taint_fsrv; /* taint mode has its own little forkserver */ + /* Custom mutators */ struct custom_mutator *mutator; @@ -889,6 +894,7 @@ u32 calculate_score(afl_state_t *, struct queue_entry *); void write_bitmap(afl_state_t *); u32 count_bits(afl_state_t *, u8 *); +u32 count_bits_len(afl_state_t *, u8 *, u32); u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 diff --git a/include/forkserver.h b/include/forkserver.h index 717493db..a5fca30e 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,6 +79,8 @@ typedef struct afl_forkserver { u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ u8 qemu_mode; /* if running in qemu mode or not */ + + u8 taint_mode; /* if running taint analysis or not */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */ diff --git a/qemu_taint/README.md b/qemu_taint/README.md index c842da0e..6a7d19af 100644 --- a/qemu_taint/README.md +++ b/qemu_taint/README.md @@ -18,7 +18,7 @@ Only touched bytes are then fuzzed by afl-fuzz ## How to use -Add the -T flag to afl-fuzz +Add the -A flag to afl-fuzz ## Caveats diff --git a/src/afl-common.c b/src/afl-common.c index 367dec72..134d3180 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -138,6 +138,7 @@ void argv_cpy_free(char **argv) { } + /* Rewrite argv for QEMU. */ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 752641d7..b4f92e5b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -481,6 +481,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 0); +fprintf(stderr, "init %p\n", fsrv->init_child_func); fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -496,10 +497,20 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, char pid_buf[16]; sprintf(pid_buf, "%d", fsrv->fsrv_pid); - if (fsrv->cmplog_binary) + + if (fsrv->qemu_mode == 2) { + + setenv("__AFL_TARGET_PID3", pid_buf, 1); + + } else if (fsrv->cmplog_binary) { + setenv("__AFL_TARGET_PID2", pid_buf, 1); - else + + } else { + setenv("__AFL_TARGET_PID1", pid_buf, 1); + + } /* Close the unneeded endpoints. */ diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index aa8d5a18..9cb1b83f 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -177,6 +177,38 @@ u32 count_bits(afl_state_t *afl, u8 *mem) { } +u32 count_bits_len(afl_state_t *afl, u8 *mem, u32 len) { + + u32 *ptr = (u32 *)mem; + u32 i = (len >> 2); + u32 ret = 0; + + if (len % 4) i++; + + while (i--) { + + u32 v = *(ptr++); + + /* This gets called on the inverse, virgin bitmap; optimize for sparse + data. */ + + if (v == 0xffffffff) { + + ret += 32; + continue; + + } + + v -= ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24; + + } + + return ret; + +} + /* Count the number of bytes set in the bitmap. Called fairly sporadically, mostly to update the status screen or calibrate and examine confirmed new paths. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 8d652155..207b3046 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -471,6 +471,19 @@ abort_calibration: afl->stage_cur = old_sc; afl->stage_max = old_sm; + /* if taint mode was selected, run the taint */ + + if (afl->fsrv.taint_mode) { + write_to_testcase(afl, use_mem, q->len); + if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == 0) { + u32 len = q->len / 8; + if (q->len % 8) len++; + u32 bits = count_bits_len(afl, afl->taint_fsrv.trace_bits, len); + if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bits); + + } + } + if (!first_run) { show_stats(afl); } return fault; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 031c4049..bc780b55 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -53,6 +53,9 @@ static void at_exit() { ptr = getenv("__AFL_TARGET_PID2"); if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); + ptr = getenv("__AFL_TARGET_PID3"); + if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); + i = 0; while (list[i] != NULL) { @@ -89,6 +92,7 @@ static void usage(u8 *argv0, int more_help) { " -o dir - output directory for fuzzer findings\n\n" "Execution control settings:\n" + " -A - use first level taint analysis (see qemu_taint/README.md)\n" " -p schedule - power schedules compute a seed's performance score. " " 0) { + "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QANUWe:p:s:V:E:L:hRP:")) > 0) { switch (opt) { + case 'A': + afl->fsrv.taint_mode = 1; + if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; } + break; + case 'I': afl->infoexec = optarg; break; @@ -485,7 +494,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!optarg) { FATAL("Wrong usage of -m"); } - if (!strcmp(optarg, "none")) { + if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) { afl->fsrv.mem_limit = 0; break; @@ -815,6 +824,14 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->fsrv.taint_mode && afl->fsrv.map_size < (MAX_FILE / 8) + 1) { + + afl->shm.map_size = (MAX_FILE / 8); + if (MAX_FILE % 8) afl->shm.map_size++; + afl->fsrv.map_size = afl->shm.map_size; + + } + if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" " @@ -869,6 +886,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); } if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); } if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); } + if (afl->fsrv.taint_mode) { FATAL("-A and -n are mutually exclusive"); } } @@ -969,7 +987,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_preload) { - if (afl->fsrv.qemu_mode) { + if (afl->fsrv.qemu_mode || afl->fsrv.taint_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -1220,7 +1238,6 @@ int main(int argc, char **argv_orig, char **envp) { ACTF("Spawning cmplog forkserver"); afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv); - // TODO: this is semi-nice afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; @@ -1230,6 +1247,29 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Cmplog forkserver successfully started"); } + + if (afl->fsrv.taint_mode) { + + ACTF("Spawning qemu_taint forkserver"); + afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv); + afl->taint_fsrv.qemu_mode = 2; + afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits; + ck_free(afl->taint_fsrv.target_path); + afl->taint_fsrv.target_path = ck_strdup(afl->fsrv.target_path); + afl->argv_taint = get_qemu_argv(argv[0], &afl->taint_fsrv.target_path, + argc - optind, argv + optind); + u32 len = strlen(afl->taint_fsrv.target_path); + strcpy(afl->taint_fsrv.target_path + len - 5, "taint"); + strcpy((afl->argv_taint[0]) + len - 5, "taint"); + if (afl->fsrv.use_stdin) + unsetenv("AFL_TAINT_INPUT"); + else + setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1); + afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); + OKF("Taint forkserver successfully started"); + + } perform_dry_run(afl); @@ -1493,8 +1533,11 @@ stop_fuzzing: } + if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv); + if (afl->fsrv.taint_mode) afl_fsrv_deinit(&afl->taint_fsrv); afl_fsrv_deinit(&afl->fsrv); if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } + if (afl->argv_taint) { ck_free(afl->argv_taint); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); ck_free(afl->sync_id); -- cgit 1.4.1 From 0bb59ba11606e0382126304f78507efe7d62fd6b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 01:09:26 +0200 Subject: code format --- include/afl-fuzz.h | 2 +- include/common.h | 1 + include/forkserver.h | 2 +- src/afl-common.c | 140 +++++++++++++++++---------------------------------- src/afl-forkserver.c | 11 ++-- src/afl-fuzz-run.c | 8 ++- src/afl-fuzz.c | 25 ++++++--- 7 files changed, 78 insertions(+), 111 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index eb7f8ca5..37e2dc6c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -371,7 +371,7 @@ typedef struct afl_state { afl_env_vars_t afl_env; char **argv; /* argv if needed */ - + char **argv_taint; /* argv for taint mode */ /* MOpt: diff --git a/include/common.h b/include/common.h index 87a7425b..42c79c62 100644 --- a/include/common.h +++ b/include/common.h @@ -55,6 +55,7 @@ extern u8 *doc_path; /* path to documentation dir */ @returns the path, allocating the string */ u8 *find_binary(u8 *fname); +u8 *find_binary_own_loc(u8 *fname, u8 *own_loc); /* Read a bitmap from file fname to memory This is for the -B option again. */ diff --git a/include/forkserver.h b/include/forkserver.h index a5fca30e..89f23ab7 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,7 +79,7 @@ typedef struct afl_forkserver { u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ u8 qemu_mode; /* if running in qemu mode or not */ - + u8 taint_mode; /* if running taint analysis or not */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */ diff --git a/src/afl-common.c b/src/afl-common.c index 134d3180..c0202821 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -138,32 +138,19 @@ void argv_cpy_free(char **argv) { } +u8 *find_binary_own_loc(u8 *fname, u8 *own_loc) { -/* Rewrite argv for QEMU. */ - -char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { - - char **new_argv = ck_alloc(sizeof(char *) * (argc + 4)); - u8 * tmp, *cp = NULL, *rsl, *own_copy; - - memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1)); - new_argv[argc - 1] = NULL; - - new_argv[2] = *target_path_p; - new_argv[1] = "--"; - - /* Now we need to actually find the QEMU binary to put in argv[0]. */ + u8 *tmp, *rsl, *own_copy, *cp; tmp = getenv("AFL_PATH"); if (tmp) { - cp = alloc_printf("%s/afl-qemu-trace", tmp); + cp = alloc_printf("%s/%s", tmp, fname); if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } - *target_path_p = new_argv[0] = cp; - return new_argv; + return cp; } @@ -174,15 +161,10 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { *rsl = 0; - cp = alloc_printf("%s/afl-qemu-trace", own_copy); + cp = alloc_printf("%s/%s", own_copy, fname); ck_free(own_copy); - if (!access(cp, X_OK)) { - - *target_path_p = new_argv[0] = cp; - return new_argv; - - } + if (!access(cp, X_OK)) { return cp; } } else { @@ -190,11 +172,35 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { } - if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { + cp = alloc_printf("%s/%s", BIN_PATH, fname); + if (!access(cp, X_OK)) { return cp; } + + ck_free(cp); + + return NULL; - if (cp) { ck_free(cp); } - *target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace"); +} + +/* Rewrite argv for QEMU. */ + +char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { + + char **new_argv = ck_alloc(sizeof(char *) * (argc + 4)); + u8 * cp = NULL; + + memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1)); + new_argv[argc - 1] = NULL; + new_argv[2] = *target_path_p; + new_argv[1] = "--"; + + /* Now we need to actually find the QEMU binary to put in argv[0]. */ + + cp = find_binary_own_loc("afl-qemu-trace", own_loc); + + if (cp) { + + *target_path_p = new_argv[0] = cp; return new_argv; } @@ -235,66 +241,16 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { /* Now we need to actually find the QEMU binary to put in argv[0]. */ - tmp = getenv("AFL_PATH"); - - if (tmp) { + cp = find_binary_own_loc("afl-qemu-trace", own_loc); - cp = alloc_printf("%s/afl-qemu-trace", tmp); - - if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } + if (cp) { ck_free(cp); + cp = find_binary_own_loc("afl-wine-trace", own_loc); - cp = alloc_printf("%s/afl-wine-trace", tmp); + if (cp) { - if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } - - *target_path_p = new_argv[0] = cp; - return new_argv; - - } - - own_copy = ck_strdup(own_loc); - rsl = strrchr(own_copy, '/'); - - if (rsl) { - - *rsl = 0; - - cp = alloc_printf("%s/afl-qemu-trace", own_copy); - - if (cp && !access(cp, X_OK)) { - - ck_free(cp); - - cp = alloc_printf("%s/afl-wine-trace", own_copy); - - if (!access(cp, X_OK)) { - - *target_path_p = new_argv[0] = cp; - return new_argv; - - } - - } - - ck_free(own_copy); - - } else { - - ck_free(own_copy); - - } - - u8 *ncp = BIN_PATH "/afl-qemu-trace"; - - if (!access(ncp, X_OK)) { - - ncp = BIN_PATH "/afl-wine-trace"; - - if (!access(ncp, X_OK)) { - - *target_path_p = new_argv[0] = ck_strdup(ncp); + *target_path_p = new_argv[0] = cp; return new_argv; } @@ -302,25 +258,21 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { } SAYF("\n" cLRD "[-] " cRST - "Oops, unable to find the '%s' binary. The binary must be " - "built\n" - " separately by following the instructions in " - "qemu_mode/README.md. " - "If you\n" - " already have the binary installed, you may need to specify " - "AFL_PATH in the\n" - " environment.\n\n" - + "Oops, unable to find the afl-qemu-trace and afl-wine-trace binaries.\n" + "The afl-qemu-trace binary must be built separately by following the " + "instructions\n" + "in qemu_mode/README.md. If you already have the binary installed, you " + "may need\n" + "to specify the location via AFL_PATH in the environment.\n\n" " Of course, even without QEMU, afl-fuzz can still work with " "binaries that are\n" " instrumented at compile time with afl-gcc. It is also possible to " "use it as a\n" " traditional non-instrumented fuzzer by specifying '-n' in the " "command " - "line.\n", - ncp); + "line.\n"); - FATAL("Failed to locate '%s'.", ncp); + FATAL("Failed to locate 'afl-qemu-trace' and 'afl-wine-trace'."); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index b4f92e5b..eeb2f8c3 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -481,7 +481,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 0); -fprintf(stderr, "init %p\n", fsrv->init_child_func); fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -497,19 +496,19 @@ fprintf(stderr, "init %p\n", fsrv->init_child_func); char pid_buf[16]; sprintf(pid_buf, "%d", fsrv->fsrv_pid); - + if (fsrv->qemu_mode == 2) { setenv("__AFL_TARGET_PID3", pid_buf, 1); } else if (fsrv->cmplog_binary) { - + setenv("__AFL_TARGET_PID2", pid_buf, 1); - + } else { - + setenv("__AFL_TARGET_PID1", pid_buf, 1); - + } /* Close the unneeded endpoints. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 207b3046..badc2239 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -472,16 +472,20 @@ abort_calibration: afl->stage_max = old_sm; /* if taint mode was selected, run the taint */ - + if (afl->fsrv.taint_mode) { + write_to_testcase(afl, use_mem, q->len); - if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == 0) { + if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == + 0) { + u32 len = q->len / 8; if (q->len % 8) len++; u32 bits = count_bits_len(afl, afl->taint_fsrv.trace_bits, len); if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bits); } + } if (!first_run) { show_stats(afl); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bc780b55..684b123e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -92,7 +92,8 @@ static void usage(u8 *argv0, int more_help) { " -o dir - output directory for fuzzer findings\n\n" "Execution control settings:\n" - " -A - use first level taint analysis (see qemu_taint/README.md)\n" + " -A - use first level taint analysis (see " + "qemu_taint/README.md)\n" " -p schedule - power schedules compute a seed's performance score. " "fsrv.taint_mode) { ACTF("Spawning qemu_taint forkserver"); @@ -1256,11 +1257,21 @@ int main(int argc, char **argv_orig, char **envp) { afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits; ck_free(afl->taint_fsrv.target_path); afl->taint_fsrv.target_path = ck_strdup(afl->fsrv.target_path); - afl->argv_taint = get_qemu_argv(argv[0], &afl->taint_fsrv.target_path, - argc - optind, argv + optind); - u32 len = strlen(afl->taint_fsrv.target_path); - strcpy(afl->taint_fsrv.target_path + len - 5, "taint"); - strcpy((afl->argv_taint[0]) + len - 5, "taint"); + afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind)); + afl->argv_taint[0] = find_binary_own_loc("afl-qemu-taint", argv[0]); + if (!afl->argv_taint[0]) + FATAL( + "Cannot find 'afl-qemu-taint', read qemu_taint/README.md on how to " + "build it."); + u32 idx = optind - 1, offset = 0; + do { + + idx++; + offset++; + afl->argv_taint[offset] = argv[idx]; + + } while (argv[idx] != NULL); + if (afl->fsrv.use_stdin) unsetenv("AFL_TAINT_INPUT"); else -- cgit 1.4.1 From a1129b67c22ff54e25d457efbe44b3ab11851b5b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 12:15:36 +0200 Subject: changes --- include/afl-fuzz.h | 1 + src/afl-fuzz-bitmap.c | 23 +++++++++++++++++++++++ src/afl-fuzz-run.c | 9 +++++---- src/afl-fuzz.c | 6 ++---- 4 files changed, 31 insertions(+), 8 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 37e2dc6c..5e4e5a19 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -896,6 +896,7 @@ void write_bitmap(afl_state_t *); u32 count_bits(afl_state_t *, u8 *); u32 count_bits_len(afl_state_t *, u8 *, u32); u32 count_bytes(afl_state_t *, u8 *); +u32 count_bytes_len(afl_state_t *, u8 *, u32); u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 void simplify_trace(afl_state_t *, u64 *); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 9cb1b83f..8aaa4ae1 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -235,6 +235,29 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) { } +u32 count_bytes_len(afl_state_t *afl, u8 *mem, u32 len) { + + u32 *ptr = (u32 *)mem; + u32 i = (len >> 2); + u32 ret = 0; + + while (i--) { + + u32 v = *(ptr++); + + if (!v) { continue; } + if (v & 0x000000ff) { ++ret; } + if (v & 0x0000ff00) { ++ret; } + if (v & 0x00ff0000) { ++ret; } + if (v & 0xff000000) { ++ret; } + + } + + return ret; + +} + + /* Count the number of non-255 bytes set in the bitmap. Used strictly for the status screen, several calls per second or so. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index badc2239..b325f788 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -479,10 +479,11 @@ abort_calibration: if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == 0) { - u32 len = q->len / 8; - if (q->len % 8) len++; - u32 bits = count_bits_len(afl, afl->taint_fsrv.trace_bits, len); - if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bits); + u32 len = q->len; + if (len % 4) + len = len + 4 - (q->len % 4); + u32 bytes = count_bytes_len(afl, afl->taint_fsrv.trace_bits, len); + if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bytes); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 684b123e..4a3d2e97 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -825,11 +825,9 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->fsrv.taint_mode && afl->fsrv.map_size < (MAX_FILE / 8) + 1) { + if (afl->fsrv.taint_mode && afl->fsrv.map_size < MAX_FILE) { - afl->shm.map_size = (MAX_FILE / 8); - if (MAX_FILE % 8) afl->shm.map_size++; - afl->fsrv.map_size = afl->shm.map_size; + afl->fsrv.map_size = afl->shm.map_size = MAX_FILE; } -- cgit 1.4.1 From 32db31b5550b73cbb20abb5e862fb08f86681ace Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 12:35:52 +0200 Subject: fixes --- include/afl-fuzz.h | 3 ++- src/afl-fuzz-bitmap.c | 1 - src/afl-fuzz-run.c | 6 +++--- src/afl-fuzz-state.c | 30 +++++++++++++++++++----------- src/afl-fuzz.c | 6 ++++-- 5 files changed, 28 insertions(+), 18 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5e4e5a19..328c8405 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -838,7 +838,8 @@ struct custom_mutator { }; -void afl_state_init(afl_state_t *, uint32_t map_size); +void afl_state_init_1(afl_state_t *, uint32_t map_size); +void afl_state_init_2(afl_state_t *, uint32_t map_size); void afl_state_deinit(afl_state_t *); /* Set stop_soon flag on all childs, kill all childs */ diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 8aaa4ae1..11a3f121 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -257,7 +257,6 @@ u32 count_bytes_len(afl_state_t *afl, u8 *mem, u32 len) { } - /* Count the number of non-255 bytes set in the bitmap. Used strictly for the status screen, several calls per second or so. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index b325f788..89ae0424 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -480,10 +480,10 @@ abort_calibration: 0) { u32 len = q->len; - if (len % 4) - len = len + 4 - (q->len % 4); + if (len % 4) len = len + 4 - (q->len % 4); u32 bytes = count_bytes_len(afl, afl->taint_fsrv.trace_bits, len); - if (afl->debug) fprintf(stderr, "Debug: tainted bytes: %u\n", bytes); + if (afl->debug) + fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, q->len); } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index e2d62bc6..aab785e1 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -75,7 +75,7 @@ static list_t afl_states = {.element_prealloc_count = 0}; /* Initializes an afl_state_t. */ -void afl_state_init(afl_state_t *afl, uint32_t map_size) { +void afl_state_init_1(afl_state_t *afl, uint32_t map_size) { /* thanks to this memset, growing vars like out_buf and out_size are NULL/0 by default. */ @@ -100,16 +100,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->cpu_aff = -1; /* Selected CPU core */ #endif /* HAVE_AFFINITY */ - afl->virgin_bits = ck_alloc(map_size); - afl->virgin_tmout = ck_alloc(map_size); - afl->virgin_crash = ck_alloc(map_size); - afl->var_bytes = ck_alloc(map_size); - afl->top_rated = ck_alloc(map_size * sizeof(void *)); - afl->clean_trace = ck_alloc(map_size); - afl->clean_trace_custom = ck_alloc(map_size); - afl->first_trace = ck_alloc(map_size); - afl->map_tmp_buf = ck_alloc(map_size); - afl->fsrv.use_stdin = 1; afl->fsrv.map_size = map_size; afl->fsrv.function_opt = (u8 *)afl; @@ -160,6 +150,24 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { } +void afl_state_init_2(afl_state_t *afl, uint32_t map_size) { + + afl->shm.map_size = map_size ? map_size : MAP_SIZE; + + afl->virgin_bits = ck_alloc(map_size); + afl->virgin_tmout = ck_alloc(map_size); + afl->virgin_crash = ck_alloc(map_size); + afl->var_bytes = ck_alloc(map_size); + afl->top_rated = ck_alloc(map_size * sizeof(void *)); + afl->clean_trace = ck_alloc(map_size); + afl->clean_trace_custom = ck_alloc(map_size); + afl->first_trace = ck_alloc(map_size); + afl->map_tmp_buf = ck_alloc(map_size); + + afl->fsrv.map_size = map_size; + +} + /*This sets up the environment variables for afl-fuzz into the afl_state * struct*/ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 4a3d2e97..93ab90e2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -262,7 +262,7 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; } map_size = get_map_size(); - afl_state_init(afl, map_size); + afl_state_init_1(afl, map_size); afl->debug = debug; afl_fsrv_init(&afl->fsrv); @@ -827,10 +827,12 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.taint_mode && afl->fsrv.map_size < MAX_FILE) { - afl->fsrv.map_size = afl->shm.map_size = MAX_FILE; + map_size = afl->fsrv.map_size = afl->shm.map_size = MAX_FILE; } + afl_state_init_2(afl, map_size); + if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" " -- cgit 1.4.1 From b60663c0318b8baf21b36b549d765ddd2eeeb54e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 18:48:12 +0200 Subject: taint integration done --- include/afl-fuzz.h | 15 +++-- llvm_mode/afl-llvm-rt.o.c | 10 +++ src/afl-common.c | 2 +- src/afl-forkserver.c | 3 +- src/afl-fuzz-bitmap.c | 2 +- src/afl-fuzz-init.c | 28 ++++++++- src/afl-fuzz-queue.c | 151 ++++++++++++++++++++++++++++++++++++++++++++-- src/afl-fuzz-run.c | 83 ++++++++++++------------- src/afl-fuzz.c | 25 ++++++-- 9 files changed, 255 insertions(+), 64 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 328c8405..19807880 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -133,8 +133,10 @@ extern s32 struct queue_entry { - u8 *fname; /* File name for the test case */ - u32 len; /* Input length */ + u8 * fname; /* File name for the test case */ + u8 * fname_taint; /* File name for taint data */ + u32 len; /* Input length */ + struct queue_entry *prev; /* previous queue entry, if any */ u8 cal_failed, /* Calibration failed? */ trim_done, /* Trimmed? */ @@ -148,7 +150,10 @@ struct queue_entry { is_ascii; /* Is the input just ascii text? */ u32 bitmap_size, /* Number of bits set in bitmap */ - fuzz_level; /* Number of fuzzing iterations */ + fuzz_level, /* Number of fuzzing iterations */ + taint_bytes_all, /* Number of tainted bytes */ + taint_bytes_new, /* Number of new tainted bytes */ + taint_bytes_highest; /* highest offset in input */ u64 exec_us, /* Execution time (us) */ handicap, /* Number of queue cycles behind */ @@ -885,7 +890,7 @@ void deinit_py(void *); void mark_as_det_done(afl_state_t *, struct queue_entry *); void mark_as_variable(afl_state_t *, struct queue_entry *); void mark_as_redundant(afl_state_t *, struct queue_entry *, u8); -void add_to_queue(afl_state_t *, u8 *, u32, u8); +void add_to_queue(afl_state_t *, u8 *, u8 *, u32, struct queue_entry *, u8); void destroy_queue(afl_state_t *); void update_bitmap_score(afl_state_t *, struct queue_entry *); void cull_queue(afl_state_t *); @@ -975,6 +980,8 @@ 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); +void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, + u8 *mem, u32 len); /* CmpLog */ diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 8cc59cbb..5ffae39c 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -831,6 +831,16 @@ void __afl_manual_init(void) { static u8 init_done; + if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) { + + init_done = 1; + if (getenv("AFL_DEBUG")) + fprintf(stderr, + "DEBUG: disabled instrumenation because of " + "AFL_DISABLE_LLVM_INSTRUMENTATION\n"); + + } + if (!init_done) { __afl_map_shm(); diff --git a/src/afl-common.c b/src/afl-common.c index c0202821..e01bde3c 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -232,7 +232,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { char **new_argv = ck_alloc(sizeof(char *) * (argc + 3)); - u8 * tmp, *cp = NULL, *rsl, *own_copy; + u8 * cp = NULL; memcpy(&new_argv[2], &argv[1], (int)(sizeof(char *)) * (argc - 1)); new_argv[argc - 1] = NULL; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index eeb2f8c3..4dc5e438 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -933,7 +933,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } else { - s32 fd = fsrv->out_fd; + s32 fd; if (fsrv->out_file) { @@ -952,6 +952,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } else { + fd = fsrv->out_fd; lseek(fd, 0, SEEK_SET); } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 11a3f121..d4ee36e1 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -648,7 +648,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #endif /* ^!SIMPLE_FILES */ - add_to_queue(afl, queue_fn, len, 0); + add_to_queue(afl, queue_fn, mem, len, afl->queue_top, 0); if (hnb == 2) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 350a8599..350a3b4c 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -712,7 +712,7 @@ void read_testcases(afl_state_t *afl) { if (!access(dfn, F_OK)) { passed_det = 1; } - add_to_queue(afl, fn2, st.st_size, passed_det); + add_to_queue(afl, fn2, NULL, st.st_size, NULL, passed_det); } @@ -960,6 +960,9 @@ void perform_dry_run(afl_state_t *afl) { } + /* perform taint gathering on the input seed */ + perform_taint_run(afl, q, q->fname, use_mem, q->len); + q = q->next; } @@ -1438,6 +1441,10 @@ static void handle_existing_out_dir(afl_state_t *afl) { u8 *orig_q = alloc_printf("%s/queue", afl->out_dir); + u8 *fnt = alloc_printf("%s/taint", afl->out_dir); + mkdir(fnt, 0755); // ignore errors + ck_free(fnt); + afl->in_dir = alloc_printf("%s/_resume", afl->out_dir); rename(orig_q, afl->in_dir); /* Ignore errors */ @@ -1494,6 +1501,15 @@ static void handle_existing_out_dir(afl_state_t *afl) { if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } ck_free(fn); + if (afl->fsrv.taint_mode) { + + fn = alloc_printf("%s/taint", afl->out_dir); + mkdir(fn, 0755); // ignore errors + if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + ck_free(fn); + + } + /* All right, let's do out_dir>/crashes/id:* and * out_dir>/hangs/id:*. */ @@ -1721,6 +1737,16 @@ void setup_dirs_fds(afl_state_t *afl) { if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); + /* Taint directory if taint_mode. */ + + if (afl->fsrv.taint_mode) { + + tmp = alloc_printf("%s/taint", afl->out_dir); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } + ck_free(tmp); + + } + /* Top-level directory for queue metadata used for session resume and related tasks. */ diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f35df914..36ec0896 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -103,6 +103,139 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { } +void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, + u8 *mem, u32 len) { + + u8 * ptr, *fn = fname; + u32 bytes = 0, plen = len; + s32 fd = -1; + struct queue_entry *prev = q->prev; + + if (plen % 4) plen = plen + 4 - (len % 4); + + if ((ptr = strrchr(fname, '/')) != NULL) fn = ptr + 1; + q->fname_taint = alloc_printf("%s/taint/%s", afl->out_dir, fn); + + if (q->fname_taint) { + + afl->taint_fsrv.map_size = plen; // speed :) + write_to_testcase(afl, mem, len); + if (afl_fsrv_run_target(&afl->taint_fsrv, afl->fsrv.exec_tmout, + &afl->stop_soon) == 0) { + + bytes = count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen); + if (afl->debug) + fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, len); + + if (bytes) { + + s32 i = len; + while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1]) + i--; + q->taint_bytes_highest = i; + + } + + } + + if (((bytes * 100) / len) < 90) { + + // we only use the taint havoc mode if the entry has less than 90% of + // overall tainted bytes + q->taint_bytes_all = bytes; + + // save the bytes away + int w = open(q->fname_taint, O_CREAT | O_WRONLY, 0644); + if (w >= 0) { + + ck_write(w, afl->taint_fsrv.trace_bits, plen, q->fname_taint); + close(w); + + } else { + + FATAL("could not create %s", q->fname_taint); + bytes = 0; + + } + + if (bytes && prev && prev->taint_bytes_all) { + + // check if there are new bytes in the taint vs the previous + int r = open(prev->fname_taint, O_RDONLY); + + if (r >= 0) { + + u8 *bufr = mmap(0, prev->len, PROT_READ, MAP_PRIVATE, r, 0); + + if ((size_t)bufr != -1) { + + u32 i; + u8 *tmp = ck_maybe_grow(BUF_PARAMS(in_scratch), plen); + memset(tmp, 0, plen); + + for (i = 0; i < len; i++) + if (afl->taint_fsrv.trace_bits[i] && (i >= prev->len || !bufr[i])) + tmp[i] = 1; + + q->taint_bytes_new = count_bytes_len(afl, tmp, plen); + + if (q->taint_bytes_new) { + + u8 *fnw = alloc_printf("%s.new", q->fname_taint); + int w = open(fnw, O_CREAT | O_WRONLY, 0644); + if (w >= 0) { + + ck_write(w, tmp, plen, fnw); + close(w); + + } else { + + q->taint_bytes_new = 0; + + } + + ck_free(fnw); + + } + + munmap(bufr, prev->len); + + } + + close(r); + + } + + } + + } else { + + bytes = 0; + + } + + } + + if (!bytes) { + + q->taint_bytes_highest = q->taint_bytes_all = q->taint_bytes_new = 0; + + if (q->fname_taint) { + + ck_free(q->fname_taint); + q->fname_taint = NULL; + + } + + } else { + + if (q->taint_bytes_all && !q->taint_bytes_new) + q->taint_bytes_new = q->taint_bytes_all; + + } + +} + /* check if ascii or UTF-8 */ static u8 check_if_text(struct queue_entry *q) { @@ -212,10 +345,12 @@ static u8 check_if_text(struct queue_entry *q) { /* Append new test case to the queue. */ -void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { +void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len, + struct queue_entry *prev_q, u8 passed_det) { struct queue_entry *q = ck_alloc(sizeof(struct queue_entry)); + q->prev = prev_q; q->fname = fname; q->len = len; q->depth = afl->cur_depth + 1; @@ -254,6 +389,17 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { afl->last_path_time = get_cur_time(); + /* trigger the tain gathering if this is not a dry run */ + if (afl->fsrv.taint_mode && mem) { + + perform_taint_run(afl, q, fname, mem, len); + + } + + /* only redqueen currently uses is_ascii */ + if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q); + + /* run custom mutators afl_custom_queue_new_entry() */ if (afl->custom_mutators_count) { LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { @@ -273,9 +419,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } - /* only redqueen currently uses is_ascii */ - if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q); - } /* Destroy the entire queue. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 89ae0424..ddbd5524 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -471,24 +471,6 @@ abort_calibration: afl->stage_cur = old_sc; afl->stage_max = old_sm; - /* if taint mode was selected, run the taint */ - - if (afl->fsrv.taint_mode) { - - write_to_testcase(afl, use_mem, q->len); - if (afl_fsrv_run_target(&afl->taint_fsrv, use_tmout, &afl->stop_soon) == - 0) { - - u32 len = q->len; - if (len % 4) len = len + 4 - (q->len % 4); - u32 bytes = count_bytes_len(afl, afl->taint_fsrv.trace_bits, len); - if (afl->debug) - fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, q->len); - - } - - } - if (!first_run) { show_stats(afl); } return fault; @@ -770,56 +752,65 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { while (remove_pos < q->len) { u32 trim_avail = MIN(remove_len, q->len - remove_pos); - u64 cksum; - write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); + if (likely((!q->taint_bytes_highest) || + (q->len - trim_avail > q->taint_bytes_highest))) { - fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); - ++afl->trim_execs; + u64 cksum; - if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } + write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); - /* Note that we don't keep track of crashes or hangs here; maybe TODO? - */ + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + ++afl->trim_execs; - cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } - /* If the deletion had no impact on the trace, make it permanent. This - isn't perfect for variable-path inputs, but we're just making a - best-effort pass, so it's not a big deal if we end up with false - negatives every now and then. */ + /* Note that we don't keep track of crashes or hangs here; maybe TODO? + */ - if (cksum == q->exec_cksum) { + cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - u32 move_tail = q->len - remove_pos - trim_avail; + /* If the deletion had no impact on the trace, make it permanent. This + isn't perfect for variable-path inputs, but we're just making a + best-effort pass, so it's not a big deal if we end up with false + negatives every now and then. */ - q->len -= trim_avail; - len_p2 = next_pow2(q->len); + if (cksum == q->exec_cksum) { - memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, - move_tail); + u32 move_tail = q->len - remove_pos - trim_avail; - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ + q->len -= trim_avail; + len_p2 = next_pow2(q->len); - if (!needs_write) { + memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, + move_tail); - needs_write = 1; - memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); + /* Let's save a clean trace, which will be needed by + update_bitmap_score once we're done with the trimming stuff. */ + + if (!needs_write) { + + needs_write = 1; + memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); + + } + + } else { + + remove_pos += remove_len; } + /* Since this can be slow, update the screen every now and then. */ + if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } + ++afl->stage_cur; + } else { remove_pos += remove_len; } - /* Since this can be slow, update the screen every now and then. */ - - if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } - ++afl->stage_cur; - } remove_len >>= 1; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 93ab90e2..6f143db7 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -244,9 +244,10 @@ static int stricmp(char const *a, char const *b) { int main(int argc, char **argv_orig, char **envp) { - s32 opt; - u64 prev_queued = 0; - u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE; + s32 opt; + u64 prev_queued = 0; + u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE, + real_map_size = 0; u8 * extras_dir = 0; u8 mem_limit_given = 0, exit_1 = 0, debug = 0; char **use_argv; @@ -827,6 +828,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.taint_mode && afl->fsrv.map_size < MAX_FILE) { + real_map_size = map_size; map_size = afl->fsrv.map_size = afl->shm.map_size = MAX_FILE; } @@ -840,8 +842,7 @@ int main(int argc, char **argv_orig, char **envp) { OKF("afl++ is open source, get it at " "https://github.com/AFLplusplus/AFLplusplus"); OKF("Power schedules from github.com/mboehme/aflfast"); - OKF("Python Mutator and llvm_mode instrument file list from " - "github.com/choller/afl"); + OKF("Python Mutator from github.com/choller/afl"); OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->is_main_node && @@ -1088,6 +1089,13 @@ int main(int argc, char **argv_orig, char **envp) { memset(afl->virgin_tmout, 255, afl->fsrv.map_size); memset(afl->virgin_crash, 255, afl->fsrv.map_size); + if (map_size != real_map_size) { + + afl->fsrv.map_size = real_map_size; + if (afl->cmplog_binary) afl->cmplog_fsrv.map_size; + + } + init_count_class16(); if (afl->is_main_node && check_main_node_exists(afl) == 1) { @@ -1252,12 +1260,16 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.taint_mode) { ACTF("Spawning qemu_taint forkserver"); + u8 *disable = getenv("AFL_DISABLE_LLVM_INSTRUMENTATION"); + setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv); afl->taint_fsrv.qemu_mode = 2; + afl->taint_fsrv.taint_mode = 1; afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits; ck_free(afl->taint_fsrv.target_path); - afl->taint_fsrv.target_path = ck_strdup(afl->fsrv.target_path); afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind)); + afl->taint_fsrv.target_path = + find_binary_own_loc("afl-qemu-taint", argv[0]); afl->argv_taint[0] = find_binary_own_loc("afl-qemu-taint", argv[0]); if (!afl->argv_taint[0]) FATAL( @@ -1278,6 +1290,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1); afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + if (!disable) unsetenv("AFL_DISABLE_LLVM_INSTRUMENTATION"); OKF("Taint forkserver successfully started"); } -- cgit 1.4.1 From e99d7e973001adea65c68113b08792144d6aa5c8 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Aug 2020 20:24:56 +0200 Subject: integration in fuzz_one --- include/afl-fuzz.h | 10 +++-- src/afl-fuzz-one.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++------- src/afl-fuzz-run.c | 25 ++++++++++++ src/afl-fuzz.c | 12 ++++++ 4 files changed, 142 insertions(+), 16 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 19807880..88392867 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -430,7 +430,9 @@ typedef struct afl_state { *in_bitmap, /* Input bitmap */ *file_extension, /* File extension */ *orig_cmdline, /* Original command line */ - *infoexec; /* Command to execute on a new crash */ + *infoexec, /* Command to execute on a new crash */ + *taint_input_file, /* fuzz_input_one input file */ + *taint_src, *taint_map; u32 hang_tmout; /* Timeout used for hang det (ms) */ @@ -441,7 +443,8 @@ typedef struct afl_state { custom_only, /* Custom mutator only mode */ python_only, /* Python-only mode */ is_main_node, /* if this is the main node */ - is_secondary_node; /* if this is a secondary instance */ + is_secondary_node, /* if this is a secondary instance */ + taint_needs_splode; /* explode fuzz input */ u32 stats_update_freq; /* Stats update frequency (execs) */ @@ -502,7 +505,8 @@ typedef struct afl_state { useless_at_start, /* Number of useless starting paths */ var_byte_count, /* Bitmap bytes with var behavior */ current_entry, /* Current queue entry ID */ - havoc_div; /* Cycle count divisor for havoc */ + havoc_div, /* Cycle count divisor for havoc */ + taint_len; u64 total_crashes, /* Total number of crashes */ unique_crashes, /* Crashes with unique signatures */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 74e09ee3..ec7c4772 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -458,27 +458,102 @@ u8 fuzz_one_original(afl_state_t *afl) { } - /* Map the test case into memory. */ + if (unlikely(afl->fsrv.taint_mode && (afl->queue_cycle % 3))) { - fd = open(afl->queue_cur->fname, O_RDONLY); + if (unlikely(afl->queue_cur->cal_failed)) goto abandon_entry; - if (unlikely(fd < 0)) { + u32 dst = 0, i; - PFATAL("Unable to open '%s'", afl->queue_cur->fname); + fd = open(afl->queue_cur->fname, O_RDONLY); + afl->taint_src = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (fd < 0 || (size_t)afl->taint_src == -1) + FATAL("unable to open '%s'", afl->queue_cur->fname); + close(fd); - } + switch (afl->queue_cycle % 3) { - len = afl->queue_cur->len; + case 0: // do nothing, but cannot happen -> else + break; - orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + case 1: // fuzz only tainted bytes + if (!afl->queue_cur->taint_bytes_all) goto abandon_entry; + afl->taint_needs_splode = 1; - if (unlikely(orig_in == MAP_FAILED)) { + fd = open(afl->taint_input_file, O_RDONLY); + len = afl->taint_len = afl->queue_cur->taint_bytes_all; + orig_in = in_buf = + mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (fd < 0 || (size_t)in_buf == -1) + FATAL("unable to open '%s'", afl->taint_input_file); + close(fd); - PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); + fd = open(afl->queue_cur->fname_taint, O_RDWR); + afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (fd < 0 || (size_t)in_buf == -1) + FATAL("unable to open '%s'", afl->queue_cur->fname_taint); + close(fd); - } + for (i = 0; i < afl->queue_cur->len && dst < len; i++) + if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i]; - close(fd); + break; + + case 2: // fuzz only newly tainted bytes + if (!afl->queue_cur->taint_bytes_new) goto abandon_entry; + afl->taint_needs_splode = 1; + + fd = open(afl->taint_input_file, O_RDONLY); + len = afl->taint_len = afl->queue_cur->taint_bytes_new; + orig_in = in_buf = + mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (fd < 0 || (size_t)in_buf == -1) + FATAL("unable to open '%s'", afl->taint_input_file); + close(fd); + + u8 *fn = alloc_printf("%s.new", afl->queue_cur->fname_taint); + fd = open(fn, O_RDWR); + afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (fd < 0 || (size_t)in_buf == -1) FATAL("unable to open '%s'", fn); + close(fd); + ck_free(fn); + + for (i = 0; i < afl->queue_cur->len && dst < len; i++) + if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i]; + + break; + + } + + goto havoc_stage; // we let the normal cycles do deterministic mode - if + + } else { + + /* Map the test case into memory. */ + afl->taint_needs_splode = 0; + + fd = open(afl->queue_cur->fname, O_RDONLY); + + if (unlikely(fd < 0)) { + + PFATAL("Unable to open '%s'", afl->queue_cur->fname); + + } + + len = afl->queue_cur->len; + + orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (unlikely(orig_in == MAP_FAILED)) { + + PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); + + } + + close(fd); + + } /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every single byte anyway, so it wouldn't give us any performance or memory usage @@ -527,7 +602,7 @@ u8 fuzz_one_original(afl_state_t *afl) { ************/ if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done && - !afl->disable_trim) { + !afl->disable_trim && !afl->taint_needs_splode) { u8 res = trim_case(afl, afl->queue_cur, in_buf); @@ -2568,7 +2643,17 @@ abandon_entry: ++afl->queue_cur->fuzz_level; - munmap(orig_in, afl->queue_cur->len); + if (afl->taint_needs_splode) { + + munmap(afl->taint_src, afl->queue_cur->len); + munmap(orig_in, afl->taint_len); + munmap(afl->taint_map, afl->queue_cur->len); + + } else { + + munmap(orig_in, afl->queue_cur->len); + + } return ret_val; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ddbd5524..31db4d7c 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -863,6 +863,8 @@ abort_trimming: } +#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size + /* Write a modified test case, run program, process results. Handle error conditions, returning 1 if it's time to bail out. This is a helper function for fuzz_one(). */ @@ -871,6 +873,27 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { u8 fault; + if (unlikely(afl->taint_needs_splode)) { + + s32 new_len = afl->queue_cur->len + len - afl->taint_len; + if (new_len < 4) new_len = 4; + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + + u32 i, taint = 0; + for (i = 0; i < new_len; i++) { + + if (afl->taint_map[i] || i > afl->queue_cur->len) + new_buf[i] = out_buf[taint++]; + else + new_buf[i] = afl->taint_src[i]; + + } + + out_buf = new_buf; + len = new_len; + + } + write_to_testcase(afl, out_buf, len); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); @@ -918,3 +941,5 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { } +#undef BUF_PARAMS + diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 6f143db7..70a99dec 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1260,12 +1260,15 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.taint_mode) { ACTF("Spawning qemu_taint forkserver"); + u8 *disable = getenv("AFL_DISABLE_LLVM_INSTRUMENTATION"); setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); + afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv); afl->taint_fsrv.qemu_mode = 2; afl->taint_fsrv.taint_mode = 1; afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits; + ck_free(afl->taint_fsrv.target_path); afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind)); afl->taint_fsrv.target_path = @@ -1290,7 +1293,16 @@ int main(int argc, char **argv_orig, char **envp) { setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1); afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + + afl->taint_input_file = alloc_printf("%s/taint/.input", afl->out_dir); + int fd = open(afl->taint_input_file, O_CREAT | O_TRUNC | O_RDWR, 0644); + if (fd < 0) + FATAL("Cannot create taint inpu file '%s'", afl->taint_input_file); + lseek(fd, MAX_FILE, SEEK_SET); + ck_write(fd, "\0", 1, afl->taint_input_file); + if (!disable) unsetenv("AFL_DISABLE_LLVM_INSTRUMENTATION"); + OKF("Taint forkserver successfully started"); } -- cgit 1.4.1 From 4f695b6f4c3ced165703363904e42492fca82112 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 11 Aug 2020 11:16:48 +0200 Subject: fixes --- include/afl-fuzz.h | 2 +- src/afl-common.c | 4 +-- src/afl-fuzz-bitmap.c | 2 ++ src/afl-fuzz-queue.c | 78 +++++++++++++++++++++++++++++++++++---------------- src/afl-fuzz-stats.c | 5 ++-- 5 files changed, 62 insertions(+), 29 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 02c36861..c578c583 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -506,7 +506,7 @@ typedef struct afl_state { var_byte_count, /* Bitmap bytes with var behavior */ current_entry, /* Current queue entry ID */ havoc_div, /* Cycle count divisor for havoc */ - taint_len; + taint_len, taint_count; u64 total_crashes, /* Total number of crashes */ unique_crashes, /* Crashes with unique signatures */ diff --git a/src/afl-common.c b/src/afl-common.c index c1302080..cefed8dc 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -471,8 +471,8 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { u64 get_cur_time(void) { - static struct timeval tv; - static struct timezone tz; + struct timeval tv; + struct timezone tz; gettimeofday(&tv, &tz); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 9f58d604..d273818d 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -245,6 +245,8 @@ u32 count_bytes_len(afl_state_t *afl, u8 *mem, u32 len) { (void)(afl); + if (len % 4) i++; + while (i--) { u32 v = *(ptr++); diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f4b58a9d..b56e10f8 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -125,42 +125,64 @@ void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, if (afl_fsrv_run_target(&afl->taint_fsrv, afl->fsrv.exec_tmout, &afl->stop_soon) == 0) { - bytes = count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen); + bytes = q->taint_bytes_all = + count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen); if (afl->debug) fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, len); - if (bytes) { + /* DEBUG FIXME TODO XXX */ + u32 i; + for (i = 0; i < len; i++) { - s32 i = len; - while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1]) - i--; - q->taint_bytes_highest = i; + if (afl->taint_fsrv.trace_bits[i] && + afl->taint_fsrv.trace_bits[i] != '!') + FATAL("invalid taint map value %02x at pos %d", + afl->taint_fsrv.trace_bits[i], i); } - } + if (len < plen) + for (i = len; i < plen; i++) { - if (((bytes * 100) / len) < 90) { + if (afl->taint_fsrv.trace_bits[i]) + FATAL("invalid taint map value %02x in padding at pos %d", + afl->taint_fsrv.trace_bits[i], i); - // we only use the taint havoc mode if the entry has less than 90% of - // overall tainted bytes - q->taint_bytes_all = bytes; + } + + } + + // if all is tainted we do not need to write taint data away + if (bytes && bytes < len) { // save the bytes away int w = open(q->fname_taint, O_CREAT | O_WRONLY, 0644); if (w >= 0) { - ck_write(w, afl->taint_fsrv.trace_bits, plen, q->fname_taint); + ck_write(w, afl->taint_fsrv.trace_bits, len, q->fname_taint); close(w); + // find the highest tainted offset in the input (for trim opt) + s32 i = len; + while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1]) + i--; + q->taint_bytes_highest = i; + + afl->taint_count++; + } else { FATAL("could not create %s", q->fname_taint); - bytes = 0; + q->taint_bytes_all = bytes = 0; } - if (bytes && prev && prev->taint_bytes_all) { + // it is possible that there is no main taint file - if the whole file + // is tainted - but a .new taint file if it had new tainted bytes + + // check if there is a previous queue entry and if it had taint + if (bytes && prev && prev->taint_bytes_all && + prev->taint_bytes_all < prev->len) { // check if there are new bytes in the taint vs the previous int r = open(prev->fname_taint, O_RDONLY); @@ -181,14 +203,28 @@ void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, q->taint_bytes_new = count_bytes_len(afl, tmp, plen); + if (afl->debug) + fprintf(stderr, "Debug: %u new taint out of %u bytes\n", bytes, + len); + if (q->taint_bytes_new) { u8 *fnw = alloc_printf("%s.new", q->fname_taint); - int w = open(fnw, O_CREAT | O_WRONLY, 0644); - if (w >= 0) { + if (fnw) { + + int w = open(fnw, O_CREAT | O_WRONLY, 0644); + if (w >= 0) { + + ck_write(w, tmp, plen, fnw); + close(w); - ck_write(w, tmp, plen, fnw); - close(w); + } else { + + q->taint_bytes_new = 0; + + } + + ck_free(fnw); } else { @@ -196,8 +232,6 @@ void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, } - ck_free(fnw); - } munmap(bufr, prev->len); @@ -210,10 +244,6 @@ void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, } - } else { - - bytes = 0; - } memcpy(afl->taint_fsrv.trace_bits, save, afl->fsrv.map_size); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index aeb290bd..0cc06e12 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -116,6 +116,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, "edges_found : %u\n" "var_byte_count : %u\n" "havoc_expansion : %u\n" + "tainted_inputs : %u\n" "afl_banner : %s\n" "afl_version : " VERSION "\n" @@ -149,8 +150,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #else -1, #endif - t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner, - afl->unicorn_mode ? "unicorn" : "", + t_bytes, afl->var_byte_count, afl->expand_havoc, afl->taint_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 " : "", -- cgit 1.4.1 From 220dc4a43d197f5ff451627a9923b874805c02aa Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 11 Aug 2020 16:25:35 +0200 Subject: review done, pray --- include/afl-fuzz.h | 3 +- src/afl-fuzz-init.c | 3 +- src/afl-fuzz-one.c | 152 ++++++++++++++++++++++++++++++++++++++++----------- src/afl-fuzz-queue.c | 6 +- src/afl-fuzz-run.c | 10 +++- src/afl-fuzz.c | 17 ++++-- 6 files changed, 144 insertions(+), 47 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c578c583..e251183c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -444,7 +444,8 @@ typedef struct afl_state { python_only, /* Python-only mode */ is_main_node, /* if this is the main node */ is_secondary_node, /* if this is a secondary instance */ - taint_needs_splode; /* explode fuzz input */ + taint_needs_splode, /* explode fuzz input */ + taint_mode; u32 stats_update_freq; /* Stats update frequency (execs) */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 669bd65a..0150e18a 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -961,8 +961,7 @@ void perform_dry_run(afl_state_t *afl) { } /* perform taint gathering on the input seed */ - if (afl->taint_mode) - perform_taint_run(afl, q, q->fname, use_mem, q->len); + if (afl->taint_mode) perform_taint_run(afl, q, q->fname, use_mem, q->len); q = q->next; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 69f885ca..7718256f 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -462,18 +462,23 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(afl->taint_mode)) { - tmp_val = afl->queue_cycle % 2; + tmp_val = afl->queue_cycle % 2; // starts with 1 ret_val = 0; - if (unlikely(afl->queue_cur->cal_failed)) goto abandon_entry; - if (unlikely(!afl->queue_cur->passed_det) && !tmp_val) goto abandon_entry; - if (tmp_val == 1 && !afl->queue_cur->taint_bytes_all) goto abandon_entry; - if (tmp_val == 0 && !afl->queue_cur->taint_bytes_new) goto abandon_entry; + if (unlikely(afl->queue_cur->cal_failed && !tmp_val)) goto abandon_entry; + if (unlikely(!afl->skip_deterministic && !afl->queue_cur->passed_det && + !tmp_val)) + goto abandon_entry; + if ((!afl->queue_cur->taint_bytes_new || + afl->queue_cur->taint_bytes_new == afl->queue_cur->len) && + !tmp_val) + goto abandon_entry; ret_val = 1; s32 dst = 0, i; temp_len = len = afl->queue_cur->len; + s32 j = 0; // tmp fd = open(afl->queue_cur->fname, O_RDONLY); afl->taint_src = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); @@ -486,15 +491,27 @@ u8 fuzz_one_original(afl_state_t *afl) { case 1: // fuzz only tainted bytes + // special case: all or nothing tainted. in this case we act like + // nothing is special. this is not the taint you are looking for ... + if (!afl->queue_cur->taint_bytes_all || + afl->queue_cur->taint_bytes_all == (u32)len) { + + orig_in = in_buf = afl->taint_src; + afl->taint_needs_splode = 0; + break; + + } + fd = open(afl->taint_input_file, O_RDONLY); temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_all; orig_in = in_buf = - mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (fd < 0 || (ssize_t)in_buf == -1) FATAL("unable to open '%s'", afl->taint_input_file); close(fd); - fd = open(afl->queue_cur->fname_taint, O_RDWR); + fd = open(afl->queue_cur->fname_taint, O_RDONLY); afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (fd < 0 || (ssize_t)in_buf == -1) @@ -504,6 +521,29 @@ u8 fuzz_one_original(afl_state_t *afl) { for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++) if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i]; + // FIXME DEBUG TODO XXX + for (i = 0; i < (s32)afl->queue_cur->len; i++) { + + switch (afl->taint_map[i]) { + + case 0x0: + break; + case '!': + j++; + break; + default: + FATAL( + "invalid taint map entry byte 0x%02x at position %d " + "(passed_det:%d)\n", + afl->taint_map[i], i, afl->queue_cur->passed_det); + + } + + } + + if (j != len) + FATAL("different taint values in map vs in queue (%d != %d)", j, len); + break; case 0: // fuzz only newly tainted bytes @@ -511,12 +551,14 @@ u8 fuzz_one_original(afl_state_t *afl) { fd = open(afl->taint_input_file, O_RDONLY); temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_new; orig_in = in_buf = - mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (fd < 0 || (ssize_t)in_buf == -1) FATAL("unable to open '%s'", afl->taint_input_file); close(fd); u8 *fn = alloc_printf("%s.new", afl->queue_cur->fname_taint); + if (!fn) FATAL("OOM"); fd = open(fn, O_RDWR); afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); @@ -528,14 +570,35 @@ u8 fuzz_one_original(afl_state_t *afl) { for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++) if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i]; + // FIXME DEBUG TODO XXX + for (i = 0; i < (s32)afl->queue_cur->len; i++) { + + switch (afl->taint_map[i]) { + + case 0x0: + break; + case '!': + j++; + break; + default: + FATAL( + "invalid taint map entry byte 0x%02x at position %d " + "(passed_det:%d)\n", + afl->taint_map[i], i, afl->queue_cur->passed_det); + + } + + } + + if (j != len) + FATAL("different taint values in map vs in queue (%d != %d)", j, len); + break; } } else { - afl->taint_needs_splode = 0; - /* Map the test case into memory. */ fd = open(afl->queue_cur->fname, O_RDONLY); @@ -574,8 +637,7 @@ u8 fuzz_one_original(afl_state_t *afl) { * CALIBRATION (only if failed earlier on) * *******************************************/ - if (unlikely(afl->queue_cur->cal_failed && - (!afl->taint_needs_splode || tmp_val == 1))) { + if (unlikely(afl->queue_cur->cal_failed)) { u8 res = FSRV_RUN_TMOUT; @@ -583,8 +645,12 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->queue_cur->exec_cksum = 0; - res = - calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0); + if (unlikely(afl->taint_needs_splode)) + res = calibrate_case(afl, afl->queue_cur, afl->taint_src, + afl->queue_cycle - 1, 0); + else + res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, + 0); if (unlikely(res == FSRV_RUN_ERROR)) { @@ -607,8 +673,8 @@ u8 fuzz_one_original(afl_state_t *afl) { * TRIMMING * ************/ - if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done && - !afl->disable_trim && !afl->taint_needs_splode) { + if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done && + !afl->disable_trim && !afl->taint_needs_splode)) { u8 res = trim_case(afl, afl->queue_cur, in_buf); @@ -645,13 +711,26 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) { - if (input_to_state_stage(afl, in_buf, out_buf, len, - afl->queue_cur->exec_cksum)) { + int res; + if (unlikely(afl->taint_needs_splode)) { - goto abandon_entry; + len = afl->queue_cur->len; + memcpy(out_buf, afl->taint_src, len); + res = input_to_state_stage(afl, afl->taint_src, out_buf, len, + afl->queue_cur->exec_cksum); + // just abandon as success + ret_val = 0; + res = 1; + + } else { + + res = input_to_state_stage(afl, in_buf, out_buf, len, + afl->queue_cur->exec_cksum); } + if (unlikely(res)) { goto abandon_entry; } + } /* Skip right away if -d is given, if it has not been chosen sufficiently @@ -2288,37 +2367,46 @@ havoc_stage: copy_len = choose_block_len(afl, afl->queue_cur->len - 1); copy_from = rand_below(afl, afl->queue_cur->len - copy_len + 1); + copy_to = rand_below(afl, temp_len + 1); } else { copy_len = choose_block_len(afl, temp_len - 1); copy_from = rand_below(afl, temp_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); } - copy_to = rand_below(afl, temp_len - copy_len + 1); - if (unlikely(copy_to > (u32)temp_len)) - copy_to = rand_below(afl, temp_len); - if (rand_below(afl, 4)) { if (copy_from != copy_to) { if (unlikely(afl->taint_needs_splode)) { - if (copy_to > (u32)temp_len) - copy_to = rand_below(afl, temp_len); + if (temp_len >= (s32)(copy_to + copy_len)) { - // fprintf(stderr, "\nout_buf %p + copy_to %u, src %p + %u, - // copy_len %u -- len %u\n", out_buf , copy_to, afl->taint_src , - // copy_from, copy_len, afl->taint_len, afl->queue_cur->len); - memmove(out_buf + copy_to, afl->taint_src + copy_from, - copy_len); + memcpy(out_buf + copy_to, afl->taint_src + copy_from, + copy_len); - } else + } else { + + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), + copy_to + copy_len); + memcpy(new_buf, in_buf, copy_to); + memcpy(new_buf + copy_to, afl->taint_src + copy_from, + copy_len); + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + out_buf = new_buf; + temp_len = copy_to + copy_len; + + } + + } else { memmove(out_buf + copy_to, out_buf + copy_from, copy_len); + } + } } else { @@ -2698,7 +2786,7 @@ abandon_entry: ++afl->queue_cur->fuzz_level; - if (afl->taint_needs_splode) { + if (unlikely(afl->taint_needs_splode)) { munmap(afl->taint_src, afl->queue_cur->len); munmap(orig_in, afl->taint_len); diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index bb44e465..a1fe146b 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -420,11 +420,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len, afl->last_path_time = get_cur_time(); /* trigger the tain gathering if this is not a dry run */ - if (afl->taint_mode && mem) { - - perform_taint_run(afl, q, fname, mem, len); - - } + if (afl->taint_mode && mem) { perform_taint_run(afl, q, fname, mem, len); } /* only redqueen currently uses is_ascii */ if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 5f928333..94cfc383 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -878,9 +878,11 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (unlikely(afl->taint_needs_splode)) { s32 new_len = afl->queue_cur->len + len - afl->taint_len; - if (new_len < 4) new_len = 4; - if (new_len > MAX_FILE) new_len = MAX_FILE; - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + if (new_len < 4) + new_len = 4; + else if (new_len > MAX_FILE) + new_len = MAX_FILE; + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), new_len); u32 i, taint = 0; for (i = 0; i < (u32)new_len; i++) { @@ -892,6 +894,8 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { } + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + out_buf = new_buf; len = new_len; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bead2ed9..106aa550 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -894,9 +894,18 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->taint_mode) { FATAL("-A and -n are mutually exclusive"); } } - - if (afl->limit_time_sig != 0 && afl->taint_mode) { FATAL("-A and -L are mutually exclusive"); } - if (afl->unicorn_mode != 0 && afl->taint_mode) { FATAL("-A and -U are mutually exclusive"); } + + if (afl->limit_time_sig != 0 && afl->taint_mode) { + + FATAL("-A and -L are mutually exclusive"); + + } + + if (afl->unicorn_mode != 0 && afl->taint_mode) { + + FATAL("-A and -U are mutually exclusive"); + + } if (get_afl_env("AFL_DISABLE_TRIM")) { afl->disable_trim = 1; } @@ -1309,7 +1318,7 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Taint forkserver successfully started"); - const rlim_t kStackSize = 256L * 1024L * 1024L; // min stack size = 256 Mb + const rlim_t kStackSize = 128L * 1024L * 1024L; // min stack size = 128 Mb struct rlimit rl; rl.rlim_cur = kStackSize; if (getrlimit(RLIMIT_STACK, &rl) != 0) -- cgit 1.4.1 From 83df65a66b8df37d0759bf9b31a61f50234d6c40 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 14 Aug 2020 00:46:15 +0200 Subject: cleaned up maybe_add_auto calls --- include/afl-fuzz.h | 4 +--- include/forkserver.h | 4 ++-- src/afl-forkserver.c | 28 +++++++++++++++++++--------- src/afl-fuzz-extras.c | 8 ++------ src/afl-fuzz-one.c | 8 ++++---- src/afl-fuzz-redqueen.c | 12 ++++++------ src/afl-fuzz-state.c | 5 +++-- 7 files changed, 37 insertions(+), 32 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 51ab0e85..cd6f7173 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -608,8 +608,6 @@ typedef struct afl_state { u32 document_counter; #endif - void *maybe_add_auto; - /* statistics file */ double last_bitmap_cvg, last_stability, last_eps; @@ -911,7 +909,7 @@ u8 has_new_bits(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); -void maybe_add_auto(void *, u8 *, u32); +void maybe_add_auto(afl_state_t *, u8 *, u32); void save_auto(afl_state_t *); void load_auto(afl_state_t *); void destroy_extras(afl_state_t *); diff --git a/include/forkserver.h b/include/forkserver.h index 717493db..b413b4bf 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -89,9 +89,9 @@ typedef struct afl_forkserver { /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); - u8 *function_opt; /* for autodictionary: afl ptr */ + u8 *afl_ptr; /* for autodictionary: afl ptr */ - void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len); + void (*autodict_func)(void *afl_ptr, u8 *mem, u32 len); } afl_forkserver_t; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 8684bcc0..01fc829a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -324,8 +324,7 @@ static void report_error_and_exit(int error) { cloning a stopped child. So, we just execute once, and then send commands through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ -void __attribute__((hot)) -afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, +void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output) { int st_pipe[2], ctl_pipe[2]; @@ -631,13 +630,18 @@ afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { - if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + if (fsrv->autodict_func == NULL || fsrv->afl_ptr == NULL) { // this is not afl-fuzz - we deny and return - if (fsrv->use_shmem_fuzz) + if (fsrv->use_shmem_fuzz) { + status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); - else + + } else { + status = (FS_OPT_ENABLED); + + } if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { FATAL("Writing to forkserver failed."); @@ -650,11 +654,16 @@ afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, if (!be_quiet) { ACTF("Using AUTODICT feature."); } - if (fsrv->use_shmem_fuzz) + if (fsrv->use_shmem_fuzz) { + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); - else + + } else { + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + } + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { FATAL("Writing to forkserver failed."); @@ -673,7 +682,8 @@ afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, } - u32 len = status, offset = 0, count = 0; + u32 offset = 0, count = 0; + u32 len = status; u8 *dict = ck_alloc(len); if (dict == NULL) { @@ -704,7 +714,7 @@ afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, while (offset < (u32)status && (u8)dict[offset] + offset < (u32)status) { - fsrv->function_ptr(fsrv->function_opt, dict + offset + 1, + fsrv->autodict_func(fsrv->afl_ptr, dict + offset + 1, (u8)dict[offset]); offset += (1 + dict[offset]); count++; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 097871c8..2f3a2d53 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -354,13 +354,9 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } /* Maybe add automatic extra. */ -/* Ugly hack: afl state is transfered as u8* because we import data via - afl-forkserver.c - which is shared with other afl tools that do not - have the afl state struct */ -void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) { +void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { - afl_state_t *afl = (afl_state_t *)afl_tmp; u32 i; /* Allow users to specify that they don't want auto dictionaries. */ @@ -544,7 +540,7 @@ void load_auto(afl_state_t *afl) { if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) { - maybe_add_auto((u8 *)afl, tmp, len); + maybe_add_auto(afl, tmp, len); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 452c5298..57b53c9f 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -681,7 +681,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) { - maybe_add_auto((u8 *)afl, a_collect, a_len); + maybe_add_auto(afl, a_collect, a_len); } @@ -692,7 +692,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) { - maybe_add_auto((u8 *)afl, a_collect, a_len); + maybe_add_auto(afl, a_collect, a_len); } @@ -2882,7 +2882,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) { - maybe_add_auto((u8 *)afl, a_collect, a_len); + maybe_add_auto(afl, a_collect, a_len); } @@ -2893,7 +2893,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) { - maybe_add_auto((u8 *)afl, a_collect, a_len); + maybe_add_auto(afl, a_collect, a_len); } diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 4c0c9155..f21dd0b0 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -500,7 +500,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } - maybe_add_auto((u8 *)afl, (u8 *)&v, shape); + maybe_add_auto(afl, (u8 *)&v, shape); u64 rev; switch (shape) { @@ -509,15 +509,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { break; case 2: rev = SWAP16((u16)v); - maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); + maybe_add_auto(afl, (u8 *)&rev, shape); break; case 4: rev = SWAP32((u32)v); - maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); + maybe_add_auto(afl, (u8 *)&rev, shape); break; case 8: rev = SWAP64(v); - maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); + maybe_add_auto(afl, (u8 *)&rev, shape); break; } @@ -772,8 +772,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { if (afl->pass_stats[key].total == 0) { - maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape)); - maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape)); + maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape)); + maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape)); } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index e2d62bc6..97e4ee93 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -112,8 +112,9 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->fsrv.use_stdin = 1; afl->fsrv.map_size = map_size; - afl->fsrv.function_opt = (u8 *)afl; - afl->fsrv.function_ptr = &maybe_add_auto; + // afl_state_t is not available in forkserver.c + afl->fsrv.afl_ptr = (void *)afl; + afl->fsrv.autodict_func = (void (*)(void *, u8 *, u32))&maybe_add_auto; afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; -- cgit 1.4.1 From d1bc0207cc6e579fe914dcbb0b70653783b64598 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 14 Aug 2020 01:33:03 +0200 Subject: no longer using alloc for autodict --- include/afl-fuzz.h | 12 +++++- include/alloc-inl.h | 115 -------------------------------------------------- src/afl-fuzz-extras.c | 46 ++++++++------------ 3 files changed, 28 insertions(+), 145 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index cd6f7173..034e8de2 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -172,6 +172,14 @@ struct extra_data { }; +struct auto_extra_data { + + u8 data[MAX_AUTO_EXTRA]; /* Dictionary token data */ + u32 len; /* Dictionary token length */ + u32 hit_cnt; /* Use count in the corpus */ + +}; + /* Fuzzing stages */ enum { @@ -571,8 +579,8 @@ typedef struct afl_state { struct extra_data *extras; /* Extra tokens to fuzz with */ u32 extras_cnt; /* Total number of tokens read */ - struct extra_data *a_extras; /* Automatically selected extras */ - u32 a_extras_cnt; /* Total number of tokens available */ + struct auto_extra_data a_extras[MAX_AUTO_EXTRAS]; /* Automatically selected extras */ + u32 a_extras_cnt; /* Total number of tokens available */ /* afl_postprocess API - Now supported via custom mutators */ diff --git a/include/alloc-inl.h b/include/alloc-inl.h index 832b2de4..0518a8c9 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -176,44 +176,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) { return (u8 *)memcpy(ret, str, size); } - -/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized - or NULL inputs. */ - -static inline void *DFL_ck_memdup(void *mem, u32 size) { - - void *ret; - - if (!mem || !size) { return NULL; } - - ALLOC_CHECK_SIZE(size); - ret = malloc(size); - ALLOC_CHECK_RESULT(ret, size); - - return memcpy(ret, mem, size); - -} - -/* Create a buffer with a block of text, appending a NUL terminator at the end. - Returns NULL for zero-sized or NULL inputs. */ - -static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) { - - u8 *ret; - - if (!mem || !size) { return NULL; } - - ALLOC_CHECK_SIZE(size); - ret = (u8 *)malloc(size + 1); - ALLOC_CHECK_RESULT(ret, size); - - memcpy(ret, mem, size); - ret[size] = 0; - - return ret; - -} - /* In non-debug mode, we just do straightforward aliasing of the above functions to user-visible names such as ck_alloc(). */ @@ -222,8 +184,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) { #define ck_realloc DFL_ck_realloc #define ck_realloc_block DFL_ck_realloc_block #define ck_strdup DFL_ck_strdup - #define ck_memdup DFL_ck_memdup - #define ck_memdup_str DFL_ck_memdup_str #define ck_free DFL_ck_free #define alloc_report() @@ -487,55 +447,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) { return memcpy(ret, str, size); -} - -/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized - or NULL inputs. */ - -static inline void *DFL_ck_memdup(void *mem, u32 size) { - - void *ret; - - if (!mem || !size) return NULL; - - ALLOC_CHECK_SIZE(size); - ret = malloc(size + ALLOC_OFF_TOTAL); - ALLOC_CHECK_RESULT(ret, size); - - ret += ALLOC_OFF_HEAD; - - ALLOC_C1(ret) = ALLOC_MAGIC_C1; - ALLOC_S(ret) = size; - ALLOC_C2(ret) = ALLOC_MAGIC_C2; - - return memcpy(ret, mem, size); - -} - -/* Create a buffer with a block of text, appending a NUL terminator at the end. - Returns NULL for zero-sized or NULL inputs. */ - -static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) { - - u8 *ret; - - if (!mem || !size) return NULL; - - ALLOC_CHECK_SIZE(size); - ret = malloc(size + ALLOC_OFF_TOTAL + 1); - ALLOC_CHECK_RESULT(ret, size); - - ret += ALLOC_OFF_HEAD; - - ALLOC_C1(ret) = ALLOC_MAGIC_C1; - ALLOC_S(ret) = size; - ALLOC_C2(ret) = ALLOC_MAGIC_C2; - - memcpy(ret, mem, size); - ret[size] = 0; - - return ret; - } #ifndef DEBUG_BUILD @@ -548,8 +459,6 @@ static inline u8 *DFL_ck_memdup_str(u8 *mem, u32 size) { #define ck_realloc DFL_ck_realloc #define ck_realloc_block DFL_ck_realloc_block #define ck_strdup DFL_ck_strdup - #define ck_memdup DFL_ck_memdup - #define ck_memdup_str DFL_ck_memdup_str #define ck_free DFL_ck_free #define alloc_report() @@ -713,24 +622,6 @@ static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func, } -static inline void *TRK_ck_memdup(void *mem, u32 size, const char *file, - const char *func, u32 line) { - - void *ret = DFL_ck_memdup(mem, size); - TRK_alloc_buf(ret, file, func, line); - return ret; - -} - -static inline void *TRK_ck_memdup_str(void *mem, u32 size, const char *file, - const char *func, u32 line) { - - void *ret = DFL_ck_memdup_str(mem, size); - TRK_alloc_buf(ret, file, func, line); - return ret; - -} - static inline void TRK_ck_free(void *ptr, const char *file, const char *func, u32 line) { @@ -754,12 +645,6 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, #define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__) - #define ck_memdup(_p1, _p2) \ - TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) - - #define ck_memdup_str(_p1, _p2) \ - TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) - #define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__) #endif /* ^!DEBUG_BUILD */ diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index d678279d..94f50394 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -25,23 +25,26 @@ #include "afl-fuzz.h" -/* Helper function for load_extras. */ +/* helper function for auto_extras qsort */ +static int compare_auto_extras_len(const void *ae1, const void *ae2) { + + return ((struct auto_extra_data *)ae1)->len - ((struct auto_extra_data *)ae2)->len; + +} -static int compare_extras_len(const void *p1, const void *p2) { +/* descending order */ - struct extra_data *e1 = (struct extra_data *)p1, - *e2 = (struct extra_data *)p2; +static int compare_auto_extras_use_d(const void *ae1, const void *ae2) { - return e1->len - e2->len; + return ((struct auto_extra_data *)ae2)->hit_cnt - ((struct auto_extra_data *)ae1)->hit_cnt; } -static int compare_extras_use_d(const void *p1, const void *p2) { +/* Helper function for load_extras. */ - struct extra_data *e1 = (struct extra_data *)p1, - *e2 = (struct extra_data *)p2; +static int compare_extras_len(const void *e1, const void *e2) { - return e2->hit_cnt - e1->hit_cnt; + return ((struct extra_data *)e1)->len - ((struct extra_data *)e2)->len; } @@ -371,7 +374,7 @@ void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { } - if (i == len) { return; } + if (i == len || unlikely(len > MAX_AUTO_EXTRA)) { return; } /* Reject builtin interesting values. */ @@ -448,10 +451,7 @@ void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { if (afl->a_extras_cnt < MAX_AUTO_EXTRAS) { - afl->a_extras = ck_realloc_block( - afl->a_extras, (afl->a_extras_cnt + 1) * sizeof(struct extra_data)); - - afl->a_extras[afl->a_extras_cnt].data = ck_memdup(mem, len); + memcpy(afl->a_extras[afl->a_extras_cnt].data, mem, len); afl->a_extras[afl->a_extras_cnt].len = len; ++afl->a_extras_cnt; @@ -459,9 +459,7 @@ void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { i = MAX_AUTO_EXTRAS / 2 + rand_below(afl, (MAX_AUTO_EXTRAS + 1) / 2); - ck_free(afl->a_extras[i].data); - - afl->a_extras[i].data = ck_memdup(mem, len); + memcpy(afl->a_extras[i].data, mem, len); afl->a_extras[i].len = len; afl->a_extras[i].hit_cnt = 0; @@ -471,13 +469,13 @@ sort_a_extras: /* First, sort all auto extras by use count, descending order. */ - qsort(afl->a_extras, afl->a_extras_cnt, sizeof(struct extra_data), - compare_extras_use_d); + qsort(afl->a_extras, afl->a_extras_cnt, sizeof(struct auto_extra_data), + compare_auto_extras_use_d); /* Then, sort the top USE_AUTO_EXTRAS entries by size. */ qsort(afl->a_extras, MIN((u32)USE_AUTO_EXTRAS, afl->a_extras_cnt), - sizeof(struct extra_data), compare_extras_len); + sizeof(struct auto_extra_data), compare_auto_extras_len); } @@ -575,13 +573,5 @@ void destroy_extras(afl_state_t *afl) { ck_free(afl->extras); - for (i = 0; i < afl->a_extras_cnt; ++i) { - - ck_free(afl->a_extras[i].data); - - } - - ck_free(afl->a_extras); - } -- cgit 1.4.1 From ce513c4f3e97d293e57e0ef90ec9e501871c5644 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 14 Aug 2020 10:10:23 +0200 Subject: fix llvm12 -fuseld warning --- include/afl-fuzz.h | 7 ++++--- include/alloc-inl.h | 1 + llvm_mode/GNUmakefile | 8 +++++++- llvm_mode/afl-clang-fast.c | 10 ++++++++++ src/afl-fuzz-extras.c | 6 ++++-- 5 files changed, 26 insertions(+), 6 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 034e8de2..ca7d10fe 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -174,7 +174,7 @@ struct extra_data { struct auto_extra_data { - u8 data[MAX_AUTO_EXTRA]; /* Dictionary token data */ + u8 data[MAX_AUTO_EXTRA]; /* Dictionary token data */ u32 len; /* Dictionary token length */ u32 hit_cnt; /* Use count in the corpus */ @@ -579,8 +579,9 @@ typedef struct afl_state { struct extra_data *extras; /* Extra tokens to fuzz with */ u32 extras_cnt; /* Total number of tokens read */ - struct auto_extra_data a_extras[MAX_AUTO_EXTRAS]; /* Automatically selected extras */ - u32 a_extras_cnt; /* Total number of tokens available */ + struct auto_extra_data + a_extras[MAX_AUTO_EXTRAS]; /* Automatically selected extras */ + u32 a_extras_cnt; /* Total number of tokens available */ /* afl_postprocess API - Now supported via custom mutators */ diff --git a/include/alloc-inl.h b/include/alloc-inl.h index 0518a8c9..306cc622 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -176,6 +176,7 @@ static inline u8 *DFL_ck_strdup(u8 *str) { return (u8 *)memcpy(ret, str, size); } + /* In non-debug mode, we just do straightforward aliasing of the above functions to user-visible names such as ck_alloc(). */ diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 0fa9b12e..57cd9f74 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -206,6 +206,10 @@ AFL_CLANG_FUSELD= ifeq "$(LLVM_LTO)" "1" ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" AFL_CLANG_FUSELD=1 + $(info echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test ) + ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=ld.lld --ld-path=$(LLVM_BINDIR)/ld.lld -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + AFL_CLANG_LDPATH=1 + endif else $(warn -fuse-ld is not working, cannot enable LTO mode) LLVM_LTO = 0 @@ -218,7 +222,9 @@ CFLAGS_SAFE := -Wall -g -Wno-pointer-sign -I ../include/ \ -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \ -DLLVM_LIBDIR=\"$(LLVM_LIBDIR)\" -DLLVM_VERSION=\"$(LLVMVER)\" \ -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \ - -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \ + -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \ + -DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" \ + -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \ -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function override CFLAGS += $(CFLAGS_SAFE) diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 37af0dfc..6e8e4a1b 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -352,7 +352,15 @@ static void edit_params(u32 argc, char **argv, char **envp) { else setenv("AFL_LLVM_LTO_AUTODICTIONARY", "1", 1); +#ifdef AFL_CLANG_LDPATH + u8 *ld_ptr = strrchr(AFL_REAL_LD, '/'); + if (!ld_ptr) ld_ptr = "ld.lld"; + cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_ptr); + cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", AFL_REAL_LD); +#else cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD); +#endif + cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; /* @@ -1013,6 +1021,8 @@ int main(int argc, char **argv, char **envp) { "\nafl-clang-lto specific environment variables:\n" "AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), e.g. " "0x10000\n" + "AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding " + "functions they are in into this file\n" "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " "global var\n" "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a " diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 94f50394..17f02984 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -28,7 +28,8 @@ /* helper function for auto_extras qsort */ static int compare_auto_extras_len(const void *ae1, const void *ae2) { - return ((struct auto_extra_data *)ae1)->len - ((struct auto_extra_data *)ae2)->len; + return ((struct auto_extra_data *)ae1)->len - + ((struct auto_extra_data *)ae2)->len; } @@ -36,7 +37,8 @@ static int compare_auto_extras_len(const void *ae1, const void *ae2) { static int compare_auto_extras_use_d(const void *ae1, const void *ae2) { - return ((struct auto_extra_data *)ae2)->hit_cnt - ((struct auto_extra_data *)ae1)->hit_cnt; + return ((struct auto_extra_data *)ae2)->hit_cnt - + ((struct auto_extra_data *)ae1)->hit_cnt; } -- cgit 1.4.1 From af14acf2c148b1aef10414d1dd6c929c49abc11e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 14 Aug 2020 14:35:05 +0200 Subject: Revert "Merge branch 'debug' into dev" This reverts commit a7537b5511ad767d2240cf2dc6d3e261daa676f9, reversing changes made to 15e799f7ae666418e75c6a79db833c5316b21f97. --- GNUmakefile | 3 - README.md | 33 ---- afl_driver.cpp | 191 ----------------------- examples/aflpp_driver/aflpp_driver.c | 40 ++--- include/afl-fuzz.h | 36 +---- include/common.h | 1 - include/envs.h | 1 - include/forkserver.h | 2 - qemu_taint/README.md | 42 ------ qemu_taint/build_qemu_taint.sh | 7 - qemu_taint/clean.sh | 3 - src/afl-common.c | 155 ++++++++++++------- src/afl-forkserver.c | 17 +-- src/afl-fuzz-bitmap.c | 62 +------- src/afl-fuzz-init.c | 42 +----- src/afl-fuzz-one.c | 284 ++++------------------------------- src/afl-fuzz-queue.c | 177 +--------------------- src/afl-fuzz-run.c | 99 ++++-------- src/afl-fuzz-state.c | 30 ++-- src/afl-fuzz-stats.c | 5 +- src/afl-fuzz.c | 127 ++-------------- 21 files changed, 223 insertions(+), 1134 deletions(-) delete mode 100644 afl_driver.cpp delete mode 100644 qemu_taint/README.md delete mode 100755 qemu_taint/build_qemu_taint.sh delete mode 100755 qemu_taint/clean.sh (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index ae529ece..f9020a90 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -521,7 +521,6 @@ clean: $(MAKE) -C examples/argv_fuzzing clean $(MAKE) -C qemu_mode/unsigaction clean $(MAKE) -C qemu_mode/libcompcov clean - test -d qemu_taint/qemu && { cd qemu_taint ; ./clean.sh ; } rm -rf qemu_mode/qemu-3.1.1 ifeq "$(IN_REPO)" "1" test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true @@ -532,7 +531,6 @@ endif deepclean: clean rm -rf qemu_mode/qemu-3.1.1.tar.xz - rm -rf qemu_taint/qemu rm -rf unicorn_mode/unicornafl git reset --hard >/dev/null 2>&1 || true @@ -590,7 +588,6 @@ install: all $(MANPAGES) install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH) rm -f $${DESTDIR}$(BIN_PATH)/afl-as if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi - if [ -f afl-qemu-taint ]; then install -m 755 afl-qemu-taint $${DESTDIR}$(BIN_PATH); fi if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/README.md b/README.md index b3dc5e45..97c0a0d7 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,3 @@ -# qemu_taint variant. - -UPDATE: **WORKS NOW** **PLEASE TEST** **:-)** - -## HOWTO - -cd qemu_taint && ./build_qemu_taint.sh - -afl-fuzz -A ... - -## CAVEATS - - * llvm shmem persistent mode does not and can not not work - * MOpt works but totally ignores the taint information, so disabled here - * custom mutators? dunno if they work or not. depends on how they work. - * not tested with qemu_mode - * there are several debug checks to ensure the data is fine which slows down - fuzzing, if the beta experiment runs fine these will be improved and it - will result in quite a speed gain. - -## THE TAINT - -taint can be seen in out/taint/ - -the id:000 mirrors the out/queue entry, except the content it 0x00 for -untainted bytes and '!' for tainted bytes. -If a file has new tainted bytes compared to from which previous entry it -was created then there is a id:000[...].new file where the new bytes are -marked '!'. - -the mutation switches between fuzzing all tainted bytes in one cycle and -only new bytes in the other cycle. - # American Fuzzy Lop plus plus (afl++) AFL++ Logo diff --git a/afl_driver.cpp b/afl_driver.cpp deleted file mode 100644 index 7d6a6fd4..00000000 --- a/afl_driver.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -// Platform detection. Copied from FuzzerInternal.h -#ifdef __linux__ -#define LIBFUZZER_LINUX 1 -#define LIBFUZZER_APPLE 0 -#define LIBFUZZER_NETBSD 0 -#define LIBFUZZER_FREEBSD 0 -#define LIBFUZZER_OPENBSD 0 -#elif __APPLE__ -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_APPLE 1 -#define LIBFUZZER_NETBSD 0 -#define LIBFUZZER_FREEBSD 0 -#define LIBFUZZER_OPENBSD 0 -#elif __NetBSD__ -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_APPLE 0 -#define LIBFUZZER_NETBSD 1 -#define LIBFUZZER_FREEBSD 0 -#define LIBFUZZER_OPENBSD 0 -#elif __FreeBSD__ -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_APPLE 0 -#define LIBFUZZER_NETBSD 0 -#define LIBFUZZER_FREEBSD 1 -#define LIBFUZZER_OPENBSD 0 -#elif __OpenBSD__ -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_APPLE 0 -#define LIBFUZZER_NETBSD 0 -#define LIBFUZZER_FREEBSD 0 -#define LIBFUZZER_OPENBSD 1 -#else -#error "Support for your platform has not been implemented" -#endif - -// libFuzzer interface is thin, so we don't include any libFuzzer headers. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); - -// Notify AFL about persistent mode. -static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; -int __afl_persistent_loop(unsigned int); -static volatile char suppress_warning2 = AFL_PERSISTENT[0]; - -// Notify AFL about deferred forkserver. -static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; -void __afl_manual_init(); -static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; - -// Input buffer. -static const size_t kMaxAflInputSize = 1024000; -static uint8_t AflInputBuf[kMaxAflInputSize]; - -// Use this optionally defined function to output sanitizer messages even if -// user asks to close stderr. -__attribute__((weak)) void __sanitizer_set_report_fd(void *); - -// Keep track of where stderr content is being written to, so that -// dup_and_close_stderr can use the correct one. -static FILE *output_file = stderr; - -// Experimental feature to use afl_driver without AFL's deferred mode. -// Needs to run before __afl_auto_init. -__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) { - if (getenv("AFL_DRIVER_DONT_DEFER")) { - if (unsetenv("__AFL_DEFER_FORKSRV")) { - perror("Failed to unset __AFL_DEFER_FORKSRV"); - abort(); - } - } -} - -// If the user asks us to duplicate stderr, then do it. -static void maybe_duplicate_stderr() { - char *stderr_duplicate_filename = - getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); - - if (!stderr_duplicate_filename) - return; - - FILE *stderr_duplicate_stream = - freopen(stderr_duplicate_filename, "a+", stderr); - - if (!stderr_duplicate_stream) { - fprintf( - stderr, - "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); - abort(); - } - output_file = stderr_duplicate_stream; -} - -// Most of these I/O functions were inspired by/copied from libFuzzer's code. -static void discard_output(int fd) { - FILE *temp = fopen("/dev/null", "w"); - if (!temp) - abort(); - dup2(fileno(temp), fd); - fclose(temp); -} - -static void close_stdout() { discard_output(STDOUT_FILENO); } - -// Prevent the targeted code from writing to "stderr" but allow sanitizers and -// this driver to do so. -static void dup_and_close_stderr() { - int output_fileno = fileno(output_file); - int output_fd = dup(output_fileno); - if (output_fd <= 0) - abort(); - FILE *new_output_file = fdopen(output_fd, "w"); - if (!new_output_file) - abort(); - if (!__sanitizer_set_report_fd) - return; - __sanitizer_set_report_fd(reinterpret_cast(output_fd)); - discard_output(output_fileno); -} - -// Close stdout and/or stderr if user asks for it. -static void maybe_close_fd_mask() { - char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK"); - if (!fd_mask_str) - return; - int fd_mask = atoi(fd_mask_str); - if (fd_mask & 2) - dup_and_close_stderr(); - if (fd_mask & 1) - close_stdout(); -} - -// Define LLVMFuzzerMutate to avoid link failures for targets that use it -// with libFuzzer's LLVMFuzzerCustomMutator. -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { - assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); - return 0; -} - -int main(int argc, char **argv) { - printf( - "======================= INFO =========================\n" - "This binary is built for AFL-fuzz.\n" - "To run the target function on individual input(s) execute this:\n" - " %s < INPUT_FILE\n" - "To fuzz with afl-fuzz execute this:\n" - " afl-fuzz [afl-flags] %s [-N]\n" - "afl-fuzz will run N iterations before " - "re-spawning the process (default: 1000)\n" - "======================================================\n", - argv[0], argv[0]); - - maybe_duplicate_stderr(); - maybe_close_fd_mask(); - if (LLVMFuzzerInitialize) - LLVMFuzzerInitialize(&argc, &argv); - // Do any other expensive one-time initialization here. - - int N = 100000; - if (argc == 2 && argv[1][0] == '-') - N = atoi(argv[1] + 1); - else if(argc == 2 && (N = atoi(argv[1])) > 0) - printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); - - assert(N > 0); - - if (!getenv("AFL_DRIVER_DONT_DEFER")) - __afl_manual_init(); - - // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization - // on the first execution of LLVMFuzzerTestOneInput is ignored. - uint8_t dummy_input[1] = {0}; - LLVMFuzzerTestOneInput(dummy_input, 1); - - while (__afl_persistent_loop(N)) { - ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); - if (n_read > 0) { - LLVMFuzzerTestOneInput(AflInputBuf, n_read); - } - } - - printf("%s: successfully executed input(s)\n", argv[0]); -} diff --git a/examples/aflpp_driver/aflpp_driver.c b/examples/aflpp_driver/aflpp_driver.c index 8e0b554a..b764338e 100644 --- a/examples/aflpp_driver/aflpp_driver.c +++ b/examples/aflpp_driver/aflpp_driver.c @@ -106,7 +106,10 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both. #error "Support for your platform has not been implemented" #endif -int __afl_sharedmem_fuzzing = 0; +int __afl_sharedmem_fuzzing = 1; +extern unsigned int * __afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; +// extern struct cmp_map *__afl_cmp_map; // libFuzzer interface is thin, so we don't include any libFuzzer headers. int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); @@ -272,7 +275,6 @@ int main(int argc, char **argv) { // Do any other expensive one-time initialization here. uint8_t dummy_input[64] = {0}; - uint8_t buf[1024000]; memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR, sizeof(AFL_DEFER_FORKSVR)); @@ -283,24 +285,16 @@ int main(int argc, char **argv) { printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); else if (argc > 1) { - if (!getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) { - - __afl_manual_init(); - - } - + __afl_sharedmem_fuzzing = 0; + __afl_manual_init(); return ExecuteFilesOnyByOne(argc, argv); } assert(N > 0); - if (!getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) { - - fprintf(stderr, "performing manual init\n"); - __afl_manual_init(); - - } + // if (!getenv("AFL_DRIVER_DONT_DEFER")) + __afl_manual_init(); // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization // on the first execution of LLVMFuzzerTestOneInput is ignored. @@ -309,13 +303,25 @@ int main(int argc, char **argv) { int num_runs = 0; while (__afl_persistent_loop(N)) { - ssize_t r = read(0, buf, sizeof(buf)); +#ifdef _DEBUG + fprintf(stderr, "CLIENT crc: %016llx len: %u\n", + hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705), + *__afl_fuzz_len); + fprintf(stderr, "RECV:"); + for (int i = 0; i < *__afl_fuzz_len; i++) + fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); + fprintf(stderr, "\n"); +#endif + if (*__afl_fuzz_len) { + + num_runs++; + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); - if (r > 0) { LLVMFuzzerTestOneInput(buf, r); } + } } - printf("%s: successfully executed input(s)\n", argv[0]); + printf("%s: successfully executed %d input(s)\n", argv[0], num_runs); } diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index ad7b0cd6..ca7d10fe 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -133,10 +133,8 @@ extern s32 struct queue_entry { - u8 * fname; /* File name for the test case */ - u8 * fname_taint; /* File name for taint data */ - u32 len; /* Input length */ - struct queue_entry *prev; /* previous queue entry, if any */ + u8 *fname; /* File name for the test case */ + u32 len; /* Input length */ u8 cal_failed, /* Calibration failed? */ trim_done, /* Trimmed? */ @@ -150,10 +148,7 @@ struct queue_entry { is_ascii; /* Is the input just ascii text? */ u32 bitmap_size, /* Number of bits set in bitmap */ - fuzz_level, /* Number of fuzzing iterations */ - taint_bytes_all, /* Number of tainted bytes */ - taint_bytes_new, /* Number of new tainted bytes */ - taint_bytes_highest; /* highest offset in input */ + fuzz_level; /* Number of fuzzing iterations */ u64 exec_us, /* Execution time (us) */ handicap, /* Number of queue cycles behind */ @@ -385,8 +380,6 @@ typedef struct afl_state { char **argv; /* argv if needed */ - char **argv_taint; /* argv for taint mode */ - /* MOpt: Lots of globals, but mostly for the status UI and other things where it really makes no sense to haul them around as function parameters. */ @@ -438,9 +431,7 @@ typedef struct afl_state { *in_bitmap, /* Input bitmap */ *file_extension, /* File extension */ *orig_cmdline, /* Original command line */ - *infoexec, /* Command to execute on a new crash */ - *taint_input_file, /* fuzz_input_one input file */ - *taint_src, *taint_map; + *infoexec; /* Command to execute on a new crash */ u32 hang_tmout; /* Timeout used for hang det (ms) */ @@ -451,9 +442,7 @@ typedef struct afl_state { custom_only, /* Custom mutator only mode */ python_only, /* Python-only mode */ is_main_node, /* if this is the main node */ - is_secondary_node, /* if this is a secondary instance */ - taint_needs_splode, /* explode fuzz input */ - taint_mode; + is_secondary_node; /* if this is a secondary instance */ u32 stats_update_freq; /* Stats update frequency (execs) */ @@ -514,8 +503,7 @@ typedef struct afl_state { useless_at_start, /* Number of useless starting paths */ var_byte_count, /* Bitmap bytes with var behavior */ current_entry, /* Current queue entry ID */ - havoc_div, /* Cycle count divisor for havoc */ - taint_len, taint_count; + havoc_div; /* Cycle count divisor for havoc */ u64 total_crashes, /* Total number of crashes */ unique_crashes, /* Crashes with unique signatures */ @@ -602,9 +590,6 @@ typedef struct afl_state { char * cmplog_binary; afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ - /* Taint mode */ - afl_forkserver_t taint_fsrv; /* taint mode has its own little forkserver */ - /* Custom mutators */ struct custom_mutator *mutator; @@ -856,8 +841,7 @@ struct custom_mutator { }; -void afl_state_init_1(afl_state_t *, uint32_t map_size); -void afl_state_init_2(afl_state_t *, uint32_t map_size); +void afl_state_init(afl_state_t *, uint32_t map_size); void afl_state_deinit(afl_state_t *); /* Set stop_soon flag on all childs, kill all childs */ @@ -903,7 +887,7 @@ void deinit_py(void *); void mark_as_det_done(afl_state_t *, struct queue_entry *); void mark_as_variable(afl_state_t *, struct queue_entry *); void mark_as_redundant(afl_state_t *, struct queue_entry *, u8); -void add_to_queue(afl_state_t *, u8 *, u8 *, u32, struct queue_entry *, u8); +void add_to_queue(afl_state_t *, u8 *, u32, u8); void destroy_queue(afl_state_t *); void update_bitmap_score(afl_state_t *, struct queue_entry *); void cull_queue(afl_state_t *); @@ -913,9 +897,7 @@ u32 calculate_score(afl_state_t *, struct queue_entry *); void write_bitmap(afl_state_t *); u32 count_bits(afl_state_t *, u8 *); -u32 count_bits_len(afl_state_t *, u8 *, u32); u32 count_bytes(afl_state_t *, u8 *); -u32 count_bytes_len(afl_state_t *, u8 *, u32); u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 void simplify_trace(afl_state_t *, u64 *); @@ -993,8 +975,6 @@ 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); -void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, - u8 *mem, u32 len); /* CmpLog */ diff --git a/include/common.h b/include/common.h index c7d57e07..87a7425b 100644 --- a/include/common.h +++ b/include/common.h @@ -55,7 +55,6 @@ extern u8 *doc_path; /* path to documentation dir */ @returns the path, allocating the string */ u8 *find_binary(u8 *fname); -u8 *find_afl_binary(u8 *fname, u8 *own_loc); /* Read a bitmap from file fname to memory This is for the -B option again. */ diff --git a/include/envs.h b/include/envs.h index bd97b9cd..96ae91ba 100644 --- a/include/envs.h +++ b/include/envs.h @@ -123,7 +123,6 @@ static char *afl_environment_variables[] = { "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", "AFL_SKIP_CRASHES", - "AFL_TAINT_INPUT", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", diff --git a/include/forkserver.h b/include/forkserver.h index 59a9f150..0a7390ed 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -80,8 +80,6 @@ typedef struct afl_forkserver { u8 qemu_mode; /* if running in qemu mode or not */ - u8 taint_mode; /* if running taint analysis or not */ - u32 *shmem_fuzz_len; /* length of the fuzzing test case */ u8 *shmem_fuzz; /* allocated memory for fuzzing */ diff --git a/qemu_taint/README.md b/qemu_taint/README.md deleted file mode 100644 index 6a7d19af..00000000 --- a/qemu_taint/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# qemu_taint - -First level taint implementation with qemu for linux user mode - -**THIS IS NOT WORKING YET** **WIP** - -## What is this for - -On new queue entries (newly discovered paths into the target) this tainter -is run with the new input and the data gathered which bytes in the input -file are actually touched. - -Only touched bytes are then fuzzed by afl-fuzz - -## How to build - -./build_qemu_taint.sh - -## How to use - -Add the -A flag to afl-fuzz - -## Caveats - -For some targets this is amazing and improves fuzzing a lot, but if a target -copies all input bytes first (e.g. for creating a crc checksum or just to -safely work with the data), then this is not helping at all. - -## Future - -Two fuzz modes for a queue entry which will be switched back and forth: - - 1. fuzz all touched bytes - 2. fuzz only bytes that are newly touched (compared to the one this queue - entry is based on) - -## TODO - - * Direct trim: trim to highest touched byte, that is all we need to do - * add 5-25% dummy bytes to the queue entries? (maybe create a 2nd one?) - * Disable trim? - diff --git a/qemu_taint/build_qemu_taint.sh b/qemu_taint/build_qemu_taint.sh deleted file mode 100755 index b54c3e04..00000000 --- a/qemu_taint/build_qemu_taint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1 -cd qemu || exit 1 -test -d .git && { git stash ; git pull ; } -cp -fv ../../include/config.h ../../include/types.h . || exit 1 -./build.sh || exit 1 -cp -fv ./afl-qemu-taint ../.. diff --git a/qemu_taint/clean.sh b/qemu_taint/clean.sh deleted file mode 100755 index 10c44cac..00000000 --- a/qemu_taint/clean.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -rm -f afl-qemu-taint qemu/afl-qemu-taint ../afl-qemu-taint -test -d qemu && { cd qemu ; ./clean.sh ; } diff --git a/src/afl-common.c b/src/afl-common.c index cefed8dc..367dec72 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -138,73 +138,62 @@ void argv_cpy_free(char **argv) { } -u8 *find_afl_binary(u8 *fname, u8 *own_loc) { - - u8 *tmp, *rsl, *own_copy, *cp; - - tmp = getenv("AFL_PATH"); - - if (tmp) { - - cp = alloc_printf("%s/%s", tmp, fname); - - if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } - - return cp; +/* Rewrite argv for QEMU. */ - } +char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { - if (own_loc) { + char **new_argv = ck_alloc(sizeof(char *) * (argc + 4)); + u8 * tmp, *cp = NULL, *rsl, *own_copy; - own_copy = ck_strdup(own_loc); - rsl = strrchr(own_copy, '/'); + memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1)); + new_argv[argc - 1] = NULL; - if (rsl) { + new_argv[2] = *target_path_p; + new_argv[1] = "--"; - *rsl = 0; + /* Now we need to actually find the QEMU binary to put in argv[0]. */ - cp = alloc_printf("%s/%s", own_copy, fname); - ck_free(own_copy); + tmp = getenv("AFL_PATH"); - if (!access(cp, X_OK)) { return cp; } + if (tmp) { - } else { + cp = alloc_printf("%s/afl-qemu-trace", tmp); - ck_free(own_copy); + if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } - } + *target_path_p = new_argv[0] = cp; + return new_argv; } - cp = alloc_printf("%s/%s", BIN_PATH, fname); - if (!access(cp, X_OK)) { return cp; } + own_copy = ck_strdup(own_loc); + rsl = strrchr(own_copy, '/'); - ck_free(cp); + if (rsl) { - return NULL; + *rsl = 0; -} + cp = alloc_printf("%s/afl-qemu-trace", own_copy); + ck_free(own_copy); -/* Rewrite argv for QEMU. */ + if (!access(cp, X_OK)) { -char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { + *target_path_p = new_argv[0] = cp; + return new_argv; - char **new_argv = ck_alloc(sizeof(char *) * (argc + 4)); - u8 * cp = NULL; + } - memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1)); - new_argv[argc - 1] = NULL; + } else { - new_argv[2] = *target_path_p; - new_argv[1] = "--"; + ck_free(own_copy); - /* Now we need to actually find the QEMU binary to put in argv[0]. */ + } - cp = find_afl_binary("afl-qemu-trace", own_loc); + if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { - if (cp) { + if (cp) { ck_free(cp); } + *target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace"); - *target_path_p = new_argv[0] = cp; return new_argv; } @@ -236,7 +225,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { char **new_argv = ck_alloc(sizeof(char *) * (argc + 3)); - u8 * cp = NULL; + u8 * tmp, *cp = NULL, *rsl, *own_copy; memcpy(&new_argv[2], &argv[1], (int)(sizeof(char *)) * (argc - 1)); new_argv[argc - 1] = NULL; @@ -245,16 +234,66 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { /* Now we need to actually find the QEMU binary to put in argv[0]. */ - cp = find_afl_binary("afl-qemu-trace", own_loc); + tmp = getenv("AFL_PATH"); + + if (tmp) { + + cp = alloc_printf("%s/afl-qemu-trace", tmp); - if (cp) { + if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } ck_free(cp); - cp = find_afl_binary("afl-wine-trace", own_loc); - if (cp) { + cp = alloc_printf("%s/afl-wine-trace", tmp); - *target_path_p = new_argv[0] = cp; + if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); } + + *target_path_p = new_argv[0] = cp; + return new_argv; + + } + + own_copy = ck_strdup(own_loc); + rsl = strrchr(own_copy, '/'); + + if (rsl) { + + *rsl = 0; + + cp = alloc_printf("%s/afl-qemu-trace", own_copy); + + if (cp && !access(cp, X_OK)) { + + ck_free(cp); + + cp = alloc_printf("%s/afl-wine-trace", own_copy); + + if (!access(cp, X_OK)) { + + *target_path_p = new_argv[0] = cp; + return new_argv; + + } + + } + + ck_free(own_copy); + + } else { + + ck_free(own_copy); + + } + + u8 *ncp = BIN_PATH "/afl-qemu-trace"; + + if (!access(ncp, X_OK)) { + + ncp = BIN_PATH "/afl-wine-trace"; + + if (!access(ncp, X_OK)) { + + *target_path_p = new_argv[0] = ck_strdup(ncp); return new_argv; } @@ -262,21 +301,25 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { } SAYF("\n" cLRD "[-] " cRST - "Oops, unable to find the afl-qemu-trace and afl-wine-trace binaries.\n" - "The afl-qemu-trace binary must be built separately by following the " - "instructions\n" - "in qemu_mode/README.md. If you already have the binary installed, you " - "may need\n" - "to specify the location via AFL_PATH in the environment.\n\n" + "Oops, unable to find the '%s' binary. The binary must be " + "built\n" + " separately by following the instructions in " + "qemu_mode/README.md. " + "If you\n" + " already have the binary installed, you may need to specify " + "AFL_PATH in the\n" + " environment.\n\n" + " Of course, even without QEMU, afl-fuzz can still work with " "binaries that are\n" " instrumented at compile time with afl-gcc. It is also possible to " "use it as a\n" " traditional non-instrumented fuzzer by specifying '-n' in the " "command " - "line.\n"); + "line.\n", + ncp); - FATAL("Failed to locate 'afl-qemu-trace' and 'afl-wine-trace'."); + FATAL("Failed to locate '%s'.", ncp); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 173cc70f..25983f26 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -498,21 +498,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, char pid_buf[16]; sprintf(pid_buf, "%d", fsrv->fsrv_pid); - - if (fsrv->taint_mode) { - - setenv("__AFL_TARGET_PID3", pid_buf, 1); - - } else if (fsrv->cmplog_binary) { - + if (fsrv->cmplog_binary) setenv("__AFL_TARGET_PID2", pid_buf, 1); - - } else { - + else setenv("__AFL_TARGET_PID1", pid_buf, 1); - } - /* Close the unneeded endpoints. */ close(ctl_pipe[0]); @@ -947,7 +937,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } else { - s32 fd; + s32 fd = fsrv->out_fd; if (fsrv->out_file) { @@ -966,7 +956,6 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } else { - fd = fsrv->out_fd; lseek(fd, 0, SEEK_SET); } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index db57061d..1b9df624 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -177,40 +177,6 @@ u32 count_bits(afl_state_t *afl, u8 *mem) { } -u32 count_bits_len(afl_state_t *afl, u8 *mem, u32 len) { - - u32 *ptr = (u32 *)mem; - u32 i = (len >> 2); - u32 ret = 0; - - (void)(afl); - - if (len % 4) i++; - - while (i--) { - - u32 v = *(ptr++); - - /* This gets called on the inverse, virgin bitmap; optimize for sparse - data. */ - - if (v == 0xffffffff) { - - ret += 32; - continue; - - } - - v -= ((v >> 1) & 0x55555555); - v = (v & 0x33333333) + ((v >> 2) & 0x33333333); - ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24; - - } - - return ret; - -} - /* Count the number of bytes set in the bitmap. Called fairly sporadically, mostly to update the status screen or calibrate and examine confirmed new paths. */ @@ -237,32 +203,6 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) { } -u32 count_bytes_len(afl_state_t *afl, u8 *mem, u32 len) { - - u32 *ptr = (u32 *)mem; - u32 i = (len >> 2); - u32 ret = 0; - - (void)(afl); - - if (len % 4) i++; - - while (i--) { - - u32 v = *(ptr++); - - if (!v) { continue; } - if (v & 0x000000ff) { ++ret; } - if (v & 0x0000ff00) { ++ret; } - if (v & 0x00ff0000) { ++ret; } - if (v & 0xff000000) { ++ret; } - - } - - return ret; - -} - /* Count the number of non-255 bytes set in the bitmap. Used strictly for the status screen, several calls per second or so. */ @@ -655,7 +595,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #endif /* ^!SIMPLE_FILES */ - add_to_queue(afl, queue_fn, mem, len, afl->queue_top, 0); + add_to_queue(afl, queue_fn, len, 0); if (hnb == 2) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 359eef85..350a8599 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -712,7 +712,7 @@ void read_testcases(afl_state_t *afl) { if (!access(dfn, F_OK)) { passed_det = 1; } - add_to_queue(afl, fn2, NULL, st.st_size, NULL, passed_det); + add_to_queue(afl, fn2, st.st_size, passed_det); } @@ -771,13 +771,9 @@ void perform_dry_run(afl_state_t *afl) { close(fd); res = calibrate_case(afl, q, use_mem, 0, 1); + ck_free(use_mem); - if (afl->stop_soon) { - - ck_free(use_mem); - return; - - } + if (afl->stop_soon) { return; } if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) { @@ -964,10 +960,6 @@ void perform_dry_run(afl_state_t *afl) { } - /* perform taint gathering on the input seed */ - if (afl->taint_mode) perform_taint_run(afl, q, q->fname, use_mem, q->len); - ck_free(use_mem); - q = q->next; } @@ -1446,10 +1438,6 @@ static void handle_existing_out_dir(afl_state_t *afl) { u8 *orig_q = alloc_printf("%s/queue", afl->out_dir); - u8 *fnt = alloc_printf("%s/taint", afl->out_dir); - mkdir(fnt, 0755); // ignore errors - ck_free(fnt); - afl->in_dir = alloc_printf("%s/_resume", afl->out_dir); rename(orig_q, afl->in_dir); /* Ignore errors */ @@ -1506,20 +1494,6 @@ static void handle_existing_out_dir(afl_state_t *afl) { if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } ck_free(fn); - if (afl->taint_mode) { - - fn = alloc_printf("%s/taint", afl->out_dir); - mkdir(fn, 0755); // ignore errors - - u8 *fn2 = alloc_printf("%s/taint/.input", afl->out_dir); - unlink(fn2); // ignore errors - ck_free(fn2); - - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } - ck_free(fn); - - } - /* All right, let's do out_dir>/crashes/id:* and * out_dir>/hangs/id:*. */ @@ -1747,16 +1721,6 @@ void setup_dirs_fds(afl_state_t *afl) { if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); - /* Taint directory if taint_mode. */ - - if (afl->taint_mode) { - - tmp = alloc_printf("%s/taint", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } - ck_free(tmp); - - } - /* Top-level directory for queue metadata used for session resume and related tasks. */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 6d52b2b4..57b53c9f 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -458,171 +458,28 @@ u8 fuzz_one_original(afl_state_t *afl) { } - u32 tmp_val = 0; - - if (unlikely(afl->taint_mode)) { - - tmp_val = afl->queue_cycle % 2; // starts with 1 - ret_val = 0; - - if (unlikely(afl->queue_cur->cal_failed && !tmp_val)) goto abandon_entry; - if (unlikely(!afl->skip_deterministic && !afl->queue_cur->passed_det && - !tmp_val)) - goto abandon_entry; - if ((!afl->queue_cur->taint_bytes_new || - afl->queue_cur->taint_bytes_new == afl->queue_cur->len) && - !tmp_val) - goto abandon_entry; - - ret_val = 1; - - s32 dst = 0, i; - temp_len = len = afl->queue_cur->len; - s32 j = 0; // tmp - - fd = open(afl->queue_cur->fname, O_RDONLY); - afl->taint_src = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (fd < 0 || (ssize_t)afl->taint_src == -1) - FATAL("unable to open '%s'", afl->queue_cur->fname); - close(fd); - afl->taint_needs_splode = 1; - - switch (tmp_val) { - - case 1: // fuzz only tainted bytes - - // special case: all or nothing tainted. in this case we act like - // nothing is special. this is not the taint you are looking for ... - if (!afl->queue_cur->taint_bytes_all || - afl->queue_cur->taint_bytes_all == (u32)len) { - - orig_in = in_buf = afl->taint_src; - afl->taint_needs_splode = 0; - break; - - } - - fd = open(afl->taint_input_file, O_RDONLY); - temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_all; - orig_in = in_buf = - mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536, - PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (fd < 0 || (ssize_t)in_buf == -1) - FATAL("unable to open '%s'", afl->taint_input_file); - close(fd); - - fd = open(afl->queue_cur->fname_taint, O_RDONLY); - afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE, - MAP_PRIVATE, fd, 0); - if (fd < 0 || (ssize_t)in_buf == -1) - FATAL("unable to open '%s'", afl->queue_cur->fname_taint); - close(fd); - - for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++) - if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i]; - - // FIXME DEBUG TODO XXX - for (i = 0; i < (s32)afl->queue_cur->len; i++) { - - switch (afl->taint_map[i]) { - - case 0x0: - break; - case '!': - j++; - break; - default: - FATAL( - "invalid taint map entry byte 0x%02x at position %d " - "(passed_det:%d)\n", - afl->taint_map[i], i, afl->queue_cur->passed_det); - - } - - } - - if (j != len) - FATAL("different taint values in map vs in queue (%d != %d)", j, len); - - break; - - case 0: // fuzz only newly tainted bytes - - fd = open(afl->taint_input_file, O_RDONLY); - temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_new; - orig_in = in_buf = - mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536, - PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (fd < 0 || (ssize_t)in_buf == -1) - FATAL("unable to open '%s'", afl->taint_input_file); - close(fd); - - u8 *fn = alloc_printf("%s.new", afl->queue_cur->fname_taint); - if (!fn) FATAL("OOM"); - fd = open(fn, O_RDWR); - afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE, - MAP_PRIVATE, fd, 0); - if (fd < 0 || (ssize_t)in_buf == -1) - FATAL("unable to open '%s' for %u bytes", fn, len); - close(fd); - ck_free(fn); - - for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++) - if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i]; - - // FIXME DEBUG TODO XXX - for (i = 0; i < (s32)afl->queue_cur->len; i++) { - - switch (afl->taint_map[i]) { - - case 0x0: - break; - case '!': - j++; - break; - default: - FATAL( - "invalid taint map entry byte 0x%02x at position %d " - "(passed_det:%d)\n", - afl->taint_map[i], i, afl->queue_cur->passed_det); - - } - - } - - if (j != len) - FATAL("different taint values in map vs in queue (%d != %d)", j, len); - - break; - - } - - } else { - - /* Map the test case into memory. */ - - fd = open(afl->queue_cur->fname, O_RDONLY); + /* Map the test case into memory. */ - if (unlikely(fd < 0)) { + fd = open(afl->queue_cur->fname, O_RDONLY); - PFATAL("Unable to open '%s'", afl->queue_cur->fname); + if (unlikely(fd < 0)) { - } + PFATAL("Unable to open '%s'", afl->queue_cur->fname); - len = afl->queue_cur->len; + } - orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + len = afl->queue_cur->len; - if (unlikely(orig_in == MAP_FAILED)) { + orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); + if (unlikely(orig_in == MAP_FAILED)) { - } - - close(fd); + PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); } + close(fd); + /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ @@ -645,12 +502,8 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->queue_cur->exec_cksum = 0; - if (unlikely(afl->taint_needs_splode)) - res = calibrate_case(afl, afl->queue_cur, afl->taint_src, - afl->queue_cycle - 1, 0); - else - res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, - 0); + res = + calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0); if (unlikely(res == FSRV_RUN_ERROR)) { @@ -673,8 +526,8 @@ u8 fuzz_one_original(afl_state_t *afl) { * TRIMMING * ************/ - if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done && - !afl->disable_trim && !afl->taint_needs_splode)) { + if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done && + !afl->disable_trim) { u8 res = trim_case(afl, afl->queue_cur, in_buf); @@ -711,26 +564,13 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) { - int res; - if (unlikely(afl->taint_needs_splode)) { - - len = afl->queue_cur->len; - memcpy(out_buf, afl->taint_src, len); - res = input_to_state_stage(afl, afl->taint_src, out_buf, len, - afl->queue_cur->exec_cksum); - // just abandon as success - ret_val = 0; - res = 1; - - } else { + if (input_to_state_stage(afl, in_buf, out_buf, len, + afl->queue_cur->exec_cksum)) { - res = input_to_state_stage(afl, in_buf, out_buf, len, - afl->queue_cur->exec_cksum); + goto abandon_entry; } - if (unlikely(res)) { goto abandon_entry; } - } /* Skip right away if -d is given, if it has not been chosen sufficiently @@ -2293,18 +2133,8 @@ havoc_stage: if (actually_clone) { - if (unlikely(afl->taint_needs_splode)) { - - clone_len = choose_block_len(afl, afl->queue_cur->len); - clone_from = - rand_below(afl, afl->queue_cur->len - clone_len + 1); - - } else { - - clone_len = choose_block_len(afl, temp_len); - clone_from = rand_below(afl, temp_len - clone_len + 1); - - } + clone_len = choose_block_len(afl, temp_len); + clone_from = rand_below(afl, temp_len - clone_len + 1); } else { @@ -2326,11 +2156,7 @@ havoc_stage: if (actually_clone) { - if (unlikely(afl->taint_needs_splode)) - memcpy(new_buf + clone_to, afl->taint_src + clone_from, - clone_len); - else - memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); + memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); } else { @@ -2342,7 +2168,7 @@ havoc_stage: } /* Tail */ - memmove(new_buf + clone_to + clone_len, out_buf + clone_to, + memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); @@ -2363,49 +2189,16 @@ havoc_stage: if (temp_len < 2) { break; } - if (unlikely(afl->taint_needs_splode)) { - - copy_len = choose_block_len(afl, afl->queue_cur->len - 1); - copy_from = rand_below(afl, afl->queue_cur->len - copy_len + 1); - copy_to = rand_below(afl, temp_len + 1); - - } else { + copy_len = choose_block_len(afl, temp_len - 1); - copy_len = choose_block_len(afl, temp_len - 1); - copy_from = rand_below(afl, temp_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); - - } + copy_from = rand_below(afl, temp_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); if (rand_below(afl, 4)) { if (copy_from != copy_to) { - if (unlikely(afl->taint_needs_splode)) { - - if (temp_len >= (s32)(copy_to + copy_len)) { - - memcpy(out_buf + copy_to, afl->taint_src + copy_from, - copy_len); - - } else { - - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - copy_to + copy_len); - memcpy(new_buf, in_buf, copy_to); - memcpy(new_buf + copy_to, afl->taint_src + copy_from, - copy_len); - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); - out_buf = new_buf; - temp_len = copy_to + copy_len; - - } - - } else { - - memmove(out_buf + copy_to, out_buf + copy_from, copy_len); - - } + memmove(out_buf + copy_to, out_buf + copy_from, copy_len); } @@ -2671,17 +2464,10 @@ havoc_stage: splices them together at some offset, then relies on the havoc code to mutate that blob. */ - u32 saved_len; - - if (unlikely(afl->taint_needs_splode)) - saved_len = afl->taint_len; - else - saved_len = afl->queue_cur->len; - retry_splicing: if (afl->use_splicing && splice_cycle++ < SPLICE_CYCLES && - afl->queued_paths > 1 && saved_len > 1) { + afl->queued_paths > 1 && afl->queue_cur->len > 1) { struct queue_entry *target; u32 tid, split_at; @@ -2694,7 +2480,7 @@ retry_splicing: if (in_buf != orig_in) { in_buf = orig_in; - len = saved_len; + len = afl->queue_cur->len; } @@ -2765,8 +2551,6 @@ retry_splicing: ret_val = 0; - goto abandon_entry; - /* we are through with this queue entry - for this iteration */ abandon_entry: @@ -2786,17 +2570,7 @@ abandon_entry: ++afl->queue_cur->fuzz_level; - if (unlikely(afl->taint_needs_splode)) { - - munmap(afl->taint_src, afl->queue_cur->len); - munmap(orig_in, afl->taint_len); - munmap(afl->taint_map, afl->queue_cur->len); - - } else { - - munmap(orig_in, afl->queue_cur->len); - - } + munmap(orig_in, afl->queue_cur->len); return ret_val; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 43794018..f35df914 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -103,169 +103,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { } -void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname, - u8 *mem, u32 len) { - - u8 * ptr, *fn = fname; - u32 bytes = 0, plen = len; - struct queue_entry *prev = q->prev; - - if (plen % 4) plen = plen + 4 - (len % 4); - - if ((ptr = strrchr(fname, '/')) != NULL) fn = ptr + 1; - q->fname_taint = alloc_printf("%s/taint/%s", afl->out_dir, fn); - - if (q->fname_taint) { - - u8 *save = ck_maybe_grow(BUF_PARAMS(out_scratch), afl->fsrv.map_size); - memcpy(save, afl->taint_fsrv.trace_bits, afl->fsrv.map_size); - - afl->taint_fsrv.map_size = plen; // speed :) - write_to_testcase(afl, mem, len); - if (afl_fsrv_run_target(&afl->taint_fsrv, afl->fsrv.exec_tmout * 4, - &afl->stop_soon) == 0) { - - bytes = q->taint_bytes_all = - count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen); - if (afl->debug) - fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, len); - - /* DEBUG FIXME TODO XXX */ - u32 i; - for (i = 0; i < len; i++) { - - if (afl->taint_fsrv.trace_bits[i] && - afl->taint_fsrv.trace_bits[i] != '!') - FATAL("invalid taint map value %02x at pos %d", - afl->taint_fsrv.trace_bits[i], i); - - } - - if (len < plen) - for (i = len; i < plen; i++) { - - if (afl->taint_fsrv.trace_bits[i]) - FATAL("invalid taint map value %02x in padding at pos %d", - afl->taint_fsrv.trace_bits[i], i); - - } - - } - - // if all is tainted we do not need to write taint data away - if (bytes && bytes < len) { - - // save the bytes away - int w = open(q->fname_taint, O_CREAT | O_WRONLY, 0644); - if (w >= 0) { - - ck_write(w, afl->taint_fsrv.trace_bits, len, q->fname_taint); - close(w); - - // find the highest tainted offset in the input (for trim opt) - s32 i = len; - while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1]) - i--; - q->taint_bytes_highest = i; - - afl->taint_count++; - - } else { - - FATAL("could not create %s", q->fname_taint); - q->taint_bytes_all = bytes = 0; - - } - - // it is possible that there is no main taint file - if the whole file - // is tainted - but a .new taint file if it had new tainted bytes - - // check if there is a previous queue entry and if it had taint - if (bytes && prev && prev->taint_bytes_all && - prev->taint_bytes_all < prev->len) { - - // check if there are new bytes in the taint vs the previous - int r = open(prev->fname_taint, O_RDONLY); - - if (r >= 0) { - - u8 *bufr = mmap(0, prev->len, PROT_READ, MAP_PRIVATE, r, 0); - - if ((ssize_t)bufr != -1) { - - u32 i; - u8 *tmp = ck_maybe_grow(BUF_PARAMS(in_scratch), plen); - memset(tmp, 0, plen); - - for (i = 0; i < len; i++) - if (afl->taint_fsrv.trace_bits[i] && (i >= prev->len || !bufr[i])) - tmp[i] = '!'; - - q->taint_bytes_new = count_bytes_len(afl, tmp, plen); - - if (afl->debug) - fprintf(stderr, "Debug: %u new taint out of %u bytes\n", bytes, - len); - - if (q->taint_bytes_new) { - - u8 *fnw = alloc_printf("%s.new", q->fname_taint); - if (fnw) { - - int w = open(fnw, O_CREAT | O_WRONLY, 0644); - if (w >= 0) { - - ck_write(w, tmp, plen, fnw); - close(w); - - } else { - - FATAL("count not create '%s'", fnw); - q->taint_bytes_new = 0; - - } - - ck_free(fnw); - - } else { - - q->taint_bytes_new = 0; - - } - - } - - munmap(bufr, prev->len); - - } - - close(r); - - } - - } - - } - - memcpy(afl->taint_fsrv.trace_bits, save, afl->fsrv.map_size); - - } - - if (!bytes) { - - q->taint_bytes_highest = q->taint_bytes_all = q->taint_bytes_new = 0; - - if (q->fname_taint) { - - ck_free(q->fname_taint); - q->fname_taint = NULL; - - } - - } - -} - /* check if ascii or UTF-8 */ static u8 check_if_text(struct queue_entry *q) { @@ -375,12 +212,10 @@ static u8 check_if_text(struct queue_entry *q) { /* Append new test case to the queue. */ -void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len, - struct queue_entry *prev_q, u8 passed_det) { +void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { struct queue_entry *q = ck_alloc(sizeof(struct queue_entry)); - q->prev = prev_q; q->fname = fname; q->len = len; q->depth = afl->cur_depth + 1; @@ -419,13 +254,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len, afl->last_path_time = get_cur_time(); - /* trigger the tain gathering if this is not a dry run */ - if (afl->taint_mode && mem) { perform_taint_run(afl, q, fname, mem, len); } - - /* only redqueen currently uses is_ascii */ - if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q); - - /* run custom mutators afl_custom_queue_new_entry() */ if (afl->custom_mutators_count) { LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { @@ -445,6 +273,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len, } + /* only redqueen currently uses is_ascii */ + if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q); + } /* Destroy the entire queue. */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 5381723d..d3f823c9 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -350,9 +350,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } - if (unlikely(afl->taint_mode)) - q->exec_cksum = 0; - else if (q->exec_cksum) { + if (q->exec_cksum) { memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); hnb = has_new_bits(afl, afl->virgin_bits); @@ -755,65 +753,56 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { while (remove_pos < q->len) { u32 trim_avail = MIN(remove_len, q->len - remove_pos); + u64 cksum; - if (likely((!q->taint_bytes_highest) || - (q->len - trim_avail > q->taint_bytes_highest))) { + write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); - u64 cksum; + fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + ++afl->trim_execs; - write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); + if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } - fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); - ++afl->trim_execs; - - if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } - - /* Note that we don't keep track of crashes or hangs here; maybe TODO? - */ - - cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - - /* If the deletion had no impact on the trace, make it permanent. This - isn't perfect for variable-path inputs, but we're just making a - best-effort pass, so it's not a big deal if we end up with false - negatives every now and then. */ - - if (cksum == q->exec_cksum) { + /* Note that we don't keep track of crashes or hangs here; maybe TODO? + */ - u32 move_tail = q->len - remove_pos - trim_avail; + cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - q->len -= trim_avail; - len_p2 = next_pow2(q->len); + /* If the deletion had no impact on the trace, make it permanent. This + isn't perfect for variable-path inputs, but we're just making a + best-effort pass, so it's not a big deal if we end up with false + negatives every now and then. */ - memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, - move_tail); + if (cksum == q->exec_cksum) { - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ + u32 move_tail = q->len - remove_pos - trim_avail; - if (!needs_write) { + q->len -= trim_avail; + len_p2 = next_pow2(q->len); - needs_write = 1; - memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); + memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, + move_tail); - } + /* Let's save a clean trace, which will be needed by + update_bitmap_score once we're done with the trimming stuff. */ - } else { + if (!needs_write) { - remove_pos += remove_len; + needs_write = 1; + memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } - /* Since this can be slow, update the screen every now and then. */ - if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } - ++afl->stage_cur; - } else { remove_pos += remove_len; } + /* Since this can be slow, update the screen every now and then. */ + + if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } + ++afl->stage_cur; + } remove_len >>= 1; @@ -866,8 +855,6 @@ abort_trimming: } -#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size - /* Write a modified test case, run program, process results. Handle error conditions, returning 1 if it's time to bail out. This is a helper function for fuzz_one(). */ @@ -877,32 +864,6 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { u8 fault; - if (unlikely(afl->taint_needs_splode)) { - - s32 new_len = afl->queue_cur->len + len - afl->taint_len; - if (new_len < 4) - new_len = 4; - else if (new_len > MAX_FILE) - new_len = MAX_FILE; - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), new_len); - - u32 i, taint = 0; - for (i = 0; i < (u32)new_len; i++) { - - if (i >= afl->taint_len || i >= afl->queue_cur->len || afl->taint_map[i]) - new_buf[i] = out_buf[taint++]; - else - new_buf[i] = afl->taint_src[i]; - - } - - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); - - out_buf = new_buf; - len = new_len; - - } - write_to_testcase(afl, out_buf, len); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); @@ -950,5 +911,3 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { } -#undef BUF_PARAMS - diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index a8416eb1..d4de91a4 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -75,7 +75,7 @@ static list_t afl_states = {.element_prealloc_count = 0}; /* Initializes an afl_state_t. */ -void afl_state_init_1(afl_state_t *afl, uint32_t map_size) { +void afl_state_init(afl_state_t *afl, uint32_t map_size) { /* thanks to this memset, growing vars like out_buf and out_size are NULL/0 by default. */ @@ -100,6 +100,16 @@ void afl_state_init_1(afl_state_t *afl, uint32_t map_size) { afl->cpu_aff = -1; /* Selected CPU core */ #endif /* HAVE_AFFINITY */ + afl->virgin_bits = ck_alloc(map_size); + afl->virgin_tmout = ck_alloc(map_size); + afl->virgin_crash = ck_alloc(map_size); + afl->var_bytes = ck_alloc(map_size); + afl->top_rated = ck_alloc(map_size * sizeof(void *)); + afl->clean_trace = ck_alloc(map_size); + afl->clean_trace_custom = ck_alloc(map_size); + afl->first_trace = ck_alloc(map_size); + afl->map_tmp_buf = ck_alloc(map_size); + afl->fsrv.use_stdin = 1; afl->fsrv.map_size = map_size; // afl_state_t is not available in forkserver.c @@ -151,24 +161,6 @@ void afl_state_init_1(afl_state_t *afl, uint32_t map_size) { } -void afl_state_init_2(afl_state_t *afl, uint32_t map_size) { - - afl->shm.map_size = map_size ? map_size : MAP_SIZE; - - afl->virgin_bits = ck_alloc(map_size); - afl->virgin_tmout = ck_alloc(map_size); - afl->virgin_crash = ck_alloc(map_size); - afl->var_bytes = ck_alloc(map_size); - afl->top_rated = ck_alloc(map_size * sizeof(void *)); - afl->clean_trace = ck_alloc(map_size); - afl->clean_trace_custom = ck_alloc(map_size); - afl->first_trace = ck_alloc(map_size); - afl->map_tmp_buf = ck_alloc(map_size); - - afl->fsrv.map_size = map_size; - -} - /*This sets up the environment variables for afl-fuzz into the afl_state * struct*/ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 0cc06e12..aeb290bd 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -116,7 +116,6 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, "edges_found : %u\n" "var_byte_count : %u\n" "havoc_expansion : %u\n" - "tainted_inputs : %u\n" "afl_banner : %s\n" "afl_version : " VERSION "\n" @@ -150,8 +149,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #else -1, #endif - t_bytes, afl->var_byte_count, afl->expand_havoc, afl->taint_count, - afl->use_banner, afl->unicorn_mode ? "unicorn" : "", + t_bytes, afl->var_byte_count, afl->expand_havoc, 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 " : "", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 106aa550..5dd092f2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -53,9 +53,6 @@ static void at_exit() { ptr = getenv("__AFL_TARGET_PID2"); if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); - ptr = getenv("__AFL_TARGET_PID3"); - if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL); - i = 0; while (list[i] != NULL) { @@ -92,8 +89,6 @@ static void usage(u8 *argv0, int more_help) { " -o dir - output directory for fuzzer findings\n\n" "Execution control settings:\n" - " -A - use first level taint analysis (see " - "qemu_taint/README.md)\n" " -p schedule - power schedules compute a seed's performance score. " "debug = 1; } map_size = get_map_size(); - afl_state_init_1(afl, map_size); + afl_state_init(afl, map_size); afl->debug = debug; afl_fsrv_init(&afl->fsrv); @@ -283,15 +277,10 @@ int main(int argc, char **argv_orig, char **envp) { while ((opt = getopt( argc, argv, - "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QANUWe:p:s:V:E:L:hRP:")) > 0) { + "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > 0) { switch (opt) { - case 'A': - afl->taint_mode = 1; - if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; } - break; - case 'I': afl->infoexec = optarg; break; @@ -499,7 +488,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!optarg) { FATAL("Wrong usage of -m"); } - if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) { + if (!strcmp(optarg, "none")) { afl->fsrv.mem_limit = 0; break; @@ -829,15 +818,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->taint_mode && afl->fsrv.map_size < MAX_FILE) { - - real_map_size = map_size; - map_size = MAX_FILE; - - } - - afl_state_init_2(afl, map_size); - if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" " @@ -845,7 +825,8 @@ int main(int argc, char **argv_orig, char **envp) { OKF("afl++ is open source, get it at " "https://github.com/AFLplusplus/AFLplusplus"); OKF("Power schedules from github.com/mboehme/aflfast"); - OKF("Python Mutator from github.com/choller/afl"); + OKF("Python Mutator and llvm_mode instrument file list from " + "github.com/choller/afl"); OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->is_main_node && @@ -891,19 +872,6 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); } if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); } if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); } - if (afl->taint_mode) { FATAL("-A and -n are mutually exclusive"); } - - } - - if (afl->limit_time_sig != 0 && afl->taint_mode) { - - FATAL("-A and -L are mutually exclusive"); - - } - - if (afl->unicorn_mode != 0 && afl->taint_mode) { - - FATAL("-A and -U are mutually exclusive"); } @@ -1004,7 +972,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_preload) { - if (afl->fsrv.qemu_mode || afl->taint_mode) { + if (afl->fsrv.qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -1100,13 +1068,6 @@ int main(int argc, char **argv_orig, char **envp) { afl->fsrv.trace_bits = afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); - if (real_map_size && map_size != real_map_size) { - - afl->fsrv.map_size = real_map_size; - if (afl->cmplog_binary) afl->cmplog_fsrv.map_size = real_map_size; - - } - if (!afl->in_bitmap) { memset(afl->virgin_bits, 255, afl->fsrv.map_size); } memset(afl->virgin_tmout, 255, afl->fsrv.map_size); memset(afl->virgin_crash, 255, afl->fsrv.map_size); @@ -1262,6 +1223,7 @@ int main(int argc, char **argv_orig, char **envp) { ACTF("Spawning cmplog forkserver"); afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv); + // TODO: this is semi-nice afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; @@ -1272,70 +1234,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->taint_mode) { - - ACTF("Spawning qemu_taint forkserver"); - - u8 *disable = getenv("AFL_DISABLE_LLVM_INSTRUMENTATION"); - setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); - - afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv); - afl->taint_fsrv.taint_mode = 1; - afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits; - - ck_free(afl->taint_fsrv.target_path); - afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind)); - afl->taint_fsrv.target_path = find_afl_binary("afl-qemu-taint", argv[0]); - afl->argv_taint[0] = find_afl_binary("afl-qemu-taint", argv[0]); - if (!afl->argv_taint[0]) - FATAL( - "Cannot find 'afl-qemu-taint', read qemu_taint/README.md on how to " - "build it."); - u32 idx = optind - 1, offset = 0; - do { - - idx++; - offset++; - afl->argv_taint[offset] = argv[idx]; - - } while (argv[idx] != NULL); - - if (afl->fsrv.use_stdin) - unsetenv("AFL_TAINT_INPUT"); - else - setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1); - afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon, - afl->afl_env.afl_debug_child_output); - - afl->taint_input_file = alloc_printf("%s/taint/.input", afl->out_dir); - int fd = open(afl->taint_input_file, O_CREAT | O_TRUNC | O_RDWR, 0644); - if (fd < 0) - FATAL("Cannot create taint inpu file '%s'", afl->taint_input_file); - lseek(fd, MAX_FILE, SEEK_SET); - ck_write(fd, "\0", 1, afl->taint_input_file); - - if (!disable) unsetenv("AFL_DISABLE_LLVM_INSTRUMENTATION"); - - OKF("Taint forkserver successfully started"); - - const rlim_t kStackSize = 128L * 1024L * 1024L; // min stack size = 128 Mb - struct rlimit rl; - rl.rlim_cur = kStackSize; - if (getrlimit(RLIMIT_STACK, &rl) != 0) - WARNF("Setting a higher stack size failed!"); - - #define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size - u8 *tmp1 = ck_maybe_grow(BUF_PARAMS(eff), MAX_FILE + 4096); - u8 *tmp2 = ck_maybe_grow(BUF_PARAMS(ex), MAX_FILE + 4096); - u8 *tmp3 = ck_maybe_grow(BUF_PARAMS(in_scratch), MAX_FILE + 4096); - u8 *tmp4 = ck_maybe_grow(BUF_PARAMS(out), MAX_FILE + 4096); - u8 *tmp5 = ck_maybe_grow(BUF_PARAMS(out_scratch), MAX_FILE + 4096); - #undef BUF_PARAMS - if (!tmp1 || !tmp2 || !tmp3 || !tmp4 || !tmp5) - FATAL("memory issues. me hungry, feed me!"); - - } - perform_dry_run(afl); cull_queue(afl); @@ -1410,7 +1308,7 @@ int main(int argc, char **argv_orig, char **envp) { break; case 1: if (afl->limit_time_sig == 0 && !afl->custom_only && - !afl->python_only && !afl->taint_mode) { + !afl->python_only) { afl->limit_time_sig = -1; afl->limit_time_puppet = 0; @@ -1598,11 +1496,8 @@ stop_fuzzing: } - if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv); - if (afl->taint_mode) afl_fsrv_deinit(&afl->taint_fsrv); afl_fsrv_deinit(&afl->fsrv); if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } - if (afl->argv_taint) { ck_free(afl->argv_taint); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); ck_free(afl->sync_id); -- cgit 1.4.1 From 7470b475a9b5e65afa78ca493867d8c980bd66db Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 18 Aug 2020 00:50:52 +0200 Subject: Reworked maybe_grow to take a single ptr, renamed to afl_realloc (#505) * maybe_grow takes a single ptr * fixed use_deflate * reworked maybe_grow_bufsize * helper to access underlying buf * remove redundant realloc_block * code format * fixes * added unit tests * renamed maybe_grow to afl_realloc * BUF_PARAMS -> AFL_BUF_PARAM --- custom_mutators/radamsa/custom_mutator_helpers.h | 2 +- examples/afl_network_proxy/afl-network-server.c | 34 +++-- examples/custom_mutators/custom_mutator_helpers.h | 4 +- include/afl-fuzz.h | 25 ++- include/alloc-inl.h | 177 ++++++++++------------ src/afl-fuzz-extras.c | 12 +- src/afl-fuzz-mutators.c | 3 +- src/afl-fuzz-one.c | 79 ++++++---- src/afl-fuzz-python.c | 20 ++- src/afl-fuzz-queue.c | 7 +- src/afl-fuzz-redqueen.c | 8 +- src/afl-fuzz-run.c | 7 +- src/afl-fuzz-state.c | 14 +- test/unittests/unit_maybe_alloc.c | 109 +++++++++---- 14 files changed, 272 insertions(+), 229 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h index 0848321f..e23c0b6a 100644 --- a/custom_mutators/radamsa/custom_mutator_helpers.h +++ b/custom_mutators/radamsa/custom_mutator_helpers.h @@ -324,7 +324,7 @@ static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { } /* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void swap_bufs(void **buf1, size_t *size1, void **buf2, +static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, size_t *size2) { void * scratch_buf = *buf1; diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index ab7874fd..c70fd47d 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -73,9 +73,8 @@ static u8 *in_file, /* Minimizer input test case */ static u8 *in_data; /* Input data for trimming */ static u8 *buf2; -static s32 in_len; -static u32 map_size = MAP_SIZE; -static size_t buf2_len; +static s32 in_len; +static u32 map_size = MAP_SIZE; static volatile u8 stop_soon; /* Ctrl-C pressed? */ @@ -272,7 +271,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("QEMU_SET_ENV", buf, 1); - ck_free(buf); + afl_free(buf); } else { @@ -343,7 +342,7 @@ static void usage(u8 *argv0) { } -int recv_testcase(int s, void **buf, size_t *max_len) { +int recv_testcase(int s, void **buf) { u32 size; s32 ret; @@ -358,7 +357,8 @@ int recv_testcase(int s, void **buf, size_t *max_len) { if ((size & 0xff000000) != 0xff000000) { - *buf = ck_maybe_grow(buf, max_len, size); + *buf = afl_realloc((void **)&buf, size); + if (unlikely(!buf)) { PFATAL("Alloc"); } received = 0; // fprintf(stderr, "unCOMPRESS (%u)\n", size); while (received < size && @@ -370,7 +370,8 @@ int recv_testcase(int s, void **buf, size_t *max_len) { #ifdef USE_DEFLATE u32 clen; size -= 0xff000000; - *buf = ck_maybe_grow(buf, max_len, size); + *buf = afl_realloc((void **)&buf, size); + if (unlikely(!buf)) { PFATAL("Alloc"); } received = 0; while (received < 4 && (ret = recv(s, &clen + received, 4 - received, 0)) > 0) @@ -379,15 +380,15 @@ int recv_testcase(int s, void **buf, size_t *max_len) { // fprintf(stderr, "received clen information of %d\n", clen); if (clen < 1) FATAL("did not receive valid compressed len information: %u", clen); - buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, clen); + buf2 = afl_realloc((void **)&buf2, clen); + if (unlikely(!buf2)) { PFATAL("Alloc"); } received = 0; while (received < clen && (ret = recv(s, buf2 + received, clen - received, 0)) > 0) received += ret; if (received != clen) FATAL("did not receive compressed information"); if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf, - *max_len, - &received) != LIBDEFLATE_SUCCESS) + size, &received) != LIBDEFLATE_SUCCESS) FATAL("decompression failed"); // fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received); // for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]); @@ -413,7 +414,6 @@ int recv_testcase(int s, void **buf, size_t *max_len) { int main(int argc, char **argv_orig, char **envp) { s32 opt, s, sock, on = 1, port = -1; - size_t max_len = 0; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; char **use_argv; struct sockaddr_in6 serveraddr, clientaddr; @@ -568,7 +568,8 @@ int main(int argc, char **argv_orig, char **envp) { sharedmem_t shm = {0}; fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); - in_data = ck_maybe_grow((void **)&in_data, &max_len, 65536); + in_data = afl_realloc((void **)&in_data, 65536); + if (unlikely(!in_data)) { PFATAL("Alloc"); } atexit(at_exit_handler); setup_signal_handlers(); @@ -639,7 +640,8 @@ int main(int argc, char **argv_orig, char **envp) { #ifdef USE_DEFLATE compressor = libdeflate_alloc_compressor(1); decompressor = libdeflate_alloc_decompressor(); - buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, map_size + 16); + buf2 = afl_realloc((void **)&buf2, map_size + 16); + if (unlikely(!buf2)) { PFATAL("alloc"); } lenptr = (u32 *)(buf2 + 4); fprintf(stderr, "Compiled with compression support\n"); #endif @@ -664,7 +666,7 @@ int main(int argc, char **argv_orig, char **envp) { #endif - while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) { + while ((in_len = recv_testcase(s, (void **)&in_data)) > 0) { // fprintf(stderr, "received %u\n", in_len); (void)run_target(fsrv, use_argv, in_data, in_len, 1); @@ -697,9 +699,9 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_deinit(&shm); afl_fsrv_deinit(fsrv); if (fsrv->target_path) { ck_free(fsrv->target_path); } - if (in_data) { ck_free(in_data); } + afl_free(in_data); #if USE_DEFLATE - if (buf2) { ck_free(buf2); } + afl_free(buf2); libdeflate_free_compressor(compressor); libdeflate_free_decompressor(decompressor); #endif diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h index 0848321f..ad5acb08 100644 --- a/examples/custom_mutators/custom_mutator_helpers.h +++ b/examples/custom_mutators/custom_mutator_helpers.h @@ -324,8 +324,8 @@ static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { } /* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { +static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, + size_t *size2) { void * scratch_buf = *buf1; size_t scratch_size = *size1; diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index ca7d10fe..dca395aa 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -126,6 +126,9 @@ #define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */ +// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc. +#define AFL_BUF_PARAM(name) ((void **)&afl->name##_buf) + extern s8 interesting_8[INTERESTING_8_LEN]; extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN]; extern s32 @@ -572,7 +575,6 @@ typedef struct afl_state { // growing buf struct queue_entry **queue_buf; - size_t queue_size; struct queue_entry **top_rated; /* Top entries for bitmap bytes */ @@ -633,24 +635,18 @@ typedef struct afl_state { /*needed for afl_fuzz_one */ // TODO: see which we can reuse - u8 * out_buf; - size_t out_size; + u8 *out_buf; - u8 * out_scratch_buf; - size_t out_scratch_size; + u8 *out_scratch_buf; - u8 * eff_buf; - size_t eff_size; + u8 *eff_buf; - u8 * in_buf; - size_t in_size; + u8 *in_buf; - u8 * in_scratch_buf; - size_t in_scratch_size; + u8 *in_scratch_buf; - u8 * ex_buf; - size_t ex_size; - u32 custom_mutators_count; + u8 *ex_buf; + u32 custom_mutators_count; list_t custom_mutator_list; @@ -666,7 +662,6 @@ struct custom_mutator { char * name_short; void * dh; u8 * post_process_buf; - size_t post_process_size; u8 stacked_custom_prob, stacked_custom; void *data; /* custom mutator data ptr */ diff --git a/include/alloc-inl.h b/include/alloc-inl.h index 306cc622..90701d18 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -30,12 +30,13 @@ #include #include #include +#include #include "config.h" #include "types.h" #include "debug.h" -/* Initial size used for ck_maybe_grow */ +/* Initial size used for afl_realloc */ #define INITIAL_GROWTH_SIZE (64) // Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators @@ -76,10 +77,6 @@ \ } while (0) - /* Allocator increments for ck_realloc_block(). */ - - #define ALLOC_BLK_INC 256 - /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized requests. */ @@ -149,15 +146,6 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) { } -/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up - repeated small reallocs without complicating the user code). */ - -static inline void *DFL_ck_realloc_block(void *orig, u32 size) { - - return DFL_ck_realloc(orig, size); - -} - /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */ static inline u8 *DFL_ck_strdup(u8 *str) { @@ -183,7 +171,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) { #define ck_alloc DFL_ck_alloc #define ck_alloc_nozero DFL_ck_alloc_nozero #define ck_realloc DFL_ck_realloc - #define ck_realloc_block DFL_ck_realloc_block #define ck_strdup DFL_ck_strdup #define ck_free DFL_ck_free @@ -239,10 +226,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) { #define ALLOC_OFF_HEAD 8 #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1) - /* Allocator increments for ck_realloc_block(). */ - - #define ALLOC_BLK_INC 256 - /* Sanity-checking macros for pointers. */ #define CHECK_PTR(_p) \ @@ -402,29 +385,6 @@ static inline void *DFL_ck_realloc(void *orig, u32 size) { } -/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up - repeated small reallocs without complicating the user code). */ - -static inline void *DFL_ck_realloc_block(void *orig, u32 size) { - - #ifndef DEBUG_BUILD - - if (orig) { - - CHECK_PTR(orig); - - if (ALLOC_S(orig) >= size) return orig; - - size += ALLOC_BLK_INC; - - } - - #endif /* !DEBUG_BUILD */ - - return DFL_ck_realloc(orig, size); - -} - /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */ static inline u8 *DFL_ck_strdup(u8 *str) { @@ -458,7 +418,6 @@ static inline u8 *DFL_ck_strdup(u8 *str) { #define ck_alloc DFL_ck_alloc #define ck_alloc_nozero DFL_ck_alloc_nozero #define ck_realloc DFL_ck_realloc - #define ck_realloc_block DFL_ck_realloc_block #define ck_strdup DFL_ck_strdup #define ck_free DFL_ck_free @@ -528,8 +487,8 @@ static inline void TRK_alloc_buf(void *ptr, const char *file, const char *func, /* No space available - allocate more. */ - TRK[bucket] = DFL_ck_realloc_block( - TRK[bucket], (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); + TRK[bucket] = DFL_ck_realloc(TRK[bucket], + (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); TRK[bucket][i].ptr = ptr; TRK[bucket][i].file = (char *)file; @@ -604,16 +563,6 @@ static inline void *TRK_ck_realloc(void *orig, u32 size, const char *file, } -static inline void *TRK_ck_realloc_block(void *orig, u32 size, const char *file, - const char *func, u32 line) { - - void *ret = DFL_ck_realloc_block(orig, size); - TRK_free_buf(orig, file, func, line); - TRK_alloc_buf(ret, file, func, line); - return ret; - -} - static inline void *TRK_ck_strdup(u8 *str, const char *file, const char *func, u32 line) { @@ -641,9 +590,6 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, #define ck_realloc(_p1, _p2) \ TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) - #define ck_realloc_block(_p1, _p2) \ - TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) - #define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__) #define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__) @@ -657,11 +603,14 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, */ static inline size_t next_pow2(size_t in) { - if (in == 0 || in > (size_t)-1) { - - return 0; /* avoid undefined behaviour under-/overflow */ + // Commented this out as this behavior doesn't change, according to unittests + // if (in == 0 || in > (size_t)-1) { - } + // + // return 0; /* avoid undefined behaviour under-/overflow + // */ + // + // } size_t out = in - 1; out |= out >> 1; @@ -673,32 +622,32 @@ static inline size_t next_pow2(size_t in) { } -/* This function makes sure *size is > size_needed after call. - It will realloc *buf otherwise. - *size will grow exponentially as per: - https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL and free *buf if size_needed is <1 or realloc failed. - @return For convenience, this function returns *buf. - */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { +/* AFL alloc buffer, the struct is here so we don't need to do fancy ptr + * arithmetics */ +struct afl_alloc_buf { - /* No need to realloc */ - if (likely(size_needed && *size >= size_needed)) { return *buf; } + /* The complete allocated size, including the header of len + * AFL_ALLOC_SIZE_OFFSET */ + size_t complete_size; + /* ptr to the first element of the actual buffer */ + u8 buf[0]; - /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; } +}; - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); +#define AFL_ALLOC_SIZE_OFFSET (offsetof(struct afl_alloc_buf, buf)) - /* handle overflow and zero size_needed */ - if (!next_size) { next_size = size_needed; } +/* Returs the container element to this ptr */ +static inline struct afl_alloc_buf *afl_alloc_bufptr(void *buf) { - /* alloc */ - *buf = realloc(*buf, next_size); - *size = *buf ? next_size : 0; + return (struct afl_alloc_buf *)((u8 *)buf - AFL_ALLOC_SIZE_OFFSET); - return *buf; +} + +/* Gets the maximum size of the buf contents (ptr->complete_size - + * AFL_ALLOC_SIZE_OFFSET) */ +static inline size_t afl_alloc_bufsize(void *buf) { + + return afl_alloc_bufptr(buf)->complete_size - AFL_ALLOC_SIZE_OFFSET; } @@ -706,45 +655,71 @@ static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { It will realloc *buf otherwise. *size will grow exponentially as per: https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will FATAL if size_needed is <1. + Will return NULL and free *buf if size_needed is <1 or realloc failed. @return For convenience, this function returns *buf. */ -static inline void *ck_maybe_grow(void **buf, size_t *size, - size_t size_needed) { +static inline void *afl_realloc(void **buf, size_t size_needed) { + + struct afl_alloc_buf *new_buf = NULL; - /* Oops. found a bug? */ - if (unlikely(size_needed < 1)) { FATAL("cannot grow to non-positive size"); } + size_t current_size = 0; + size_t next_size = 0; + + if (likely(*buf)) { + + /* the size is always stored at buf - 1*size_t */ + new_buf = afl_alloc_bufptr(*buf); + current_size = new_buf->complete_size; + + } + + size_needed += AFL_ALLOC_SIZE_OFFSET; /* No need to realloc */ - if (likely(*size >= size_needed)) { return *buf; } + if (likely(current_size >= size_needed)) { return *buf; } /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) { size_needed = INITIAL_GROWTH_SIZE; } + if (size_needed < INITIAL_GROWTH_SIZE) { - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); + next_size = INITIAL_GROWTH_SIZE; - /* handle overflow */ - if (!next_size) { next_size = size_needed; } + } else { + + /* grow exponentially */ + next_size = next_pow2(size_needed); + + /* handle overflow: fall back to the original size_needed */ + if (unlikely(!next_size)) { next_size = size_needed; } + + } /* alloc */ - *buf = ck_realloc(*buf, next_size); - *size = next_size; + new_buf = realloc(new_buf, next_size); + if (unlikely(!new_buf)) { + *buf = NULL; + return NULL; + + } + + new_buf->complete_size = next_size; + *buf = (void *)(new_buf->buf); return *buf; } +static inline void afl_free(void *buf) { + + if (buf) { free(afl_alloc_bufptr(buf)); } + +} + /* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { +static inline void afl_swap_bufs(void **buf1, void **buf2) { - void * scratch_buf = *buf1; - size_t scratch_size = *size1; + void *scratch_buf = *buf1; *buf1 = *buf2; - *size1 = *size2; *buf2 = scratch_buf; - *size2 = scratch_size; } diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 17f02984..88262a98 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -152,8 +152,10 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, /* Okay, let's allocate memory and copy data between "...", handling \xNN escaping, \\, and \". */ - afl->extras = ck_realloc_block( - afl->extras, (afl->extras_cnt + 1) * sizeof(struct extra_data)); + afl->extras = + afl_realloc((void **)&afl->extras, + (afl->extras_cnt + 1) * sizeof(struct extra_data)); + if (unlikely(!afl->extras)) { PFATAL("alloc"); } wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr); @@ -296,8 +298,10 @@ void load_extras(afl_state_t *afl, u8 *dir) { if (min_len > st.st_size) { min_len = st.st_size; } if (max_len < st.st_size) { max_len = st.st_size; } - afl->extras = ck_realloc_block( - afl->extras, (afl->extras_cnt + 1) * sizeof(struct extra_data)); + afl->extras = + afl_realloc((void **)&afl->extras, + (afl->extras_cnt + 1) * sizeof(struct extra_data)); + if (unlikely(!afl->extras)) { PFATAL("alloc"); } afl->extras[afl->extras_cnt].data = ck_alloc(st.st_size); afl->extras[afl->extras_cnt].len = st.st_size; diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 0fa646f9..22578df9 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -122,9 +122,8 @@ void destroy_custom_mutators(afl_state_t *afl) { if (el->post_process_buf) { - ck_free(el->post_process_buf); + afl_free(el->post_process_buf); el->post_process_buf = NULL; - el->post_process_size = 0; } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 0a4be320..3bf0c195 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -364,8 +364,6 @@ 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 - /* 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. */ @@ -384,9 +382,6 @@ u8 fuzz_one_original(afl_state_t *afl) { u8 a_collect[MAX_AUTO_EXTRA]; u32 a_len = 0; -/* Not pretty, but saves a lot of writing */ -#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size - #ifdef IGNORE_FINDS /* In IGNORE_FINDS mode, skip any entries that weren't in the @@ -484,7 +479,8 @@ u8 fuzz_one_original(afl_state_t *afl) { single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } afl->subseq_tmouts = 0; @@ -800,7 +796,8 @@ u8 fuzz_one_original(afl_state_t *afl) { /* Initialize effector map for the next step (see comments below). Always flag first and last byte as doing something. */ - eff_map = ck_maybe_grow(BUF_PARAMS(eff), EFF_ALEN(len)); + eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len)); + if (unlikely(!eff_map)) { PFATAL("alloc"); } eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { @@ -1557,7 +1554,8 @@ skip_interest: orig_hit_cnt = new_hit_cnt; - ex_tmp = ck_maybe_grow(BUF_PARAMS(ex), len + MAX_DICT_FILE); + ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE); + if (unlikely(!ex_tmp)) { PFATAL("alloc"); } for (i = 0; i <= (u32)len; ++i) { @@ -1733,7 +1731,8 @@ custom_mutator_stage: fd = open(target->fname, O_RDONLY); if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len); + new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } ck_read(fd, new_buf, target->len, target->fname); close(fd); @@ -1908,7 +1907,8 @@ havoc_stage: temp_len = new_len; if (out_buf != custom_havoc_buf) { - ck_maybe_grow(BUF_PARAMS(out), temp_len); + afl_realloc(AFL_BUF_PARAM(out), temp_len); + if (unlikely(!afl->out_buf)) { PFATAL("alloc"); } memcpy(out_buf, custom_havoc_buf, temp_len); } @@ -2147,7 +2147,8 @@ havoc_stage: clone_to = rand_below(afl, temp_len); new_buf = - ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); + afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } /* Head */ @@ -2172,7 +2173,7 @@ havoc_stage: memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); out_buf = new_buf; new_buf = NULL; temp_len += clone_len; @@ -2287,7 +2288,8 @@ havoc_stage: if (temp_len + extra_len >= MAX_FILE) { break; } - out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } /* Tail */ memmove(out_buf + insert_at + extra_len, out_buf + insert_at, @@ -2343,7 +2345,8 @@ havoc_stage: } u32 new_len = target->len; - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + u8 *new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), new_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } ck_read(fd, new_buf, new_len, target->fname); @@ -2383,7 +2386,8 @@ havoc_stage: clone_to = rand_below(afl, temp_len); u8 *temp_buf = - ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); + afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); + if (unlikely(!temp_buf)) { PFATAL("alloc"); } /* Head */ @@ -2397,7 +2401,7 @@ havoc_stage: memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); out_buf = temp_buf; temp_len += clone_len; @@ -2418,7 +2422,8 @@ havoc_stage: /* out_buf might have been mangled a bit, so let's restore it to its original size and shape. */ - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } temp_len = len; memcpy(out_buf, in_buf, len); @@ -2513,7 +2518,8 @@ retry_splicing: if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } - new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), target->len); + new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } ck_read(fd, new_buf, target->len, target->fname); @@ -2535,10 +2541,11 @@ retry_splicing: len = target->len; memcpy(new_buf, in_buf, split_at); - swap_bufs(BUF_PARAMS(in), BUF_PARAMS(in_scratch)); + afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); goto custom_mutator_stage; @@ -2679,7 +2686,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } afl->subseq_tmouts = 0; @@ -3001,7 +3009,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { /* Initialize effector map for the next step (see comments below). Always flag first and last byte as doing something. */ - eff_map = ck_maybe_grow(BUF_PARAMS(eff), EFF_ALEN(len)); + eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len)); + if (unlikely(!eff_map)) { PFATAL("alloc"); } eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { @@ -3758,7 +3767,8 @@ skip_interest: orig_hit_cnt = new_hit_cnt; - ex_tmp = ck_maybe_grow(BUF_PARAMS(ex), len + MAX_DICT_FILE); + ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE); + if (unlikely(!ex_tmp)) { PFATAL("alloc"); } for (i = 0; i <= (u32)len; ++i) { @@ -4196,8 +4206,9 @@ pacemaker_fuzzing: clone_to = rand_below(afl, temp_len); - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - temp_len + clone_len); + new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), + temp_len + clone_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } /* Head */ @@ -4223,7 +4234,7 @@ pacemaker_fuzzing: memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); out_buf = new_buf; temp_len += clone_len; MOpt_globals.cycles_v2[STAGE_Clone75] += 1; @@ -4340,7 +4351,8 @@ pacemaker_fuzzing: if (temp_len + extra_len >= MAX_FILE) break; - out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } /* Tail */ memmove(out_buf + insert_at + extra_len, out_buf + insert_at, @@ -4373,7 +4385,8 @@ pacemaker_fuzzing: /* out_buf might have been mangled a bit, so let's restore it to its original size and shape. */ - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } temp_len = len; memcpy(out_buf, in_buf, len); @@ -4518,7 +4531,8 @@ pacemaker_fuzzing: if (fd < 0) { PFATAL("Unable to open '%s'", target->fname); } - new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), target->len); + new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } ck_read(fd, new_buf, target->len, target->fname); @@ -4545,9 +4559,10 @@ pacemaker_fuzzing: len = target->len; memcpy(new_buf, in_buf, split_at); - swap_bufs(BUF_PARAMS(in), BUF_PARAMS(in_scratch)); + afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); goto havoc_stage_puppet; @@ -4880,5 +4895,3 @@ u8 fuzz_one(afl_state_t *afl) { } -#undef BUF_PARAMS - diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index a077469e..e540f548 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -40,9 +40,7 @@ static void *unsupported(afl_state_t *afl, unsigned int seed) { /* sorry for this makro... it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */ - #define BUF_PARAMS(name) \ - (void **)&((py_mutator_t *)py_mutator)->name##_buf, \ - &((py_mutator_t *)py_mutator)->name##_size + #define BUF_PARAMS(name) (void **)&((py_mutator_t *)py_mutator)->name##_buf static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, u8 *add_buf, size_t add_buf_size, size_t max_size) { @@ -97,7 +95,8 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, mutated_size = PyByteArray_Size(py_value); - *out_buf = ck_maybe_grow(BUF_PARAMS(fuzz), mutated_size); + *out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size); + if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size); Py_DECREF(py_value); @@ -317,7 +316,6 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, mutator = ck_alloc(sizeof(struct custom_mutator)); mutator->post_process_buf = NULL; - mutator->post_process_size = 0; mutator->name = module_name; ACTF("Loading Python mutator library from '%s'...", module_name); @@ -419,7 +417,11 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size, py_out_buf_size = PyByteArray_Size(py_value); - ck_maybe_grow(BUF_PARAMS(post_process), py_out_buf_size); + if (unlikely(!afl_realloc(BUF_PARAMS(post_process), py_out_buf_size))) { + + PFATAL("alloc"); + + } memcpy(py->post_process_buf, PyByteArray_AsString(py_value), py_out_buf_size); @@ -527,7 +529,8 @@ size_t trim_py(void *py_mutator, u8 **out_buf) { if (py_value != NULL) { ret = PyByteArray_Size(py_value); - *out_buf = ck_maybe_grow(BUF_PARAMS(trim), ret); + *out_buf = afl_realloc(BUF_PARAMS(trim), ret); + if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(*out_buf, PyByteArray_AsString(py_value), ret); Py_DECREF(py_value); @@ -592,7 +595,8 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size, } else { /* A new buf is needed... */ - *out_buf = ck_maybe_grow(BUF_PARAMS(havoc), mutated_size); + *out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size); + if (unlikely(!out_buf)) { PFATAL("alloc"); } } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f35df914..0c472845 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -26,8 +26,6 @@ #include #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. */ @@ -248,8 +246,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } - struct queue_entry **queue_buf = ck_maybe_grow( - BUF_PARAMS(queue), afl->queued_paths * sizeof(struct queue_entry *)); + struct queue_entry **queue_buf = afl_realloc( + AFL_BUF_PARAM(queue), afl->queued_paths * sizeof(struct queue_entry *)); + if (unlikely(!queue_buf)) { PFATAL("alloc"); } queue_buf[afl->queued_paths - 1] = q; afl->last_path_time = get_cur_time(); diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index f21dd0b0..1ae6ab54 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -313,8 +313,6 @@ static unsigned long long strntoull(const char *str, size_t sz, char **end, } -#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size - static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 pattern, u64 repl, u64 o_pattern, u32 idx, u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse, @@ -358,7 +356,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, 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 = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } memcpy(new_buf, buf, idx); snprintf(new_buf + idx, num_len, "%lld", num); @@ -371,7 +370,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, 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 = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } memcpy(new_buf, buf, idx); snprintf(new_buf + idx, num_len, "%llu", unum); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index d3f823c9..d71ec339 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -135,8 +135,6 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) { } -#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size - /* The same, but with an adjustable gap. Used for trimming. */ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, @@ -149,7 +147,8 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, This memory is used to carry out the post_processing(if present) after copying the testcase by removing the gaps. This can break though */ - u8 *mem_trimmed = ck_maybe_grow(BUF_PARAMS(out_scratch), len - skip_len + 1); + u8 *mem_trimmed = afl_realloc(AFL_BUF_PARAM(out_scratch), len - skip_len + 1); + if (unlikely(!mem_trimmed)) { PFATAL("alloc"); } ssize_t new_size = len - skip_len; void * new_mem = mem; @@ -288,8 +287,6 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } -#undef BUF_PARAMS - /* Calibrate a new test case. This is done when processing the input directory to warn about flaky or otherwise problematic test cases early on; and when new paths are discovered to detect variable behavior and so on. */ diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index d4de91a4..e68e7786 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -421,13 +421,13 @@ 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); } - if (afl->in_buf) { free(afl->in_buf); } - if (afl->in_scratch_buf) { free(afl->in_scratch_buf); } - if (afl->ex_buf) { free(afl->ex_buf); } + afl_free(afl->queue_buf); + afl_free(afl->out_buf); + afl_free(afl->out_scratch_buf); + afl_free(afl->eff_buf); + afl_free(afl->in_buf); + afl_free(afl->in_scratch_buf); + afl_free(afl->ex_buf); ck_free(afl->virgin_bits); ck_free(afl->virgin_tmout); diff --git a/test/unittests/unit_maybe_alloc.c b/test/unittests/unit_maybe_alloc.c index 889ced8a..e452e2f2 100644 --- a/test/unittests/unit_maybe_alloc.c +++ b/test/unittests/unit_maybe_alloc.c @@ -42,7 +42,24 @@ int __wrap_printf(const char *format, ...) { return 1; } -#define BUF_PARAMS (void **)&buf, &size +#define VOID_BUF (void **)&buf + +static void *create_fake_maybe_grow_of(size_t size) { + + size += AFL_ALLOC_SIZE_OFFSET; + + // fake a realloc buf + + struct afl_alloc_buf *buf = malloc(size); + if (!buf) { + perror("Could not allocate fake buf"); + return NULL; + } + buf->complete_size = size; // The size + void *actual_buf = (void *)(buf->buf); + return actual_buf; + +} /* static int setup(void **state) { @@ -52,29 +69,55 @@ static int setup(void **state) { } */ +static void test_pow2(void **state) { + (void)state; + + assert_int_equal(next_pow2(64), 64); + assert_int_equal(next_pow2(63), 64); + assert_int_not_equal(next_pow2(65), 65); + assert_int_equal(next_pow2(0x100), 0x100); + assert_int_equal(next_pow2(0x180), 0x200); + assert_int_equal(next_pow2(108), 0x80); + assert_int_equal(next_pow2(0), 0); + assert_int_equal(next_pow2(1), 1); + assert_int_equal(next_pow2(2), 2); + assert_int_equal(next_pow2(3), 4); + assert_int_equal(next_pow2(0xFFFFFF), 0x1000000); + assert_int_equal(next_pow2(0xFFFFFFF), 0x10000000); + assert_int_equal(next_pow2(0xFFFFFF0), 0x10000000); + assert_int_equal(next_pow2(SIZE_MAX), 0); + assert_int_equal(next_pow2(-1), 0); + assert_int_equal(next_pow2(-2), 0); + +} + static void test_null_allocs(void **state) { (void)state; void *buf = NULL; - size_t size = 0; - void *ptr = ck_maybe_grow(BUF_PARAMS, 100); + void *ptr = afl_realloc(VOID_BUF, 100); + if (unlikely(!buf)) { PFATAL("alloc"); } + size_t size = afl_alloc_bufsize(buf); assert_true(buf == ptr); assert_true(size >= 100); - ck_free(ptr); + afl_free(ptr); } static void test_nonpow2_size(void **state) { (void)state; - char *buf = ck_alloc(150); - size_t size = 150; + char *buf = create_fake_maybe_grow_of(150); + buf[140] = '5'; - char *ptr = ck_maybe_grow(BUF_PARAMS, 160); + + char *ptr = afl_realloc(VOID_BUF, 160); + if (unlikely(!ptr)) { PFATAL("alloc"); } + size_t size = afl_alloc_bufsize(buf); assert_ptr_equal(buf, ptr); assert_true(size >= 160); assert_true(buf[140] == '5'); - ck_free(ptr); + afl_free(ptr); } @@ -83,32 +126,37 @@ static void test_zero_size(void **state) { char *buf = NULL; size_t size = 0; - assert_non_null(maybe_grow(BUF_PARAMS, 0)); - free(buf); + char *new_buf = afl_realloc(VOID_BUF, 0); + assert_non_null(new_buf); + assert_ptr_equal(buf, new_buf); + afl_free(buf); buf = NULL; size = 0; - char *ptr = ck_maybe_grow(BUF_PARAMS, 100); + char *ptr = afl_realloc(VOID_BUF, 100); + if (unlikely(!ptr)) { PFATAL("alloc"); } + size = afl_alloc_bufsize(buf); assert_non_null(ptr); assert_ptr_equal(buf, ptr); assert_true(size >= 100); - expect_assert_failure(ck_maybe_grow(BUF_PARAMS, 0)); - - ck_free(ptr); + afl_free(ptr); } + static void test_unchanged_size(void **state) { (void)state; - void *buf = ck_alloc(100); - size_t size = 100; - void *buf_before = buf; - void *buf_after = ck_maybe_grow(BUF_PARAMS, 100); - assert_ptr_equal(buf, buf_after); + // fake a realloc buf + void *actual_buf = create_fake_maybe_grow_of(100); + + void *buf_before = actual_buf; + void *buf_after = afl_realloc(&actual_buf, 100); + if (unlikely(!buf_after)) { PFATAL("alloc"); } + assert_ptr_equal(actual_buf, buf_after); assert_ptr_equal(buf_after, buf_before); - ck_free(buf); + afl_free(buf_after); } @@ -118,29 +166,35 @@ static void test_grow_multiple(void **state) { char *buf = NULL; size_t size = 0; - char *ptr = ck_maybe_grow(BUF_PARAMS, 100); + char *ptr = afl_realloc(VOID_BUF, 100); + if (unlikely(!ptr)) { PFATAL("alloc"); } + size = afl_alloc_bufsize(ptr); assert_ptr_equal(ptr, buf); assert_true(size >= 100); - assert_int_equal(size, next_pow2(size)); + assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET); buf[50] = '5'; - ptr = (char *)ck_maybe_grow(BUF_PARAMS, 1000); + ptr = (char *)afl_realloc(VOID_BUF, 1000); + if (unlikely(!ptr)) { PFATAL("alloc"); } + size = afl_alloc_bufsize(ptr); assert_ptr_equal(ptr, buf); assert_true(size >= 100); - assert_int_equal(size, next_pow2(size)); + assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET); buf[500] = '5'; - ptr = (char *)ck_maybe_grow(BUF_PARAMS, 10000); + ptr = (char *)afl_realloc(VOID_BUF, 10000); + if (unlikely(!ptr)) { PFATAL("alloc"); } + size = afl_alloc_bufsize(ptr); assert_ptr_equal(ptr, buf); assert_true(size >= 10000); - assert_int_equal(size, next_pow2(size)); + assert_int_equal(size, next_pow2(size) - AFL_ALLOC_SIZE_OFFSET); buf[5000] = '5'; assert_int_equal(buf[50], '5'); assert_int_equal(buf[500], '5'); assert_int_equal(buf[5000], '5'); - ck_free(buf); + afl_free(buf); } @@ -157,6 +211,7 @@ int main(int argc, char **argv) { (void)argv; const struct CMUnitTest tests[] = { + cmocka_unit_test(test_pow2), cmocka_unit_test(test_null_allocs), cmocka_unit_test(test_nonpow2_size), cmocka_unit_test(test_zero_size), -- cgit 1.4.1 From 1a94cfe2af023a33c0a0defa5933541731136922 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 18 Aug 2020 01:31:40 +0200 Subject: moved autodict extras away from extras_a --- include/afl-fuzz.h | 1 + include/forkserver.h | 2 +- src/afl-forkserver.c | 4 +-- src/afl-fuzz-extras.c | 98 ++++++++++++++++++++++++++++++++++++++++----------- src/afl-fuzz-state.c | 2 +- 5 files changed, 82 insertions(+), 25 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index dca395aa..c04ba396 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -913,6 +913,7 @@ u8 has_new_bits(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); +void add_extra(afl_state_t *afl, u8 *mem, u32 len); void maybe_add_auto(afl_state_t *, u8 *, u32); void save_auto(afl_state_t *); void load_auto(afl_state_t *); diff --git a/include/forkserver.h b/include/forkserver.h index 0a7390ed..d824c1c9 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -91,7 +91,7 @@ typedef struct afl_forkserver { u8 *afl_ptr; /* for autodictionary: afl ptr */ - void (*autodict_func)(void *afl_ptr, u8 *mem, u32 len); + void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len); } afl_forkserver_t; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 25983f26..85450e4a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -630,7 +630,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { - if (fsrv->autodict_func == NULL || fsrv->afl_ptr == NULL) { + if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { // this is not afl-fuzz - we deny and return if (fsrv->use_shmem_fuzz) { @@ -715,7 +715,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, while (offset < (u32)status && (u8)dict[offset] + offset < (u32)status) { - fsrv->autodict_func(fsrv->afl_ptr, dict + offset + 1, + fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, (u8)dict[offset]); offset += (1 + dict[offset]); count++; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 88262a98..77a6c05e 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -227,6 +227,38 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, } +static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, u8 *dir) { + + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; + + if (!afl->extras_cnt) { + FATAL("No usable files in '%s'", dir); } + + qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), + compare_extras_len); + + OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt, + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len), + stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len)); + + if (max_len > 32) { + + WARNF("Some tokens are relatively large (%s) - consider trimming.", + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len)); + + } + + if (afl->extras_cnt > MAX_DET_EXTRAS) { + + WARNF("More than %d tokens - will use them probabilistically.", + MAX_DET_EXTRAS); + + } + +} + + + /* Read extras from the extras directory and sort them by size. */ void load_extras(afl_state_t *afl, u8 *dir) { @@ -256,7 +288,8 @@ void load_extras(afl_state_t *afl, u8 *dir) { if (errno == ENOTDIR) { load_extras_file(afl, dir, &min_len, &max_len, dict_level); - goto check_and_sort; + extras_check_and_sort(afl, min_len, max_len, dir); + return; } @@ -321,44 +354,67 @@ void load_extras(afl_state_t *afl, u8 *dir) { closedir(d); -check_and_sort: + extras_check_and_sort(afl, min_len, max_len, dir); - if (!afl->extras_cnt) { FATAL("No usable files in '%s'", dir); } +} - qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), - compare_extras_len); +/* Helper function for maybe_add_auto(afl, ) */ - OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt, - stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len), - stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len)); +static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { - if (max_len > 32) { + while (len--) { - WARNF("Some tokens are relatively large (%s) - consider trimming.", - stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len)); + if (tolower(*(m1++)) ^ tolower(*(m2++))) { return 1; } } - if (afl->extras_cnt > MAX_DET_EXTRAS) { + return 0; - WARNF("More than %d tokens - will use them probabilistically.", - MAX_DET_EXTRAS); +} - } +/* Adds a new extra / dict entry. */ +void add_extra(afl_state_t *afl, u8 *mem, u32 len) { -} + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; -/* Helper function for maybe_add_auto(afl, ) */ + if (len > MAX_DICT_FILE) { -static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { + FATAL( + "Extra '%.*s' is too big (%s, limit is %s)", (int)len, mem, + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len), + stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); - while (len--) { + } else if (len > 32) { - if (tolower(*(m1++)) ^ tolower(*(m2++))) { return 1; } + WARNF( + "Extra '%.*s' is pretty large, consider trimming.", (int)len, mem + ); } - return 0; + afl->extras = + afl_realloc((void **)&afl->extras, + (afl->extras_cnt + 1) * sizeof(struct extra_data)); + if (unlikely(!afl->extras)) { PFATAL("alloc"); } + + afl->extras[afl->extras_cnt].data = ck_alloc(len); + afl->extras[afl->extras_cnt].len = len; + + memcpy(afl->extras[afl->extras_cnt].data, mem, len); + + afl->extras_cnt++; + + qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), + compare_extras_len); + + /* We only want to print this once */ + + if (afl->extras_cnt == MAX_DET_EXTRAS + 1) { + + WARNF("More than %d tokens - will use them probabilistically.", + MAX_DET_EXTRAS); + + } } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index e68e7786..7e9f15b7 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -114,7 +114,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->fsrv.map_size = map_size; // afl_state_t is not available in forkserver.c afl->fsrv.afl_ptr = (void *)afl; - afl->fsrv.autodict_func = (void (*)(void *, u8 *, u32)) & maybe_add_auto; + afl->fsrv.add_extra_func = (void (*)(void *, u8 *, u32)) &add_extra; afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; -- cgit 1.4.1 From 47878f697485e0543ce9e5d81369aa1ecc56e55e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 21 Aug 2020 23:33:35 +0200 Subject: add execs_done to plot file --- docs/Changelog.md | 1 + include/afl-fuzz.h | 2 +- src/afl-fuzz-stats.c | 17 ++++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index d00d59d7..8bbb4e19 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,7 @@ sending a mail to . - afl-fuzz: - Fix for auto dictionary entries found during fuzzing to not throw out a -x dictionary + - added total execs done to plot file - llvm_mode: - Ported SanCov to LTO, and made it the default for LTO. better instrumentation locations diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c04ba396..1deeddd3 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -624,7 +624,7 @@ typedef struct afl_state { /* plot file saves from last run */ u32 plot_prev_qp, plot_prev_pf, plot_prev_pnf, plot_prev_ce, plot_prev_md; - u64 plot_prev_qc, plot_prev_uc, plot_prev_uh; + u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed; u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs; double stats_avg_exec; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index aeb290bd..0ce35cb7 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -206,7 +206,8 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { afl->plot_prev_qc == afl->queue_cycle && afl->plot_prev_uc == afl->unique_crashes && afl->plot_prev_uh == afl->unique_hangs && - afl->plot_prev_md == afl->max_depth) || + afl->plot_prev_md == afl->max_depth && + afl->plot_prev_ed == afl->fsrv.total_execs) || unlikely(!afl->queue_cycle) || unlikely(get_cur_time() - afl->start_time <= 60)) { @@ -222,6 +223,7 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { afl->plot_prev_uc = afl->unique_crashes; afl->plot_prev_uh = afl->unique_hangs; afl->plot_prev_md = afl->max_depth; + afl->plot_prev_ed = afl->fsrv.total_execs; /* Fields in the file: @@ -229,12 +231,13 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { favored_not_fuzzed, afl->unique_crashes, afl->unique_hangs, afl->max_depth, execs_per_sec */ - fprintf(afl->fsrv.plot_file, - "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n", - get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry, - afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, - bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, - eps); /* ignore errors */ + fprintf( + afl->fsrv.plot_file, + "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu\n", + get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry, + afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, + bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, + afl->plot_prev_ed); /* ignore errors */ fflush(afl->fsrv.plot_file); -- cgit 1.4.1 From 1301552101af899557a93a7535d8a57874fe6edf Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sun, 23 Aug 2020 01:48:36 +0200 Subject: added AFL_MAX_DET_EXTRAS env var --- include/afl-fuzz.h | 5 +++-- include/envs.h | 1 + src/afl-forkserver.c | 2 +- src/afl-fuzz-extras.c | 8 ++++---- src/afl-fuzz-one.c | 16 ++++++++-------- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 19 +++++++++++++++++-- 7 files changed, 41 insertions(+), 17 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1deeddd3..148e6e84 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -353,7 +353,7 @@ typedef struct afl_env_vars { 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; + *afl_hang_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras; } afl_env_vars_t; @@ -506,7 +506,8 @@ typedef struct afl_state { useless_at_start, /* Number of useless starting paths */ var_byte_count, /* Bitmap bytes with var behavior */ current_entry, /* Current queue entry ID */ - havoc_div; /* Cycle count divisor for havoc */ + havoc_div, /* Cycle count divisor for havoc */ + max_det_extras; /* deterministic extra count (dicts)*/ u64 total_crashes, /* Total number of crashes */ unique_crashes, /* Crashes with unique signatures */ diff --git a/include/envs.h b/include/envs.h index 96ae91ba..4d50d0ff 100644 --- a/include/envs.h +++ b/include/envs.h @@ -102,6 +102,7 @@ static char *afl_environment_variables[] = { "AFL_NO_X86", // not really an env but we dont want to warn on it "AFL_MAP_SIZE", "AFL_MAPSIZE", + "AFL_MAX_DET_EXTRAS", "AFL_PATH", "AFL_PERFORMANCE_FILE", "AFL_PRELOAD", diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 52a14602..9d9e81cd 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -115,7 +115,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->out_file = NULL; fsrv_to->init_child_func = fsrv_exec_child; - //Note: do not copy ->add_extra_func + // Note: do not copy ->add_extra_func list_append(&fsrv_list, fsrv_to); diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 1452c55e..03c5152a 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -248,10 +248,10 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, } - if (afl->extras_cnt > MAX_DET_EXTRAS) { + if (afl->extras_cnt > afl->max_det_extras) { WARNF("More than %d tokens - will use them probabilistically.", - MAX_DET_EXTRAS); + afl->max_det_extras); } @@ -403,10 +403,10 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { /* We only want to print this once */ - if (afl->extras_cnt == MAX_DET_EXTRAS + 1) { + if (afl->extras_cnt == afl->max_det_extras + 1) { WARNF("More than %d tokens - will use them probabilistically.", - MAX_DET_EXTRAS); + afl->max_det_extras); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 3bf0c195..c0c036db 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1509,13 +1509,13 @@ skip_interest: for (j = 0; j < afl->extras_cnt; ++j) { - /* Skip extras probabilistically if afl->extras_cnt > MAX_DET_EXTRAS. Also - skip them if there's no room to insert the payload, if the token + /* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS. + Also skip them if there's no room to insert the payload, if the token is redundant, or if its entire span has no bytes set in the effector map. */ - if ((afl->extras_cnt > MAX_DET_EXTRAS && - rand_below(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) || + if ((afl->extras_cnt > afl->max_det_extras && + rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) || afl->extras[j].len > len - i || !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) || !memchr(eff_map + EFF_APOS(i), 1, @@ -3722,13 +3722,13 @@ skip_interest: for (j = 0; j < afl->extras_cnt; ++j) { - /* Skip extras probabilistically if afl->extras_cnt > MAX_DET_EXTRAS. Also - skip them if there's no room to insert the payload, if the token + /* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS. + Also skip them if there's no room to insert the payload, if the token is redundant, or if its entire span has no bytes set in the effector map. */ - if ((afl->extras_cnt > MAX_DET_EXTRAS && - rand_below(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) || + if ((afl->extras_cnt > afl->max_det_extras && + rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) || afl->extras[j].len > len - i || !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) || !memchr(eff_map + EFF_APOS(i), 1, diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index dd0e316c..74798584 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -349,6 +349,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_preload = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_MAX_DET_EXTRAS", + + afl_environment_variable_len)) { + + afl->afl_env.afl_max_det_extras = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 5dd092f2..664cc076 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -177,6 +177,8 @@ static void usage(u8 *argv0, int more_help) { "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" " the target was compiled for\n" + "AFL_MAX_DET_EXTRAS: if the dict/extras file contains more tokens than this threshold,\n" + " the tokens will sometimes be skipped during fuzzing.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" @@ -949,8 +951,21 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_hang_tmout) { - afl->hang_tmout = atoi(afl->afl_env.afl_hang_tmout); - if (!afl->hang_tmout) { FATAL("Invalid value of AFL_HANG_TMOUT"); } + s32 hang_tmout = atoi(afl->afl_env.afl_hang_tmout); + if (hang_tmout < 1) { FATAL("Invalid value for AFL_HANG_TMOUT"); } + afl->hang_tmout = (u32)hang_tmout; + + } + + if (afl->afl_env.afl_max_det_extras) { + + s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); + if (max_det_extras < 1) { FATAL("Invalid value for AFL_MAX_DET_EXTRAS"); } + afl->max_det_extras = (u32)max_det_extras; + + } else { + + afl->max_det_extras = MAX_DET_EXTRAS; } -- cgit 1.4.1 From 425908a00cdcaa4d49a513d283431b8b6eed0486 Mon Sep 17 00:00:00 2001 From: Marius Muench Date: Sun, 23 Aug 2020 10:39:34 +0200 Subject: Option for specifying forkserver initialization timeout via environment variable (#522) * Addition of AFL_FORKSRV_INIT_TMOUT env var This commit introduces a new environment variable which allows to specify the timespan AFL should wait for initial contact with the forkserver. This is useful for fuzz-targets requiring a rather long setup time before the actual fuzzing can be started (e.g., unicorn). * add .swp files to .gitignore * Inherit init_tmout in afl_fsrv_init_dup Without this patch, the forkserver would spawn with a timeout of 0 in cmplog mode, leading to an immediate crash. Additionally, this commit removes a spurious whitespace. * Initialize afl->fsrv.init_tmout in afl_fsrv_init Not all afl-components will need the new AFL_FORKSRV_INIT_TMOUT environment variable. Hence, it's initialized to the safe "default" value from before in afl_fsrv_init now. --- .gitignore | 1 + include/afl-fuzz.h | 3 ++- include/envs.h | 1 + include/forkserver.h | 1 + src/afl-forkserver.c | 6 ++++-- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 17 +++++++++++++++++ 7 files changed, 33 insertions(+), 3 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/.gitignore b/.gitignore index b2c2fc62..4307fc4c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .sync_tmp *.o *.so +*.swp *.pyc *.dSYM as diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 148e6e84..1f1dda3a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -353,7 +353,8 @@ typedef struct afl_env_vars { 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, *afl_max_det_extras; + *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, + *afl_max_det_extras; } afl_env_vars_t; diff --git a/include/envs.h b/include/envs.h index 4d50d0ff..c7761e19 100644 --- a/include/envs.h +++ b/include/envs.h @@ -48,6 +48,7 @@ static char *afl_environment_variables[] = { "AFL_GCC_INSTRUMENT_FILE", "AFL_GCJ", "AFL_HANG_TMOUT", + "AFL_FORKSRV_INIT_TMOUT", "AFL_HARDEN", "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IMPORT_FIRST", diff --git a/include/forkserver.h b/include/forkserver.h index d824c1c9..300ecffc 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -56,6 +56,7 @@ typedef struct afl_forkserver { u8 no_unlink; /* do not unlink cur_input */ u32 exec_tmout; /* Configurable exec timeout (ms) */ + u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ u32 snapshot; /* is snapshot feature used */ u64 mem_limit; /* Memory cap for child (MB) */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 9d9e81cd..51734579 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -79,6 +79,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->use_stdin = 1; fsrv->no_unlink = 0; fsrv->exec_tmout = EXEC_TIMEOUT; + fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT; fsrv->mem_limit = MEM_LIMIT; fsrv->out_file = NULL; @@ -101,6 +102,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->out_fd = from->out_fd; fsrv_to->dev_null_fd = from->dev_null_fd; fsrv_to->exec_tmout = from->exec_tmout; + fsrv_to->init_tmout = from->init_tmout; fsrv_to->mem_limit = from->mem_limit; fsrv_to->map_size = from->map_size; fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz; @@ -519,13 +521,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u32 time_ms = read_s32_timed(fsrv->fsrv_st_fd, &status, - fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p); + fsrv->init_tmout, stop_soon_p); if (!time_ms) { kill(fsrv->fsrv_pid, SIGKILL); - } else if (time_ms > fsrv->exec_tmout * FORK_WAIT_MULT) { + } else if (time_ms > fsrv->init_tmout) { fsrv->last_run_timed_out = 1; kill(fsrv->fsrv_pid, SIGKILL); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 74798584..a8db8578 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -356,6 +356,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_max_det_extras = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_FORKSRV_INIT_TMOUT", + + afl_environment_variable_len)) { + + afl->afl_env.afl_forksrv_init_tmout = + (u8 *) get_afl_env(afl_environment_variables[i]); + } } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 664cc076..ae5cb087 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -173,6 +173,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" + "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" @@ -969,6 +970,22 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_forksrv_init_tmout) { + + afl->fsrv.init_tmout = atoi(afl->afl_env.afl_forksrv_init_tmout); + if (!afl->fsrv.init_tmout) { + + FATAL("Invalid value of AFL_FORKSRV_INIT_TMOUT"); + + } + + } else { + + afl->fsrv.init_tmout = afl->fsrv.exec_tmout * FORK_WAIT_MULT; + + } + + if (afl->non_instrumented_mode == 2 && afl->no_forkserver) { FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); -- cgit 1.4.1 From c7f0d3066875bca0ec28e9429df40293339dc05c Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 24 Aug 2020 17:32:41 +0200 Subject: added afl_custom_fuzz_count --- GNUmakefile | 12 ++--- docs/Changelog.md | 3 ++ docs/custom_mutators.md | 9 ++++ include/afl-fuzz.h | 20 ++++++++ src/afl-forkserver.c | 2 +- src/afl-fuzz-extras.c | 4 +- src/afl-fuzz-mutators.c | 5 ++ src/afl-fuzz-one.c | 129 +++++++++++++++++++++++++++--------------------- src/afl-fuzz-python.c | 44 +++++++++++++++++ 9 files changed, 162 insertions(+), 66 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index 3c5e10ed..cae172dd 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -37,18 +37,18 @@ MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 ASAN_OPTIONS=detect_leaks=0 ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" "" -ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" CFLAGS_FLTO ?= -flto=full -else - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" - CFLAGS_FLTO ?= -flto=thin else - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + CFLAGS_FLTO ?= -flto=thin + else + ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" CFLAGS_FLTO ?= -flto + endif endif endif endif -endif ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli diff --git a/docs/Changelog.md b/docs/Changelog.md index f7bc9600..45fbd528 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -18,6 +18,9 @@ sending a mail to . dict entries without recompiling. - AFL_FORKSRV_INIT_TMOUT env variable added to control the time to wait for the forkserver to come up without the need to increase the overall timeout. + - custom mutators: + - added afl_custom_fuzz_count/fuzz_count function to allow specifying the + number of fuzz attempts for custom_fuzz - llvm_mode: - Ported SanCov to LTO, and made it the default for LTO. better instrumentation locations diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index a22c809b..75dbea21 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -32,6 +32,7 @@ performed with the custom mutator. C/C++: ```c void *afl_custom_init(afl_t *afl, unsigned int seed); +uint32_t afl_custom_fuzz_count(void *data, const u8 *buf, size_t buf_size); size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size); size_t afl_custom_post_process(void *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf); int32_t afl_custom_init_trim(void *data, uint8_t *buf, size_t buf_size); @@ -49,6 +50,9 @@ Python: def init(seed): pass +def fuzz_count(buf, add_buf, max_size): + return cnt + def fuzz(buf, add_buf, max_size): return mutated_out @@ -88,6 +92,11 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): This method determines whether the custom fuzzer should fuzz the current queue entry or not +- `fuzz_count` (optional): + + This method can be used to instruct afl-fuzz how often to perform a fuzz + attempt on this input data. + - `fuzz` (optional): This method performs custom mutations on a given input. It also accepts an diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1f1dda3a..01aa1a73 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -288,6 +288,7 @@ enum { enum { /* 00 */ PY_FUNC_INIT, + /* 01 */ PY_FUNC_FUZZ_COUNT, /* 01 */ PY_FUNC_FUZZ, /* 02 */ PY_FUNC_POST_PROCESS, /* 03 */ PY_FUNC_INIT_TRIM, @@ -679,6 +680,24 @@ struct custom_mutator { */ void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed); + /** + * This method is called just before fuzzing a queue entry with the custom + * mutator, and receives the initial buffer. It should return the number of + * fuzzes to perform. + * + * A value of 0 means no fuzzing of this queue entry. + * + * The function is now allowed to change the data. + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param buf Buffer containing the test case + * @param buf_size Size of the test case + * @return The amount of fuzzes to perform on this queue entry, 0 = skip + */ + u32 (*afl_custom_fuzz_count)(void *data, const u8 *buf, size_t buf_size); + /** * Perform custom mutations on a given input * @@ -867,6 +886,7 @@ u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf, struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *); void finalize_py_module(void *); +u32 fuzz_count_py(void *, const u8 *, size_t); size_t post_process_py(void *, u8 *, size_t, u8 **); s32 init_trim_py(void *, u8 *, size_t); s32 post_trim_py(void *, u8); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index c496975f..72f3dc3b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -634,7 +634,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { - // this is not afl-fuzz - we deny and return + // this is not afl-fuzz - or it is cmplog - we deny and return if (fsrv->use_shmem_fuzz) { status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 8cc2425f..d6c368d1 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -251,7 +251,7 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, if (afl->extras_cnt > afl->max_det_extras) { OKF("More than %d tokens - will use them probabilistically.", - afl->max_det_extras); + afl->max_det_extras); } @@ -406,7 +406,7 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { if (afl->extras_cnt == afl->max_det_extras + 1) { OKF("More than %d tokens - will use them probabilistically.", - afl->max_det_extras); + afl->max_det_extras); } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 22578df9..d24b7db9 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -166,6 +166,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { } + /* "afl_custom_fuzz_count", optional */ + mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count"); + if (!mutator->afl_custom_fuzz_count) + ACTF("optional symbol 'afl_custom_fuzz_count' not found."); + /* "afl_custom_deinit", optional for backward compatibility */ mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit"); if (!mutator->afl_custom_deinit) diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c0c036db..03c0d3a1 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1672,7 +1672,7 @@ custom_mutator_stage: if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; } - const u32 max_seed_size = MAX_FILE; + const u32 max_seed_size = MAX_FILE, saved_max = afl->stage_max; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -1680,104 +1680,119 @@ custom_mutator_stage: if (el->afl_custom_fuzz) { + if (el->afl_custom_fuzz_count) + afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len); + else + afl->stage_max = saved_max; + has_custom_fuzz = true; afl->stage_short = el->name_short; - for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; - ++afl->stage_cur) { + if (afl->stage_max) { - struct queue_entry *target; - u32 tid; - u8 * new_buf; + for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; + ++afl->stage_cur) { - retry_external_pick: - /* Pick a random other queue entry for passing to external API */ + struct queue_entry *target; + u32 tid; + u8 * new_buf; - do { + retry_external_pick: + /* Pick a random other queue entry for passing to external API */ - tid = rand_below(afl, afl->queued_paths); + do { - } while (tid == afl->current_entry && afl->queued_paths > 1); + tid = rand_below(afl, afl->queued_paths); - target = afl->queue; + } while (tid == afl->current_entry && afl->queued_paths > 1); - while (tid >= 100) { + target = afl->queue; - target = target->next_100; - tid -= 100; + while (tid >= 100) { - } - - while (tid--) { + target = target->next_100; + tid -= 100; - target = target->next; + } - } + while (tid--) { - /* Make sure that the target has a reasonable length. */ + target = target->next; - while (target && (target->len < 2 || target == afl->queue_cur) && - afl->queued_paths > 3) { + } - target = target->next; - ++afl->splicing_with; + /* Make sure that the target has a reasonable length. */ - } + while (target && (target->len < 2 || target == afl->queue_cur) && + afl->queued_paths > 3) { - if (!target) { goto retry_external_pick; } + target = target->next; + ++afl->splicing_with; - /* Read the additional testcase into a new buffer. */ - fd = open(target->fname, O_RDONLY); - if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } + } - new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - ck_read(fd, new_buf, target->len, target->fname); - close(fd); + if (!target) { goto retry_external_pick; } - u8 *mutated_buf = NULL; + /* Read the additional testcase into a new buffer. */ + fd = open(target->fname, O_RDONLY); + if (unlikely(fd < 0)) { - size_t mutated_size = - el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf, - target->len, max_seed_size); + PFATAL("Unable to open '%s'", target->fname); - if (unlikely(!mutated_buf)) { + } - FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); + new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + ck_read(fd, new_buf, target->len, target->fname); + close(fd); - } + u8 *mutated_buf = NULL; - if (mutated_size > 0) { + size_t mutated_size = + el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf, + target->len, max_seed_size); - if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { + if (unlikely(!mutated_buf)) { - goto abandon_entry; + FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); } - /* If we're finding new stuff, let's run for a bit longer, limits - permitting. */ - - if (afl->queued_paths != havoc_queued) { + if (mutated_size > 0) { - if (perf_score <= afl->havoc_max_mult * 100) { + if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { - afl->stage_max *= 2; - perf_score *= 2; + goto abandon_entry; } - havoc_queued = afl->queued_paths; + /* If we're finding new stuff, let's run for a bit longer, limits + permitting. */ + + if (afl->queued_paths != havoc_queued) { + + if (perf_score <= afl->havoc_max_mult * 100) { + + afl->stage_max *= 2; + perf_score *= 2; + + } + + havoc_queued = afl->queued_paths; + + } } - } + /* `(afl->)out_buf` may have been changed by the call to custom_fuzz + */ + /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs + * Memcpy. + */ + memcpy(out_buf, in_buf, len); - /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */ - /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy. - */ - memcpy(out_buf, in_buf, len); + } } diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index e540f548..68540dd7 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -347,6 +347,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, } + if (py_functions[PY_FUNC_FUZZ_COUNT]) { + + mutator->afl_custom_fuzz_count = fuzz_count_py; + + } + if (py_functions[PY_FUNC_POST_TRIM]) { mutator->afl_custom_post_trim = post_trim_py; @@ -477,6 +483,44 @@ s32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) { } +u32 fuzz_count_py(void *py_mutator, const u8 *buf, size_t buf_size) { + + PyObject *py_args, *py_value; + + py_args = PyTuple_New(1); + py_value = PyByteArray_FromStringAndSize(buf, buf_size); + if (!py_value) { + + Py_DECREF(py_args); + FATAL("Failed to convert arguments"); + + } + + PyTuple_SetItem(py_args, 0, py_value); + + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ_COUNT], py_args); + Py_DECREF(py_args); + + if (py_value != NULL) { + + #if PY_MAJOR_VERSION >= 3 + u32 retcnt = (u32)PyLong_AsLong(py_value); + #else + u32 retcnt = PyInt_AsLong(py_value); + #endif + Py_DECREF(py_value); + return retcnt; + + } else { + + PyErr_Print(); + FATAL("Call failed"); + + } + +} + s32 post_trim_py(void *py_mutator, u8 success) { PyObject *py_args, *py_value; -- cgit 1.4.1 From 6a34c5aa3e0a1da06a5268ecabfc92ab36ce96dc Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 24 Aug 2020 18:06:07 +0200 Subject: fix python implementation for new function --- include/afl-fuzz.h | 2 +- src/afl-fuzz-python.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 01aa1a73..91915bf6 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -288,7 +288,6 @@ enum { enum { /* 00 */ PY_FUNC_INIT, - /* 01 */ PY_FUNC_FUZZ_COUNT, /* 01 */ PY_FUNC_FUZZ, /* 02 */ PY_FUNC_POST_PROCESS, /* 03 */ PY_FUNC_INIT_TRIM, @@ -299,6 +298,7 @@ enum { /* 08 */ PY_FUNC_QUEUE_GET, /* 09 */ PY_FUNC_QUEUE_NEW_ENTRY, /* 10 */ PY_FUNC_DEINIT, + /* 11 */ PY_FUNC_FUZZ_COUNT, PY_FUNC_COUNT }; diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 68540dd7..32c8ac89 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -144,6 +144,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); if (!py_functions[PY_FUNC_FUZZ]) py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate"); + py_functions[PY_FUNC_FUZZ_COUNT] = PyObject_GetAttrString(py_module, "fuzz_count"); if (!py_functions[PY_FUNC_FUZZ]) WARNF("fuzz function not found in python module"); py_functions[PY_FUNC_POST_PROCESS] = @@ -187,7 +188,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { // Implenting the havoc and queue API is optional for now if (PyErr_Occurred()) { PyErr_Print(); } - } else { + } else if (py_idx != PY_FUNC_FUZZ_COUNT) { if (PyErr_Occurred()) { PyErr_Print(); } fprintf(stderr, -- cgit 1.4.1 From 19eddbb0c76406db6d790681ef519c4d91e8814e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 24 Aug 2020 18:12:08 +0200 Subject: make py functions as optional as they are in the doc --- include/afl-fuzz.h | 24 +++++++++++++----------- src/afl-fuzz-python.c | 18 ++++++------------ 2 files changed, 19 insertions(+), 23 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 91915bf6..24e8ca9b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -288,17 +288,19 @@ enum { enum { /* 00 */ PY_FUNC_INIT, - /* 01 */ PY_FUNC_FUZZ, - /* 02 */ PY_FUNC_POST_PROCESS, - /* 03 */ PY_FUNC_INIT_TRIM, - /* 04 */ PY_FUNC_POST_TRIM, - /* 05 */ PY_FUNC_TRIM, - /* 06 */ PY_FUNC_HAVOC_MUTATION, - /* 07 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY, - /* 08 */ PY_FUNC_QUEUE_GET, - /* 09 */ PY_FUNC_QUEUE_NEW_ENTRY, - /* 10 */ PY_FUNC_DEINIT, - /* 11 */ PY_FUNC_FUZZ_COUNT, + /* 01 */ PY_FUNC_DEINIT, + /* FROM HERE ON BELOW ALL ARE OPTIONAL */ + /* 02 */ PY_OPTIONAL = 2, + /* 02 */ PY_FUNC_FUZZ = 2, + /* 03 */ PY_FUNC_FUZZ_COUNT, + /* 04 */ PY_FUNC_POST_PROCESS, + /* 05 */ PY_FUNC_INIT_TRIM, + /* 06 */ PY_FUNC_POST_TRIM, + /* 07 */ PY_FUNC_TRIM, + /* 08 */ PY_FUNC_HAVOC_MUTATION, + /* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY, + /* 10 */ PY_FUNC_QUEUE_GET, + /* 11 */ PY_FUNC_QUEUE_NEW_ENTRY, PY_FUNC_COUNT }; diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 32c8ac89..adb92649 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -144,7 +144,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); if (!py_functions[PY_FUNC_FUZZ]) py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate"); - py_functions[PY_FUNC_FUZZ_COUNT] = PyObject_GetAttrString(py_module, "fuzz_count"); + py_functions[PY_FUNC_FUZZ_COUNT] = + PyObject_GetAttrString(py_module, "fuzz_count"); if (!py_functions[PY_FUNC_FUZZ]) WARNF("fuzz function not found in python module"); py_functions[PY_FUNC_POST_PROCESS] = @@ -170,27 +171,20 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) { - if (py_idx == PY_FUNC_POST_PROCESS) { - - // Implenting the post_process API is optional for now - if (PyErr_Occurred()) { PyErr_Print(); } - - } else if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) { + if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) { // Implementing the trim API is optional for now if (PyErr_Occurred()) { PyErr_Print(); } py_notrim = 1; - } else if ((py_idx >= PY_FUNC_HAVOC_MUTATION) && + } else if (py_idx >= PY_OPTIONAL) { - (py_idx <= PY_FUNC_QUEUE_NEW_ENTRY)) { + // Only _init and _deinit are not optional currently - // Implenting the havoc and queue API is optional for now if (PyErr_Occurred()) { PyErr_Print(); } - } else if (py_idx != PY_FUNC_FUZZ_COUNT) { + } else { - if (PyErr_Occurred()) { PyErr_Print(); } fprintf(stderr, "Cannot find/call function with index %d in external " "Python module.\n", -- cgit 1.4.1 From 96ef7083c84cbd1892233cc36bcc139f77515a19 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 26 Aug 2020 05:28:33 +0200 Subject: using unbiased rand_below --- include/afl-fuzz.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 24e8ca9b..5c391049 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1027,7 +1027,12 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { } - return rand_next(afl) % limit; + /* Modulo is biased - we don't want our fuzzing to be biased so let's do it right. */ + u64 unbiased_rnd; + do { + unbiased_rnd = rand_next(afl); + } while (unbiased_rnd >= (UINT64_MAX - (UINT64_MAX % limit))); + return unbiased_rnd % limit; } -- cgit 1.4.1 From 4be0ea596b86d4320545859c29bf0454dd765379 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 26 Aug 2020 13:04:03 +0200 Subject: rand unlikely added --- include/afl-fuzz.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5c391049..c5b01da8 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1031,7 +1031,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { u64 unbiased_rnd; do { unbiased_rnd = rand_next(afl); - } while (unbiased_rnd >= (UINT64_MAX - (UINT64_MAX % limit))); + } while (unlikely(unbiased_rnd >= (UINT64_MAX - (UINT64_MAX % limit)))); return unbiased_rnd % limit; } -- cgit 1.4.1 From 4566bcf122c251c023abce0683666921bd4df755 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 31 Aug 2020 10:57:01 +0200 Subject: code-format --- include/afl-fuzz.h | 8 ++++++-- llvm_mode/afl-clang-fast.c | 8 ++++++++ llvm_mode/afl-llvm-common.cc | 8 ++------ llvm_mode/afl-llvm-lto-instrumentation.so.cc | 8 +++----- src/afl-fuzz-init.c | 11 ++++++++--- 5 files changed, 27 insertions(+), 16 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c5b01da8..97e60347 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1027,11 +1027,15 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { } - /* Modulo is biased - we don't want our fuzzing to be biased so let's do it right. */ - u64 unbiased_rnd; + /* Modulo is biased - we don't want our fuzzing to be biased so let's do it + * right. */ + u64 unbiased_rnd; do { + unbiased_rnd = rand_next(afl); + } while (unlikely(unbiased_rnd >= (UINT64_MAX - (UINT64_MAX % limit)))); + return unbiased_rnd % limit; } diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 6ea98111..173dc268 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -812,16 +812,24 @@ int main(int argc, char **argv, char **envp) { ptr += strlen("ngram"); while (*ptr && (*ptr < '0' || *ptr > '9')) { + ptr++; + } + if (!*ptr) { + ptr = getenv("AFL_LLVM_NGRAM_SIZE"); if (!ptr || !*ptr) { + FATAL( "you must set the NGRAM size with (e.g. for value 2) " "AFL_LLVM_INSTRUMENT=ngram-2"); + } + } + ngram_size = atoi(ptr); if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) FATAL( diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc index 7dd5a02a..189b4ec6 100644 --- a/llvm_mode/afl-llvm-common.cc +++ b/llvm_mode/afl-llvm-common.cc @@ -344,14 +344,10 @@ static std::string getSourceName(llvm::Function *F) { (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) if (Loc) { - StringRef instFilename; + StringRef instFilename; DILocation *cDILoc = dyn_cast(Loc.getAsMDNode()); - if (cDILoc) { - - instFilename = cDILoc->getFilename(); - - } + if (cDILoc) { instFilename = cDILoc->getFilename(); } if (instFilename.str().empty()) { diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index c25cad9d..b8d9fce9 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -379,11 +379,9 @@ bool AFLLTOPass::runOnModule(Module &M) { else Str1 = TmpStr.str(); bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); - if (TmpStr.empty()) - HasStr2 = false; - (void) HasStr2 /* never read */ - else - Str2 = TmpStr.str(); + if (TmpStr.empty()) HasStr2 = false; + (void)HasStr2 /* never read */ + else Str2 = TmpStr.str(); if (debug) fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 7b7ba006..852fc3fb 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1843,7 +1843,8 @@ void setup_stdio_file(afl_state_t *afl) { if (afl->file_extension) { - afl->fsrv.out_file = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension); + afl->fsrv.out_file = + alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension); } else { @@ -1851,11 +1852,15 @@ void setup_stdio_file(afl_state_t *afl) { } - unlink(afl->fsrv.out_file); /* Ignore errors */ + unlink(afl->fsrv.out_file); /* Ignore errors */ afl->fsrv.out_fd = open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, 0600); - if (afl->fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", afl->fsrv.out_file); } + if (afl->fsrv.out_fd < 0) { + + PFATAL("Unable to create '%s'", afl->fsrv.out_file); + + } } -- cgit 1.4.1 From 92b1f9cf36e7df8ce4b957e503cffca7296da048 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 31 Aug 2020 12:11:38 +0200 Subject: added SO link about rand for clarification --- include/afl-fuzz.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c5b01da8..964f369d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1027,7 +1027,9 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { } - /* Modulo is biased - we don't want our fuzzing to be biased so let's do it right. */ + /* Modulo is biased - we don't want our fuzzing to be biased so let's do it right, see + https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator + */ u64 unbiased_rnd; do { unbiased_rnd = rand_next(afl); -- cgit 1.4.1 From 6adaacbb3aed2f967b4f3aeacdc41e91502914b3 Mon Sep 17 00:00:00 2001 From: Thomas Rooijakkers Date: Fri, 4 Sep 2020 15:46:46 +0200 Subject: Seperate fuzzer_setup from fuzzer_stats, only write fuzzer_setup at the start --- include/afl-fuzz.h | 10 +++--- src/afl-fuzz-stats.c | 93 +++++++++++++++++++++++++++++++++++++--------------- src/afl-fuzz.c | 1 + 3 files changed, 73 insertions(+), 31 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f3a76492..f9858669 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -945,10 +945,12 @@ void destroy_extras(afl_state_t *); /* Stats */ -void write_stats_file(afl_state_t *, double, double, double); -void maybe_update_plot_file(afl_state_t *, double, double); -void show_stats(afl_state_t *); -void show_init_stats(afl_state_t *); +FILE *open_file(const char *); +void write_fuzzer_setup_file(afl_state_t *); +void write_stats_file(afl_state_t *, double, double, double); +void maybe_update_plot_file(afl_state_t *, double, double); +void show_stats(afl_state_t *); +void show_init_stats(afl_state_t *); /* Run */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 38c954e5..45b1326c 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -27,6 +27,69 @@ #include "envs.h" #include +/* Open file for writing */ + +FILE *open_file(const char *fn) { + + s32 fd; + FILE *f; + + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd < 0) { PFATAL("Unable to create '%s'", fn); } + + f = fdopen(fd, "w"); + + if (!f) { PFATAL("fdopen() failed"); } + + return f; + +} + +/* Write fuzzer setup file */ + +void write_fuzzer_setup_file(afl_state_t *afl) { + + u8 fn[PATH_MAX]; + FILE *f; + + snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); + f = open_file(fn); + + char * val; + uint32_t i = 0; + uint32_t s_afl_env = + sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - + 1; + + uint32_t max_len = 0; + uint32_t cur_len = 0; + for (i = 0; i < s_afl_env; i++) { + + if ((val = getenv(afl_environment_variables[i])) != NULL) { + + cur_len = strlen(afl_environment_variables[i]); + max_len = cur_len > max_len ? cur_len : max_len; + + } + + } + + for (i = 0; i < s_afl_env; i++) { + + if ((val = getenv(afl_environment_variables[i])) != NULL) { + + fprintf(f, "%*.*s : %s\n", -max_len, strlen(afl_environment_variables[i]), + afl_environment_variables[i], val); + + } + + } + + fclose(f); + +} + /* Update stats file for unattended monitoring. */ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, @@ -37,20 +100,12 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #endif unsigned long long int cur_time = get_cur_time(); + u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); u8 fn[PATH_MAX]; - s32 fd; FILE * f; - u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); - - fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); - - if (fd < 0) { PFATAL("Unable to create '%s'", fn); } - - f = fdopen(fd, "w"); - - if (!f) { PFATAL("fdopen() failed"); } + f = open_file(fn); /* Keep last values in case we're called from another context where exec/sec stats and such are not readily available. */ @@ -165,27 +220,11 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, : "default", afl->orig_cmdline); - char * val; - uint32_t i = 0; - uint32_t s_afl_env = - sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - - 1; - - for (i = 0; i < s_afl_env; i++) { - - if ((val = get_afl_env(afl_environment_variables[i])) != NULL) { - - fprintf(f, "%-18.*s: %s\n", strlen(afl_environment_variables[i]), - afl_environment_variables[i], val); - - } - - } - /* ignore errors */ if (afl->debug) { + uint32_t i = 0; fprintf(f, "virgin_bytes :"); for (i = 0; i < afl->fsrv.map_size; i++) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 0df6c15c..ae060b07 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1274,6 +1274,7 @@ int main(int argc, char **argv_orig, char **envp) { seek_to = find_start_position(afl); + write_fuzzer_setup_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); -- cgit 1.4.1 From 809a7cffe2de74b048143f0820fa922c9a18aff5 Mon Sep 17 00:00:00 2001 From: Thomas Rooijakkers Date: Fri, 4 Sep 2020 16:02:09 +0200 Subject: Write set environment variables in an env file style. --- include/afl-fuzz.h | 2 +- src/afl-fuzz-stats.c | 27 ++++++--------------------- src/afl-fuzz.c | 2 +- 3 files changed, 8 insertions(+), 23 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f9858669..eebd74c7 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -946,7 +946,7 @@ void destroy_extras(afl_state_t *); /* Stats */ FILE *open_file(const char *); -void write_fuzzer_setup_file(afl_state_t *); +void write_fuzzer_config_file(afl_state_t *); void write_stats_file(afl_state_t *, double, double, double); void maybe_update_plot_file(afl_state_t *, double, double); void show_stats(afl_state_t *); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 45b1326c..298ad229 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -48,39 +48,24 @@ FILE *open_file(const char *fn) { /* Write fuzzer setup file */ -void write_fuzzer_setup_file(afl_state_t *afl) { +void write_fuzzer_config_file(afl_state_t *afl) { u8 fn[PATH_MAX]; FILE *f; - snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); + snprintf(fn, PATH_MAX, "%s/fuzzer_config", afl->out_dir); f = open_file(fn); - char * val; - uint32_t i = 0; + char *val; + uint32_t s_afl_env = sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - 1; - - uint32_t max_len = 0; - uint32_t cur_len = 0; - for (i = 0; i < s_afl_env; i++) { - - if ((val = getenv(afl_environment_variables[i])) != NULL) { - - cur_len = strlen(afl_environment_variables[i]); - max_len = cur_len > max_len ? cur_len : max_len; - - } - - } - - for (i = 0; i < s_afl_env; i++) { + for (uint32_t i = 0; i < s_afl_env; i++) { if ((val = getenv(afl_environment_variables[i])) != NULL) { - fprintf(f, "%*.*s : %s\n", -max_len, strlen(afl_environment_variables[i]), - afl_environment_variables[i], val); + fprintf(f, "%s=%s\n", afl_environment_variables[i], val); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ae060b07..e9ea8b62 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1274,7 +1274,7 @@ int main(int argc, char **argv_orig, char **envp) { seek_to = find_start_position(afl); - write_fuzzer_setup_file(afl); + write_fuzzer_config_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); -- cgit 1.4.1 From 50f61b64b1bbf2f5354bcff4f1d225965fee2d06 Mon Sep 17 00:00:00 2001 From: Thomas Rooijakkers Date: Fri, 4 Sep 2020 16:22:22 +0200 Subject: Make open_file() inline --- include/afl-fuzz.h | 11 +++++------ src/afl-fuzz-stats.c | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index eebd74c7..e3c3d5aa 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -945,12 +945,11 @@ void destroy_extras(afl_state_t *); /* Stats */ -FILE *open_file(const char *); -void write_fuzzer_config_file(afl_state_t *); -void write_stats_file(afl_state_t *, double, double, double); -void maybe_update_plot_file(afl_state_t *, double, double); -void show_stats(afl_state_t *); -void show_init_stats(afl_state_t *); +void write_fuzzer_config_file(afl_state_t *); +void write_stats_file(afl_state_t *, double, double, double); +void maybe_update_plot_file(afl_state_t *, double, double); +void show_stats(afl_state_t *); +void show_init_stats(afl_state_t *); /* Run */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 298ad229..b59a40e4 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -29,7 +29,7 @@ /* Open file for writing */ -FILE *open_file(const char *fn) { +inline FILE *open_file(const char *fn) { s32 fd; FILE *f; -- cgit 1.4.1 From 6c715f1a69f91d4336023a8ba10fb4a7e126f9c2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 4 Sep 2020 17:04:42 +0200 Subject: more changes to fuzzer_setup --- docs/Changelog.md | 6 +++-- include/afl-fuzz.h | 2 +- include/common.h | 6 +++++ src/afl-common.c | 33 +++++++++++++++++++++++++ src/afl-fuzz-stats.c | 70 ++++++++++++++++++++++++++++------------------------ src/afl-fuzz.c | 3 ++- 6 files changed, 84 insertions(+), 36 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index d1ee9656..0d93ee1f 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,7 +15,7 @@ sending a mail to . https://github.com/AFLplusplus/Grammar-Mutator - a few QOL changes for Apple and its outdated gmake - afl-fuzz: - - Fix for auto dictionary entries found during fuzzing to not throw out + - fix for auto dictionary entries found during fuzzing to not throw out a -x dictionary - added total execs done to plot file - AFL_MAX_DET_EXTRAS env variable added to control the amount of @@ -25,11 +25,13 @@ sending a mail to . timeout. - bugfix for cmplog that results in a heap overflow based on target data (thanks to the magma team for reporting!) + - write fuzzing setup into out/fuzzer_setup (environment variables and + command line) - custom mutators: - added afl_custom_fuzz_count/fuzz_count function to allow specifying the number of fuzz attempts for custom_fuzz - llvm_mode: - - Ported SanCov to LTO, and made it the default for LTO. better + - ported SanCov to LTO, and made it the default for LTO. better instrumentation locations - Further llvm 12 support (fast moving target like afl++ :-) ) - deprecated LLVM SKIPSINGLEBLOCK env environment diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e3c3d5aa..358cb5dc 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -945,7 +945,7 @@ void destroy_extras(afl_state_t *); /* Stats */ -void write_fuzzer_config_file(afl_state_t *); +void write_setup_file(afl_state_t *, int, char **); void write_stats_file(afl_state_t *, double, double, double); void maybe_update_plot_file(afl_state_t *, double, double); void show_stats(afl_state_t *); diff --git a/include/common.h b/include/common.h index 87a7425b..c364ade0 100644 --- a/include/common.h +++ b/include/common.h @@ -110,5 +110,11 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms); /* Reads the map size from ENV */ u32 get_map_size(void); +/* create a stream file */ +FILE *create_ffile(u8 *fn); + +/* create a file */ +s32 create_file(u8 *fn); + #endif diff --git a/src/afl-common.c b/src/afl-common.c index 367dec72..d66440aa 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -877,3 +877,36 @@ u32 get_map_size(void) { } +/* Create a stream file */ + +FILE *create_ffile(u8 *fn) { + + s32 fd; + FILE *f; + + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd < 0) { PFATAL("Unable to create '%s'", fn); } + + f = fdopen(fd, "w"); + + if (!f) { PFATAL("fdopen() failed"); } + + return f; + +} + +/* Create a file */ + +s32 create_file(u8 *fn) { + + s32 fd; + + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd < 0) { PFATAL("Unable to create '%s'", fn); } + + return fd; + +} + diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index b59a40e4..a84f1c7a 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -27,51 +27,57 @@ #include "envs.h" #include -/* Open file for writing */ - -inline FILE *open_file(const char *fn) { - - s32 fd; - FILE *f; - - fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); +/* Write fuzzer setup file */ - if (fd < 0) { PFATAL("Unable to create '%s'", fn); } +void write_setup_file(afl_state_t *afl, int argc, char **argv) { - f = fdopen(fd, "w"); + char *val; + u8 fn[PATH_MAX]; + snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); + FILE *f = create_ffile(fn); - if (!f) { PFATAL("fdopen() failed"); } + fprintf(f, "# environment variables:\n"); + u32 s_afl_env = + sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - + 1; + for (u32 i = 0; i < s_afl_env; i++) { - return f; + if ((val = getenv(afl_environment_variables[i])) != NULL) { -} + fprintf(f, "%s=%s\n", afl_environment_variables[i], val); -/* Write fuzzer setup file */ + } -void write_fuzzer_config_file(afl_state_t *afl) { + } - u8 fn[PATH_MAX]; - FILE *f; + fprintf(f, "# command line:\n"); - snprintf(fn, PATH_MAX, "%s/fuzzer_config", afl->out_dir); - f = open_file(fn); + s32 i; + size_t j; + for (i = 0; i < argc; i++) { - char *val; + if (i) fprintf(f, " "); + if (index(argv[i], '\'')) { - uint32_t s_afl_env = - sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - - 1; - for (uint32_t i = 0; i < s_afl_env; i++) { + fprintf(f, "'"); + for (j = 0; j < strlen(argv[i]); j++) + if (argv[i][j] == '\'') + fprintf(f, "'\"'\"'"); + else + fprintf(f, "%c", argv[i][j]); + fprintf(f, "'"); - if ((val = getenv(afl_environment_variables[i])) != NULL) { + } else { - fprintf(f, "%s=%s\n", afl_environment_variables[i], val); + fprintf(f, "'%s'", argv[i]); } } + fprintf(f, "\n"); fclose(f); + (void)(afl_environment_deprecated); } @@ -84,13 +90,13 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, struct rusage rus; #endif - unsigned long long int cur_time = get_cur_time(); - u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); - u8 fn[PATH_MAX]; - FILE * f; + u64 cur_time = get_cur_time(); + u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); + u8 fn[PATH_MAX]; + FILE *f; snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); - f = open_file(fn); + f = create_ffile(fn); /* Keep last values in case we're called from another context where exec/sec stats and such are not readily available. */ @@ -209,7 +215,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, if (afl->debug) { - uint32_t i = 0; + u32 i = 0; fprintf(f, "virgin_bytes :"); for (i = 0; i < afl->fsrv.map_size; i++) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e9ea8b62..c12d5db5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1128,6 +1128,8 @@ int main(int argc, char **argv_orig, char **envp) { setup_custom_mutators(afl); + write_setup_file(afl, argc, argv); + setup_cmdline_file(afl, argv + optind); read_testcases(afl); @@ -1274,7 +1276,6 @@ int main(int argc, char **argv_orig, char **envp) { seek_to = find_start_position(afl); - write_fuzzer_config_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); -- cgit 1.4.1 From 0625eb0a051247c7b39df987289ad9a0e089a181 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 4 Sep 2020 22:26:39 +0200 Subject: avoid signed ints for amounts (which are positive) --- include/afl-fuzz.h | 2 +- src/afl-fuzz-stats.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 358cb5dc..1a05f4f4 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -945,7 +945,7 @@ void destroy_extras(afl_state_t *); /* Stats */ -void write_setup_file(afl_state_t *, int, char **); +void write_setup_file(afl_state_t *, u32, char **); void write_stats_file(afl_state_t *, double, double, double); void maybe_update_plot_file(afl_state_t *, double, double); void show_stats(afl_state_t *); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 05cbafef..07d83f07 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -29,20 +29,20 @@ /* Write fuzzer setup file */ -void write_setup_file(afl_state_t *afl, int argc, char **argv) { +void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { char *val; u8 fn[PATH_MAX]; snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); FILE *f = create_ffile(fn); - s32 i; + u32 i; fprintf(f, "# environment variables:\n"); - s32 s_afl_env = (s32) + u32 s_afl_env = sizeof(afl_environment_variables) / sizeof(afl_environment_variables[0]) - - 1; + 1U; - for (i = 0; i < s_afl_env; i++) { + for (i = 0; i < s_afl_env; ++i) { if ((val = getenv(afl_environment_variables[i])) != NULL) { @@ -55,7 +55,7 @@ void write_setup_file(afl_state_t *afl, int argc, char **argv) { fprintf(f, "# command line:\n"); size_t j; - for (i = 0; i < argc; i++) { + for (i = 0; i < argc; ++i) { if (i) fprintf(f, " "); if (index(argv[i], '\'')) { -- cgit 1.4.1 From 4b3ad5f037ee9a36aa057bf55a69acca1f573922 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 5 Sep 2020 12:32:10 +0200 Subject: add cull queue, -i subdir traversal --- GNUmakefile | 230 ++++++++++++++++++++++++-------------------------- GNUmakefile.llvm | 7 +- README.md | 179 +++++++++++++++++++++++---------------- include/afl-fuzz.h | 6 +- src/afl-fuzz-extras.c | 113 ++++++++++++++++++++----- src/afl-fuzz-init.c | 108 +++++++++++++++++++++--- src/afl-fuzz-one.c | 31 +------ src/afl-fuzz-queue.c | 7 -- src/afl-fuzz.c | 33 +++++--- 9 files changed, 437 insertions(+), 277 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index e1f6da95..0046a481 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -24,30 +24,31 @@ BIN_PATH = $(PREFIX)/bin HELPER_PATH = $(PREFIX)/lib/afl DOC_PATH = $(PREFIX)/share/doc/afl MISC_PATH = $(PREFIX)/share/afl -MAN_PATH = $(PREFIX)/share/man/man8 +MAN_PATH = $(PREFIX)/man/man8 PROGNAME = afl VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2) # PROGS intentionally omit afl-as, which gets installed elsewhere. -PROGS = afl-gcc afl-g++ afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze +PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 +ASAN_OPTIONS=detect_leaks=0 ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" "" - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" +ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" CFLAGS_FLTO ?= -flto=full - else - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" +else + ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" CFLAGS_FLTO ?= -flto=thin - else - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + else + ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" CFLAGS_FLTO ?= -flto - endif endif endif endif +endif ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli @@ -61,10 +62,7 @@ ifneq "$(shell uname)" "Darwin" endif endif # OS X does not like _FORTIFY_SOURCE=2 - # _FORTIFY_SOURCE=2 does not like -O0 - ifndef DEBUG - CFLAGS_OPT += -D_FORTIFY_SOURCE=2 - endif + CFLAGS_OPT += -D_FORTIFY_SOURCE=2 endif ifeq "$(shell uname)" "SunOS" @@ -206,10 +204,7 @@ else endif ifneq "$(filter Linux GNU%,$(shell uname))" "" - # _FORTIFY_SOURCE=2 does not like -O0 - ifndef DEBUG override CFLAGS += -D_FORTIFY_SOURCE=2 - endif LDFLAGS += -ldl -lrt endif @@ -223,11 +218,7 @@ ifneq "$(findstring NetBSD, $(shell uname))" "" LDFLAGS += -lpthread endif -ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" - TEST_CC = afl-gcc -else - TEST_CC = afl-clang -endif +TEST_CC = afl-gcc COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h @@ -277,28 +268,47 @@ ifdef TEST_MMAP LDFLAGS += -Wno-deprecated-declarations endif -all: test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done +.PHONY: all +all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done + +.PHONY: llvm +llvm: + -$(MAKE) -f GNUmakefile.llvm + @test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; } -man: afl-gcc all $(MANPAGES) +.PHONY: gcc_plugin +gcc_plugin: + -$(MAKE) -f GNUmakefile.gcc_plugin +.PHONY: man +man: $(MANPAGES) + +.PHONY: test +test: tests + +.PHONY: tests tests: source-only @cd test ; ./test-all.sh @rm -f test/errors +.PHONY: performance-tests performance-tests: performance-test +.PHONY: test-performance test-performance: performance-test +.PHONY: performance-test performance-test: source-only @cd test ; ./test-performance.sh # hint: make targets are also listed in the top level README.md +.PHONY: help help: @echo "HELP --- the following make targets exist:" @echo "==========================================" @echo "all: just the main afl++ binaries" @echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap" - @echo "source-only: everything for source code fuzzing: llvm_mode, gcc_plugin, libdislocator, libtokencap" + @echo "source-only: everything for source code fuzzing: gcc_plugin, libdislocator, libtokencap" @echo "distrib: everything (for both binary-only and source code fuzzing)" @echo "man: creates simple man pages from the help option of the programs" @echo "install: installs everything you have compiled with the build option above" @@ -322,8 +332,8 @@ help: @echo "==========================================" @echo e.g.: make ASAN_BUILD=1 +.PHONY: test_x86 ifndef AFL_NO_X86 - test_x86: @echo "[*] Checking for the default compiler cc..." @type $(CC) >/dev/null || ( echo; echo "Oops, looks like there is no compiler '"$(CC)"' in your path."; echo; echo "Don't panic! You can restart with '"$(_)" CC='."; echo; exit 1 ) @@ -332,148 +342,129 @@ test_x86: @echo "[*] Checking for the ability to compile x86 code..." @echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) $(CFLAGS) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 ) @rm -f .test1 - else - test_x86: @echo "[!] Note: skipping x86 compilation checks (AFL_NO_X86 set)." - endif - +.PHONY: test_shm ifeq "$(SHMAT_OK)" "1" - test_shm: @echo "[+] shmat seems to be working." @rm -f .test2 - else - test_shm: @echo "[-] shmat seems not to be working, switching to mmap implementation" - endif - +.PHONY: test_python ifeq "$(PYTHON_OK)" "1" - test_python: @rm -f .test 2> /dev/null @echo "[+] $(PYTHON_VERSION) support seems to be working." - else - test_python: @echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue" - endif - +.PHONY: ready ready: @echo "[+] Everything seems to be working, ready to compile." -afl-g++: afl-gcc - -afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(CPPFLAGS) src/$@.c -o $@ $(LDFLAGS) - set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done - afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(CPPFLAGS) src/$@.c -o $@ $(LDFLAGS) - ln -sf afl-as as + $(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS) + @ln -sf afl-as as src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h - $(CC) $(CFLAGS) $(CPPFLAGS) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o + $(CC) -Iinclude $(SPECIAL_PERFORMANCE) -O3 -fno-unroll-loops -c src/afl-performance.c -o src/afl-performance.o src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h - $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-common.c -o src/afl-common.o + $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-common.c -o src/afl-common.o src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h - $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-forkserver.c -o src/afl-forkserver.o + $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-forkserver.c -o src/afl-forkserver.o src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h - $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CPPFLAGS) -c src/afl-sharedmem.c -o src/afl-sharedmem.o + $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) $(CPPFLAGS) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS) afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS) afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(CPPFLAGS) src/$@.c src/afl-common.o -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS) +.PHONY: document +document: afl-fuzz-document # document all mutations and only do one run (use with only one input file!) -document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86 - $(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) $(CPPFLAGS) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS) +afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86 + $(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS) test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES) - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o unit_maybe_alloc: test/unittests/unit_maybe_alloc.o - @$(CC) $(CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_maybe_alloc test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o unit_hash: test/unittests/unit_hash.o src/afl-performance.o - @$(CC) $(CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_hash test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_rand test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES) - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o unit_list: test/unittests/unit_list.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_list test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES) - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o unit_preallocable: test/unittests/unit_preallocable.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CPPFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_preallocable +.PHONY: unit_clean unit_clean: @rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o +.PHONY: unit ifneq "$(shell uname)" "Darwin" - -unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash - +unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash else - unit: @echo [-] unit tests are skipped on Darwin \(lacks GNU linker feature --wrap\) - endif +.PHONY: code-format code-format: ./.custom-format.py -i src/*.c ./.custom-format.py -i include/*.h ./.custom-format.py -i libdislocator/*.c ./.custom-format.py -i libtokencap/*.c - ./.custom-format.py -i llvm_mode/*.c - ./.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/*.cc + ./.custom-format.py -i instrumentation/*.h + ./.custom-format.py -i instrumentation/*.cc + ./.custom-format.py -i instrumentation/*.c ./.custom-format.py -i custom_mutators/*/*.c @#./.custom-format.py -i custom_mutators/*/*.h # destroys input.h :-( ./.custom-format.py -i examples/*/*.c @@ -489,38 +480,40 @@ code-format: ./.custom-format.py -i *.c +.PHONY: test_build ifndef AFL_NO_X86 - -test_build: afl-gcc afl-as afl-showmap +test_build: afl-cc afl-as afl-showmap @echo "[*] Testing the CC wrapper and instrumentation output..." - @unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_AS_FORCE_INSTRUMENT=1 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 ) + @unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 ) ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi + @echo @echo "[+] All right, the instrumentation seems to be working!" - else - -test_build: afl-gcc afl-as afl-showmap +test_build: afl-cc afl-as afl-showmap @echo "[!] Note: skipping build tests (you may need to use LLVM or QEMU mode)." - endif - +.PHONY: all_done all_done: test_build - @if [ ! "`type clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.md for a faster alternative to afl-gcc."; fi + @test -e afl-cc && echo "[+] Main compiler 'afl-cc' successfully built!" || { echo "[-] Main compiler 'afl-cc' failed to built, set up a working build environment first!" ; exit 1 ; } + @test -e cmplog-instructions-pass.so && echo "[+] LLVM mode for 'afl-cc' successfully built!" || echo "[-] LLVM mode for 'afl-cc' failed to built, likely you either have not llvm installed or you have not set LLVM_CONFIG pointing to e.g. llvm-config-11. See instrumenation/README.llvm.md how to do this. Highly recommended!" + @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to built, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" + @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to built, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it" @echo "[+] All done! Be sure to review the README.md - it's pretty short and useful." @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null .NOTPARALLEL: clean all +.PHONY: clean clean: - rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-gcc-rt.o afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* + rm -f $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ rm -rf out_dir qemu_mode/qemu-3.1.1 *.dSYM */*.dSYM - -$(MAKE) -C llvm_mode clean - -$(MAKE) -C gcc_plugin clean + -$(MAKE) -f GNUmakefile.llvm clean + -$(MAKE) -f GNUmakefile.gcc_plugin clean $(MAKE) -C libdislocator clean $(MAKE) -C libtokencap clean $(MAKE) -C examples/afl_network_proxy clean @@ -530,20 +523,22 @@ clean: $(MAKE) -C qemu_mode/libcompcov clean rm -rf qemu_mode/qemu-3.1.1 ifeq "$(IN_REPO)" "1" - test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true + test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true else rm -rf qemu_mode/qemu-3.1.1.tar.xz rm -rf unicorn_mode/unicornafl endif +.PHONY: deepclean deepclean: clean rm -rf qemu_mode/qemu-3.1.1.tar.xz rm -rf unicorn_mode/unicornafl git reset --hard >/dev/null 2>&1 || true +.PHONY: distrib distrib: all - -$(MAKE) -C llvm_mode - -$(MAKE) -C gcc_plugin + -$(MAKE) -f GNUmakefile.llvm + -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C libdislocator $(MAKE) -C libtokencap $(MAKE) -C examples/afl_network_proxy @@ -552,6 +547,7 @@ distrib: all -cd qemu_mode && sh ./build_qemu_support.sh cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh +.PHONY: binary-only binary-only: all $(MAKE) -C libdislocator $(MAKE) -C libtokencap @@ -561,9 +557,10 @@ binary-only: all -cd qemu_mode && sh ./build_qemu_support.sh cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh +.PHONY: source-only source-only: all - -$(MAKE) -C llvm_mode - -$(MAKE) -C gcc_plugin + -$(MAKE) -f GNUmakefile.llvm + -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C libdislocator $(MAKE) -C libtokencap @#$(MAKE) -C examples/afl_network_proxy @@ -573,8 +570,7 @@ source-only: all %.8: % @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ @echo .SH NAME >> $@ - @printf "%s" ".B $* \- " >> $@ - @./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> $@ + @echo .B $* >> $@ @echo >> $@ @echo .SH SYNOPSIS >> $@ @./$* -h 2>&1 | head -n 3 | tail -n 1 | sed 's/^\.\///' >> $@ @@ -590,30 +586,28 @@ source-only: all @echo .SH LICENSE >> $@ @echo Apache License Version 2.0, January 2004 >> $@ +.PHONY: install install: all $(MANPAGES) - install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) - rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh + @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) + @rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh + @rm -f $${DESTDIR}$(BIN_PATH)/afl-as install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH) - rm -f $${DESTDIR}$(BIN_PATH)/afl-as - if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi - if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi - if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi - if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi - if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi - if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi - if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi - if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi - if [ -f libAFLDriver.a ]; then install -m 644 libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi - if [ -f libAFLQemuDriver.a ]; then install -m 644 libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi - - set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++ - set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi - - mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH) + @if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi + @if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi + @if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi + @if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi + @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi + @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi + @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi + @if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi + @if [ -f examples/aflpp_driver/libAFLDriver.a ]; then install -m 644 examples/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi + @if [ -f examples/aflpp_driver/libAFLQemuDriver.a ]; then install -m 644 examples/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi + -$(MAKE) -f GNUmakefile.llvm install + -$(MAKE) -f GNUmakefile.gcc_plugin install + ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc + ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-g++ + @mkdir -m 0755 -p ${DESTDIR}$(MAN_PATH) install -m0644 *.8 ${DESTDIR}$(MAN_PATH) - install -m 755 afl-as $${DESTDIR}$(HELPER_PATH) ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH) diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index d4502319..d76e0b28 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -419,17 +419,14 @@ document: ./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c | test_deps $(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@ - ln -sf ./afl-compiler-rt.o ./afl-llvm-rt.o ./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 32-bit variant of the runtime (-m32)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi - @test -e ./afl-compiler-rt-32.o && ln -sf ./afl-compiler-rt-32.o ./afl-llvm-rt-32.o ./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 64-bit variant of the runtime (-m64)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi - @test -e ./afl-compiler-rt-64.o && ln -sf ./afl-compiler-rt-64.o ./afl-llvm-rt-64.o .PHONY: test_build test_build: $(PROGS) @@ -454,8 +451,8 @@ install: all @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-lto-instrumentation.so ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi - @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o; fi - @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o; fi + @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi @if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi diff --git a/README.md b/README.md index 4cad6b47..96b34260 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ ![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=stable) - Release Version: [2.68c](https://github.com/AFLplusplus/AFLplusplus/releases) + Release Version: [2.67c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 3.00a + Github Version: 2.67d Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) @@ -22,6 +22,26 @@ afl++ is a superior fork to Google's afl - more speed, more and better mutations, more and better instrumentation, custom module support, etc. +## Major changes in afl++ 3.0 + +With afl++ 3.0 we introduced changes that break some previous afl and afl++ +behaviours: + + * There are no llvm_mode and gcc_plugin subdirectories anymore and there is + only one compiler: afl-cc. All previous compilers now symlink to this one + compiler. All instrumentation source code is now in the `instrumentation/` + folder. + * qemu_mode got upgraded to QEMU 5.1, but to be able to build this a current + ninja build tool version and python3 setuptools are required. + qemu_mode also got new options like snapshotting, instrumenting specific + shared libraries, etc. and QEMU 5.1 supports more CPU targets so this is + worth it. + * When instrumenting targets, afl-cc will not supersede optimizations. This + allows to fuzz targets as same as they are built for debug or release. + * afl-fuzz' `-i` option now descends into subdirectories. + * afl-fuzz will skip over empty dictionaries and too large test cases instead + of failing. + ## Contents 1. [Features](#important-features-of-afl) @@ -39,7 +59,7 @@ with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and Android support and much, much, much more. - | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode | + | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | qemu_mode | unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:| | NeverZero | x86[_64]| x(1) | (2) | x | x | | Persistent Mode | | x | x | x86[_64]/arm[64] | x | @@ -47,9 +67,8 @@ | CmpLog | | x | | x86[_64]/arm[64] | | | Selective Instrumentation| | x | x | (x)(3) | | | Non-Colliding Coverage | | x(4) | | (x)(5) | | - | InsTrim | | x | | | | | Ngram prev_loc Coverage | | x(6) | | | | - | Context Coverage | | x | | | | + | Context Coverage | | x(6) | | | | | Auto Dictionary | | x(7) | | | | | Snapshot LKM Support | | x | | (x)(5) | | @@ -59,11 +78,11 @@ 4. with pcguard mode and LTO mode for LLVM >= 11 5. upcoming, development in the branch 6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1 - 7. only in LTO mode with LLVM >= 11 + 7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x` Among others, the following features and patches have been integrated: - * NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage + * NeverZero patch for afl-gcc, instrumentation, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage * Persistent mode, deferred forkserver and in-memory fuzzing for qemu_mode * Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk) * The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf) @@ -71,10 +90,9 @@ * AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast) * The MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL) * LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass) - * InsTrim, a CFG llvm_mode instrumentation implementation: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim) * C. Holler's afl-fuzz Python mutator module: [https://github.com/choller/afl](https://github.com/choller/afl) * Custom mutator by a library (instead of Python) by kyakdan - * LAF-Intel/CompCov support for llvm_mode, qemu_mode and unicorn_mode (with enhanced capabilities) + * LAF-Intel/CompCov support for instrumentation, qemu_mode and unicorn_mode (with enhanced capabilities) * Radamsa and honggfuzz mutators (as custom mutators). * QBDI mode to fuzz android native libraries via Quarkslab's [QBDI](https://github.com/QBDI/QBDI) framework * Frida and ptrace mode to fuzz binary-only libraries, etc. @@ -88,7 +106,7 @@ send a mail to . See [docs/QuickStartGuide.md](docs/QuickStartGuide.md) if you don't have time to - read this file. + read this file - however this is not recommended! ## Branches @@ -105,13 +123,14 @@ ## Help wanted -We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-) +We were happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/) +and we will try to participate again in 2021! We have several ideas we would like to see in AFL++ to make it even better. However, we already work on so many things that we do not have the time for all the big ideas. -This can be your way to support and contribute to AFL++ - extend it to +This can be your way to support and contribute to AFL++ - extend it to do something cool. We have an idea list in [docs/ideas.md](docs/ideas.md). @@ -132,7 +151,7 @@ This image is automatically generated when a push to the stable repo happens. You will find your target source code in /src in the container. If you want to build afl++ yourself you have many options. -The easiest is to build and install everything: +The easiest choice is to build and install everything: ```shell sudo apt install build-essential libtool-bin python3-dev automake flex bison libglib2.0-dev libpixman-1-dev clang python3-setuptools llvm @@ -142,9 +161,9 @@ sudo make install It is recommended to install the newest available gcc, clang and llvm-dev possible in your distribution! -Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and +Note that "make distrib" also builds instrumentation, qemu_mode, unicorn_mode and more. If you just want plain afl++ then do "make all", however compiling and -using at least llvm_mode is highly recommended for much better results - +using at least instrumentation is highly recommended for much better results - hence in this case ```shell @@ -156,7 +175,7 @@ These build targets exist: * all: just the main afl++ binaries * binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap -* source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap +* source-only: everything for source code fuzzing: instrumentation, libdislocator, libtokencap * distrib: everything (for both binary-only and source code fuzzing) * man: creates simple man pages from the help option of the programs * install: installs everything you have compiled with the build options above @@ -212,18 +231,19 @@ If you have a binary-only target please skip to [#Instrumenting binary-only apps Fuzzing source code is a three-step process. -1. compile the target with a special compiler that prepares the target to be +1. Compile the target with a special compiler that prepares the target to be fuzzed efficiently. This step is called "instrumenting a target". 2. Prepare the fuzzing by selecting and optimizing the input corpus for the target. -3. perform the fuzzing of the target by randomly mutating input and assessing +3. Perform the fuzzing of the target by randomly mutating input and assessing if a generated input was processed in a new path in the target binary. ### 1. Instrumenting that target #### a) Selecting the best afl++ compiler for instrumenting the target -afl++ comes with different compilers and instrumentation options. +afl++ comes with a central compiler `afl-cc` that incorporates various different +kinds of compiler targets and and instrumentation options. The following evaluation flow will help you to select the best possible. It is highly recommended to have the newest llvm version possible installed, @@ -231,49 +251,62 @@ anything below 9 is not recommended. ``` +--------------------------------+ -| clang/clang++ 11+ is available | --> use afl-clang-lto and afl-clang-lto++ -+--------------------------------+ see [llvm/README.lto.md](llvm/README.lto.md) +| clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++) ++--------------------------------+ see [instrumentation/README.lto.md](instrumentation/README.lto.md) | - | if not, or if the target fails with afl-clang-lto/++ + | if not, or if the target fails with LTO afl-clang-lto/++ | v +---------------------------------+ -| clang/clang++ 3.3+ is available | --> use afl-clang-fast and afl-clang-fast++ -+---------------------------------+ see [llvm/README.md](llvm/README.md) +| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) ++---------------------------------+ see [instrumentation/README.md](instrumentation/README.md) | - | if not, or if the target fails with afl-clang-fast/++ + | if not, or if the target fails with LLVM afl-clang-fast/++ | v +--------------------------------+ - | if you want to instrument only | -> use afl-gcc-fast and afl-gcc-fast++ - | parts of the target | see [gcc_plugin/README.md](gcc_plugin/README.md) and - +--------------------------------+ [gcc_plugin/README.instrument_list.md](gcc_plugin/README.instrument_list.md) + | if you want to instrument only | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast) + | parts of the target | see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and + +--------------------------------+ [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md) | | if not, or if you do not have a gcc with plugin support | v - use afl-gcc and afl-g++ (or afl-clang and afl-clang++) + use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang) ``` Clickable README links for the chosen compiler: - * [afl-clang-lto](llvm/README.lto.md) - * [afl-clang-fast](llvm/README.md) - * [afl-gcc-fast](gcc_plugin/README.md) - * afl-gcc has no README as it has no features + * [LTO mode - afl-clang-lto](instrumentation/README.lto.md) + * [LLVM mode - afl-clang-fast](instrumentation/README.md) + * [GCC_PLUGIN mode - afl-gcc-fast](instrumentation/README.gcc_plugin.md) + * GCC mode (afl-gcc) has no README as it has no own features + +You can select the mode for the afl-cc compiler by: + 1. passing --afl-MODE command line options to the compiler via CFLAGS/CXXFLAGS/CPPFLAGS + 2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, + afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++, + afl-gcc-fast, afl-g++-fast + 3. using the environment variable AFL_CC_COMPILER with MODE + +MODE can be one of: LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN +(afl-g*-fast) or GCC (afl-gcc/afl-g++). + +Because no afl specific command-line options are accepted (beside the +--afl-MODE command), the compile-time tools make fairly broad use of environment +variables, which can be listed with `afl-cc -hh` or by reading [docs/env_variables.md](docs/env_variables.md). #### b) Selecting instrumentation options -The following options are available when you instrument with afl-clang-fast or -afl-clang-lto: +The following options are available when you instrument with LTO mode (afl-clang-fast/afl-clang-lto): * Splitting integer, string, float and switch comparisons so afl++ can easier solve these. This is an important option if you do not have a very good and large input corpus. This technique is called laf-intel or COMPCOV. 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 (and usually a better than laf-intel) is to + You can read more about this in [instrumentation/README.laf-intel.md](instrumentation/README.laf-intel.md) + * A different technique (and usually a better one 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 these values into the fuzzing data at different locations. This technique is very fast and good - if the target does not @@ -282,12 +315,13 @@ afl-clang-lto: If you want to use this technique, then you have to compile the target twice, once specifically with/for this mode, and pass this binary to afl-fuzz via the `-c` parameter. - Not that you can compile also just a cmplog binary and use that for both - however there will a performance penality. - You can read more about this in [llvm_mode/README.cmplog.md](llvm_mode/README.cmplog.md) + Note that you can compile also just a cmplog binary and use that for both + however there will be a performance penality. + You can read more about this in [instrumentation/README.cmplog.md](instrumentation/README.cmplog.md) -If you use afl-clang-fast, afl-clang-lto or afl-gcc-fast you have the option to -selectively only instrument parts of the target that you are interested in: +If you use LTO, LLVM or GCC_PLUGIN mode (afl-clang-fast/afl-clang-lto/afl-gcc-fast) + you have the option to selectively only instrument parts of the target that you +are interested in: * To instrument only those parts of the target that you are interested in create a file with all the filenames of the source code that should be @@ -299,29 +333,29 @@ selectively only instrument parts of the target that you are interested in: `export AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per default to instrument unless noted (DENYLIST) or not perform instrumentation unless requested (ALLOWLIST). - **NOTE:** In optimization functions might be inlined and then not match! - see [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md) + **NOTE:** During optimization functions might be inlined and then would not match! + See [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md) For afl-clang-fast > 6.0 or if PCGUARD instrumentation is used then use the llvm sancov allow-list feature: [http://clang.llvm.org/docs/SanitizerCoverage.html](http://clang.llvm.org/docs/SanitizerCoverage.html) The llvm sancov format works with the allowlist/denylist feature of afl++ - however afl++ is more flexible in the format. + however afl++'s format is more flexible. There are many more options and modes available however these are most of the time less effective. See: - * [llvm_mode/README.ctx.md](llvm_mode/README.ctx.md) - * [llvm_mode/README.ngram.md](llvm_mode/README.ngram.md) - * [llvm_mode/README.instrim.md](llvm_mode/README.instrim.md) + * [instrumentation/README.ctx.md](instrumentation/README.ctx.md) + * [instrumentation/README.ngram.md](instrumentation/README.ngram.md) + * [instrumentation/README.instrim.md](instrumentation/README.instrim.md) -afl++ employs never zero counting in its bitmap. You can read more about this +afl++ performs "never zero" counting in its bitmap. You can read more about this here: - * [llvm_mode/README.neverzero.md](llvm_mode/README.neverzero.md) + * [instrumentation/README.neverzero.md](instrumentation/README.neverzero.md) #### c) Modify the target If the target has features that make fuzzing more difficult, e.g. checksums, HMAC, etc. then modify the source code so that this is removed. -This can even be done for productional source code be eliminating +This can even be done for operational source code by eliminating these checks within this specific defines: ``` @@ -332,13 +366,15 @@ these checks within this specific defines: #endif ``` +All afl++ compilers will set this preprocessor definition automatically. + #### d) Instrument the target In this step the target source code is compiled so that it can be fuzzed. Basically you have to tell the target build system that the selected afl++ compiler is used. Also - if possible - you should always configure the -build system that the target is compiled statically and not dynamically. +build system such that the target is compiled statically and not dynamically. How to do this is described below. Then build the target. (Usually with `make`) @@ -349,20 +385,22 @@ For `configure` build systems this is usually done by: `CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared` Note that if you are using the (better) afl-clang-lto compiler you also have to -set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is -described in [llvm/README.lto.md](llvm/README.lto.md) +set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is +described in [instrumentation/README.lto.md](instrumentation/README.lto.md). ##### cmake -For `configure` build systems this is usually done by: -`mkdir build; cd build; CC=afl-clang-fast CXX=afl-clang-fast++ cmake ..` - -Some cmake scripts require something like `-DCMAKE_CC=... -DCMAKE_CXX=...` -or `-DCMAKE_C_COMPILER=... DCMAKE_CPP_COMPILER=...` instead. +For `cmake` build systems this is usually done by: +`mkdir build; cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..` Note that if you are using the (better) afl-clang-lto compiler you also have to -set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is -described in [llvm/README.lto.md](llvm/README.lto.md) +set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is +described in [instrumentation/README.lto.md](instrumentation/README.lto.md). + +##### meson + +For meson you have to set the afl++ compiler with the very first command! +`CC=afl-cc CXX=afl-c++ meson` ##### other build systems or if configure/cmake didn't work @@ -370,7 +408,7 @@ Sometimes cmake and configure do not pick up the afl++ compiler, or the ranlib/ar that is needed - because this was just not foreseen by the developer of the target. Or they have non-standard options. Figure out if there is a non-standard way to set this, otherwise set up the build normally and edit the -generated build environment afterwards manually to point to the right compiler +generated build environment afterwards manually to point it to the right compiler (and/or ranlib and ar). #### d) Better instrumentation @@ -383,12 +421,12 @@ This requires the usage of afl-clang-lto or afl-clang-fast. This is the so-called `persistent mode`, which is much, much faster but requires that you code a source file that is specifically calling the target functions that you want to fuzz, plus a few specific afl++ functions around -it. See [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) for details. +it. See [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md) for details. Basically if you do not fuzz a target in persistent mode then you are just doing it for a hobby and not professionally :-) -### 2. Preparing the fuzzing +### 2. Preparing the fuzzing campaign As you fuzz the target with mutated input, having as diverse inputs for the target as possible improves the efficiency a lot. @@ -401,7 +439,7 @@ reported bugs, test suites, random downloads from the internet, unit test case data - from all kind of PNG software. If the input format is not known, you can also modify a target program to write -away normal data it receives and processes to a file and use these. +normal data it receives and processes to a file and use these. #### b) Making the input corpus unique @@ -415,7 +453,7 @@ the run afl-cmin like this: `afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -d @@` Note that the INPUTFILE argument that the target program would read from has to be set as `@@`. -If the target reads from stdin instead, just omit the `@@` as this is the +If the target reads from stdin instead, just omit the `@@` as this is the default. #### c) Minimizing all corpus files @@ -432,7 +470,7 @@ for i in *; do done ``` -This can also be parallelized, e.g. with `parallel` +This step can also be parallelized, e.g. with `parallel` #### Done! @@ -456,7 +494,7 @@ before the start of afl-fuzz as this improves performance by a x2 speed increase #### a) Running afl-fuzz -Before to do even a test run of afl-fuzz execute `sudo afl-system-config` (on +Before you do even a test run of afl-fuzz execute `sudo afl-system-config` (on the host if you execute afl-fuzz in a docker container). This reconfigures the system for optimal speed - which afl-fuzz checks and bails otherwise. Set `export AFL_SKIP_CPUFREQ=1` for afl-fuzz to skip this check if you cannot @@ -588,7 +626,7 @@ then terminate it. The main node will pick it up and make it available to the other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no free core. -Note that you in nearly all cases you can never reach full coverage. A lot of +Note that you in nearly all cases can never reach full coverage. A lot of functionality is usually behind options that were not activated or fuzz e.g. if you fuzz a library to convert image formats and your target is the png to tiff API then you will not touch any of the other library APIs and features. @@ -607,7 +645,7 @@ switch or honggfuzz. #### f) Improve the speed! - * Use [persistent mode](llvm_mode/README.persistent_mode.md) (x2-x20 speed increase) + * Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase) * If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md) * Linux: Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase) * Linux: Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure) @@ -1035,7 +1073,6 @@ without feedback, bug reports, or patches from: Andrea Biondo Vincent Le Garrec Khaled Yakdan Kuang-che Wu Josephine Calliotte Konrad Welc - Thomas Rooijakkers ``` Thank you! diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1a05f4f4..4281c554 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -162,8 +162,7 @@ struct queue_entry { u8 *trace_mini; /* Trace bytes, if kept */ u32 tc_ref; /* Trace bytes ref count */ - struct queue_entry *next, /* Next element, if any */ - *next_100; /* 100 elements ahead */ + struct queue_entry *next; /* Next element, if any */ }; @@ -575,8 +574,7 @@ typedef struct afl_state { struct queue_entry *queue, /* Fuzzing queue (linked list) */ *queue_cur, /* Current offset within the queue */ - *queue_top, /* Top of the list */ - *q_prev100; /* Previous 100 marker */ + *queue_top; /* Top of the list */ // growing buf struct queue_entry **queue_buf; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index d6c368d1..58ce5b6f 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -101,7 +101,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, if (rptr < lptr || *rptr != '"') { - FATAL("Malformed name=\"value\" pair in line %u.", cur_line); + WARNF("Malformed name=\"value\" pair in line %u.", cur_line); + continue; } @@ -141,13 +142,19 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, if (*lptr != '"') { - FATAL("Malformed name=\"keyword\" pair in line %u.", cur_line); + WARNF("Malformed name=\"keyword\" pair in line %u.", cur_line); + continue; } ++lptr; - if (!*lptr) { FATAL("Empty keyword in line %u.", cur_line); } + if (!*lptr) { + + WARNF("Empty keyword in line %u.", cur_line); + continue; + + } /* Okay, let's allocate memory and copy data between "...", handling \xNN escaping, \\, and \". */ @@ -169,7 +176,9 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, case 1 ... 31: case 128 ... 255: - FATAL("Non-printable characters in line %u.", cur_line); + WARNF("Non-printable characters in line %u.", cur_line); + continue; + break; case '\\': @@ -185,7 +194,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) { - FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line); + WARNF("Invalid escaping (not \\xNN) in line %u.", cur_line); + continue; } @@ -209,10 +219,11 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, if (afl->extras[afl->extras_cnt].len > MAX_DICT_FILE) { - FATAL( + WARNF( "Keyword too big in line %u (%s, limit is %s)", cur_line, stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), klen), stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); + continue; } @@ -232,14 +243,19 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; - if (!afl->extras_cnt) { FATAL("No usable files in '%s'", dir); } + if (!afl->extras_cnt) { + + WARNF("No usable data in '%s'", dir); + return; + + } qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), compare_extras_len); - OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt, - stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len), - stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len)); + ACTF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt, + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len), + stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len)); if (max_len > 32) { @@ -250,8 +266,8 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, if (afl->extras_cnt > afl->max_det_extras) { - OKF("More than %d tokens - will use them probabilistically.", - afl->max_det_extras); + WARNF("More than %d tokens - will use them probabilistically.", + afl->max_det_extras); } @@ -320,9 +336,10 @@ void load_extras(afl_state_t *afl, u8 *dir) { if (st.st_size > MAX_DICT_FILE) { WARNF( - "Extra '%s' is very big (%s, limit is %s)", fn, + "Extra '%s' is too big (%s, limit is %s)", fn, stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), st.st_size), stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); + continue; } @@ -370,16 +387,74 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } -/* Adds a new extra / dict entry. Used for LTO autodict. */ +/* Removes duplicates from the loaded extras. This can happen if multiple files + are loaded */ + +void dedup_extras(afl_state_t *afl) { + + if (afl->extras_cnt < 2) return; + + u32 i, j, orig_cnt = afl->extras_cnt; + + for (i = 0; i < afl->extras_cnt - 1; i++) { + + for (j = i + 1; j < afl->extras_cnt; j++) { + + restart_dedup: + + // if the goto was used we could be at the end of the list + if (j >= afl->extras_cnt || afl->extras[i].len != afl->extras[j].len) + break; + + if (memcmp(afl->extras[i].data, afl->extras[j].data, + afl->extras[i].len) == 0) { + + ck_free(afl->extras[j].data); + if (j + 1 < afl->extras_cnt) // not at the end of the list? + memmove((char *)&afl->extras[j], (char *)&afl->extras[j + 1], + (afl->extras_cnt - j - 1) * sizeof(struct extra_data)); + afl->extras_cnt--; + goto restart_dedup; // restart if several duplicates are in a row + + } + + } + + } + + if (afl->extras_cnt != orig_cnt) + afl->extras = afl_realloc((void **)&afl->extras, + afl->extras_cnt * sizeof(struct extra_data)); + +} + +/* Adds a new extra / dict entry. */ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { - u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; + u32 i, found = 0; + + for (i = 0; i < afl->extras_cnt; i++) { + + if (afl->extras[i].len == len) { + + if (memcmp(afl->extras[i].data, mem, len) == 0) return; + found = 1; + + } else { + + if (found) break; + + } + + } if (len > MAX_DICT_FILE) { - WARNF("Extra '%.*s' is very big (%s, limit is %s)", (int)len, mem, + WARNF("Extra '%.*s' is too big (%s, limit is %s)", (int)len, mem, stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len), stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); + return; } else if (len > 32) { @@ -405,8 +480,8 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { if (afl->extras_cnt == afl->max_det_extras + 1) { - OKF("More than %d tokens - will use them probabilistically.", - afl->max_det_extras); + WARNF("More than %d tokens - will use them probabilistically.", + afl->max_det_extras); } @@ -609,7 +684,7 @@ void load_auto(afl_state_t *afl) { } else { - OKF("No auto-generated dictionary tokens to reuse."); + ACTF("No auto-generated dictionary tokens to reuse."); } diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 102f04b9..713849a1 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -611,17 +611,17 @@ void read_foreign_testcases(afl_state_t *afl, int first) { /* Read all testcases from the input directory, then queue them for testing. Called at startup. */ -void read_testcases(afl_state_t *afl) { +void read_testcases(afl_state_t *afl, u8 *directory) { struct dirent **nl; - s32 nl_cnt; + s32 nl_cnt, subdirs = 1; u32 i; - u8 * fn1; - + u8 * fn1, *dir = directory; u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; /* Auto-detect non-in-place resumption attempts. */ +if (dir == NULL) { fn1 = alloc_printf("%s/queue", afl->in_dir); if (!access(fn1, F_OK)) { @@ -632,16 +632,18 @@ void read_testcases(afl_state_t *afl) { ck_free(fn1); } + dir = afl->in_dir; +} - ACTF("Scanning '%s'...", afl->in_dir); + ACTF("Scanning '%s'...", dir); /* 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->in_dir, &nl, NULL, alphasort); + nl_cnt = scandir(dir, &nl, NULL, alphasort); - if (nl_cnt < 0) { + if (nl_cnt < 0 && directory == NULL) { if (errno == ENOENT || errno == ENOTDIR) { @@ -656,7 +658,7 @@ void read_testcases(afl_state_t *afl) { } - PFATAL("Unable to open '%s'", afl->in_dir); + PFATAL("Unable to open '%s'", dir); } @@ -674,19 +676,29 @@ void read_testcases(afl_state_t *afl) { u8 dfn[PATH_MAX]; snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, nl[i]->d_name); - u8 *fn2 = alloc_printf("%s/%s", afl->in_dir, nl[i]->d_name); + u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); u8 passed_det = 0; - free(nl[i]); /* not tracked */ - if (lstat(fn2, &st) || access(fn2, R_OK)) { PFATAL("Unable to access '%s'", fn2); } - /* This also takes care of . and .. */ + /* obviously we want to skip "descending" into . and .. directories, + however it is a good idea to skip also directories that start with + a dot */ + if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { + + free(nl[i]); /* not tracked */ + read_testcases(afl, fn2); + ck_free(fn2); + continue; + + } + + free(nl[i]); if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { @@ -718,7 +730,7 @@ void read_testcases(afl_state_t *afl) { free(nl); /* not tracked */ - if (!afl->queued_paths) { + if (!afl->queued_paths && directory == NULL) { SAYF("\n" cLRD "[-] " cRST "Looks like there are no valid test cases in the input directory! The " @@ -985,6 +997,76 @@ void perform_dry_run(afl_state_t *afl) { } + /* Now we remove all entries from the queue that have a duplicate trace map */ + + q = afl->queue; + struct queue_entry *p, *prev = NULL; + int duplicates = 0; + +restart_outer_cull_loop: + + while (q) { + + if (q->cal_failed || !q->exec_cksum) continue; + + restart_inner_cull_loop: + + p = q->next; + + while (p) { + + if (!p->cal_failed && p->exec_cksum == q->exec_cksum) { + + duplicates = 1; + --afl->pending_not_fuzzed; + + // We do not remove any of the memory allocated because for + // splicing the data might still be interesting. + // We only decouple them from the linked list. + // This will result in some leaks at exit, but who cares. + + // we keep the shorter file + if (p->len >= q->len) { + + q->next = p->next; + goto restart_inner_cull_loop; + + } else { + + if (prev) + prev->next = q = p; + else + afl->queue = q = p; + goto restart_outer_cull_loop; + + } + + } + + p = p->next; + + } + + prev = q; + q = q->next; + + } + + if (duplicates) { + + afl->max_depth = 0; + q = afl->queue; + while (q) { + + if (q->depth > afl->max_depth) afl->max_depth = q->depth; + q = q->next; + + } + + afl->q_prev100 = afl->queue = afl->queue_top = afl->queue; + + } + OKF("All test cases processed."); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index bf568c38..5737c1f5 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1707,20 +1707,8 @@ custom_mutator_stage: } while (tid == afl->current_entry && afl->queued_paths > 1); - target = afl->queue; - - while (tid >= 100) { - - target = target->next_100; - tid -= 100; - - } - - while (tid--) { - - target = target->next; - - } + afl->splicing_with = tid; + target = afl->queue_buf[tid]; /* Make sure that the target has a reasonable length. */ @@ -4518,20 +4506,7 @@ pacemaker_fuzzing: } 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 c6d8225f..db91813b 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -239,13 +239,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { afl->cycles_wo_finds = 0; - if (!(afl->queued_paths % 100)) { - - afl->q_prev100->next_100 = q; - afl->q_prev100 = q; - - } - struct queue_entry **queue_buf = afl_realloc( AFL_BUF_PARAM(queue), afl->queued_paths * sizeof(struct queue_entry *)); if (unlikely(!queue_buf)) { PFATAL("alloc"); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c12d5db5..bfaa22e8 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -119,8 +119,8 @@ static void usage(u8 *argv0, int more_help) { "etc.)\n" " -d - quick & dirty mode (skips deterministic steps)\n" " -n - fuzz without instrumentation (non-instrumented mode)\n" - " -x dict_file - optional fuzzer dictionary (see README.md, its really " - "good!)\n\n" + " -x dict_file - fuzzer dictionary (see README.md, specify up to 4 " + "times)\n\n" "Testing settings:\n" " -s seed - use a fixed seed for the RNG\n" @@ -243,11 +243,11 @@ static int stricmp(char const *a, char const *b) { int main(int argc, char **argv_orig, char **envp) { - s32 opt; + s32 opt, i; u64 prev_queued = 0; u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE; - u8 * extras_dir = 0; - u8 mem_limit_given = 0, exit_1 = 0, debug = 0; + u8 * extras_dir[4]; + u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0; char **use_argv; struct timeval tv; @@ -450,8 +450,13 @@ int main(int argc, char **argv_orig, char **envp) { case 'x': /* dictionary */ - if (extras_dir) { FATAL("Multiple -x options not supported"); } - extras_dir = optarg; + if (extras_dir_cnt >= 4) { + + FATAL("More than four -x options are not supported"); + + } + + extras_dir[extras_dir_cnt++] = optarg; break; case 't': { /* timeout */ @@ -828,10 +833,6 @@ int main(int argc, char **argv_orig, char **envp) { "Eißfeldt, Andrea Fioraldi and Dominik Maier"); OKF("afl++ is open source, get it at " "https://github.com/AFLplusplus/AFLplusplus"); - OKF("Power schedules from github.com/mboehme/aflfast"); - OKF("Python Mutator and llvm_mode instrument file list from " - "github.com/choller/afl"); - OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->is_main_node && afl->afl_env.afl_custom_mutator_only) { @@ -1139,7 +1140,15 @@ int main(int argc, char **argv_orig, char **envp) { pivot_inputs(afl); - if (extras_dir) { load_extras(afl, extras_dir); } + if (extras_dir_cnt) { + + for (i = 0; i < extras_dir_cnt; i++) + load_extras(afl, extras_dir[i]); + + dedup_extras(afl); + OKF("Loaded a total of %u extras.", afl->extras_cnt); + + } if (!afl->timeout_given) { find_timeout(afl); } -- cgit 1.4.1 From e30b2c6af6e369844c92c00a20ebdd53473a747c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 5 Sep 2020 13:18:28 +0200 Subject: final changes for pre-3.0 --- .gitignore | 6 ++ Android.bp | 6 +- GNUmakefile | 3 +- GNUmakefile.gcc_plugin | 1 + GNUmakefile.llvm | 8 ++- README.md | 2 +- docs/Changelog.md | 14 ++++ docs/FAQ.md | 104 +++++++++++++++--------------- docs/INSTALL.md | 19 +++--- docs/env_variables.md | 121 ++++++++++++++++++----------------- docs/ideas.md | 57 ----------------- docs/life_pro_tips.md | 4 +- docs/perf_tips.md | 8 +-- docs/sister_projects.md | 4 +- docs/status_screen.md | 2 +- examples/README.md | 2 +- examples/aflpp_driver/aflpp_driver.c | 2 +- include/afl-fuzz.h | 3 +- include/config.h | 4 +- include/envs.h | 1 + qemu_mode/patches/afl-qemu-cpu-inl.h | 2 +- src/afl-fuzz-init.c | 3 +- src/afl-fuzz-queue.c | 13 ++-- src/afl-fuzz-stats.c | 8 +-- src/afl-fuzz.c | 3 +- test/test-gcc-plugin.sh | 2 +- test/test-unittests.sh | 2 + 27 files changed, 188 insertions(+), 216 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/.gitignore b/.gitignore index 0527a0b2..e3adb6ef 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,12 @@ afl-showmap.8 afl-system-config.8 afl-tmin.8 afl-whatsup.8 +afl-c++ +afl-cc +afl-lto +afl-lto++ +afl-lto++.8 +afl-lto.8 qemu_mode/libcompcov/compcovtest qemu_mode/qemu-* unicorn_mode/samples/*/\.test-* diff --git a/Android.bp b/Android.bp index e59129db..2c2114b2 100644 --- a/Android.bp +++ b/Android.bp @@ -101,7 +101,7 @@ cc_binary_host { ], srcs: [ - "llvm_mode/afl-clang-fast.c", + "src/afl-cc.c", ], } @@ -119,7 +119,7 @@ cc_binary_host { ], srcs: [ - "llvm_mode/afl-clang-fast.c", + "src/afl-cc.c", ], } @@ -136,6 +136,6 @@ cc_library_static { ], srcs: [ - "llvm_mode/afl-llvm-rt.o.c", + "instrumentation/afl-llvm-rt.o.c", ], } diff --git a/GNUmakefile b/GNUmakefile index 0046a481..7455483c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -533,7 +533,7 @@ endif deepclean: clean rm -rf qemu_mode/qemu-3.1.1.tar.xz rm -rf unicorn_mode/unicornafl - git reset --hard >/dev/null 2>&1 || true + # NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true .PHONY: distrib distrib: all @@ -591,6 +591,7 @@ install: all $(MANPAGES) @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) @rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh @rm -f $${DESTDIR}$(BIN_PATH)/afl-as + @rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH) @if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi @if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index aeb1ef16..b73fcfda 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -158,6 +158,7 @@ vpath % .. install: all ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc-fast ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast + ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH) install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index d76e0b28..1bb3d265 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -423,10 +423,12 @@ document: ./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 32-bit variant of the runtime (-m32)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @test -e afl-compiler-rt-32.o && ln -sf afl-compiler-rt-32.o afl-llvm-rt-64.o ./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 64-bit variant of the runtime (-m64)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @test -e afl-compiler-rt-64.o && ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o .PHONY: test_build test_build: $(PROGS) @@ -448,11 +450,11 @@ all_done: test_build install: all @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) @if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi - @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt.o ;fi @if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-lto-instrumentation.so ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi - @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi - @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt-32.o ;fi + @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt-64.o ; fi @if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi @if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi diff --git a/README.md b/README.md index 96b34260..c886489d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Release Version: [2.67c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 2.67d + Github Version: 3.00a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6321aee4..9de03e78 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,20 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.00a (develop) + - llvm_mode/ and gcc_plugin/ moved to instrumentation/ + - all compilers combined to afl-cc which emulates the previous ones + - afl-llvm/gcc-rt.o merged into afl-compiler-rt.o + - afl-fuzz + - reading testcases from -i now descends into subdirectories + - allow up to 4 -x command line options + - loaded extras now have a duplicate protection + - instrumentation + - new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz + -x dictionary of string comparisons found during compilation + - not overriding -Ox or -fno-unroll-loops anymore + + ### Version ++2.68c (release) - added the GSoC excellent afl++ grammar mutator by Shengtuo to our custom_mutators/ (see custom_mutators/README.md) - or get it here: diff --git a/docs/FAQ.md b/docs/FAQ.md index 064638f4..24942492 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -4,11 +4,11 @@ * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) - * [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service) - * [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program) + * [How do I fuzz a network service?](#how-to-fuzz-a-network-service) + * [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program) * [What is an edge?](#what-is-an-edge) * [Why is my stability below 100%?](#why-is-my-stability-below-100) - * [How can I improve the stability value?](#how-can-i-improve-the-stability-value) + * [How can I improve the stability value](#how-can-i-improve-the-stability-value) If you find an interesting or important question missing, submit it via [https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues) @@ -18,52 +18,51 @@ If you find an interesting or important question missing, submit it via American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting in 2013/2014, and when he left Google end of 2017 he stopped developing it. -At the end of 2019 the Google fuzzing team took over maintenance of AFL, however -it is only accepting PRs from the community and is not developing enhancements +At the end of 2019 the Google fuzzing team took over maintance of AFL, however +it is only accepting PR from the community and is not developing enhancements anymore. -In the second quarter of 2019, 1 1/2 year later when no further development of -AFL had happened and it became clear there would none be coming, afl++ -was born, where initially community patches were collected and applied -for bug fixes and enhancements. Then from various AFL spin-offs - mostly academic +In the second quarter of 2019, 1 1/2 years after no further development of +AFL had happened and it became clear there would be none coming, afl++ +was born, where initially first community patches were collected and applied +for bugs and enhancements. Then from various AFL spin-offs - mostly academic research - features were integrated. This already resulted in a much advanced AFL. Until the end of 2019 the afl++ team had grown to four active developers which -then implemented their own research and features, making it now by far the most +then implemented their own research and feature, making it now by far the most flexible and feature rich guided fuzzer available as open source. And in independent fuzzing benchmarks it is one of the best fuzzers available, e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) -## How to improve the fuzzing speed? +## How to improve the fuzzing speed - 1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) - 2. Use [persistent mode](llvm_mode/README.persistent_mode.md) (x2-x20 speed increase) + 1. use [instrumentation](docs/README.llvm.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) + 2. Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase) 3. Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase) - 4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input file directory on a tempfs location, see [docs/env_variables.md](docs/env_variables.md) - 5. Improve Linux kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system less secure) + 4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md) + 5. Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure) 6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem 7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads) ## How do I fuzz a network service? -The short answer is - you cannot, at least not "out of the box". +The short answer is - you cannot, at least "out of the box". -Using a network channel is inadequate for several reasons: -- it has a slow-down of x10-20 on the fuzzing speed -- it does not scale to fuzzing multiple instances easily, -- instead of one initial data packet often a back-and-forth interplay of packets is needed for stateful protocols (which is totally unsupported by most coverage aware fuzzers). +Using network has a slow-down of x10-20 on the fuzzing speed, does not scale, +and finally usually it is more than one initial data packet but a back-and-forth +which is totally unsupported by most coverage aware fuzzers. The established method to fuzz network services is to modify the source code to read from a file or stdin (fd 0) (or even faster via shared memory, combine -this with persistent mode [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) +this with persistent mode [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md) and you have a performance gain of x10 instead of a performance loss of over -x10 - that is a x100 difference!). +x10 - that is a x100 difference! If modifying the source is not an option (e.g. because you only have a binary and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD -to emulate the network. This is also much faster than the real network would be. -See [examples/socket_fuzzing/](../examples/socket_fuzzing/). +to emulate the network. This is also much faster than network would be. +See [examples/socket_fuzzing/](../examples/socket_fuzzing/) There is an outdated afl++ branch that implements networking if you are desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) - @@ -74,7 +73,7 @@ which allows you to define network state with different type of data packets. If the GUI program can read the fuzz data from a file (via the command line, a fixed location or via an environment variable) without needing any user -interaction then it would be suitable for fuzzing. +interaction then then yes. Otherwise it is not possible without modifying the source code - which is a very good idea anyway as the GUI functionality is a huge CPU/time overhead @@ -83,13 +82,13 @@ for the fuzzing. So create a new `main()` that just reads the test case and calls the functionality for processing the input that the GUI program is using. -## What is an "edge"? +## What is an "edge" A program contains `functions`, `functions` contain the compiled machine code. The compiled machine code in a `function` can be in a single or many `basic blocks`. A `basic block` is the largest possible number of subsequent machine code -instructions that has exactly one entrypoint (which can be be entered by multiple other basic blocks) -and runs linearly without branching or jumping to other addresses (except at the end). +instructions that runs independent, meaning it does not split up to different +locations nor is it jumped into it from a different location: ``` function() { A: @@ -99,7 +98,7 @@ function() { if (x) goto C; else goto D; C: some code - goto E + goto D D: some code goto B @@ -109,7 +108,7 @@ function() { ``` Every code block between two jump locations is a `basic block`. -An `edge` is then the unique relationship between two directly connected `basic blocks` (from the +An `edge` is then the unique relationship between two `basic blocks` (from the code example above): ``` Block A @@ -124,9 +123,8 @@ code example above): Block E ``` Every line between two blocks is an `edge`. -Note that a few basic block loop to itself, this too would be an edge. -## Why is my stability below 100%? +## Why is my stability below 100% Stability is measured by how many percent of the edges in the target are "stable". Sending the same input again and again should take the exact same @@ -134,37 +132,37 @@ path through the target every time. If that is the case, the stability is 100%. If however randomness happens, e.g. a thread reading other external data, reaction to timing, etc. then in some of the re-executions with the same data -the edge coverage result will be different accross runs. +the result in the edge information will be different accross runs. Those edges that change are then flagged "unstable". The more "unstable" edges, the more difficult for afl++ to identify valid new paths. A value above 90% is usually fine and a value above 80% is also still ok, and -even a value above 20% can still result in successful finds of bugs. -However, it is recommended that for values below 90% or 80% you should take -countermeasures to improve stability. +even above 20% can still result in successful finds of bugs. +However, it is recommended that below 90% or 80% you should take measures to +improve the stability. -## How can I improve the stability value? +## How can I improve the stability value -For fuzzing a 100% stable target that covers all edges is the best case. +For fuzzing a 100% stable target that covers all edges is the best. A 90% stable target that covers all edges is however better than a 100% stable target that ignores 10% of the edges. With instability you basically have a partial coverage loss on an edge, with -ignored functions you have a full loss on that edges. +ignore you have a full loss on that edge. There are functions that are unstable, but also provide value to coverage, eg init functions that use fuzz data as input for example. -If however a function that has nothing to do with the input data is the -source of instability, e.g. checking jitter, or is a hash map function etc. -then it should not be instrumented. +If however it is a function that has nothing to do with the input data is the +source, e.g. checking jitter, or is a hash map function etc. then it should +not be instrumented. -To be able to exclude these functions (based on AFL++'s measured stability) -the following process will allow to identify functions with variable edges. +To be able to make this decision the following process will allow you to +identify the functions with variable edges so you can make this decision. -Four steps are required to do this and it also requires quite some knowledge -of coding and/or disassembly and is effectively possible only with +Four steps are required to do this and requires quite some knowledge of +coding and/or disassembly and it is only effectively possible with afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. 1. First step: Identify which edge ID numbers are unstable @@ -173,7 +171,7 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. The out/fuzzer_stats file will then show the edge IDs that were identified as unstable. - 2. Second step: Find the responsible function(s). + 2. Second step: Find the responsible function. a) For LTO instrumented binaries this can be documented during compile time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`. @@ -182,10 +180,10 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. 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 + instrumentation/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. (Example code is already there). - Then recompile and reinstall llvm_mode and rebuild your target. + Then recompile and reinstall instrumentation and rebuild your target. Run the recompiled target with afl-fuzz for a while and then check the file that you wrote with the backtrace information. Alternatively you can use `gdb` to hook __sanitizer_cov_trace_pc_guard_init @@ -193,20 +191,20 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. and set a write breakpoint to that address (`watch 0x.....`). c) in all other instrumentation types this is not possible. So just - recompile with the two mentioned above. This is just for + recompile with the the two mentioned above. This is just for identifying the functions that have unstable edges. 3. Third step: create a text file with the filenames/functions Identify which source code files contain the functions that you need to remove from instrumentation, or just specify the functions you want to - skip for instrumentation. Note that optimization might inline functions! + skip instrumenting. Note that optimization might inline functions! - Simply follow this document on how to do this: [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md) + Simply follow this document on how to do this: [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md) If PCGUARD is used, then you need to follow this guide (needs llvm 12+!): [http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation) - Only exclude those functions from instrumentation that provide no value + Only deny those functions from instrumentation that provide no value for coverage - that is if it does not process any fuzz data directly or indirectly (e.g. hash maps, thread management etc.). If however a function directly or indirectly handles fuzz data then you diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 766f24d7..fb7b5642 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -24,7 +24,7 @@ There are no special dependencies to speak of; you will need GNU make and a working compiler (gcc or clang). Some of the optional scripts bundled with the program may depend on bash, gdb, and similar basic tools. -If you are using clang, please review llvm_mode/README.md; the LLVM +If you are using clang, please review README.llvm.md; the LLVM integration mode can offer substantial performance gains compared to the traditional approach. @@ -52,10 +52,10 @@ sudo gmake install Keep in mind that if you are using csh as your shell, the syntax of some of the shell commands given in the README.md and other docs will be different. -The `llvm_mode` requires a dynamically linked, fully-operational installation of +The `llvm` requires a dynamically linked, fully-operational installation of clang. At least on FreeBSD, the clang binaries are static and do not include some of the essential tools, so if you want to make it work, you may need to -follow the instructions in llvm_mode/README.md. +follow the instructions in README.llvm.md. Beyond that, everything should work as advertised. @@ -97,27 +97,24 @@ and definitely don't look POSIX-compliant. This means two things: User emulation mode of QEMU does not appear to be supported on MacOS X, so black-box instrumentation mode (`-Q`) will not work. -The llvm_mode requires a fully-operational installation of clang. The one that +The llvm instrumentation requires a fully-operational installation of clang. The one that comes with Xcode is missing some of the essential headers and helper tools. -See llvm_mode/README.md for advice on how to build the compiler from scratch. +See README.llvm.md for advice on how to build the compiler from scratch. ## 4. Linux or *BSD on non-x86 systems Standard build will fail on non-x86 systems, but you should be able to leverage two other options: - - The LLVM mode (see llvm_mode/README.md), which does not rely on + - The LLVM mode (see README.llvm.md), which does not rely on x86-specific assembly shims. It's fast and robust, but requires a complete installation of clang. - The QEMU mode (see qemu_mode/README.md), which can be also used for fuzzing cross-platform binaries. It's slower and more fragile, but can be used even when you don't have the source for the tested app. -If you're not sure what you need, you need the LLVM mode. To get it, try: - -```bash -AFL_NO_X86=1 gmake && gmake -C llvm_mode -``` +If you're not sure what you need, you need the LLVM mode, which is built by +default. ...and compile your target program with afl-clang-fast or afl-clang-fast++ instead of the traditional afl-gcc or afl-clang wrappers. diff --git a/docs/env_variables.md b/docs/env_variables.md index c47d10e8..9d289f6d 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -5,13 +5,25 @@ users or for some types of custom fuzzing setups. See README.md for the general instruction manual. -## 1) Settings for afl-gcc, afl-clang, and afl-as - and gcc_plugin afl-gcc-fast +## 1) Settings for all compilers -Because they can't directly accept command-line options, the compile-time -tools make fairly broad use of environmental variables: +Starting with afl++ 3.0 there is only one compiler: afl-cc +To select the different instrumentation modes this can be done by + 1. passing --afl-MODE command line options to the compiler + 2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, + afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++, + afl-gcc-fast, afl-g++-fast + 3. using the environment variable AFL_CC_COMPILER with MODE - - Most afl tools do not print any output if stdout/stderr are redirected. - If you want to save the output in a file then set the AFL_DEBUG +MODE can one of LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN +(afl-g*-fast) or GCC (afl-gcc/afl-g++). + +Because beside the --afl-MODE command no afl specific command-line options +are accepted, the compile-time tools make fairly broad use of environmental +variables: + + - Most afl tools do not print any ouput if stout/stderr are redirected. + If you want to have the output into a file then set the AFL_DEBUG environment variable. This is sadly necessary for various build processes which fail otherwise. @@ -24,6 +36,8 @@ tools make fairly broad use of environmental variables: will cause problems in programs built with -Werror, simply because -O3 enables more thorough code analysis and can spew out additional warnings. To disable optimizations, set AFL_DONT_OPTIMIZE. + However if -O... and/or -fno-unroll-loops are set, these are not + overriden. - Setting AFL_USE_ASAN automatically enables ASAN, provided that your compiler supports that. Note that fuzzing with ASAN is mildly challenging @@ -44,7 +58,7 @@ tools make fairly broad use of environmental variables: you instrument hand-written assembly when compiling clang code by plugging a normalizer into the chain. (There is no equivalent feature for GCC.) - - Setting AFL_INST_RATIO to a percentage between 0% and 100% controls the + - Setting AFL_INST_RATIO to a percentage between 0 and 100% controls the probability of instrumenting every branch. This is (very rarely) useful when dealing with exceptionally complex programs that saturate the output bitmap. Examples include v8, ffmpeg, and perl. @@ -55,19 +69,16 @@ tools make fairly broad use of environmental variables: Setting AFL_INST_RATIO to 0 is a valid choice. This will instrument only the transitions between function entry points, but not individual branches. + Note that this is an outdated variable. A few instances (e.g. afl-gcc) + still support these, but state-of-the-art (e.g. LLVM LTO and LLVM PCGUARD) + do not need this. + - AFL_NO_BUILTIN causes the compiler to generate code suitable for use with libtokencap.so (but perhaps running a bit slower than without the flag). - TMPDIR is used by afl-as for temporary files; if this variable is not set, the tool defaults to /tmp. - - Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented - assembly files. Useful for troubleshooting problems or understanding how - the tool works. To get them in a predictable place, try something like: - - mkdir assembly_here - TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all - - If you are a weird person that wants to compile and instrument asm text files then use the AFL_AS_FORCE_INSTRUMENT variable: AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo @@ -78,19 +89,24 @@ tools make fairly broad use of environmental variables: - Setting AFL_CAL_FAST will speed up the initial calibration, if the application is very slow -## 2) Settings for afl-clang-fast / afl-clang-fast++ / afl-gcc-fast / afl-g++-fast +## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++ -The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset +The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset of the settings discussed in section #1, with the exception of: + - LLVM modes support `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` which will + write all constant string comparisons to this file to be used with + afl-fuzz' `-x` option. + - AFL_AS, since this toolchain does not directly invoke GNU as. - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are created. - - AFL_INST_RATIO, as we by default use collision free instrumentation. + - AFL_INST_RATIO, as we by default collision free instrumentation is used. + Not all passes support this option though as it is an outdated feature. -Then there are a few specific features that are only available in llvm_mode: +Then there are a few specific features that are only available in instrumentation: ### Select the instrumentation mode @@ -121,7 +137,7 @@ Then there are a few specific features that are only available in llvm_mode: 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 instrumentations are performed which + 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 @@ -136,7 +152,7 @@ Then there are a few specific features that are only available in llvm_mode: - AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written into the instrumentation is set in a global variable - See llvm_mode/README.LTO.md for more information. + See instrumentation/README.LTO.md for more information. ### INSTRIM @@ -154,7 +170,7 @@ Then there are a few specific features that are only available in llvm_mode: afl-fuzz will only be able to see the path the loop took, but not how many times it was called (unless it is a complex loop). - See llvm_mode/README.instrim.md + See instrumentation/README.instrim.md ### NGRAM @@ -165,7 +181,7 @@ Then there are a few specific features that are only available in llvm_mode: config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. - See llvm_mode/README.ctx.md + See instrumentation/README.ctx.md ### CTX @@ -176,7 +192,7 @@ Then there are a few specific features that are only available in llvm_mode: config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. - See llvm_mode/README.ngram.md + See instrumentation/README.ngram.md ### LAF-INTEL @@ -196,17 +212,17 @@ Then there are a few specific features that are only available in llvm_mode: - Setting AFL_LLVM_LAF_ALL sets all of the above - See llvm_mode/README.laf-intel.md for more information. + See instrumentation/README.laf-intel.md for more information. ### INSTRUMENT LIST (selectively instrument files and functions) - This feature allows selective instrumentation of the source + This feature allows selectively instrumentation of the source - Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or function will only instrument (or skip) those files that match the names listed in the specified file. - See llvm_mode/README.instrument_list.md for more information. + See instrumentation/README.instrument_list.md for more information. ### NOT_ZERO @@ -220,27 +236,34 @@ Then there are a few specific features that are only available in llvm_mode: test. If the target performs only few loops then this will give a small performance boost. - See llvm_mode/README.neverzero.md + See instrumentation/README.neverzero.md ### CMPLOG - Setting AFL_LLVM_CMPLOG=1 during compilation will tell afl-clang-fast to - produce a CmpLog binary. See llvm_mode/README.cmplog.md + produce a CmpLog binary. See instrumentation/README.cmplog.md - See llvm_mode/README.neverzero.md + See instrumentation/README.neverzero.md -Then there are a few specific features that are only available in the gcc_plugin: +## 3) Settings for GCC / GCC_PLUGIN modes -### INSTRUMENT_FILE +Then there are a few specific features that are only available in GCC and +GCC_PLUGIN mode. - This feature allows selective instrumentation of the source + - Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented + assembly files. Useful for troubleshooting problems or understanding how + the tool works. (GCC mode only) + To get them in a predictable place, try something like: - - Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those - files that match the names listed in this file (one filename per line). + mkdir assembly_here + TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all + - Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those + files that match the names listed in this file (one filename per line). See gcc_plugin/README.instrument_list.md for more information. + (GCC_PLUGIN mode only) -## 3) Settings for afl-fuzz +## 4) Settings for afl-fuzz The main fuzzer binary accepts several options that disable a couple of sanity checks or alter some of the more exotic semantics of the tool: @@ -278,14 +301,6 @@ checks or alter some of the more exotic semantics of the tool: don't want AFL to spend too much time classifying that stuff and just rapidly put all timeouts in that bin. - - Setting AFL_FORKSRV_INIT_TMOUT allows yout to specify a different timeout - to wait for the forkserver to spin up. The default is the `-t` value times - `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the - default would wait `1000` milis. Setting a different time here is useful - if the target has a very slow startup time, for example when doing - full-system fuzzing or emulation, but you don't want the actual runs - to wait too long for timeouts. - - AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics. This can be useful to speed up the fuzzing of text-based file formats. @@ -377,22 +392,12 @@ checks or alter some of the more exotic semantics of the tool: 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. - - - Setting AFL_MAX_DET_EXTRAS changes the count of dictionary entries/extras - (default 200), after which the entries will be used probabilistically. - So, if the dict/extras file (`-x`) contains more tokens than this threshold, - not all of the tokens will be used in each fuzzing step, every time. - Instead, there is a chance that the entry will be skipped during fuzzing. - This makes sure that the fuzzer doesn't spend all its time only inserting - the extras, but will still do other mutations. However, it decreases the - likelihood for each token to be inserted, before the next queue entry is fuzzed. - Either way, all tokens will be used eventually, in a longer fuzzing campaign. - Outdated environment variables that are that not supported anymore: AFL_DEFER_FORKSRV AFL_PERSISTENT -## 4) Settings for afl-qemu-trace +## 5) Settings for afl-qemu-trace The QEMU wrapper used to instrument binary-only code supports several settings: @@ -446,7 +451,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings: stack pointer in which QEMU can find the return address when `start addr` is hitted. -## 5) Settings for afl-cmin +## 6) Settings for afl-cmin The corpus minimization script offers very little customization: @@ -472,12 +477,12 @@ to match when minimizing crashes. This will make minimization less useful, but may prevent the tool from "jumping" from one crashing condition to another in very buggy software. You probably want to combine it with the -e flag. -## 7) Settings for afl-analyze +## 8) Settings for afl-analyze You can set AFL_ANALYZE_HEX to get file offsets printed as hexadecimal instead of decimal. -## 8) Settings for libdislocator +## 9) Settings for libdislocator The library honors these environmental variables: @@ -499,12 +504,12 @@ The library honors these environmental variables: - AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to max_align_t to be compliant with the C standard. -## 9) Settings for libtokencap +## 10) Settings for libtokencap This library accepts AFL_TOKEN_FILE to indicate the location to which the discovered tokens should be written. -## 10) Third-party variables set by afl-fuzz & other tools +## 11) Third-party variables set by afl-fuzz & other tools Several variables are not directly interpreted by afl-fuzz, but are set to optimal values if not already present in the environment: diff --git a/docs/ideas.md b/docs/ideas.md index 65e2e8e6..a5d40963 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -3,49 +3,6 @@ In the following, we describe a variety of ideas that could be implemented for future AFL++ versions. -For GSOC2020 interested students please see -[https://github.com/AFLplusplus/AFLplusplus/issues/208](https://github.com/AFLplusplus/AFLplusplus/issues/208) - -## Flexible Grammar Mutator (currently in development) - -Currently, AFL++'s mutation does not have deeper knowledge about the fuzzed -binary, apart from feedback, even though the developer may have insights -about the target. - -A developer may choose to provide dictionaries and implement own mutations -in python or C, but an easy mutator that behaves according to a given grammar, -does not exist. - -State-of-the-art research on grammar fuzzing has some problems in their -implementations like code quality, scalability, or ease of use and other -common issues of the academic code. - -We aim to develop a pluggable grammar mutator for afl++ that combines -various results. - -Mentor: andreafioraldi - -## perf-fuzz Linux Kernel Module - -Expand on [snapshot LKM](https://github.com/AFLplusplus/AFL-Snapshot-LKM) -To make it thread safe, can snapshot several processes at once and increase -overall performance. - -Mentor: any - -## QEMU 5-based Instrumentation - -First tests to use QEMU 4 for binary-only AFL++ showed that caching behavior -changed, which vastly decreases fuzzing speeds. - -In this task test if QEMU 5 performs better and port the afl++ QEMU 3.1 -patches to QEMU 5. - -Understanding the current instrumentation and fixing the current caching -issues will be needed. - -Mentor: andreafioraldi - ## WASM Instrumentation Currently, AFL++ can be used for source code fuzzing and traditional binaries. @@ -66,20 +23,6 @@ Either improve a single mutator thorugh learning of many different bugs Mentor: domenukk -## Reengineer `afl-fuzz` as Thread Safe, Embeddable Library (currently in development) - -Right now, afl-fuzz is single threaded, cannot safely be embedded in tools, -and not multi-threaded. It makes use of a large number of globals, must always -be the parent process and exec child processes. -Instead, afl-fuzz could be refactored to contain no global state and globals. -This allows for different use cases that could be implemented during this -project. -Note that in the mean time a lot has happened here already, but e.g. making -it all work and implement multithreading in afl-fuzz ... there is still quite -some work to do. - -Mentor: hexcoder- or vanhauser-thc - ## Collision-free Binary-Only Maps AFL++ supports collison-free maps using an LTO (link-time-optimization) pass. diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index a5bd7286..0004c297 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -30,10 +30,10 @@ Check out the `fuzzer_stats` file in the AFL output dir or try `afl-whatsup`. It could be important - consult docs/status_screen.md right away! ## Know your target? Convert it to persistent mode for a huge performance gain! -Consult section #5 in llvm_mode/README.md for tips. +Consult section #5 in README.llvm.md for tips. ## Using clang? -Check out llvm_mode/ for a faster alternative to afl-gcc! +Check out instrumentation/ for a faster alternative to afl-gcc! ## Did you know that AFL can fuzz closed-source or cross-platform binaries? Check out qemu_mode/README.md and unicorn_mode/README.md for more. diff --git a/docs/perf_tips.md b/docs/perf_tips.md index 731dc238..fbcb4d8d 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -51,7 +51,7 @@ a file. ## 3. Use LLVM instrumentation When fuzzing slow targets, you can gain 20-100% performance improvement by -using the LLVM-based instrumentation mode described in [the llvm_mode README](../llvm_mode/README.md). +using the LLVM-based instrumentation mode described in [the instrumentation README](../instrumentation/README.llvm.md). Note that this mode requires the use of clang and will not work with GCC. The LLVM mode also offers a "persistent", in-process fuzzing mode that can @@ -62,12 +62,12 @@ modes require you to edit the source code of the fuzzed program, but the changes often amount to just strategically placing a single line or two. If there are important data comparisons performed (e.g. `strcmp(ptr, MAGIC_HDR)`) -then using laf-intel (see llvm_mode/README.laf-intel.md) will help `afl-fuzz` a lot +then using laf-intel (see instrumentation/README.laf-intel.md) will help `afl-fuzz` a lot to get to the important parts in the code. If you are only interested in specific parts of the code being fuzzed, you can instrument_files the files that are actually relevant. This improves the speed and -accuracy of afl. See llvm_mode/README.instrument_list.md +accuracy of afl. See instrumentation/README.instrument_list.md Also use the InsTrim mode on larger binaries, this improves performance and coverage a lot. @@ -110,7 +110,7 @@ e.g.: https://launchpad.net/libeatmydata In programs that are slow due to unavoidable initialization overhead, you may -want to try the LLVM deferred forkserver mode (see llvm_mode/README.md), +want to try the LLVM deferred forkserver mode (see README.llvm.md), which can give you speed gains up to 10x, as mentioned above. Last but not least, if you are using ASAN and the performance is unacceptable, diff --git a/docs/sister_projects.md b/docs/sister_projects.md index a501ecbd..640e59f7 100644 --- a/docs/sister_projects.md +++ b/docs/sister_projects.md @@ -52,7 +52,7 @@ options. Provides an evolutionary instrumentation-guided fuzzing harness that allows some programs to be fuzzed without the fork / execve overhead. (Similar functionality is now available as the "persistent" feature described in -[the llvm_mode readme](../llvm_mode/README.md)) +[the llvm_mode readme](../instrumentation/README.llvm.md)) http://llvm.org/docs/LibFuzzer.html @@ -245,7 +245,7 @@ https://code.google.com/p/address-sanitizer/wiki/AsanCoverage#Coverage_counters ### AFL JS (Han Choongwoo) One-off optimizations to speed up the fuzzing of JavaScriptCore (now likely -superseded by LLVM deferred forkserver init - see llvm_mode/README.md). +superseded by LLVM deferred forkserver init - see README.llvm.md). https://github.com/tunz/afl-fuzz-js diff --git a/docs/status_screen.md b/docs/status_screen.md index b89468ce..2eeb8f3f 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -324,7 +324,7 @@ there are several things to look at: - Multiple threads executing at once in semi-random order. This is harmless when the 'stability' metric stays over 90% or so, but can become an issue if not. Here's what to try: - * Use afl-clang-fast from [llvm_mode](../llvm_mode/) - it uses a thread-local tracking + * Use afl-clang-fast from [instrumentation](../instrumentation/) - it uses a thread-local tracking model that is less prone to concurrency issues, * See if the target can be compiled or run without threads. Common `./configure` options include `--without-threads`, `--disable-pthreads`, or diff --git a/examples/README.md b/examples/README.md index d28aadbe..46a92c6e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -47,7 +47,7 @@ Here's a quick overview of the stuff you can find in this directory: Note that the minimize_corpus.sh tool has graduated from the examples/ directory and is now available as ../afl-cmin. The LLVM mode has likewise -graduated to ../llvm_mode/*. +graduated to ../instrumentation/*. Most of the tools in this directory are meant chiefly as examples that need to be tweaked for your specific needs. They come with some basic documentation, diff --git a/examples/aflpp_driver/aflpp_driver.c b/examples/aflpp_driver/aflpp_driver.c index ff5446e9..82e55fc4 100644 --- a/examples/aflpp_driver/aflpp_driver.c +++ b/examples/aflpp_driver/aflpp_driver.c @@ -27,7 +27,7 @@ EOF # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c # Build afl-llvm-rt.o.c from the AFL distribution. -clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c +clang -c -w $AFL_HOME/instrumentation/afl-llvm-rt.o.c # Build this file, link it with afl-llvm-rt.o.o and the target code. clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o # Run AFL: diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4281c554..9e469864 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -935,6 +935,7 @@ u8 has_new_bits(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); +void dedup_extras(afl_state_t *); void add_extra(afl_state_t *afl, u8 *mem, u32 len); void maybe_add_auto(afl_state_t *, u8 *, u32); void save_auto(afl_state_t *); @@ -972,7 +973,7 @@ u8 fuzz_one(afl_state_t *); void bind_to_free_cpu(afl_state_t *); #endif void setup_post(afl_state_t *); -void read_testcases(afl_state_t *); +void read_testcases(afl_state_t *, u8 *); void perform_dry_run(afl_state_t *); void pivot_inputs(afl_state_t *); u32 find_start_position(afl_state_t *); diff --git a/include/config.h b/include/config.h index 77407d50..8cc70075 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.68c" +#define VERSION "++3.00a" /****************************************************** * * @@ -195,7 +195,7 @@ steps; past this point, the "extras/user" step will be still carried out, but with proportionally lower odds: */ -#define MAX_DET_EXTRAS 200 +#define MAX_DET_EXTRAS 256 /* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing (first value), and to keep in memory as candidates. The latter should be much diff --git a/include/envs.h b/include/envs.h index 2dc1dbbf..d9968fcd 100644 --- a/include/envs.h +++ b/include/envs.h @@ -69,6 +69,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", + "AFL_LLVM_DICT2FILE", "AFL_LLVM_DOCUMENT_IDS", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 63b7581d..0e38f38b 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -466,7 +466,7 @@ void afl_forkserver(CPUState *cpu) { } /* A simplified persistent mode handler, used as explained in - * llvm_mode/README.md. */ + * instrumentation/README.llvm.md */ void afl_persistent_loop(void) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 713849a1..1351d274 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -626,6 +626,7 @@ if (dir == NULL) { if (!access(fn1, F_OK)) { afl->in_dir = fn1; + subdirs = 0; } else { @@ -1063,7 +1064,7 @@ restart_outer_cull_loop: } - afl->q_prev100 = afl->queue = afl->queue_top = afl->queue; + afl->queue = afl->queue_top = afl->queue; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index db91813b..af52aa45 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -138,8 +138,7 @@ static u8 check_if_text(struct queue_entry *q) { } // non-overlong 2-byte - if (len - offset > 1 && - ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && + if (len - offset > 1 && ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) { offset += 2; @@ -230,7 +229,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } else { - afl->q_prev100 = afl->queue = afl->queue_top = q; + afl->queue = afl->queue_top = q; } @@ -274,15 +273,15 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { void destroy_queue(afl_state_t *afl) { - struct queue_entry *q = afl->queue, *n; + struct queue_entry *q; + u32 i; - while (q) { + for (i = 0; i < afl->queued_paths; i++) { - n = q->next; + q = afl->queue_buf[i]; ck_free(q->fname); ck_free(q->trace_mini); ck_free(q); - q = n; } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 51eed14b..c60c65aa 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -982,10 +982,9 @@ void show_stats(afl_state_t *afl) { void show_init_stats(afl_state_t *afl) { struct queue_entry *q = afl->queue; - u32 min_bits = 0, max_bits = 0; + u32 min_bits = 0, max_bits = 0, max_len = 0, count = 0; u64 min_us = 0, max_us = 0; u64 avg_us = 0; - u32 max_len = 0; u8 val_bufs[4][STRINGIFY_VAL_SIZE_MAX]; #define IB(i) val_bufs[(i)], sizeof(val_bufs[(i)]) @@ -1006,6 +1005,7 @@ void show_init_stats(afl_state_t *afl) { if (q->len > max_len) { max_len = q->len; } + ++count; q = q->next; } @@ -1072,10 +1072,10 @@ void show_init_stats(afl_state_t *afl) { OKF("Here are some useful stats:\n\n" cGRA " Test case count : " cRST - "%u favored, %u variable, %u total\n" cGRA " Bitmap range : " cRST + "%u favored, %u variable, %u ignored, %u total\n" cGRA " Bitmap range : " cRST "%u to %u bits (average: %0.02f bits)\n" cGRA " Exec timing : " cRST "%s to %s us (average: %s us)\n", - afl->queued_favored, afl->queued_variable, afl->queued_paths, min_bits, + afl->queued_favored, afl->queued_variable, afl->queued_paths - count, afl->queued_paths, min_bits, max_bits, ((double)afl->total_bitmap_size) / (afl->total_bitmap_entries ? afl->total_bitmap_entries : 1), diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bfaa22e8..73ca6aaa 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1133,8 +1133,9 @@ int main(int argc, char **argv_orig, char **envp) { setup_cmdline_file(afl, argv + optind); - read_testcases(afl); + read_testcases(afl, NULL); // read_foreign_testcases(afl, 1); for the moment dont do this + OKF("Loaded a total of %u seeds.", afl->queued_paths); load_auto(afl); diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh index 2ed10a72..8b8cbd8e 100755 --- a/test/test-gcc-plugin.sh +++ b/test/test-gcc-plugin.sh @@ -3,7 +3,7 @@ . ./test-pre.sh $ECHO "$BLUE[*] Testing: gcc_plugin" -test -e ../afl-gcc-fast -a -e ../afl-gcc-rt.o && { +test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && { SAVE_AFL_CC=${AFL_CC} export AFL_CC=`command -v gcc` ../afl-gcc-fast -o test-instr.plain.gccpi ../test-instr.c > /dev/null 2>&1 diff --git a/test/test-unittests.sh b/test/test-unittests.sh index f540b5f8..58c2eea9 100755 --- a/test/test-unittests.sh +++ b/test/test-unittests.sh @@ -7,3 +7,5 @@ unset AFL_CC make -C .. unit || CODE=1 INCOMPLETE=1 : . ./test-post.sh + +rm -rf unittests/unit_hash unittests/unit_rand -- cgit 1.4.1 From 4561a9590fc9a8c9ef3676b119f04c2e6d0794c0 Mon Sep 17 00:00:00 2001 From: Edznux Date: Thu, 17 Sep 2020 01:29:09 +0200 Subject: WIP. basic state working: submitting statsd metrics (path, crashes, hangs) --- include/afl-fuzz.h | 9 ++++++ src/afl-fuzz-run.c | 5 ++- src/afl-fuzz-statsd.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/afl-fuzz-statsd.c (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1a05f4f4..5fff7feb 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -65,6 +65,8 @@ #include #include +#include + #include #include #ifndef USEMMAP @@ -76,6 +78,7 @@ #include #include #include +#include #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__NetBSD__) || defined(__DragonFly__) @@ -951,6 +954,12 @@ void maybe_update_plot_file(afl_state_t *, double, double); void show_stats(afl_state_t *); void show_init_stats(afl_state_t *); +/* StatsD */ + +int statsd_init(char *host, int port); +int send_statsd_metric(afl_state_t *afl); +void statsd_format_metric(afl_state_t *afl, char *buff, int bufflen); + /* Run */ fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index d71ec339..8dc0b334 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -901,7 +901,10 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { afl->stage_cur + 1 == afl->stage_max) { show_stats(afl); - + if(send_statsd_metric(afl)){ + //Change me to something realistic; don't fail on connection / lookup fail for metrics... + exit(1); + } } return 0; diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c new file mode 100644 index 00000000..aa12ca9a --- /dev/null +++ b/src/afl-fuzz-statsd.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "afl-fuzz.h" + + +int sock = 0; +struct sockaddr_in server; +int error = 0; + +int statsd_init(char *host, int port){ + if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){ + perror("socket"); + exit(1); + } + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_port = htons(port); + + struct addrinfo *result; + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + if ( (error = getaddrinfo(host, NULL, &hints, &result)) ) { + perror("getaddrinfo"); + exit(1); + } + + memcpy(&(server.sin_addr), &((struct sockaddr_in*)result->ai_addr)->sin_addr, sizeof(struct in_addr)); + freeaddrinfo(result); + + return 0; +} + +int send_statsd_metric(afl_state_t *afl){ + u64 cur_ms = get_cur_time(); + if (cur_ms - afl->stats_last_plot_ms < 1000) { + return 0; + } + + error = statsd_init("127.0.0.1", 12345); + if (error){ + perror("Failed to init statsd client. Aborting"); + return -1; + } + + if(!sock){ + perror("sock"); + return -1; + } + char buff[512]; + statsd_format_metric(afl, buff, 512); + + if (sendto(sock, buff, strlen(buff), 0, (struct sockaddr *) &server, sizeof(server)) == -1) { + perror("sendto"); + return -1; + } + close(sock); + sock=0; + + return 0; +} + + +void statsd_format_metric(afl_state_t *afl, char *buff, int bufflen){ + char *format = "fuzzing.afl.cycle_done:%llu|c\n" + "fuzzing.afl.total_path:%lu|c\n" + "fuzzing.afl.unique_crashes:%llu|c\n" + "fuzzing.afl.total_crashes:%llu|c\n" + "fuzzing.afl.unique_hangs:%llu|c\n"; + snprintf(buff, bufflen, format, + afl->queue_cycle, + afl->queued_paths, + afl->unique_crashes, + afl->total_crashes, + afl->unique_hangs + ); +} \ No newline at end of file -- cgit 1.4.1 From 7ff9800804f6f4f88b70d8aaf882b66e0ce40c8f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 19 Sep 2020 15:13:15 +0200 Subject: fix exploit, mmopt and rare schedule --- include/afl-fuzz.h | 14 +++++++------- src/afl-fuzz-queue.c | 2 +- src/afl-fuzz.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 9e469864..9404c417 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -243,13 +243,13 @@ enum { enum { /* 00 */ EXPLORE, /* AFL default, Exploration-based constant schedule */ - /* 01 */ EXPLOIT, /* AFL's exploitation-based const. */ - /* 02 */ FAST, /* Exponential schedule */ - /* 03 */ COE, /* Cut-Off Exponential schedule */ - /* 04 */ LIN, /* Linear schedule */ - /* 05 */ QUAD, /* Quadratic schedule */ - /* 06 */ RARE, /* Rare edges */ - /* 07 */ MMOPT, /* Modified MOPT schedule */ + /* 01 */ MMOPT, /* Modified MOPT schedule */ + /* 02 */ EXPLOIT, /* AFL's exploitation-based const. */ + /* 03 */ FAST, /* Exponential schedule */ + /* 04 */ COE, /* Cut-Off Exponential schedule */ + /* 05 */ LIN, /* Linear schedule */ + /* 06 */ QUAD, /* Quadratic schedule */ + /* 07 */ RARE, /* Rare edges */ /* 08 */ SEEK, /* EXPLORE that ignores timings */ POWER_SCHEDULES_NUM diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 336b7f4f..ddd08f1c 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -710,7 +710,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } - if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { + if (unlikely(afl->schedule >= EXPLOIT && afl->schedule <= QUAD)) { if (factor > MAX_FACTOR) { factor = MAX_FACTOR; } perf_score *= factor / POWER_BETA; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ea24011e..11037f73 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1366,7 +1366,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->expand_havoc = 2; break; case 2: - if (!have_p) afl->schedule = EXPLOIT; + //if (!have_p) afl->schedule = EXPLOIT; afl->expand_havoc = 3; break; case 3: -- cgit 1.4.1 From 888d63748a3c6aafd974cb9d96cdb8d3916e82bb Mon Sep 17 00:00:00 2001 From: Vitalii Akolzin Date: Thu, 24 Sep 2020 18:25:32 +0300 Subject: Fix potential endless loop in custom_mutator_stage Co-authored-by: Ivan Gulakov --- include/afl-fuzz.h | 3 +++ src/afl-fuzz-one.c | 64 ++++++++++++++++++++++++++++++++-------------------- src/afl-fuzz-queue.c | 2 ++ src/afl-fuzz-state.c | 2 ++ 4 files changed, 46 insertions(+), 25 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 9404c417..0efd48ec 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -657,6 +657,9 @@ typedef struct afl_state { * they do not call another function */ u8 *map_tmp_buf; + /* queue entries ready for splicing count (len > 1) */ + u32 ready_for_splicing_count; + } afl_state_t; struct custom_mutator { diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 5737c1f5..edae2a88 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1696,50 +1696,58 @@ custom_mutator_stage: struct queue_entry *target; u32 tid; - u8 * new_buf; + u8 * new_buf = NULL; + u32 target_len = 0; - retry_external_pick: - /* Pick a random other queue entry for passing to external API */ + if (afl->ready_for_splicing_count > 1 || + (afl->ready_for_splicing_count == 1 && + afl->queue_cur->len == 1)) { - do { + retry_external_pick: + /* Pick a random other queue entry for passing to external API */ - tid = rand_below(afl, afl->queued_paths); + do { - } while (tid == afl->current_entry && afl->queued_paths > 1); + tid = rand_below(afl, afl->queued_paths); - afl->splicing_with = tid; - target = afl->queue_buf[tid]; + } while (tid == afl->current_entry && afl->queued_paths > 1); - /* Make sure that the target has a reasonable length. */ + afl->splicing_with = tid; + target = afl->queue_buf[tid]; - while (target && (target->len < 2 || target == afl->queue_cur) && - afl->queued_paths > 3) { + /* Make sure that the target has a reasonable length. */ - target = target->next; - ++afl->splicing_with; + while (target && (target->len < 2 || target == afl->queue_cur) && + afl->queued_paths > 2) { - } + target = target->next; + ++afl->splicing_with; - if (!target) { goto retry_external_pick; } + } - /* Read the additional testcase into a new buffer. */ - fd = open(target->fname, O_RDONLY); - if (unlikely(fd < 0)) { + if (!target) { goto retry_external_pick; } - PFATAL("Unable to open '%s'", target->fname); + /* Read the additional testcase into a new buffer. */ + fd = open(target->fname, O_RDONLY); + if (unlikely(fd < 0)) { - } + PFATAL("Unable to open '%s'", target->fname); - new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - ck_read(fd, new_buf, target->len, target->fname); - close(fd); + } + + new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + ck_read(fd, new_buf, target->len, target->fname); + close(fd); + target_len = target->len; + + } u8 *mutated_buf = NULL; size_t mutated_size = el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf, - target->len, max_seed_size); + target_len, max_seed_size); if (unlikely(!mutated_buf)) { @@ -2738,6 +2746,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done) { + u32 old_len = afl->queue_cur->len; + u8 res = trim_case(afl, afl->queue_cur, in_buf); if (res == FSRV_RUN_ERROR) { @@ -2759,6 +2769,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { len = afl->queue_cur->len; + /* maybe current entry stop being ready for splicing */ + if (old_len > 1 && afl->queue_cur->len == 1) + afl->ready_for_splicing_count--; + } memcpy(out_buf, in_buf, len); diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index ddd08f1c..14aa34fc 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -234,6 +234,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } + if (q->len > 1) afl->ready_for_splicing_count++; + ++afl->queued_paths; ++afl->pending_not_fuzzed; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index ae45d571..9f68bb51 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -155,6 +155,8 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_last_execs = 0; afl->stats_avg_exec = -1; + afl->ready_for_splicing_count = 0; + init_mopt_globals(afl); list_append(&afl_states, afl); -- cgit 1.4.1 From 6b3b1775b6b274bc62f9c79f686fc79fa110d0a8 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 25 Sep 2020 12:03:24 +0200 Subject: improving on splice candidate check patch --- include/afl-fuzz.h | 4 ++-- include/config.h | 2 +- src/afl-fuzz-one.c | 33 +++++++++------------------------ src/afl-fuzz-queue.c | 2 +- src/afl-fuzz-state.c | 48 +++++++++++++----------------------------------- 5 files changed, 26 insertions(+), 63 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 0efd48ec..441ecc61 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -483,7 +483,7 @@ typedef struct afl_state { disable_trim, /* Never trim in fuzz_one */ shmem_testcase_mode, /* If sharedmem testcases are used */ expand_havoc, /* perform expensive havoc after no find */ - cycle_schedules; /* cycle power schedules ? */ + cycle_schedules; /* cycle power schedules? */ u8 *virgin_bits, /* Regions yet untouched by fuzzing */ *virgin_tmout, /* Bits we haven't seen in tmouts */ @@ -657,7 +657,7 @@ typedef struct afl_state { * they do not call another function */ u8 *map_tmp_buf; - /* queue entries ready for splicing count (len > 1) */ + /* queue entries ready for splicing count (len > 4) */ u32 ready_for_splicing_count; } afl_state_t; diff --git a/include/config.h b/include/config.h index a01491e7..7c8e0c7d 100644 --- a/include/config.h +++ b/include/config.h @@ -136,7 +136,7 @@ two cycles where smaller blocks are favored: */ #define HAVOC_BLK_SMALL 32 -#define HAVOC_BLK_MEDIUM 128 +#define HAVOC_BLK_MEDIUM 128 #define HAVOC_BLK_LARGE 1500 /* Extra-large blocks, selected very rarely (<5% of the time): */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 8c1aa179..e96c4311 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1699,36 +1699,22 @@ custom_mutator_stage: u8 * new_buf = NULL; u32 target_len = 0; - /* check if splicing is possible (if the only entry has len > 1 - * check it is not current entry) - */ - if (afl->ready_for_splicing_count > 1 || - (afl->ready_for_splicing_count == 1 && - afl->queue_cur->len == 1)) { + /* check if splicing makes sense yet (enough entries) */ + if (likely(afl->ready_for_splicing_count > 1)) { - retry_external_pick: - /* Pick a random other queue entry for passing to external API */ + /* Pick a random other queue entry for passing to external API + that has the necessary length */ do { tid = rand_below(afl, afl->queued_paths); - } while (tid == afl->current_entry && afl->queued_paths > 1); - - afl->splicing_with = tid; - target = afl->queue_buf[tid]; - - /* Make sure that the target has a reasonable length. */ - - while (target && (target->len < 2 || target == afl->queue_cur) && - afl->queued_paths > 2) { - - target = target->next; - ++afl->splicing_with; + } while (unlikely(tid == afl->current_entry && - } + afl->queue_buf[tid]->len >= 4)); - if (!target) { goto retry_external_pick; } + target = afl->queue_buf[tid]; + afl->splicing_with = tid; /* Read the additional testcase into a new buffer. */ fd = open(target->fname, O_RDONLY); @@ -2773,8 +2759,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { len = afl->queue_cur->len; /* maybe current entry is not ready for splicing anymore */ - if (old_len > 1 && afl->queue_cur->len == 1) - afl->ready_for_splicing_count--; + if (unlikely(len <= 4 && old_len > 4)) afl->ready_for_splicing_count--; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 14aa34fc..53c3e984 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -234,7 +234,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } - if (q->len > 1) afl->ready_for_splicing_count++; + if (likely(q->len > 4)) afl->ready_for_splicing_count++; ++afl->queued_paths; ++afl->pending_not_fuzzed; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 9f68bb51..5e0995fe 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -95,6 +95,11 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stage_name = "init"; /* Name of the current fuzz stage */ afl->splicing_with = -1; /* Splicing with which test case? */ afl->cpu_to_bind = -1; + afl->cal_cycles = CAL_CYCLES; + afl->cal_cycles_long = CAL_CYCLES_LONG; + afl->hang_tmout = EXEC_TIMEOUT; + afl->stats_update_freq = 1; + afl->stats_avg_exec = -1; #ifdef HAVE_AFFINITY afl->cpu_aff = -1; /* Selected CPU core */ @@ -115,48 +120,13 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { // afl_state_t is not available in forkserver.c afl->fsrv.afl_ptr = (void *)afl; afl->fsrv.add_extra_func = (void (*)(void *, u8 *, u32)) & add_extra; - - afl->cal_cycles = CAL_CYCLES; - afl->cal_cycles_long = CAL_CYCLES_LONG; - afl->fsrv.exec_tmout = EXEC_TIMEOUT; - afl->hang_tmout = EXEC_TIMEOUT; - afl->fsrv.mem_limit = MEM_LIMIT; - - afl->stats_update_freq = 1; - afl->fsrv.dev_urandom_fd = -1; afl->fsrv.dev_null_fd = -1; - afl->fsrv.child_pid = -1; afl->fsrv.out_dir_fd = -1; - afl->cmplog_prev_timed_out = 0; - - /* statis file */ - afl->last_bitmap_cvg = 0; - afl->last_stability = 0; - afl->last_eps = 0; - - /* plot file saves from last run */ - afl->plot_prev_qp = 0; - afl->plot_prev_pf = 0; - afl->plot_prev_pnf = 0; - afl->plot_prev_ce = 0; - afl->plot_prev_md = 0; - afl->plot_prev_qc = 0; - afl->plot_prev_uc = 0; - afl->plot_prev_uh = 0; - - afl->stats_last_stats_ms = 0; - afl->stats_last_plot_ms = 0; - afl->stats_last_ms = 0; - afl->stats_last_execs = 0; - afl->stats_avg_exec = -1; - - afl->ready_for_splicing_count = 0; - init_mopt_globals(afl); list_append(&afl_states, afl); @@ -177,6 +147,14 @@ void read_afl_environment(afl_state_t *afl, char **envp) { WARNF("Potentially mistyped AFL environment variable: %s", env); issue_detected = 1; + } else if (strncmp(env, "USE_", 4) == 0) { + + WARNF( + "Potentially mistyped AFL environment variable: %s, did you mean " + "AFL_%s?", + env, env); + issue_detected = 1; + } else if (strncmp(env, "AFL_", 4) == 0) { int i = 0, match = 0; -- cgit 1.4.1 From a55e0d11891f0cc19a4ec6cc67c4e5e0d1c7f465 Mon Sep 17 00:00:00 2001 From: Edznux Date: Fri, 25 Sep 2020 23:28:15 +0200 Subject: WIP envs --- include/afl-fuzz.h | 2 +- include/envs.h | 2 ++ src/afl-fuzz-statsd.c | 70 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 58 insertions(+), 16 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5fff7feb..65327d93 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -958,7 +958,7 @@ void show_init_stats(afl_state_t *); int statsd_init(char *host, int port); int send_statsd_metric(afl_state_t *afl); -void statsd_format_metric(afl_state_t *afl, char *buff, int bufflen); +int statsd_format_metric(afl_state_t *afl, char *formatted[], size_t *num_of_tags); /* Run */ diff --git a/include/envs.h b/include/envs.h index 2dc1dbbf..6776a7cd 100644 --- a/include/envs.h +++ b/include/envs.h @@ -129,6 +129,8 @@ static char *afl_environment_variables[] = { "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", "AFL_SKIP_CRASHES", + "AFL_STATSD_HOST", + "AFL_STATSD_PORT", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index aa12ca9a..d09d1f6e 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -9,6 +9,9 @@ #include "afl-fuzz.h" +#define MAX_STATSD_PACKET_SIZE 1024 +#define MAX_TAG_LEN 200 + int sock = 0; struct sockaddr_in server; int error = 0; @@ -46,8 +49,21 @@ int send_statsd_metric(afl_state_t *afl){ if (cur_ms - afl->stats_last_plot_ms < 1000) { return 0; } + + u16 port = 8125; + char* host = "127.0.0.1"; - error = statsd_init("127.0.0.1", 12345); + char* port_env; + char* host_env; + if ((port_env = getenv("AFL_STATSD_PORT")) != NULL) { + port = atoi(port_env); + } + if ((host_env = getenv("AFL_STATSD_HOST")) != NULL) { + // sanitization check ? + host = host_env; + } + + error = statsd_init(host, port); if (error){ perror("Failed to init statsd client. Aborting"); return -1; @@ -57,31 +73,55 @@ int send_statsd_metric(afl_state_t *afl){ perror("sock"); return -1; } - char buff[512]; - statsd_format_metric(afl, buff, 512); - - if (sendto(sock, buff, strlen(buff), 0, (struct sockaddr *) &server, sizeof(server)) == -1) { - perror("sendto"); - return -1; + char *formatted[] = {}; + size_t *num_of_tags = 0; + statsd_format_metric(afl, &formatted, num_of_tags); + for (size_t i = 0; i < &num_of_tags; i++){ + printf("%ld\n", i); + printf("%s\n", formatted[i]); + if (sendto(sock, formatted[i], strlen(formatted[i]), 0, (struct sockaddr *) &server, sizeof(server)) == -1) { + perror("sendto"); + return -1; + } } + close(sock); sock=0; return 0; } +int statsd_format_metric(afl_state_t *afl, char *formatted[], size_t *num_of_tags){ + + char *tags = "key:value"; + + *num_of_tags = 0; // reset + + const char *metrics[] = { + "fuzzing.afl.cycle_done:%llu|g|#%s\n", + "fuzzing.afl.total_path:%lu|g|#%s\n", + "fuzzing.afl.unique_crashes:%llu|g|#%s\n", + "fuzzing.afl.total_crashes:%llu|g|#%s\n", + "fuzzing.afl.unique_hangs:%llu|g|#%s\n" + }; -void statsd_format_metric(afl_state_t *afl, char *buff, int bufflen){ - char *format = "fuzzing.afl.cycle_done:%llu|c\n" - "fuzzing.afl.total_path:%lu|c\n" - "fuzzing.afl.unique_crashes:%llu|c\n" - "fuzzing.afl.total_crashes:%llu|c\n" - "fuzzing.afl.unique_hangs:%llu|c\n"; - snprintf(buff, bufflen, format, + const int metricValues[] = { afl->queue_cycle, afl->queued_paths, afl->unique_crashes, afl->total_crashes, afl->unique_hangs - ); + }; + + *num_of_tags = sizeof(metrics)/sizeof(metrics[0]); + + for (size_t i = 0; i < &num_of_tags; i++){ + char *tmp = malloc(MAX_STATSD_PACKET_SIZE); + if(tmp == NULL){ + return -1; + } + snprintf(tmp, MAX_STATSD_PACKET_SIZE, metrics[i], metricValues[i], tags); + formatted[i] = tmp; + } + return 0; } \ No newline at end of file -- cgit 1.4.1 From e69b25e34be8028921389bbb114135c3028d0a3d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 28 Sep 2020 10:13:00 +0200 Subject: increase havoc_stack_pow2 on no finds --- include/afl-fuzz.h | 1 + src/afl-fuzz-one.c | 4 ++-- src/afl-fuzz-state.c | 1 + src/afl-fuzz.c | 5 +++++ 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 441ecc61..aa278820 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -443,6 +443,7 @@ typedef struct afl_state { u8 cal_cycles, /* Calibration cycles defaults */ cal_cycles_long, /* Calibration cycles defaults */ + havoc_stack_pow2, /* HAVOC_STACK_POW2 */ no_unlink, /* do not unlink cur_input */ debug, /* Debug mode */ custom_only, /* Custom mutator only mode */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index e96c4311..c04b492b 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1884,7 +1884,7 @@ havoc_stage: 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)); + u32 use_stacking = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2)); afl->stage_cur_val = use_stacking; @@ -3970,7 +3970,7 @@ pacemaker_fuzzing: 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)); + u32 use_stacking = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2)); afl->stage_cur_val = use_stacking; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 5e0995fe..a8e56e60 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -95,6 +95,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stage_name = "init"; /* Name of the current fuzz stage */ afl->splicing_with = -1; /* Splicing with which test case? */ afl->cpu_to_bind = -1; + afl->havoc_stack_pow2 = HAVOC_STACK_POW2; afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 002be0be..28507857 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1368,9 +1368,14 @@ int main(int argc, char **argv_orig, char **envp) { break; case 2: // if (!have_p) afl->schedule = EXPLOIT; + afl->havoc_stack_pow2++; afl->expand_havoc = 3; break; case 3: + afl->havoc_stack_pow2++; + afl->expand_havoc = 4; + break; + case 4: // nothing else currently break; -- cgit 1.4.1 From e87eca7fe8ec3ed0ba79e7722350ad502b67218b Mon Sep 17 00:00:00 2001 From: Marcel Boehme Date: Tue, 29 Sep 2020 11:53:27 +0000 Subject: Patching and improving AFLFast schedules. --- GNUmakefile | 2 +- include/afl-fuzz.h | 4 ++- src/afl-fuzz-bitmap.c | 18 +++-------- src/afl-fuzz-init.c | 8 +++++ src/afl-fuzz-queue.c | 84 +++++++++++++++++++++++++++++++++------------------ src/afl-fuzz.c | 7 +++++ 6 files changed, 78 insertions(+), 45 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index 889c0e7d..c885a935 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -205,7 +205,7 @@ endif ifneq "$(filter Linux GNU%,$(shell uname))" "" override CFLAGS += -D_FORTIFY_SOURCE=2 - LDFLAGS += -ldl -lrt + LDFLAGS += -ldl -lrt -lm endif ifneq "$(findstring FreeBSD, $(shell uname))" "" diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index aa278820..f65fc40f 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -155,7 +155,6 @@ struct queue_entry { u64 exec_us, /* Execution time (us) */ handicap, /* Number of queue cycles behind */ - n_fuzz, /* Number of fuzz, does not overflow*/ depth, /* Path depth */ exec_cksum; /* Checksum of the execution trace */ @@ -492,6 +491,9 @@ typedef struct afl_state { u8 *var_bytes; /* Bytes that appear to be variable */ + #define n_fuzz_size (1 << 21) + u32 *n_fuzz; + volatile u8 stop_soon, /* Ctrl-C pressed? */ clear_screen; /* Window resized? */ diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 1b9df624..64de86a2 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -555,19 +555,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - struct queue_entry *q = afl->queue; - while (q) { - - if (q->exec_cksum == cksum) { - - ++q->n_fuzz; - break; - - } - - q = q->next; - - } + /* Saturated increment */ + if (afl->n_fuzz[cksum % n_fuzz_size] < 0xFFFFFFFF) + afl->n_fuzz[cksum % n_fuzz_size]++; } @@ -610,6 +600,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { afl->queue_top->exec_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + afl->n_fuzz[cksum % n_fuzz_size] = 1; + /* Try to calibrate inline; this also calls update_bitmap_score() when successful. */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index cbac3822..b825837f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -729,6 +729,14 @@ void read_testcases(afl_state_t *afl, u8 *directory) { add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size, passed_det); + if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { + + u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + + afl->n_fuzz[cksum % n_fuzz_size] = 1; + + } + } free(nl); /* not tracked */ diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 53c3e984..dfabba7b 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -25,6 +25,7 @@ #include "afl-fuzz.h" #include #include +#include /* Mark deterministic checks as done for a particular queue entry. We use the .state file to avoid repeating deterministic fuzzing when resuming aborted @@ -218,7 +219,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->len = len; q->depth = afl->cur_depth + 1; q->passed_det = passed_det; - q->n_fuzz = 1; q->trace_mini = NULL; if (q->depth > afl->max_depth) { afl->max_depth = q->depth; } @@ -307,8 +307,10 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { u64 fav_factor; u64 fuzz_p2; - if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) - fuzz_p2 = next_pow2(q->n_fuzz); + if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) + fuzz_p2 = 0; // Skip the fuzz_p2 comparison + else if (unlikely(afl->schedule == RARE)) + fuzz_p2 = next_pow2(afl->n_fuzz[q->exec_cksum % n_fuzz_size]); else fuzz_p2 = q->fuzz_level; @@ -334,7 +336,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { u64 top_rated_fav_factor; u64 top_rated_fuzz_p2; if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) - top_rated_fuzz_p2 = next_pow2(afl->top_rated[i]->n_fuzz); + top_rated_fuzz_p2 = next_pow2(afl->n_fuzz[afl->top_rated[i]->exec_cksum % n_fuzz_size]); else top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level; @@ -605,11 +607,10 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } - u64 fuzz = q->n_fuzz; - u64 fuzz_total; + u32 n_paths; + double factor = 1.0; + long double fuzz_mu; - u32 n_paths, fuzz_mu; - u32 factor = 1; switch (afl->schedule) { @@ -624,60 +625,83 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { break; case COE: - fuzz_total = 0; + fuzz_mu = 0.0; n_paths = 0; + // Don't modify perf_score for unfuzzed seeds + if (q->fuzz_level == 0) break; + struct queue_entry *queue_it = afl->queue; while (queue_it) { - fuzz_total += queue_it->n_fuzz; + fuzz_mu += log2(afl->n_fuzz[q->exec_cksum % n_fuzz_size]); n_paths++; + queue_it = queue_it->next; } if (unlikely(!n_paths)) { FATAL("Queue state corrupt"); } - fuzz_mu = fuzz_total / n_paths; - if (fuzz <= fuzz_mu) { + fuzz_mu = fuzz_mu / n_paths; - if (q->fuzz_level < 16) { + if (log2(afl->n_fuzz[q->exec_cksum % n_fuzz_size]) > fuzz_mu) { - factor = ((u32)(1 << q->fuzz_level)); + /* Never skip favourites */ + if (!q->favored) factor = 0; - } else { + break; - factor = MAX_FACTOR; + } - } + // Fall through + case FAST: - } else { + // Don't modify unfuzzed seeds + if (q->fuzz_level == 0) break; - factor = 0; + switch ((u32)log2(afl->n_fuzz[q->exec_cksum % n_fuzz_size])) { - } + case 0 ... 1: + factor = 4; + break; - break; + case 2 ... 3: + factor = 3; + break; - case FAST: - if (q->fuzz_level < 16) { + case 4: + factor = 2; + break; - factor = ((u32)(1 << q->fuzz_level)) / (fuzz == 0 ? 1 : fuzz); + case 5: + break; - } else { + case 6: + if (!q->favored) factor = 0.8; + break; - factor = MAX_FACTOR / (fuzz == 0 ? 1 : next_pow2(fuzz)); + case 7: + if (!q->favored) factor = 0.6; + break; + + default: + if (!q->favored) factor = 0.4; + break; } + if (q->favored) + factor *= 1.15; + break; case LIN: - factor = q->fuzz_level / (fuzz == 0 ? 1 : fuzz); + factor = q->fuzz_level / (afl->n_fuzz[q->exec_cksum % n_fuzz_size] + 1); break; case QUAD: - factor = q->fuzz_level * q->fuzz_level / (fuzz == 0 ? 1 : fuzz); + factor = q->fuzz_level * q->fuzz_level / (afl->n_fuzz[q->exec_cksum % n_fuzz_size] + 1); break; case MMOPT: @@ -703,7 +727,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { // the more often fuzz result paths are equal to this queue entry, // reduce its value perf_score *= - (1 - (double)((double)q->n_fuzz / (double)afl->fsrv.total_execs)); + (1 - (double)((double)afl->n_fuzz[q->exec_cksum % n_fuzz_size] / (double)afl->fsrv.total_execs)); break; @@ -724,7 +748,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { perf_score *= 2; - } else if (perf_score < 1) { + } else if (afl->schedule != COE && perf_score < 1) { // Add a lower bound to AFLFast's energy assignment strategies perf_score = 1; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 28507857..889f753d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -936,6 +936,13 @@ int main(int argc, char **argv_orig, char **envp) { } + /* Dynamically allocate memory for AFLFast schedules */ + if (afl->schedule >= FAST && afl->schedule <= RARE) { + + afl->n_fuzz = ck_alloc(n_fuzz_size * sizeof(u32)); + + } + if (get_afl_env("AFL_NO_FORKSRV")) { afl->no_forkserver = 1; } if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; } if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; } -- cgit 1.4.1 From 383cd487a2c28012c80341f8517e473120af4d19 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 29 Sep 2020 15:02:57 +0200 Subject: small improvements to Marcel's patch, fix laf-intel + redqueen crashes --- docs/Changelog.md | 1 + include/afl-fuzz.h | 5 +-- instrumentation/afl-llvm-dict2file.so.cc | 14 ++++++--- instrumentation/cmplog-instructions-pass.cc | 6 ++-- instrumentation/cmplog-routines-pass.cc | 11 ++++--- instrumentation/compare-transform-pass.so.cc | 24 ++++++++------ instrumentation/split-compares-pass.so.cc | 47 +++++++++++++++++----------- instrumentation/split-switches-pass.so.cc | 21 +++++++------ src/afl-fuzz-bitmap.c | 13 +++++--- src/afl-fuzz-init.c | 4 +-- src/afl-fuzz-queue.c | 30 +++++++++--------- src/afl-fuzz.c | 2 +- 12 files changed, 104 insertions(+), 74 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index 789b1f74..0f923423 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,6 +14,7 @@ sending a mail to . - all compilers combined to afl-cc which emulates the previous ones - afl-llvm/gcc-rt.o merged into afl-compiler-rt.o - afl-fuzz + - Marcel Boehme submitted a patch that improves all AFFast schedules :) - reading testcases from -i now descends into subdirectories - allow up to 4 -x command line options - loaded extras now have a duplicate protection diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f65fc40f..fb661ce5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -151,7 +151,8 @@ struct queue_entry { is_ascii; /* Is the input just ascii text? */ u32 bitmap_size, /* Number of bits set in bitmap */ - fuzz_level; /* Number of fuzzing iterations */ + fuzz_level, /* Number of fuzzing iterations */ + n_fuzz_entry; /* offset in n_fuzz */ u64 exec_us, /* Execution time (us) */ handicap, /* Number of queue cycles behind */ @@ -491,7 +492,7 @@ typedef struct afl_state { u8 *var_bytes; /* Bytes that appear to be variable */ - #define n_fuzz_size (1 << 21) +#define N_FUZZ_SIZE (1 << 21) u32 *n_fuzz; volatile u8 stop_soon, /* Ctrl-C pressed? */ diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index e04ebda8..bd8eb27a 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -381,8 +381,9 @@ bool AFLdict2filePass::runOnModule(Module &M) { if (debug) fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n", - FuncName.c_str(), (void*)Str1P, Str1P->getName().str().c_str(), - Str1.c_str(), HasStr1 == true ? "true" : "false", (void*)Str2P, + FuncName.c_str(), (void *)Str1P, + Str1P->getName().str().c_str(), Str1.c_str(), + HasStr1 == true ? "true" : "false", (void *)Str2P, Str2P->getName().str().c_str(), Str2.c_str(), HasStr2 == true ? "true" : "false"); @@ -436,7 +437,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { valueMap[Str1P] = new std::string(Str2); if (debug) - fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), (void*)Str1P); + fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), + (void *)Str1P); continue; } @@ -455,7 +457,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { Str2 = *strng; HasStr2 = true; if (debug) - fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(), (void*)Str2P); + fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(), + (void *)Str2P); } @@ -497,7 +500,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { Str1 = *strng; HasStr1 = true; if (debug) - fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(), (void*)Str1P); + fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(), + (void *)Str1P); } diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index d5de3dbb..9921de0c 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -210,7 +210,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } if (!icomps.size()) return false; - if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp instructions\n"; + // if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp + // instructions\n"; for (auto &selectcmpInst : icomps) { @@ -259,8 +260,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { bool CmpLogInstructions::runOnModule(Module &M) { if (getenv("AFL_QUIET") == NULL) - llvm::errs() - << "Running cmplog-instructions-pass by andreafioraldi@gmail.com\n"; + printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n"); else be_quiet = 1; hookInstrs(M); diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc index c44f38c4..e92883ae 100644 --- a/instrumentation/cmplog-routines-pass.cc +++ b/instrumentation/cmplog-routines-pass.cc @@ -149,9 +149,11 @@ bool CmpLogRoutines::hookRtns(Module &M) { } if (!calls.size()) return false; - if (!be_quiet) - errs() << "Hooking " << calls.size() - << " calls with pointers as arguments\n"; + /* + if (!be_quiet) + errs() << "Hooking " << calls.size() + << " calls with pointers as arguments\n"; + */ for (auto &callInst : calls) { @@ -179,8 +181,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { bool CmpLogRoutines::runOnModule(Module &M) { if (getenv("AFL_QUIET") == NULL) - llvm::errs() - << "Running cmplog-routines-pass by andreafioraldi@gmail.com\n"; + printf("Running cmplog-routines-pass by andreafioraldi@gmail.com\n"); else be_quiet = 1; hookRtns(M); diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 9d2f4a92..3a4abd6e 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -339,8 +339,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (!calls.size()) return false; if (!be_quiet) - errs() << "Replacing " << calls.size() - << " calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n"; + printf( + "Replacing %lu calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n", + calls.size()); for (auto &callInst : calls) { @@ -426,11 +427,14 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, else unrollLen = constStrLen; - if (!be_quiet) - errs() << callInst->getCalledFunction()->getName() << ": unroll len " - << unrollLen - << ((isSizedcmp && !isConstSized) ? ", variable n" : "") << ": " - << ConstStr << "\n"; + /* + if (!be_quiet) + errs() << callInst->getCalledFunction()->getName() << ": unroll len " + << unrollLen + << ((isSizedcmp && !isConstSized) ? ", variable n" : "") << ": + " + << ConstStr << "\n"; + */ /* split before the call instruction */ BasicBlock *bb = callInst->getParent(); @@ -556,10 +560,12 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, bool CompareTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) - llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, " - "extended by heiko@hexco.de\n"; + printf( + "Running compare-transform-pass by laf.intel@gmail.com, extended by " + "heiko@hexco.de\n"); else be_quiet = 1; + transformCmps(M, true, true, true, true, true); verifyModule(M); diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 2fb90e5e..6d0c52a4 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -1262,8 +1262,9 @@ bool SplitComparesTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) { - errs() << "Split-compare-pass by laf.intel@gmail.com, extended by " - "heiko@hexco.de\n"; + printf( + "Split-compare-pass by laf.intel@gmail.com, extended by " + "heiko@hexco.de\n"); } else { @@ -1275,13 +1276,15 @@ bool SplitComparesTransform::runOnModule(Module &M) { count = splitFPCompares(M); - if (!be_quiet) { + /* + if (!be_quiet) { - errs() << "Split-floatingpoint-compare-pass: " << count - << " FP comparisons split\n"; + errs() << "Split-floatingpoint-compare-pass: " << count + << " FP comparisons split\n"; - } + } + */ simplifyFPCompares(M); } @@ -1294,10 +1297,12 @@ bool SplitComparesTransform::runOnModule(Module &M) { case 64: count = splitIntCompares(M, bitw); - if (!be_quiet) - errs() << "Split-integer-compare-pass " << bitw << "bit: " << count - << " split\n"; - + /* + if (!be_quiet) + errs() << "Split-integer-compare-pass " << bitw << "bit: " << + count + << " split\n"; + */ bitw >>= 1; #if LLVM_VERSION_MAJOR > 3 || \ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7) @@ -1305,10 +1310,12 @@ bool SplitComparesTransform::runOnModule(Module &M) { #endif case 32: count = splitIntCompares(M, bitw); - if (!be_quiet) - errs() << "Split-integer-compare-pass " << bitw << "bit: " << count - << " split\n"; - + /* + if (!be_quiet) + errs() << "Split-integer-compare-pass " << bitw << "bit: " << + count + << " split\n"; + */ bitw >>= 1; #if LLVM_VERSION_MAJOR > 3 || \ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7) @@ -1316,15 +1323,17 @@ bool SplitComparesTransform::runOnModule(Module &M) { #endif case 16: count = splitIntCompares(M, bitw); - if (!be_quiet) - errs() << "Split-integer-compare-pass " << bitw << "bit: " << count - << " split\n"; - + /* + if (!be_quiet) + errs() << "Split-integer-compare-pass " << bitw << "bit: " << + count + << " split\n"; + */ bitw >>= 1; break; default: - if (!be_quiet) errs() << "NOT Running split-compare-pass \n"; + // if (!be_quiet) errs() << "NOT Running split-compare-pass \n"; return false; break; diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index a79d4114..97ab04a4 100644 --- a/instrumentation/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc @@ -327,10 +327,11 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { } if (!switches.size()) return false; - if (!be_quiet) - errs() << "Rewriting " << switches.size() << " switch statements " - << "\n"; - + /* + if (!be_quiet) + errs() << "Rewriting " << switches.size() << " switch statements " + << "\n"; + */ for (auto &SI : switches) { BasicBlock *CurBlock = SI->getParent(); @@ -341,15 +342,17 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { BasicBlock *Default = SI->getDefaultDest(); unsigned bitw = Val->getType()->getIntegerBitWidth(); - if (!be_quiet) - errs() << "switch: " << SI->getNumCases() << " cases " << bitw - << " bit\n"; + /* + if (!be_quiet) + errs() << "switch: " << SI->getNumCases() << " cases " << bitw + << " bit\n"; + */ /* If there is only the default destination or the condition checks 8 bit or * less, don't bother with the code below. */ if (!SI->getNumCases() || bitw <= 8) { - if (!be_quiet) errs() << "skip trivial switch..\n"; + // if (!be_quiet) errs() << "skip trivial switch..\n"; continue; } @@ -415,7 +418,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { bool SplitSwitchesTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) - llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n"; + printf("Running split-switches-pass by laf.intel@gmail.com\n"); else be_quiet = 1; splitSwitches(M); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 64de86a2..a22223b9 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -556,8 +556,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); /* Saturated increment */ - if (afl->n_fuzz[cksum % n_fuzz_size] < 0xFFFFFFFF) - afl->n_fuzz[cksum % n_fuzz_size]++; + if (afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF) + afl->n_fuzz[cksum % N_FUZZ_SIZE]++; } @@ -597,10 +597,15 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (cksum) afl->queue_top->exec_cksum = cksum; else - afl->queue_top->exec_cksum = + cksum = afl->queue_top->exec_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - afl->n_fuzz[cksum % n_fuzz_size] = 1; + if (afl->schedule >= FAST && afl->schedule <= RARE) { + + afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; + afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; + + } /* Try to calibrate inline; this also calls update_bitmap_score() when successful. */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b825837f..65478a78 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -732,8 +732,8 @@ void read_testcases(afl_state_t *afl, u8 *directory) { if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - - afl->n_fuzz[cksum % n_fuzz_size] = 1; + afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; + afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index dfabba7b..0d7d0314 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -308,9 +308,9 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { u64 fuzz_p2; if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) - fuzz_p2 = 0; // Skip the fuzz_p2 comparison + fuzz_p2 = 0; // Skip the fuzz_p2 comparison else if (unlikely(afl->schedule == RARE)) - fuzz_p2 = next_pow2(afl->n_fuzz[q->exec_cksum % n_fuzz_size]); + fuzz_p2 = next_pow2(afl->n_fuzz[q->n_fuzz_entry]); else fuzz_p2 = q->fuzz_level; @@ -336,7 +336,8 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { u64 top_rated_fav_factor; u64 top_rated_fuzz_p2; if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) - top_rated_fuzz_p2 = next_pow2(afl->n_fuzz[afl->top_rated[i]->exec_cksum % n_fuzz_size]); + top_rated_fuzz_p2 = + next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]); else top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level; @@ -607,11 +608,10 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } - u32 n_paths; - double factor = 1.0; + u32 n_paths; + double factor = 1.0; long double fuzz_mu; - switch (afl->schedule) { case EXPLORE: @@ -634,7 +634,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { struct queue_entry *queue_it = afl->queue; while (queue_it) { - fuzz_mu += log2(afl->n_fuzz[q->exec_cksum % n_fuzz_size]); + fuzz_mu += log2(afl->n_fuzz[q->n_fuzz_entry]); n_paths++; queue_it = queue_it->next; @@ -645,7 +645,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { fuzz_mu = fuzz_mu / n_paths; - if (log2(afl->n_fuzz[q->exec_cksum % n_fuzz_size]) > fuzz_mu) { + if (log2(afl->n_fuzz[q->n_fuzz_entry]) > fuzz_mu) { /* Never skip favourites */ if (!q->favored) factor = 0; @@ -660,7 +660,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { // Don't modify unfuzzed seeds if (q->fuzz_level == 0) break; - switch ((u32)log2(afl->n_fuzz[q->exec_cksum % n_fuzz_size])) { + switch ((u32)log2(afl->n_fuzz[q->n_fuzz_entry])) { case 0 ... 1: factor = 4; @@ -691,17 +691,17 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } - if (q->favored) - factor *= 1.15; + if (q->favored) factor *= 1.15; break; case LIN: - factor = q->fuzz_level / (afl->n_fuzz[q->exec_cksum % n_fuzz_size] + 1); + factor = q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1); break; case QUAD: - factor = q->fuzz_level * q->fuzz_level / (afl->n_fuzz[q->exec_cksum % n_fuzz_size] + 1); + factor = + q->fuzz_level * q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1); break; case MMOPT: @@ -726,8 +726,8 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { perf_score += (q->tc_ref * 10); // the more often fuzz result paths are equal to this queue entry, // reduce its value - perf_score *= - (1 - (double)((double)afl->n_fuzz[q->exec_cksum % n_fuzz_size] / (double)afl->fsrv.total_execs)); + perf_score *= (1 - (double)((double)afl->n_fuzz[q->n_fuzz_entry] / + (double)afl->fsrv.total_execs)); break; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 889f753d..273d1c14 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -939,7 +939,7 @@ int main(int argc, char **argv_orig, char **envp) { /* Dynamically allocate memory for AFLFast schedules */ if (afl->schedule >= FAST && afl->schedule <= RARE) { - afl->n_fuzz = ck_alloc(n_fuzz_size * sizeof(u32)); + afl->n_fuzz = ck_alloc(N_FUZZ_SIZE * sizeof(u32)); } -- cgit 1.4.1 From 223974336196a8f3617548e8ca88ee084794ed60 Mon Sep 17 00:00:00 2001 From: Edznux Date: Thu, 1 Oct 2020 00:11:01 +0200 Subject: Rewrote format metric to be simpler/more static --- include/afl-fuzz.h | 2 +- src/afl-fuzz-statsd.c | 78 ++++++++++++++++++++++----------------------------- 2 files changed, 35 insertions(+), 45 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 65327d93..61672169 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -958,7 +958,7 @@ void show_init_stats(afl_state_t *); int statsd_init(char *host, int port); int send_statsd_metric(afl_state_t *afl); -int statsd_format_metric(afl_state_t *afl, char *formatted[], size_t *num_of_tags); +int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); /* Run */ diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index d09d1f6e..a53569c3 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -9,7 +9,7 @@ #include "afl-fuzz.h" -#define MAX_STATSD_PACKET_SIZE 1024 +#define MAX_STATSD_PACKET_SIZE 1400 #define MAX_TAG_LEN 200 int sock = 0; @@ -56,6 +56,7 @@ int send_statsd_metric(afl_state_t *afl){ char* port_env; char* host_env; if ((port_env = getenv("AFL_STATSD_PORT")) != NULL) { + // sanitization check ? port = atoi(port_env); } if ((host_env = getenv("AFL_STATSD_HOST")) != NULL) { @@ -73,55 +74,44 @@ int send_statsd_metric(afl_state_t *afl){ perror("sock"); return -1; } - char *formatted[] = {}; - size_t *num_of_tags = 0; - statsd_format_metric(afl, &formatted, num_of_tags); - for (size_t i = 0; i < &num_of_tags; i++){ - printf("%ld\n", i); - printf("%s\n", formatted[i]); - if (sendto(sock, formatted[i], strlen(formatted[i]), 0, (struct sockaddr *) &server, sizeof(server)) == -1) { - perror("sendto"); - return -1; - } + + char buff[MAX_STATSD_PACKET_SIZE] = {0}; + + statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); + if (sendto(sock, buff, MAX_STATSD_PACKET_SIZE, 0, + (struct sockaddr *)&server, sizeof(server)) == -1) { + perror("sendto"); + return -1; } - + close(sock); sock=0; return 0; } -int statsd_format_metric(afl_state_t *afl, char *formatted[], size_t *num_of_tags){ +int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen){ + /* + metric format: + :|| + tags format: + #key:value,key:value,key + */ + char tags[MAX_TAG_LEN * 2] = {0}; + snprintf(tags, MAX_TAG_LEN * 2, + "banner:%s,afl_version:%s", + afl->use_banner, + VERSION); + // Sends multiple metrics with one UDP Packet. + // bufflen will limit to the max safe size. + snprintf(buff, bufflen, + "fuzzing.afl.cycle_done:%llu|g|#%s\n" + "fuzzing.afl.total_path:%u|g|#%s\n" + "fuzzing.afl.unique_crashes:%llu|g|#%s\n" + "fuzzing.afl.total_crashes:%llu|g|#%s\n" + "fuzzing.afl.unique_hangs:%llu|g|#%s\n", + afl->queue_cycle, tags, afl->queued_paths, tags, afl->unique_crashes, + tags, afl->total_crashes, tags, afl->unique_hangs, tags); - char *tags = "key:value"; - - *num_of_tags = 0; // reset - - const char *metrics[] = { - "fuzzing.afl.cycle_done:%llu|g|#%s\n", - "fuzzing.afl.total_path:%lu|g|#%s\n", - "fuzzing.afl.unique_crashes:%llu|g|#%s\n", - "fuzzing.afl.total_crashes:%llu|g|#%s\n", - "fuzzing.afl.unique_hangs:%llu|g|#%s\n" - }; - - const int metricValues[] = { - afl->queue_cycle, - afl->queued_paths, - afl->unique_crashes, - afl->total_crashes, - afl->unique_hangs - }; - - *num_of_tags = sizeof(metrics)/sizeof(metrics[0]); - - for (size_t i = 0; i < &num_of_tags; i++){ - char *tmp = malloc(MAX_STATSD_PACKET_SIZE); - if(tmp == NULL){ - return -1; - } - snprintf(tmp, MAX_STATSD_PACKET_SIZE, metrics[i], metricValues[i], tags); - formatted[i] = tmp; - } - return 0; + return 0; } \ No newline at end of file -- cgit 1.4.1 From ff8c6d24156811333c855755fea8fafc43e133bc Mon Sep 17 00:00:00 2001 From: Edznux Date: Sun, 4 Oct 2020 03:22:28 +0200 Subject: Adds other metrics --- include/afl-fuzz.h | 2 +- src/afl-fuzz-statsd.c | 74 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 19 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 61672169..eecfcf75 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -956,7 +956,7 @@ void show_init_stats(afl_state_t *); /* StatsD */ -int statsd_init(char *host, int port); +int statsd_socket_init(char *host, int port); int send_statsd_metric(afl_state_t *afl); int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index a53569c3..d9cd12d2 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -9,14 +9,15 @@ #include "afl-fuzz.h" -#define MAX_STATSD_PACKET_SIZE 1400 +#define MAX_STATSD_PACKET_SIZE 4096 #define MAX_TAG_LEN 200 +#define METRIC_PREFIX "fuzzing" int sock = 0; struct sockaddr_in server; int error = 0; -int statsd_init(char *host, int port){ +int statsd_socket_init(char *host, int port){ if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){ perror("socket"); exit(1); @@ -45,11 +46,9 @@ int statsd_init(char *host, int port){ } int send_statsd_metric(afl_state_t *afl){ - u64 cur_ms = get_cur_time(); - if (cur_ms - afl->stats_last_plot_ms < 1000) { - return 0; - } - + /* default port and host. + Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment variable, if they exists. + */ u16 port = 8125; char* host = "127.0.0.1"; @@ -64,7 +63,7 @@ int send_statsd_metric(afl_state_t *afl){ host = host_env; } - error = statsd_init(host, port); + error = statsd_socket_init(host, port); if (error){ perror("Failed to init statsd client. Aborting"); return -1; @@ -78,7 +77,7 @@ int send_statsd_metric(afl_state_t *afl){ char buff[MAX_STATSD_PACKET_SIZE] = {0}; statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); - if (sendto(sock, buff, MAX_STATSD_PACKET_SIZE, 0, + if (sendto(sock, buff, strlen(buff), 0, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("sendto"); return -1; @@ -95,23 +94,62 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen){ metric format: :|| tags format: - #key:value,key:value,key + */ + #ifdef USE_STATSD_TAGS + /* #key:value,key:value,key */ char tags[MAX_TAG_LEN * 2] = {0}; snprintf(tags, MAX_TAG_LEN * 2, - "banner:%s,afl_version:%s", + "|#banner:%s,afl_version:%s", afl->use_banner, VERSION); + #else + char *tags = ""; + #endif // Sends multiple metrics with one UDP Packet. // bufflen will limit to the max safe size. snprintf(buff, bufflen, - "fuzzing.afl.cycle_done:%llu|g|#%s\n" - "fuzzing.afl.total_path:%u|g|#%s\n" - "fuzzing.afl.unique_crashes:%llu|g|#%s\n" - "fuzzing.afl.total_crashes:%llu|g|#%s\n" - "fuzzing.afl.unique_hangs:%llu|g|#%s\n", - afl->queue_cycle, tags, afl->queued_paths, tags, afl->unique_crashes, - tags, afl->total_crashes, tags, afl->unique_hangs, tags); + METRIC_PREFIX".cycle_done:%llu|g%s\n" + METRIC_PREFIX".cycles_wo_finds:%llu|g%s\n" + METRIC_PREFIX".execs_done:%llu|g%s\n" + METRIC_PREFIX".execs_per_sec:%0.02f|g%s\n" + METRIC_PREFIX".paths_total:%u|g%s\n" + METRIC_PREFIX".paths_favored:%u|g%s\n" + METRIC_PREFIX".paths_found:%u|g%s\n" + METRIC_PREFIX".paths_imported:%u|g%s\n" + METRIC_PREFIX".max_depth:%u|g%s\n" + METRIC_PREFIX".cur_path:%u|g%s\n" + METRIC_PREFIX".pending_favs:%u|g%s\n" + METRIC_PREFIX".pending_total:%u|g%s\n" + METRIC_PREFIX".variable_paths:%u|g%s\n" + METRIC_PREFIX".unique_crashes:%llu|g%s\n" + METRIC_PREFIX".unique_hangs:%llu|g%s\n" + METRIC_PREFIX".total_crashes:%llu|g%s\n" + METRIC_PREFIX".slowest_exec_ms:%u|g%s\n" + METRIC_PREFIX".edges_found:%u|g%s\n" + METRIC_PREFIX".var_byte_count:%u|g%s\n" + METRIC_PREFIX".havoc_expansion:%u|g%s\n", + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, + afl->cycles_wo_finds, tags, + afl->fsrv.total_execs, tags, + afl->fsrv.total_execs / ((double)(get_cur_time() - afl->start_time) / 1000), tags, + afl->queued_paths, tags, + afl->queued_favored, tags, + afl->queued_discovered, tags, + afl->queued_imported, tags, + afl->max_depth, tags, + afl->current_entry, tags, + afl->pending_favored, tags, + afl->pending_not_fuzzed, tags, + afl->queued_variable, tags, + afl->unique_crashes, tags, + afl->unique_hangs, tags, + afl->total_crashes, tags, + afl->slowest_exec_ms, tags, + count_non_255_bytes(afl, afl->virgin_bits), tags, + afl->var_byte_count, tags, + afl->expand_havoc, tags + ); return 0; } \ No newline at end of file -- cgit 1.4.1 From ca6106a1dc5b39df9f167b3d30ea4472636564c9 Mon Sep 17 00:00:00 2001 From: Edznux Date: Sun, 4 Oct 2020 14:24:25 +0200 Subject: Refactor --- include/afl-fuzz.h | 4 ++- include/config.h | 2 ++ src/afl-fuzz-stats.c | 6 +++-- src/afl-fuzz-statsd.c | 73 ++++++++++++++++++++++++++------------------------- 4 files changed, 46 insertions(+), 39 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index eecfcf75..f341e300 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -635,6 +635,8 @@ typedef struct afl_state { u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed; u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs; + // StatsD + u64 statsd_last_send_ms; double stats_avg_exec; u8 *clean_trace; @@ -957,7 +959,7 @@ void show_init_stats(afl_state_t *); /* StatsD */ int statsd_socket_init(char *host, int port); -int send_statsd_metric(afl_state_t *afl); +int statsd_send_metric(afl_state_t *afl); int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); /* Run */ diff --git a/include/config.h b/include/config.h index c55dda2b..8cdf0633 100644 --- a/include/config.h +++ b/include/config.h @@ -47,6 +47,8 @@ Server config can be adjusted with AFL_STATSD_HOST and AFL_STATSD_PORT env var. #define USE_STATSD #define STATSD_UPDATE_SEC 1 +#define STATSD_DEFAULT_PORT 8125 +#define STATSD_DEFAULT_HOST "127.0.0.1" /* If you want to have the original afl internal memory corruption checks. Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index bbbe6ba6..ffef7647 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -423,8 +423,10 @@ void show_stats(afl_state_t *afl) { } #ifdef USE_STATSD - if (cur_ms - afl->stats_last_stats_ms > STATSD_UPDATE_SEC * 1000) { - if(send_statsd_metric(afl)){ + if (cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000) { + /* reset counter, even if send failed. */ + afl->statsd_last_send_ms = cur_ms; + if(statsd_send_metric(afl)){ WARNF("coundln't send statsd metric."); } } diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index d9cd12d2..5bd1b537 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -13,11 +13,12 @@ #define MAX_TAG_LEN 200 #define METRIC_PREFIX "fuzzing" -int sock = 0; struct sockaddr_in server; int error = 0; +int statds_sock = 0; int statsd_socket_init(char *host, int port){ + int sock; if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){ perror("socket"); exit(1); @@ -42,72 +43,72 @@ int statsd_socket_init(char *host, int port){ memcpy(&(server.sin_addr), &((struct sockaddr_in*)result->ai_addr)->sin_addr, sizeof(struct in_addr)); freeaddrinfo(result); - return 0; + return sock; } -int send_statsd_metric(afl_state_t *afl){ - /* default port and host. +int statsd_send_metric(afl_state_t *afl){ + + char buff[MAX_STATSD_PACKET_SIZE] = {0}; + /* Default port and host. Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment variable, if they exists. - */ - u16 port = 8125; - char* host = "127.0.0.1"; + */ + u16 port = STATSD_DEFAULT_PORT; + char* host = STATSD_DEFAULT_HOST; char* port_env; char* host_env; if ((port_env = getenv("AFL_STATSD_PORT")) != NULL) { - // sanitization check ? port = atoi(port_env); } if ((host_env = getenv("AFL_STATSD_HOST")) != NULL) { - // sanitization check ? host = host_env; } - - error = statsd_socket_init(host, port); - if (error){ - perror("Failed to init statsd client. Aborting"); - return -1; - } - - if(!sock){ - perror("sock"); - return -1; - } - char buff[MAX_STATSD_PACKET_SIZE] = {0}; + /* statds_sock is a global variable. We set it once in the beginning and reuse the socket. + If the sendto later fail, we reset it to 0 to be able to recreate it. + */ + if(!statds_sock){ + statds_sock = statsd_socket_init(host, port); + if(!statds_sock){ + perror("Cannot create socket"); + return -1; + } + } statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); - if (sendto(sock, buff, strlen(buff), 0, - (struct sockaddr *)&server, sizeof(server)) == -1) { - perror("sendto"); - return -1; + if (sendto(statds_sock, buff, strlen(buff), 0, (struct sockaddr *)&server, sizeof(server)) == -1) { + if(!close(statds_sock)){ + perror("Cannot close socket"); + } + statds_sock = 0; + perror("Cannot sendto"); + return -1; } - close(sock); - sock=0; - return 0; } int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen){ - /* - metric format: - :|| - tags format: + /* Metric format: + :| */ #ifdef USE_STATSD_TAGS - /* #key:value,key:value,key + /* Tags format: DogStatsD + :||#key:value,key:value,key */ char tags[MAX_TAG_LEN * 2] = {0}; snprintf(tags, MAX_TAG_LEN * 2, "|#banner:%s,afl_version:%s", afl->use_banner, VERSION); - #else + #else + /* No tags. + */ char *tags = ""; #endif - // Sends multiple metrics with one UDP Packet. - // bufflen will limit to the max safe size. + /* Sends multiple metrics with one UDP Packet. + bufflen will limit to the max safe size. + */ snprintf(buff, bufflen, METRIC_PREFIX".cycle_done:%llu|g%s\n" METRIC_PREFIX".cycles_wo_finds:%llu|g%s\n" -- cgit 1.4.1 From 1a12db1b59e792c7a46e606fba60bdf855d00c29 Mon Sep 17 00:00:00 2001 From: Edznux Date: Sun, 4 Oct 2020 16:11:05 +0200 Subject: Code format --- include/afl-fuzz.h | 1 + src/afl-fuzz-run.c | 1 + src/afl-fuzz-stats.c | 11 ++- src/afl-fuzz-statsd.c | 256 +++++++++++++++++++++++++------------------------- 4 files changed, 136 insertions(+), 133 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 427e1aec..75dfc4e5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -635,6 +635,7 @@ typedef struct afl_state { u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs; // StatsD u64 statsd_last_send_ms; + double stats_avg_exec; u8 *clean_trace; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 5e74dff3..ee22b0f6 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -903,6 +903,7 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { afl->stage_cur + 1 == afl->stage_max) { show_stats(afl); + } return 0; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 2f1e3367..942670b4 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -423,15 +423,16 @@ void show_stats(afl_state_t *afl) { } - #ifdef USE_STATSD +#ifdef USE_STATSD if (cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000) { + /* reset counter, even if send failed. */ afl->statsd_last_send_ms = cur_ms; - if(statsd_send_metric(afl)){ - WARNF("coundln't send statsd metric."); - } + if (statsd_send_metric(afl)) { WARNF("coundln't send statsd metric."); } + } - #endif + +#endif /* Every now and then, write plot data. */ diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index 298138be..e94f090c 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -8,149 +8,149 @@ #include #include "afl-fuzz.h" - #define MAX_STATSD_PACKET_SIZE 4096 #define MAX_TAG_LEN 200 #define METRIC_PREFIX "fuzzing" struct sockaddr_in server; -int error = 0; -int statds_sock = 0; - -int statsd_socket_init(char *host, int port){ - int sock; - if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){ - perror("socket"); - exit(1); - } +int error = 0; +int statds_sock = 0; - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; - server.sin_port = htons(port); - - struct addrinfo *result; - struct addrinfo hints; +int statsd_socket_init(char *host, int port) { - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; + int sock; + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { - if ( (error = getaddrinfo(host, NULL, &hints, &result)) ) { - perror("getaddrinfo"); - exit(1); - } + FATAL("Failed to create socket"); + + } + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_port = htons(port); + + struct addrinfo *result; + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; - memcpy(&(server.sin_addr), &((struct sockaddr_in*)result->ai_addr)->sin_addr, sizeof(struct in_addr)); - freeaddrinfo(result); + if ((error = getaddrinfo(host, NULL, &hints, &result))) { + + FATAL("Fail to getaddrinfo"); + + } + + memcpy(&(server.sin_addr), &((struct sockaddr_in *)result->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(result); + + return sock; - return sock; } -int statsd_send_metric(afl_state_t *afl){ - - char buff[MAX_STATSD_PACKET_SIZE] = {0}; - /* Default port and host. - Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment variable, if they exists. - */ - u16 port = STATSD_DEFAULT_PORT; - char* host = STATSD_DEFAULT_HOST; - - char* port_env; - char* host_env; - if ((port_env = getenv("AFL_STATSD_PORT")) != NULL) { - port = atoi(port_env); - } - if ((host_env = getenv("AFL_STATSD_HOST")) != NULL) { - host = host_env; - } +int statsd_send_metric(afl_state_t *afl) { - /* statds_sock is a global variable. We set it once in the beginning and reuse the socket. - If the sendto later fail, we reset it to 0 to be able to recreate it. - */ - if(!statds_sock){ - statds_sock = statsd_socket_init(host, port); - if(!statds_sock){ - perror("Cannot create socket"); - return -1; - } - } + char buff[MAX_STATSD_PACKET_SIZE] = {0}; + /* Default port and host. + Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment + variable, if they exists. + */ + u16 port = STATSD_DEFAULT_PORT; + char *host = STATSD_DEFAULT_HOST; + + char *port_env; + char *host_env; + if ((port_env = getenv("AFL_STATSD_PORT")) != NULL) { port = atoi(port_env); } + if ((host_env = getenv("AFL_STATSD_HOST")) != NULL) { host = host_env; } + + /* statds_sock is a global variable. We set it once in the beginning and reuse + the socket. If the sendto later fail, we reset it to 0 to be able to recreate + it. + */ + if (!statds_sock) { + + statds_sock = statsd_socket_init(host, port); + if (!statds_sock) { + + WARNF("Cannot create socket"); + return -1; - statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); - if (sendto(statds_sock, buff, strlen(buff), 0, (struct sockaddr *)&server, sizeof(server)) == -1) { - if(!close(statds_sock)){ - perror("Cannot close socket"); - } - statds_sock = 0; - perror("Cannot sendto"); - return -1; } - return 0; + } + + statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); + if (sendto(statds_sock, buff, strlen(buff), 0, (struct sockaddr *)&server, + sizeof(server)) == -1) { + + if (!close(statds_sock)) { perror("Cannot close socket"); } + statds_sock = 0; + WARNF("Cannot sendto"); + return -1; + + } + + return 0; + +} + +int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) { + +/* Metric format: +:| +*/ +#ifdef USE_DOGSTATSD_TAGS + /* Tags format: DogStatsD + :||#key:value,key:value,key + */ + char tags[MAX_TAG_LEN * 2] = {0}; + snprintf(tags, MAX_TAG_LEN * 2, "|#banner:%s,afl_version:%s", afl->use_banner, + VERSION); +#else + /* No tags. + */ + char *tags = ""; +#endif + /* Sends multiple metrics with one UDP Packet. + bufflen will limit to the max safe size. + */ + snprintf(buff, bufflen, + METRIC_PREFIX ".cycle_done:%llu|g%s\n" METRIC_PREFIX + ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX + ".execs_done:%llu|g%s\n" METRIC_PREFIX + ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX + ".paths_total:%u|g%s\n" METRIC_PREFIX + ".paths_favored:%u|g%s\n" METRIC_PREFIX + ".paths_found:%u|g%s\n" METRIC_PREFIX + ".paths_imported:%u|g%s\n" METRIC_PREFIX + ".max_depth:%u|g%s\n" METRIC_PREFIX + ".cur_path:%u|g%s\n" METRIC_PREFIX + ".pending_favs:%u|g%s\n" METRIC_PREFIX + ".pending_total:%u|g%s\n" METRIC_PREFIX + ".variable_paths:%u|g%s\n" METRIC_PREFIX + ".unique_crashes:%llu|g%s\n" METRIC_PREFIX + ".unique_hangs:%llu|g%s\n" METRIC_PREFIX + ".total_crashes:%llu|g%s\n" METRIC_PREFIX + ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX + ".edges_found:%u|g%s\n" METRIC_PREFIX + ".var_byte_count:%u|g%s\n" METRIC_PREFIX + ".havoc_expansion:%u|g%s\n", + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, + afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags, + afl->fsrv.total_execs / + ((double)(get_cur_time() - afl->start_time) / 1000), + tags, afl->queued_paths, tags, afl->queued_favored, tags, + afl->queued_discovered, tags, afl->queued_imported, tags, + afl->max_depth, tags, afl->current_entry, tags, afl->pending_favored, + tags, afl->pending_not_fuzzed, tags, afl->queued_variable, tags, + afl->unique_crashes, tags, afl->unique_hangs, tags, + afl->total_crashes, tags, afl->slowest_exec_ms, tags, + count_non_255_bytes(afl, afl->virgin_bits), tags, + afl->var_byte_count, tags, afl->expand_havoc, tags); + + return 0; + } -int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen){ - /* Metric format: - :| - */ - #ifdef USE_DOGSTATSD_TAGS - /* Tags format: DogStatsD - :||#key:value,key:value,key - */ - char tags[MAX_TAG_LEN * 2] = {0}; - snprintf(tags, MAX_TAG_LEN * 2, - "|#banner:%s,afl_version:%s", - afl->use_banner, - VERSION); - #else - /* No tags. - */ - char *tags = ""; - #endif - /* Sends multiple metrics with one UDP Packet. - bufflen will limit to the max safe size. - */ - snprintf(buff, bufflen, - METRIC_PREFIX".cycle_done:%llu|g%s\n" - METRIC_PREFIX".cycles_wo_finds:%llu|g%s\n" - METRIC_PREFIX".execs_done:%llu|g%s\n" - METRIC_PREFIX".execs_per_sec:%0.02f|g%s\n" - METRIC_PREFIX".paths_total:%u|g%s\n" - METRIC_PREFIX".paths_favored:%u|g%s\n" - METRIC_PREFIX".paths_found:%u|g%s\n" - METRIC_PREFIX".paths_imported:%u|g%s\n" - METRIC_PREFIX".max_depth:%u|g%s\n" - METRIC_PREFIX".cur_path:%u|g%s\n" - METRIC_PREFIX".pending_favs:%u|g%s\n" - METRIC_PREFIX".pending_total:%u|g%s\n" - METRIC_PREFIX".variable_paths:%u|g%s\n" - METRIC_PREFIX".unique_crashes:%llu|g%s\n" - METRIC_PREFIX".unique_hangs:%llu|g%s\n" - METRIC_PREFIX".total_crashes:%llu|g%s\n" - METRIC_PREFIX".slowest_exec_ms:%u|g%s\n" - METRIC_PREFIX".edges_found:%u|g%s\n" - METRIC_PREFIX".var_byte_count:%u|g%s\n" - METRIC_PREFIX".havoc_expansion:%u|g%s\n", - afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, - afl->cycles_wo_finds, tags, - afl->fsrv.total_execs, tags, - afl->fsrv.total_execs / ((double)(get_cur_time() - afl->start_time) / 1000), tags, - afl->queued_paths, tags, - afl->queued_favored, tags, - afl->queued_discovered, tags, - afl->queued_imported, tags, - afl->max_depth, tags, - afl->current_entry, tags, - afl->pending_favored, tags, - afl->pending_not_fuzzed, tags, - afl->queued_variable, tags, - afl->unique_crashes, tags, - afl->unique_hangs, tags, - afl->total_crashes, tags, - afl->slowest_exec_ms, tags, - count_non_255_bytes(afl, afl->virgin_bits), tags, - afl->var_byte_count, tags, - afl->expand_havoc, tags - ); - - return 0; -} \ No newline at end of file -- cgit 1.4.1 From 2bf3a70e2b5cd0961cb5b1d525f3fd58c4408ba5 Mon Sep 17 00:00:00 2001 From: Edznux Date: Mon, 5 Oct 2020 22:01:50 +0200 Subject: Correctly handle env var. --- include/afl-fuzz.h | 2 +- src/afl-fuzz-state.c | 13 +++++++++++++ src/afl-fuzz-statsd.c | 6 ++---- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 75dfc4e5..d79920bd 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -359,7 +359,7 @@ typedef struct afl_env_vars { u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, - *afl_max_det_extras; + *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port; } afl_env_vars_t; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 4e817843..aefa226d 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -363,6 +363,19 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_forksrv_init_tmout = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_STATSD_HOST", + + afl_environment_variable_len)) { + + afl->afl_env.afl_statsd_host = + (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_STATSD_PORT", + + afl_environment_variable_len)) { + + afl->afl_env.afl_statsd_port = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index e94f090c..7ae2efca 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -60,10 +60,8 @@ int statsd_send_metric(afl_state_t *afl) { u16 port = STATSD_DEFAULT_PORT; char *host = STATSD_DEFAULT_HOST; - char *port_env; - char *host_env; - if ((port_env = getenv("AFL_STATSD_PORT")) != NULL) { port = atoi(port_env); } - if ((host_env = getenv("AFL_STATSD_HOST")) != NULL) { host = host_env; } + if (afl->afl_env.afl_statsd_port) { port = atoi(afl->afl_env.afl_statsd_port); } + if (afl->afl_env.afl_statsd_host) { host = afl->afl_env.afl_statsd_host; } /* statds_sock is a global variable. We set it once in the beginning and reuse the socket. If the sendto later fail, we reset it to 0 to be able to recreate -- cgit 1.4.1 From 916b6fd3171bab1b17e576e088f094080ff5f6cf Mon Sep 17 00:00:00 2001 From: Edznux Date: Mon, 5 Oct 2020 22:21:01 +0200 Subject: Refactor global var into afl_state_t struct --- include/afl-fuzz.h | 7 +++++-- src/afl-fuzz-statsd.c | 51 +++++++++++++++++++++++---------------------------- 2 files changed, 28 insertions(+), 30 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index d79920bd..7eeeb79b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -633,8 +633,11 @@ typedef struct afl_state { u64 plot_prev_qc, plot_prev_uc, plot_prev_uh, plot_prev_ed; u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs; - // StatsD + + /* StatsD */ u64 statsd_last_send_ms; + struct sockaddr_in statsd_server; + int statsd_sock; double stats_avg_exec; @@ -958,7 +961,7 @@ void show_init_stats(afl_state_t *); /* StatsD */ -int statsd_socket_init(char *host, int port); +int statsd_socket_init(afl_state_t *afl); int statsd_send_metric(afl_state_t *afl); int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index 7ae2efca..0ec1bcb7 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -12,11 +12,16 @@ #define MAX_TAG_LEN 200 #define METRIC_PREFIX "fuzzing" -struct sockaddr_in server; -int error = 0; -int statds_sock = 0; +int statsd_socket_init(afl_state_t *afl) { + /* Default port and host. + Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment + variable, if they exists. + */ + u16 port = STATSD_DEFAULT_PORT; + char *host = STATSD_DEFAULT_HOST; -int statsd_socket_init(char *host, int port) { + if (afl->afl_env.afl_statsd_port) { port = atoi(afl->afl_env.afl_statsd_port); } + if (afl->afl_env.afl_statsd_host) { host = afl->afl_env.afl_statsd_host; } int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { @@ -25,9 +30,9 @@ int statsd_socket_init(char *host, int port) { } - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; - server.sin_port = htons(port); + memset(&afl->statsd_server, 0, sizeof(afl->statsd_server)); + afl->statsd_server.sin_family = AF_INET; + afl->statsd_server.sin_port = htons(port); struct addrinfo *result; struct addrinfo hints; @@ -36,13 +41,13 @@ int statsd_socket_init(char *host, int port) { hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; - if ((error = getaddrinfo(host, NULL, &hints, &result))) { + if ((getaddrinfo(host, NULL, &hints, &result))) { FATAL("Fail to getaddrinfo"); } - memcpy(&(server.sin_addr), &((struct sockaddr_in *)result->ai_addr)->sin_addr, + memcpy(&(afl->statsd_server.sin_addr), &((struct sockaddr_in *)result->ai_addr)->sin_addr, sizeof(struct in_addr)); freeaddrinfo(result); @@ -53,24 +58,14 @@ int statsd_socket_init(char *host, int port) { int statsd_send_metric(afl_state_t *afl) { char buff[MAX_STATSD_PACKET_SIZE] = {0}; - /* Default port and host. - Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment - variable, if they exists. - */ - u16 port = STATSD_DEFAULT_PORT; - char *host = STATSD_DEFAULT_HOST; - - if (afl->afl_env.afl_statsd_port) { port = atoi(afl->afl_env.afl_statsd_port); } - if (afl->afl_env.afl_statsd_host) { host = afl->afl_env.afl_statsd_host; } - /* statds_sock is a global variable. We set it once in the beginning and reuse - the socket. If the sendto later fail, we reset it to 0 to be able to recreate - it. + /* afl->statsd_sock is set once in the initialisation of afl-fuzz and reused each time + If the sendto later fail, we reset it to 0 to be able to recreates it. */ - if (!statds_sock) { + if (!afl->statsd_sock) { - statds_sock = statsd_socket_init(host, port); - if (!statds_sock) { + afl->statsd_sock = statsd_socket_init(afl); + if (!afl->statsd_sock) { WARNF("Cannot create socket"); return -1; @@ -80,11 +75,11 @@ int statsd_send_metric(afl_state_t *afl) { } statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); - if (sendto(statds_sock, buff, strlen(buff), 0, (struct sockaddr *)&server, - sizeof(server)) == -1) { + if (sendto(afl->statsd_sock, buff, strlen(buff), 0, (struct sockaddr *)&afl->statsd_server, + sizeof(afl->statsd_server)) == -1) { - if (!close(statds_sock)) { perror("Cannot close socket"); } - statds_sock = 0; + if (!close(afl->statsd_sock)) { perror("Cannot close socket"); } + afl->statsd_sock = 0; WARNF("Cannot sendto"); return -1; -- cgit 1.4.1 From 9ac9aa25111b67cd6a2ee7ce8376a445368b215f Mon Sep 17 00:00:00 2001 From: Edznux Date: Mon, 5 Oct 2020 22:21:24 +0200 Subject: Fix code format --- include/afl-fuzz.h | 4 ++-- src/afl-fuzz-state.c | 1 + src/afl-fuzz-statsd.c | 19 ++++++++++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 7eeeb79b..92375b2c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -635,9 +635,9 @@ typedef struct afl_state { u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs; /* StatsD */ - u64 statsd_last_send_ms; + u64 statsd_last_send_ms; struct sockaddr_in statsd_server; - int statsd_sock; + int statsd_sock; double stats_avg_exec; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index aefa226d..5e719a85 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -369,6 +369,7 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_statsd_host = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_STATSD_PORT", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index 0ec1bcb7..9cb8fde4 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -13,6 +13,7 @@ #define METRIC_PREFIX "fuzzing" int statsd_socket_init(afl_state_t *afl) { + /* Default port and host. Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment variable, if they exists. @@ -20,7 +21,12 @@ int statsd_socket_init(afl_state_t *afl) { u16 port = STATSD_DEFAULT_PORT; char *host = STATSD_DEFAULT_HOST; - if (afl->afl_env.afl_statsd_port) { port = atoi(afl->afl_env.afl_statsd_port); } + if (afl->afl_env.afl_statsd_port) { + + port = atoi(afl->afl_env.afl_statsd_port); + + } + if (afl->afl_env.afl_statsd_host) { host = afl->afl_env.afl_statsd_host; } int sock; @@ -47,7 +53,8 @@ int statsd_socket_init(afl_state_t *afl) { } - memcpy(&(afl->statsd_server.sin_addr), &((struct sockaddr_in *)result->ai_addr)->sin_addr, + memcpy(&(afl->statsd_server.sin_addr), + &((struct sockaddr_in *)result->ai_addr)->sin_addr, sizeof(struct in_addr)); freeaddrinfo(result); @@ -59,8 +66,9 @@ int statsd_send_metric(afl_state_t *afl) { char buff[MAX_STATSD_PACKET_SIZE] = {0}; - /* afl->statsd_sock is set once in the initialisation of afl-fuzz and reused each time - If the sendto later fail, we reset it to 0 to be able to recreates it. + /* afl->statsd_sock is set once in the initialisation of afl-fuzz and reused + each time If the sendto later fail, we reset it to 0 to be able to recreates + it. */ if (!afl->statsd_sock) { @@ -75,7 +83,8 @@ int statsd_send_metric(afl_state_t *afl) { } statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE); - if (sendto(afl->statsd_sock, buff, strlen(buff), 0, (struct sockaddr *)&afl->statsd_server, + if (sendto(afl->statsd_sock, buff, strlen(buff), 0, + (struct sockaddr *)&afl->statsd_server, sizeof(afl->statsd_server)) == -1) { if (!close(afl->statsd_sock)) { perror("Cannot close socket"); } -- cgit 1.4.1 From a4b60ca5b61c9bca5fa7b67528baeb3a8ea9320e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 6 Oct 2020 15:37:59 +0200 Subject: testcase cache added --- include/afl-fuzz.h | 15 ++++++ include/config.h | 8 +++ src/afl-fuzz-one.c | 148 ++++++++++++++++++--------------------------------- src/afl-fuzz-queue.c | 65 ++++++++++++++++++++++ src/afl-fuzz.c | 3 +- 5 files changed, 142 insertions(+), 97 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index fb661ce5..46da8c7d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -162,6 +162,9 @@ struct queue_entry { u8 *trace_mini; /* Trace bytes, if kept */ u32 tc_ref; /* Trace bytes ref count */ + u8 *testcase_buf; /* The testcase buffer, if loaded. */ + u32 testcase_refs; /* count of users of testcase buf */ + struct queue_entry *next; /* Next element, if any */ }; @@ -664,6 +667,11 @@ typedef struct afl_state { /* queue entries ready for splicing count (len > 4) */ u32 ready_for_splicing_count; + /* How many queue entries currently have cached testcases */ + u32 q_testcase_cache_count; + /* Refs to each queue entry with cached testcase (for eviction, if cache_count is too large) */ + struct queue_entry *q_testcase_cache[TESTCASE_CACHE_SIZE]; + } afl_state_t; struct custom_mutator { @@ -1101,5 +1109,12 @@ static inline u64 next_p2(u64 val) { } +/* Returns the testcase buf from the file behind this queue entry. + Increases the refcount. */ +u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q); + +/* Tell afl that this testcase may be evicted from the cache */ +void queue_testcase_release(afl_state_t *afl, struct queue_entry *q); + #endif diff --git a/include/config.h b/include/config.h index 7c8e0c7d..38a734ce 100644 --- a/include/config.h +++ b/include/config.h @@ -295,6 +295,14 @@ #define RESEED_RNG 100000 +/* The amount of entries in the testcase cache, held in memory. +Decrease if RAM usage is high. */ +#define TESTCASE_CACHE_SIZE 2048 + +#if TESTCASE_CACHE_SIZE < 4 + #error "Dangerously low cache size: Set TESTCASE_CACHE_SIZE to 4 or more in config.h! +#endif + /* Maximum line length passed from GCC to 'as' and used for parsing configuration files: */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c04b492b..20558618 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -370,7 +370,7 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { u8 fuzz_one_original(afl_state_t *afl) { - s32 len, fd, temp_len; + s32 len, temp_len; u32 j; u32 i; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -453,28 +453,9 @@ u8 fuzz_one_original(afl_state_t *afl) { } - /* Map the test case into memory. */ - - fd = open(afl->queue_cur->fname, O_RDONLY); - - if (unlikely(fd < 0)) { - - PFATAL("Unable to open '%s'", afl->queue_cur->fname); - - } - + orig_in = in_buf = queue_testcase_take(afl, afl->queue_cur); len = afl->queue_cur->len; - orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (unlikely(orig_in == MAP_FAILED)) { - - PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); - - } - - close(fd); - /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ @@ -1694,7 +1675,7 @@ custom_mutator_stage: for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - struct queue_entry *target; + struct queue_entry *target = NULL; u32 tid; u8 * new_buf = NULL; u32 target_len = 0; @@ -1717,17 +1698,7 @@ custom_mutator_stage: afl->splicing_with = tid; /* Read the additional testcase into a new buffer. */ - fd = open(target->fname, O_RDONLY); - if (unlikely(fd < 0)) { - - PFATAL("Unable to open '%s'", target->fname); - - } - - new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - ck_read(fd, new_buf, target->len, target->fname); - close(fd); + new_buf = queue_testcase_take(afl, target); target_len = target->len; } @@ -1738,6 +1709,11 @@ custom_mutator_stage: el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf, target_len, max_seed_size); + if (new_buf) { + queue_testcase_release(afl, target); + new_buf = NULL; + } + if (unlikely(!mutated_buf)) { FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); @@ -2320,51 +2296,44 @@ havoc_stage: /* Overwrite bytes with a randomly selected chunk from another testcase or insert that chunk. */ - if (afl->queued_paths < 4) break; + if (afl->queued_paths < 4) { break; } /* Pick a random queue entry and seek to it. */ u32 tid; - do + do { tid = rand_below(afl, afl->queued_paths); - while (tid == afl->current_entry); + } 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)) + 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)) { + if (!target) { break; } - PFATAL("Unable to open '%s'", target->fname); - - } u32 new_len = target->len; - u8 *new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), new_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - ck_read(fd, new_buf, new_len, target->fname); - close(fd); + /* Get the testcase contents for splicing. */ + u8 *new_buf = queue_testcase_take(afl, target); u8 overwrite = 0; - if (temp_len >= 2 && rand_below(afl, 2)) + if (temp_len >= 2 && rand_below(afl, 2)) { overwrite = 1; + } else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { - if (temp_len >= 2) + if (temp_len >= 2) { overwrite = 1; - else + } else { + queue_testcase_release(afl, target); + new_buf = NULL; break; + } } @@ -2411,6 +2380,9 @@ havoc_stage: } + /* We don't need this splice testcase anymore */ + queue_testcase_release(afl, target); + new_buf = NULL; break; } @@ -2516,24 +2488,16 @@ retry_splicing: if (!target) { goto retry_splicing; } - /* Read the testcase into a new buffer. */ - - fd = open(target->fname, O_RDONLY); - - if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } - + /* Get the testcase buffer */ + u8 *splice_buf = queue_testcase_take(afl, target); new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); if (unlikely(!new_buf)) { PFATAL("alloc"); } - ck_read(fd, new_buf, target->len, target->fname); - - close(fd); - /* Find a suitable splicing location, somewhere between the first and the last differing byte. Bail out if the difference is just a single byte or so. */ - locate_diffs(in_buf, new_buf, MIN(len, (s64)target->len), &f_diff, &l_diff); + locate_diffs(in_buf, splice_buf, MIN(len, (s64)target->len), &f_diff, &l_diff); if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; } @@ -2545,6 +2509,7 @@ retry_splicing: len = target->len; memcpy(new_buf, in_buf, split_at); + memcpy(new_buf + split_at, splice_buf + split_at, target->len - split_at); afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; @@ -2552,6 +2517,9 @@ retry_splicing: if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); + queue_testcase_release(afl, target); + splice_buf = NULL; + goto custom_mutator_stage; /* ???: While integrating Python module, the author decided to jump to python stage, but the reason behind this is not clear.*/ @@ -2582,7 +2550,8 @@ abandon_entry: ++afl->queue_cur->fuzz_level; - munmap(orig_in, afl->queue_cur->len); + queue_testcase_release(afl, afl->queue_cur); + orig_in = NULL; return ret_val; @@ -2604,7 +2573,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } - s32 len, fd, temp_len; + s32 len, temp_len; u32 i; u32 j; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -2669,23 +2638,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } /* Map the test case into memory. */ - - fd = open(afl->queue_cur->fname, O_RDONLY); - - if (fd < 0) { PFATAL("Unable to open '%s'", afl->queue_cur->fname); } - + orig_in = in_buf = queue_testcase_take(afl, afl->queue_cur); len = afl->queue_cur->len; - orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (orig_in == MAP_FAILED) { - - PFATAL("Unable to mmap '%s'", afl->queue_cur->fname); - - } - - close(fd); - /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ @@ -4522,31 +4477,24 @@ pacemaker_fuzzing: if (!target) { goto retry_splicing_puppet; } /* Read the testcase into a new buffer. */ - - fd = open(target->fname, O_RDONLY); - - if (fd < 0) { PFATAL("Unable to open '%s'", target->fname); } - - new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - ck_read(fd, new_buf, target->len, target->fname); - - close(fd); + u8 *splicing_buf = queue_testcase_take(afl, target); /* Find a suitable splicin g location, somewhere between the first and the last differing byte. Bail out if the difference is just a single byte or so. */ - locate_diffs(in_buf, new_buf, MIN(len, (s32)target->len), &f_diff, + locate_diffs(in_buf, splicing_buf, MIN(len, (s32)target->len), &f_diff, &l_diff); if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { + queue_testcase_release(afl, target); goto retry_splicing_puppet; } + new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); + /* Split somewhere between the first and last differing byte. */ split_at = f_diff + rand_below(afl, l_diff - f_diff); @@ -4555,12 +4503,16 @@ pacemaker_fuzzing: len = target->len; memcpy(new_buf, in_buf, split_at); + memcpy(new_buf + split_at, splicing_buf + split_at, target->len - split_at); afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); + queue_testcase_release(afl, target); + splicing_buf = NULL; + goto havoc_stage_puppet; } /* if splice_cycle */ @@ -4594,7 +4546,8 @@ pacemaker_fuzzing: // if (afl->queue_cur->favored) --afl->pending_favored; // } - munmap(orig_in, afl->queue_cur->len); + queue_testcase_release(afl, afl->queue_cur); + orig_in = NULL; if (afl->key_puppet == 1) { @@ -4730,6 +4683,9 @@ pacemaker_fuzzing: } /* block */ + queue_testcase_release(afl, afl->queue_cur); + orig_in = NULL; + return ret_val; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 0d7d0314..e2387aaa 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -220,6 +220,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->depth = afl->cur_depth + 1; q->passed_det = passed_det; q->trace_mini = NULL; + q->testcase_buf = NULL; if (q->depth > afl->max_depth) { afl->max_depth = q->depth; } @@ -767,3 +768,67 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } +/* Tell afl that this testcase may be evicted from the cache */ +inline void queue_testcase_release(afl_state_t *afl, struct queue_entry *q) { + (void) afl; + q->testcase_refs--; + if (unlikely(q->testcase_refs < 0)) { FATAL("Testcase refcount smaller than 0"); } +} + +/* Returns the testcase buf from the file behind this queue entry. + Increases the refcount. */ +u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q) { + if (!q->testcase_buf) { + u32 tid = 0; + /* Buf not cached, let's do that now */ + + if (likely(afl->q_testcase_cache_count == TESTCASE_CACHE_SIZE)) { + /* Cache full. We neet to evict one to map one. + Get a random one which is not in use */ + do { + + tid = rand_below(afl, afl->q_testcase_cache_count); + + } while (afl->q_testcase_cache[tid]->testcase_refs > 0); + + struct queue_entry *old_cached = afl->q_testcase_cache[tid]; + /* free the current buf from cache */ + munmap(old_cached->testcase_buf, old_cached->len); + old_cached->testcase_buf = NULL; + + } else { + tid = afl->q_testcase_cache_count; + afl->q_testcase_cache_count++; + } + + /* Map the test case into memory. */ + + int fd = open(q->fname, O_RDONLY); + + if (unlikely(fd < 0)) { + + PFATAL("Unable to open '%s'", q->fname); + + } + + u32 len = q->len; + + q->testcase_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (unlikely(q->testcase_buf == MAP_FAILED)) { + + PFATAL("Unable to mmap '%s' with len %d", q->fname, len); + + } + + close(fd); + + /* Register us as cached */ + afl->q_testcase_cache[tid] = q; + + } + q->testcase_refs++; + if (!q->testcase_buf) { FATAL("Testcase buf is NULL, this should never happen"); } + return q->testcase_buf; + +} diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 2f8aa3fd..dd9aaa8f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1152,8 +1152,9 @@ int main(int argc, char **argv_orig, char **envp) { if (extras_dir_cnt) { - for (i = 0; i < extras_dir_cnt; i++) + for (i = 0; i < extras_dir_cnt; i++) { load_extras(afl, extras_dir[i]); + } dedup_extras(afl); OKF("Loaded a total of %u extras.", afl->extras_cnt); -- cgit 1.4.1 From 74dc227c4412d0121c9b972e5d89db89f54c6b3a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 6 Oct 2020 15:38:36 +0200 Subject: code format --- include/afl-fuzz.h | 5 +++-- include/config.h | 3 ++- src/afl-fuzz-one.c | 22 +++++++++++++++++----- src/afl-fuzz-queue.c | 34 ++++++++++++++++++++++++---------- src/afl-fuzz.c | 2 ++ 5 files changed, 48 insertions(+), 18 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 46da8c7d..5ab787e0 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -163,7 +163,7 @@ struct queue_entry { u32 tc_ref; /* Trace bytes ref count */ u8 *testcase_buf; /* The testcase buffer, if loaded. */ - u32 testcase_refs; /* count of users of testcase buf */ + u32 testcase_refs; /* count of users of testcase buf */ struct queue_entry *next; /* Next element, if any */ @@ -669,7 +669,8 @@ typedef struct afl_state { /* How many queue entries currently have cached testcases */ u32 q_testcase_cache_count; - /* Refs to each queue entry with cached testcase (for eviction, if cache_count is too large) */ + /* Refs to each queue entry with cached testcase (for eviction, if cache_count + * is too large) */ struct queue_entry *q_testcase_cache[TESTCASE_CACHE_SIZE]; } afl_state_t; diff --git a/include/config.h b/include/config.h index 38a734ce..ec378036 100644 --- a/include/config.h +++ b/include/config.h @@ -300,7 +300,8 @@ Decrease if RAM usage is high. */ #define TESTCASE_CACHE_SIZE 2048 #if TESTCASE_CACHE_SIZE < 4 - #error "Dangerously low cache size: Set TESTCASE_CACHE_SIZE to 4 or more in config.h! + #error \ + "Dangerously low cache size: Set TESTCASE_CACHE_SIZE to 4 or more in config.h! #endif /* Maximum line length passed from GCC to 'as' and used for parsing diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 20558618..a5f77f11 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1710,8 +1710,10 @@ custom_mutator_stage: target_len, max_seed_size); if (new_buf) { + queue_testcase_release(afl, target); new_buf = NULL; + } if (unlikely(!mutated_buf)) { @@ -2302,7 +2304,9 @@ havoc_stage: u32 tid; do { + tid = rand_below(afl, afl->queued_paths); + } while (tid == afl->current_entry); struct queue_entry *target = afl->queue_buf[tid]; @@ -2310,12 +2314,13 @@ havoc_stage: /* Make sure that the target has a reasonable length. */ while (target && (target->len < 2 || target == afl->queue_cur)) { + target = target->next; + } if (!target) { break; } - u32 new_len = target->len; /* Get the testcase contents for splicing. */ @@ -2323,16 +2328,21 @@ havoc_stage: 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 + HAVOC_BLK_XL >= MAX_FILE) { if (temp_len >= 2) { + overwrite = 1; + } else { + queue_testcase_release(afl, target); new_buf = NULL; break; + } } @@ -2497,7 +2507,8 @@ retry_splicing: the last differing byte. Bail out if the difference is just a single byte or so. */ - locate_diffs(in_buf, splice_buf, MIN(len, (s64)target->len), &f_diff, &l_diff); + locate_diffs(in_buf, splice_buf, MIN(len, (s64)target->len), &f_diff, + &l_diff); if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; } @@ -4503,7 +4514,8 @@ pacemaker_fuzzing: len = target->len; memcpy(new_buf, in_buf, split_at); - memcpy(new_buf + split_at, splicing_buf + split_at, target->len - split_at); + memcpy(new_buf + split_at, splicing_buf + split_at, + target->len - split_at); afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; out_buf = afl_realloc(AFL_BUF_PARAM(out), len); diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index e2387aaa..721f9ac7 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -770,24 +770,33 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { /* Tell afl that this testcase may be evicted from the cache */ inline void queue_testcase_release(afl_state_t *afl, struct queue_entry *q) { - (void) afl; + + (void)afl; q->testcase_refs--; - if (unlikely(q->testcase_refs < 0)) { FATAL("Testcase refcount smaller than 0"); } + if (unlikely(q->testcase_refs < 0)) { + + FATAL("Testcase refcount smaller than 0"); + + } + } /* Returns the testcase buf from the file behind this queue entry. Increases the refcount. */ u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q) { + if (!q->testcase_buf) { + u32 tid = 0; /* Buf not cached, let's do that now */ if (likely(afl->q_testcase_cache_count == TESTCASE_CACHE_SIZE)) { + /* Cache full. We neet to evict one to map one. Get a random one which is not in use */ do { - tid = rand_below(afl, afl->q_testcase_cache_count); + tid = rand_below(afl, afl->q_testcase_cache_count); } while (afl->q_testcase_cache[tid]->testcase_refs > 0); @@ -795,21 +804,19 @@ u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q) { /* free the current buf from cache */ munmap(old_cached->testcase_buf, old_cached->len); old_cached->testcase_buf = NULL; - + } else { + tid = afl->q_testcase_cache_count; afl->q_testcase_cache_count++; + } /* Map the test case into memory. */ int fd = open(q->fname, O_RDONLY); - if (unlikely(fd < 0)) { - - PFATAL("Unable to open '%s'", q->fname); - - } + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); } u32 len = q->len; @@ -827,8 +834,15 @@ u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q) { afl->q_testcase_cache[tid] = q; } + q->testcase_refs++; - if (!q->testcase_buf) { FATAL("Testcase buf is NULL, this should never happen"); } + if (!q->testcase_buf) { + + FATAL("Testcase buf is NULL, this should never happen"); + + } + return q->testcase_buf; } + diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index dd9aaa8f..9b7c1445 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1153,7 +1153,9 @@ int main(int argc, char **argv_orig, char **envp) { if (extras_dir_cnt) { for (i = 0; i < extras_dir_cnt; i++) { + load_extras(afl, extras_dir[i]); + } dedup_extras(afl); -- cgit 1.4.1 From 3d7bdc9f0b6892cb359fc07a0cef387851cbd8b1 Mon Sep 17 00:00:00 2001 From: Edznux Date: Tue, 6 Oct 2020 23:00:11 +0200 Subject: [WIP: segfault on non dogstatsd] Adding MACROS for format --- include/afl-fuzz.h | 13 +++-- include/config.h | 3 -- include/envs.h | 1 + src/afl-fuzz-state.c | 7 +++ src/afl-fuzz-statsd.c | 140 +++++++++++++++++++++++++++++++++++++------------- src/afl-fuzz.c | 5 ++ 6 files changed, 127 insertions(+), 42 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 92375b2c..ffb518ad 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -359,7 +359,8 @@ typedef struct afl_env_vars { u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, - *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port; + *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, + *afl_statsd_tags_flavor; } afl_env_vars_t; @@ -638,6 +639,9 @@ typedef struct afl_state { u64 statsd_last_send_ms; struct sockaddr_in statsd_server; int statsd_sock; + char * statsd_tags_flavor; + char * statsd_tags_format; + char * statsd_metric_format; double stats_avg_exec; @@ -961,9 +965,10 @@ void show_init_stats(afl_state_t *); /* StatsD */ -int statsd_socket_init(afl_state_t *afl); -int statsd_send_metric(afl_state_t *afl); -int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); +void statsd_setup_format(afl_state_t *afl); +int statsd_socket_init(afl_state_t *afl); +int statsd_send_metric(afl_state_t *afl); +int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); /* Run */ diff --git a/include/config.h b/include/config.h index c0a04565..3d6b0395 100644 --- a/include/config.h +++ b/include/config.h @@ -50,9 +50,6 @@ Server config can be adjusted with AFL_STATSD_HOST and AFL_STATSD_PORT env var. #define STATSD_DEFAULT_PORT 8125 #define STATSD_DEFAULT_HOST "127.0.0.1" -/* comment out to disable tags. */ -#define USE_DOGSTATSD_TAGS - /* If you want to have the original afl internal memory corruption checks. Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */ diff --git a/include/envs.h b/include/envs.h index 1fc9e83d..16da14cb 100644 --- a/include/envs.h +++ b/include/envs.h @@ -137,6 +137,7 @@ static char *afl_environment_variables[] = { "AFL_SKIP_CRASHES", "AFL_STATSD_HOST", "AFL_STATSD_PORT", + "AFL_STATSD_TAGS_FLAVOR", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 5e719a85..77b30b5b 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -377,6 +377,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_statsd_port = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_STATSD_TAGS_FLAVOR", + + afl_environment_variable_len)) { + + afl->afl_env.afl_statsd_tags_flavor = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index 9cb8fde4..f77df17e 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -12,6 +12,107 @@ #define MAX_TAG_LEN 200 #define METRIC_PREFIX "fuzzing" +/* Tags format for metrics + DogStatsD: + metric.name:||#key:value,key2:value2 + + InfluxDB + metric.name,key=value,key2=value2:| + + Librato + metric.name#key=value,key2=value2:| + + SignalFX + metric.name[key=value,key2=value2]:| + +*/ + +// after the whole metric. +#define DOGSTATSD_TAGS_FORMAT "|#banner:%s,afl_version:%s" + +// just after the metric name. +#define LIBRATO_TAGS_FORMAT "#banner=%s,afl_version=%s" +#define INFLUXDB_TAGS_FORMAT ",banner=%s,afl_version=%s" +#define SIGNALFX_TAGS_FORMAT "[banner=%s,afl_version=%s]" + +// For DogstatsD +#define STATSD_TAGS_AFTER_METRICS \ + METRIC_PREFIX \ + ".cycle_done:%llu|g%s\n" METRIC_PREFIX \ + ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX \ + ".execs_done:%llu|g%s\n" METRIC_PREFIX \ + ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX \ + ".paths_total:%u|g%s\n" METRIC_PREFIX \ + ".paths_favored:%u|g%s\n" METRIC_PREFIX \ + ".paths_found:%u|g%s\n" METRIC_PREFIX \ + ".paths_imported:%u|g%s\n" METRIC_PREFIX \ + ".max_depth:%u|g%s\n" METRIC_PREFIX ".cur_path:%u|g%s\n" METRIC_PREFIX \ + ".pending_favs:%u|g%s\n" METRIC_PREFIX \ + ".pending_total:%u|g%s\n" METRIC_PREFIX \ + ".variable_paths:%u|g%s\n" METRIC_PREFIX \ + ".unique_crashes:%llu|g%s\n" METRIC_PREFIX \ + ".unique_hangs:%llu|g%s\n" METRIC_PREFIX \ + ".total_crashes:%llu|g%s\n" METRIC_PREFIX \ + ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX \ + ".edges_found:%u|g%s\n" METRIC_PREFIX \ + ".var_byte_count:%u|g%s\n" METRIC_PREFIX ".havoc_expansion:%u|g%s\n" + +// For Librato, InfluxDB, SignalFX +#define STATSD_TAGS_MID_METRICS \ + METRIC_PREFIX \ + ".cycle_done%s:%llu|g\n" METRIC_PREFIX \ + ".cycles_wo_finds%s:%llu|g\n" METRIC_PREFIX \ + ".execs_done%s:%llu|g\n" METRIC_PREFIX \ + ".execs_per_sec%s:%0.02f|g\n" METRIC_PREFIX \ + ".paths_total%s:%u|g\n" METRIC_PREFIX \ + ".paths_favored%s:%u|g\n" METRIC_PREFIX \ + ".paths_found%s:%u|g\n" METRIC_PREFIX \ + ".paths_imported%s:%u|g\n" METRIC_PREFIX \ + ".max_depth%s:%u|g\n" METRIC_PREFIX ".cur_path%s:%u|g\n" METRIC_PREFIX \ + ".pending_favs%s:%u|g\n" METRIC_PREFIX \ + ".pending_total%s:%u|g\n" METRIC_PREFIX \ + ".variable_paths%s:%u|g\n" METRIC_PREFIX \ + ".unique_crashes%s:%llu|g\n" METRIC_PREFIX \ + ".unique_hangs%s:%llu|g\n" METRIC_PREFIX \ + ".total_crashes%s:%llu|g\n" METRIC_PREFIX \ + ".slowest_exec_ms%s:%u|g\n" METRIC_PREFIX \ + ".edges_found%s:%u|g\n" METRIC_PREFIX \ + ".var_byte_count%s:%u|g\n" METRIC_PREFIX ".havoc_expansion%s:%u|g\n" + +void statsd_setup_format(afl_state_t *afl) { + + if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "dogstatsd") == 0) { + + afl->statsd_tags_format = DOGSTATSD_TAGS_FORMAT; + afl->statsd_metric_format = STATSD_TAGS_AFTER_METRICS; + + } else if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "librato") == 0) { + + afl->statsd_tags_format = LIBRATO_TAGS_FORMAT; + afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + + } else if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "influxdb") == 0) { + + afl->statsd_tags_format = INFLUXDB_TAGS_FORMAT; + afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + + } else if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "signalfx") == 0) { + + afl->statsd_tags_format = SIGNALFX_TAGS_FORMAT; + afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + + } else { + + // No tags at all. + afl->statsd_tags_format = ""; + // Still need to pick a format. Doesn't change anything since if will be + // replaced by the empty string anyway. + afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + + } + +} + int statsd_socket_init(afl_state_t *afl) { /* Default port and host. @@ -87,7 +188,7 @@ int statsd_send_metric(afl_state_t *afl) { (struct sockaddr *)&afl->statsd_server, sizeof(afl->statsd_server)) == -1) { - if (!close(afl->statsd_sock)) { perror("Cannot close socket"); } + if (!close(afl->statsd_sock)) { FATAL("Cannot close socket"); } afl->statsd_sock = 0; WARNF("Cannot sendto"); return -1; @@ -100,45 +201,14 @@ int statsd_send_metric(afl_state_t *afl) { int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) { -/* Metric format: -:| -*/ -#ifdef USE_DOGSTATSD_TAGS - /* Tags format: DogStatsD - :||#key:value,key:value,key - */ char tags[MAX_TAG_LEN * 2] = {0}; - snprintf(tags, MAX_TAG_LEN * 2, "|#banner:%s,afl_version:%s", afl->use_banner, + snprintf(tags, MAX_TAG_LEN * 2, afl->statsd_tags_format, afl->use_banner, VERSION); -#else - /* No tags. - */ - char *tags = ""; -#endif + /* Sends multiple metrics with one UDP Packet. bufflen will limit to the max safe size. */ - snprintf(buff, bufflen, - METRIC_PREFIX ".cycle_done:%llu|g%s\n" METRIC_PREFIX - ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX - ".execs_done:%llu|g%s\n" METRIC_PREFIX - ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX - ".paths_total:%u|g%s\n" METRIC_PREFIX - ".paths_favored:%u|g%s\n" METRIC_PREFIX - ".paths_found:%u|g%s\n" METRIC_PREFIX - ".paths_imported:%u|g%s\n" METRIC_PREFIX - ".max_depth:%u|g%s\n" METRIC_PREFIX - ".cur_path:%u|g%s\n" METRIC_PREFIX - ".pending_favs:%u|g%s\n" METRIC_PREFIX - ".pending_total:%u|g%s\n" METRIC_PREFIX - ".variable_paths:%u|g%s\n" METRIC_PREFIX - ".unique_crashes:%llu|g%s\n" METRIC_PREFIX - ".unique_hangs:%llu|g%s\n" METRIC_PREFIX - ".total_crashes:%llu|g%s\n" METRIC_PREFIX - ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX - ".edges_found:%u|g%s\n" METRIC_PREFIX - ".var_byte_count:%u|g%s\n" METRIC_PREFIX - ".havoc_expansion:%u|g%s\n", + snprintf(buff, bufflen, afl->statsd_metric_format, afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags, afl->fsrv.total_execs / diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 0b08f426..e0e9487f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -891,6 +891,11 @@ int main(int argc, char **argv_orig, char **envp) { } + #ifdef USE_STATSD + statsd_setup_format(afl); + statsd_socket_init(afl); + #endif + if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) { WARNF(cLRD -- cgit 1.4.1 From 17abe7d36e1bf63e149b3c0be20d3d0b7076746f Mon Sep 17 00:00:00 2001 From: Edznux Date: Tue, 6 Oct 2020 23:23:45 +0200 Subject: Fixed segfault because wrong order in args --- include/afl-fuzz.h | 1 + src/afl-fuzz-statsd.c | 137 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 83 insertions(+), 55 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index ffb518ad..df7dd644 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -642,6 +642,7 @@ typedef struct afl_state { char * statsd_tags_flavor; char * statsd_tags_format; char * statsd_metric_format; + int statsd_metric_format_type; double stats_avg_exec; diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c index f77df17e..e6640977 100644 --- a/src/afl-fuzz-statsd.c +++ b/src/afl-fuzz-statsd.c @@ -36,70 +36,74 @@ #define SIGNALFX_TAGS_FORMAT "[banner=%s,afl_version=%s]" // For DogstatsD -#define STATSD_TAGS_AFTER_METRICS \ - METRIC_PREFIX \ - ".cycle_done:%llu|g%s\n" METRIC_PREFIX \ - ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX \ - ".execs_done:%llu|g%s\n" METRIC_PREFIX \ - ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX \ - ".paths_total:%u|g%s\n" METRIC_PREFIX \ - ".paths_favored:%u|g%s\n" METRIC_PREFIX \ - ".paths_found:%u|g%s\n" METRIC_PREFIX \ - ".paths_imported:%u|g%s\n" METRIC_PREFIX \ - ".max_depth:%u|g%s\n" METRIC_PREFIX ".cur_path:%u|g%s\n" METRIC_PREFIX \ - ".pending_favs:%u|g%s\n" METRIC_PREFIX \ - ".pending_total:%u|g%s\n" METRIC_PREFIX \ - ".variable_paths:%u|g%s\n" METRIC_PREFIX \ - ".unique_crashes:%llu|g%s\n" METRIC_PREFIX \ - ".unique_hangs:%llu|g%s\n" METRIC_PREFIX \ - ".total_crashes:%llu|g%s\n" METRIC_PREFIX \ - ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX \ - ".edges_found:%u|g%s\n" METRIC_PREFIX \ - ".var_byte_count:%u|g%s\n" METRIC_PREFIX ".havoc_expansion:%u|g%s\n" +#define STATSD_TAGS_TYPE_SUFFIX 1 +#define STATSD_TAGS_SUFFIX_METRICS \ + METRIC_PREFIX \ + ".cycle_done:%llu|g%s\n" METRIC_PREFIX \ + ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX \ + ".execs_done:%llu|g%s\n" METRIC_PREFIX \ + ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX \ + ".paths_total:%u|g%s\n" METRIC_PREFIX \ + ".paths_favored:%u|g%s\n" METRIC_PREFIX \ + ".paths_found:%u|g%s\n" METRIC_PREFIX \ + ".paths_imported:%u|g%s\n" METRIC_PREFIX ".max_depth:%u|g%s\n" METRIC_PREFIX \ + ".cur_path:%u|g%s\n" METRIC_PREFIX ".pending_favs:%u|g%s\n" METRIC_PREFIX \ + ".pending_total:%u|g%s\n" METRIC_PREFIX \ + ".variable_paths:%u|g%s\n" METRIC_PREFIX \ + ".unique_crashes:%llu|g%s\n" METRIC_PREFIX \ + ".unique_hangs:%llu|g%s\n" METRIC_PREFIX \ + ".total_crashes:%llu|g%s\n" METRIC_PREFIX \ + ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX \ + ".edges_found:%u|g%s\n" METRIC_PREFIX \ + ".var_byte_count:%u|g%s\n" METRIC_PREFIX ".havoc_expansion:%u|g%s\n" // For Librato, InfluxDB, SignalFX -#define STATSD_TAGS_MID_METRICS \ - METRIC_PREFIX \ - ".cycle_done%s:%llu|g\n" METRIC_PREFIX \ - ".cycles_wo_finds%s:%llu|g\n" METRIC_PREFIX \ - ".execs_done%s:%llu|g\n" METRIC_PREFIX \ - ".execs_per_sec%s:%0.02f|g\n" METRIC_PREFIX \ - ".paths_total%s:%u|g\n" METRIC_PREFIX \ - ".paths_favored%s:%u|g\n" METRIC_PREFIX \ - ".paths_found%s:%u|g\n" METRIC_PREFIX \ - ".paths_imported%s:%u|g\n" METRIC_PREFIX \ - ".max_depth%s:%u|g\n" METRIC_PREFIX ".cur_path%s:%u|g\n" METRIC_PREFIX \ - ".pending_favs%s:%u|g\n" METRIC_PREFIX \ - ".pending_total%s:%u|g\n" METRIC_PREFIX \ - ".variable_paths%s:%u|g\n" METRIC_PREFIX \ - ".unique_crashes%s:%llu|g\n" METRIC_PREFIX \ - ".unique_hangs%s:%llu|g\n" METRIC_PREFIX \ - ".total_crashes%s:%llu|g\n" METRIC_PREFIX \ - ".slowest_exec_ms%s:%u|g\n" METRIC_PREFIX \ - ".edges_found%s:%u|g\n" METRIC_PREFIX \ - ".var_byte_count%s:%u|g\n" METRIC_PREFIX ".havoc_expansion%s:%u|g\n" +#define STATSD_TAGS_TYPE_MID 2 +#define STATSD_TAGS_MID_METRICS \ + METRIC_PREFIX \ + ".cycle_done%s:%llu|g\n" METRIC_PREFIX \ + ".cycles_wo_finds%s:%llu|g\n" METRIC_PREFIX \ + ".execs_done%s:%llu|g\n" METRIC_PREFIX \ + ".execs_per_sec%s:%0.02f|g\n" METRIC_PREFIX \ + ".paths_total%s:%u|g\n" METRIC_PREFIX \ + ".paths_favored%s:%u|g\n" METRIC_PREFIX \ + ".paths_found%s:%u|g\n" METRIC_PREFIX \ + ".paths_imported%s:%u|g\n" METRIC_PREFIX ".max_depth%s:%u|g\n" METRIC_PREFIX \ + ".cur_path%s:%u|g\n" METRIC_PREFIX ".pending_favs%s:%u|g\n" METRIC_PREFIX \ + ".pending_total%s:%u|g\n" METRIC_PREFIX \ + ".variable_paths%s:%u|g\n" METRIC_PREFIX \ + ".unique_crashes%s:%llu|g\n" METRIC_PREFIX \ + ".unique_hangs%s:%llu|g\n" METRIC_PREFIX \ + ".total_crashes%s:%llu|g\n" METRIC_PREFIX \ + ".slowest_exec_ms%s:%u|g\n" METRIC_PREFIX \ + ".edges_found%s:%u|g\n" METRIC_PREFIX \ + ".var_byte_count%s:%u|g\n" METRIC_PREFIX ".havoc_expansion%s:%u|g\n" void statsd_setup_format(afl_state_t *afl) { if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "dogstatsd") == 0) { afl->statsd_tags_format = DOGSTATSD_TAGS_FORMAT; - afl->statsd_metric_format = STATSD_TAGS_AFTER_METRICS; + afl->statsd_metric_format = STATSD_TAGS_SUFFIX_METRICS; + afl->statsd_metric_format_type = STATSD_TAGS_TYPE_SUFFIX; } else if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "librato") == 0) { afl->statsd_tags_format = LIBRATO_TAGS_FORMAT; afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID; } else if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "influxdb") == 0) { afl->statsd_tags_format = INFLUXDB_TAGS_FORMAT; afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID; } else if (strcmp(afl->afl_env.afl_statsd_tags_flavor, "signalfx") == 0) { afl->statsd_tags_format = SIGNALFX_TAGS_FORMAT; afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID; } else { @@ -108,6 +112,7 @@ void statsd_setup_format(afl_state_t *afl) { // Still need to pick a format. Doesn't change anything since if will be // replaced by the empty string anyway. afl->statsd_metric_format = STATSD_TAGS_MID_METRICS; + afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID; } @@ -188,7 +193,7 @@ int statsd_send_metric(afl_state_t *afl) { (struct sockaddr *)&afl->statsd_server, sizeof(afl->statsd_server)) == -1) { - if (!close(afl->statsd_sock)) { FATAL("Cannot close socket"); } + if (!close(afl->statsd_sock)) { PFATAL("Cannot close socket"); } afl->statsd_sock = 0; WARNF("Cannot sendto"); return -1; @@ -208,19 +213,41 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) { /* Sends multiple metrics with one UDP Packet. bufflen will limit to the max safe size. */ - snprintf(buff, bufflen, afl->statsd_metric_format, - afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, - afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags, - afl->fsrv.total_execs / - ((double)(get_cur_time() - afl->start_time) / 1000), - tags, afl->queued_paths, tags, afl->queued_favored, tags, - afl->queued_discovered, tags, afl->queued_imported, tags, - afl->max_depth, tags, afl->current_entry, tags, afl->pending_favored, - tags, afl->pending_not_fuzzed, tags, afl->queued_variable, tags, - afl->unique_crashes, tags, afl->unique_hangs, tags, - afl->total_crashes, tags, afl->slowest_exec_ms, tags, - count_non_255_bytes(afl, afl->virgin_bits), tags, - afl->var_byte_count, tags, afl->expand_havoc, tags); + if (afl->statsd_metric_format_type == STATSD_TAGS_TYPE_SUFFIX) { + + snprintf(buff, bufflen, afl->statsd_metric_format, + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, + afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags, + afl->fsrv.total_execs / + ((double)(get_cur_time() - afl->start_time) / 1000), + tags, afl->queued_paths, tags, afl->queued_favored, tags, + afl->queued_discovered, tags, afl->queued_imported, tags, + afl->max_depth, tags, afl->current_entry, tags, + afl->pending_favored, tags, afl->pending_not_fuzzed, tags, + afl->queued_variable, tags, afl->unique_crashes, tags, + afl->unique_hangs, tags, afl->total_crashes, tags, + afl->slowest_exec_ms, tags, + count_non_255_bytes(afl, afl->virgin_bits), tags, + afl->var_byte_count, tags, afl->expand_havoc, tags); + + } else if (afl->statsd_metric_format_type == STATSD_TAGS_TYPE_MID) { + + snprintf(buff, bufflen, afl->statsd_metric_format, tags, + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags, + afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags, + afl->fsrv.total_execs / + ((double)(get_cur_time() - afl->start_time) / 1000), + tags, afl->queued_paths, tags, afl->queued_favored, tags, + afl->queued_discovered, tags, afl->queued_imported, tags, + afl->max_depth, tags, afl->current_entry, tags, + afl->pending_favored, tags, afl->pending_not_fuzzed, tags, + afl->queued_variable, tags, afl->unique_crashes, tags, + afl->unique_hangs, tags, afl->total_crashes, tags, + afl->slowest_exec_ms, tags, + count_non_255_bytes(afl, afl->virgin_bits), tags, + afl->var_byte_count, tags, afl->expand_havoc); + + } return 0; -- cgit 1.4.1 From 0220a8ff6670da2b9fd8cb883528d2a86f683c74 Mon Sep 17 00:00:00 2001 From: Edznux Date: Thu, 8 Oct 2020 20:48:46 +0200 Subject: Add env var toggle for StatsD --- include/afl-fuzz.h | 2 +- include/config.h | 7 +++---- include/envs.h | 1 + src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz-stats.c | 15 ++++++++------- src/afl-fuzz.c | 8 +++----- 6 files changed, 23 insertions(+), 17 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index df7dd644..8ad0ced1 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -355,7 +355,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_expand_havoc; + afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/config.h b/include/config.h index 3d6b0395..405c2712 100644 --- a/include/config.h +++ b/include/config.h @@ -41,11 +41,10 @@ #define USE_COLOR -/* Enable sending statistics over a StatsD daemon. -Server config can be adjusted with AFL_STATSD_HOST and AFL_STATSD_PORT env var. +/* StatsD config + Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment + variable. */ - -#define USE_STATSD #define STATSD_UPDATE_SEC 1 #define STATSD_DEFAULT_PORT 8125 #define STATSD_DEFAULT_HOST "127.0.0.1" diff --git a/include/envs.h b/include/envs.h index 16da14cb..51520312 100644 --- a/include/envs.h +++ b/include/envs.h @@ -135,6 +135,7 @@ static char *afl_environment_variables[] = { "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", "AFL_SKIP_CRASHES", + "AFL_STATSD", "AFL_STATSD_HOST", "AFL_STATSD_PORT", "AFL_STATSD_TAGS_FLAVOR", diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 77b30b5b..a7c7aff9 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -316,6 +316,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_cal_fast = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_STATSD", + + afl_environment_variable_len)) { + + afl->afl_env.afl_statsd = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TMPDIR", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 942670b4..0d6c6a66 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -423,16 +423,17 @@ void show_stats(afl_state_t *afl) { } -#ifdef USE_STATSD - if (cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000) { + if (unlikely(afl->afl_env.afl_statsd == 1)) { - /* reset counter, even if send failed. */ - afl->statsd_last_send_ms = cur_ms; - if (statsd_send_metric(afl)) { WARNF("coundln't send statsd metric."); } + if (cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000) { - } + /* reset counter, even if send failed. */ + afl->statsd_last_send_ms = cur_ms; + if (statsd_send_metric(afl)) { WARNF("coundln't send statsd metric."); } -#endif + } + + } /* Every now and then, write plot data. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c26e53b9..2c2f0ba5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -194,7 +194,8 @@ static void usage(u8 *argv0, int more_help) { "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" - "AFL_STATSD_HOST: change default statsd host. (default 127.0.0.1)" + "AFL_STATSD: enables StatsD metrics collection" + "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)" "AFL_STATSD_PORT: change default statsd port (default: 8125)" "AFL_STATSD_TAGS_FLAVOR: change default statsd tags format (default will disable tags)." " Supported formats are: 'dogstatsd', 'librato', 'signalfx' and 'influxdb'" @@ -893,10 +894,7 @@ int main(int argc, char **argv_orig, char **envp) { } - #ifdef USE_STATSD - statsd_setup_format(afl); - - #endif + if (unlikely(afl->afl_env.afl_statsd == 1)) { statsd_setup_format(afl); } if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) { -- cgit 1.4.1 From 6a397d6111a21ebbf736237609c1c69d47c40f03 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 11 Oct 2020 14:31:31 +0200 Subject: add new seed selection algo and make it the default --- docs/Changelog.md | 4 ++ include/afl-fuzz.h | 14 +++++- src/afl-fuzz-init.c | 8 ++++ src/afl-fuzz-one.c | 10 ++++- src/afl-fuzz-queue.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/afl-fuzz.c | 100 +++++++++++++++++++++++++++++------------ 6 files changed, 227 insertions(+), 33 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9eb47e18..f15f1d93 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,10 @@ sending a mail to . - memory limits are now disabled by default, set them with -m if required - deterministic fuzzing is now disabled by default and can be enabled with -D. It is still enabled by default for -M. + - a new seed selection was implemented that uses weighted randoms based on + a schedule performance score, which is much better that the previous + walk the whole queue approach. Select the old mode with -Z (auto enabled + with -M) - statsd support by Edznux, thanks a lot! - Marcel Boehme submitted a patch that improves all AFFast schedules :) - reading testcases from -i now descends into subdirectories diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e9d148e9..45de197d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -151,7 +151,8 @@ struct queue_entry { favored, /* Currently favored? */ fs_redundant, /* Marked as redundant in the fs? */ fully_colorized, /* Do not run redqueen stage again */ - is_ascii; /* Is the input just ascii text? */ + is_ascii, /* Is the input just ascii text? */ + disabled; /* Is disabled from fuzz selection */ u32 bitmap_size, /* Number of bits set in bitmap */ fuzz_level, /* Number of fuzzing iterations */ @@ -165,6 +166,8 @@ struct queue_entry { u8 *trace_mini; /* Trace bytes, if kept */ u32 tc_ref; /* Trace bytes ref count */ + double perf_score; /* performance score */ + struct queue_entry *next; /* Next element, if any */ }; @@ -488,12 +491,17 @@ typedef struct afl_state { disable_trim, /* Never trim in fuzz_one */ shmem_testcase_mode, /* If sharedmem testcases are used */ expand_havoc, /* perform expensive havoc after no find */ - cycle_schedules; /* cycle power schedules? */ + cycle_schedules, /* cycle power schedules? */ + old_seed_selection; /* use vanilla afl seed selection */ u8 *virgin_bits, /* Regions yet untouched by fuzzing */ *virgin_tmout, /* Bits we haven't seen in tmouts */ *virgin_crash; /* Bits we haven't seen in crashes */ + double *alias_probability; /* alias weighted probabilities */ + u32 * alias_table; /* alias weighted random lookup table */ + u32 active_paths; /* enabled entries in the queue */ + u8 *var_bytes; /* Bytes that appear to be variable */ #define N_FUZZ_SIZE (1 << 21) @@ -1009,6 +1017,8 @@ void find_timeout(afl_state_t *); double get_runnable_processes(void); void nuke_resume_dir(afl_state_t *); int check_main_node_exists(afl_state_t *); +u32 select_next_queue_entry(afl_state_t *afl); +void create_alias_table(afl_state_t *afl); void setup_dirs_fds(afl_state_t *); void setup_cmdline_file(afl_state_t *, char **); void setup_stdio_file(afl_state_t *); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 65478a78..881bf10f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -959,6 +959,8 @@ void perform_dry_run(afl_state_t *afl) { /* Remove from fuzzing queue but keep for splicing */ struct queue_entry *p = afl->queue; + p->disabled = 1; + p->perf_score = 0; while (p && p->next != q) p = p->next; @@ -968,6 +970,7 @@ void perform_dry_run(afl_state_t *afl) { afl->queue = q->next; --afl->pending_not_fuzzed; + --afl->active_paths; afl->max_depth = 0; p = afl->queue; @@ -1054,6 +1057,7 @@ restart_outer_cull_loop: duplicates = 1; --afl->pending_not_fuzzed; + afl->active_paths--; // We do not remove any of the memory allocated because for // splicing the data might still be interesting. @@ -1063,11 +1067,15 @@ restart_outer_cull_loop: // we keep the shorter file if (p->len >= q->len) { + p->disabled = 1; + p->perf_score = 0; q->next = p->next; goto restart_inner_cull_loop; } else { + q->disabled = 1; + q->perf_score = 0; if (prev) prev->next = q = p; else diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c04b492b..6ef728e0 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -554,7 +554,10 @@ u8 fuzz_one_original(afl_state_t *afl) { * PERFORMANCE SCORE * *********************/ - orig_perf = perf_score = calculate_score(afl, afl->queue_cur); + if (likely(!afl->old_seed_selection)) + orig_perf = perf_score = afl->queue_cur->perf_score; + else + orig_perf = perf_score = calculate_score(afl, afl->queue_cur); if (unlikely(perf_score == 0)) { goto abandon_entry; } @@ -2769,7 +2772,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { * PERFORMANCE SCORE * *********************/ - orig_perf = perf_score = calculate_score(afl, afl->queue_cur); + if (likely(!afl->old_seed_selection)) + orig_perf = perf_score = afl->queue_cur->perf_score; + else + orig_perf = perf_score = calculate_score(afl, afl->queue_cur); if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 0d7d0314..d608e890 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -27,6 +27,129 @@ #include #include +inline u32 select_next_queue_entry(afl_state_t *afl) { + + u32 r = rand_below(afl, 0xffffffff); + u32 s = r % afl->queued_paths; + // fprintf(stderr, "select: r=%u s=%u ... r < prob[s]=%f ? s=%u : + // alias[%u]=%u\n", r, s, afl->alias_probability[s], s, s, + // afl->alias_table[s]); + return (r < afl->alias_probability[s] ? s : afl->alias_table[s]); + +} + +void create_alias_table(afl_state_t *afl) { + + u32 n = afl->queued_paths, i = 0, a, g; + + afl->alias_table = + (u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32)); + afl->alias_probability = (double *)afl_realloc( + (void **)&afl->alias_probability, n * sizeof(double)); + double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double)); + int * S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32)); + int * L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32)); + + if (!P || !S || !L) FATAL("could not aquire memory for alias table"); + memset((void *)afl->alias_table, 0, n * sizeof(u32)); + memset((void *)afl->alias_probability, 0, n * sizeof(double)); + + double sum = 0; + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + + if (!q->disabled) q->perf_score = calculate_score(afl, q); + + sum += q->perf_score; + /* + if (afl->debug) + fprintf(stderr, "entry %u: score=%f %s (sum: %f)\n", i, q->perf_score, + q->disabled ? "disabled" : "", sum); + */ + + } + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + + P[i] = q->perf_score * n / sum; + + } + + int nS = 0, nL = 0, s; + for (s = (s32)n - 1; s >= 0; --s) { + + if (P[s] < 1) + S[nS++] = s; + else + L[nL++] = s; + + } + + while (nS && nL) { + + a = S[--nS]; + g = L[--nL]; + afl->alias_probability[a] = P[a]; + afl->alias_table[a] = g; + P[g] = P[g] + P[a] - 1; + if (P[g] < 1) + S[nS++] = g; + else + L[nL++] = g; + + } + + while (nL) + afl->alias_probability[L[--nL]] = 1; + + while (nS) + afl->alias_probability[S[--nS]] = 1; + + /* + if (afl->debug) { + + fprintf(stderr, " %-3s %-3s %-9s\n", "entry", "alias", "prob"); + for (u32 i = 0; i < n; ++i) + fprintf(stderr, " %3i %3i %9.7f\n", i, afl->alias_table[i], + afl->alias_probability[i]); + + } + + int prob = 0; + fprintf(stderr, "Alias:"); + for (i = 0; i < n; i++) { + + fprintf(stderr, " [%u]=%u", i, afl->alias_table[i]); + if (afl->alias_table[i] >= n) + prob = i; + + } + + fprintf(stderr, "\n"); + + if (prob) { + + fprintf(stderr, "PROBLEM! alias[%u] = %u\n", prob, + afl->alias_table[prob]); + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + + fprintf(stderr, "%u: score=%f\n", i, q->perf_score); + + } + + } + + */ + +} + /* Mark deterministic checks as done for a particular queue entry. We use the .state file to avoid repeating deterministic fuzzing when resuming aborted scans. */ @@ -237,6 +360,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { if (likely(q->len > 4)) afl->ready_for_splicing_count++; ++afl->queued_paths; + ++afl->active_paths; ++afl->pending_not_fuzzed; afl->cycles_wo_finds = 0; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 24df2997..004adffe 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -115,6 +115,8 @@ static void usage(u8 *argv0, int more_help) { " if using QEMU, just use -c 0.\n\n" "Fuzzing behavior settings:\n" + " -Z - sequential queue selection instead of weighted " + "random\n" " -N - do not unlink the fuzzing input file (for devices " "etc.)\n" " -n - fuzz without instrumentation (non-instrumented mode)\n" @@ -131,8 +133,7 @@ static void usage(u8 *argv0, int more_help) { "Other stuff:\n" " -M/-S id - distributed mode (see docs/parallel_fuzzing.md)\n" - " use -D to force -S secondary to perform deterministic " - "fuzzing\n" + " -M auto-sets -D and -Z (use -d to disable -D)\n" " -F path - sync to a foreign fuzzer queue directory (requires " "-M, can\n" " be specified up to %u times)\n" @@ -250,7 +251,7 @@ int main(int argc, char **argv_orig, char **envp) { s32 opt, i; u64 prev_queued = 0; - u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE; + u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = MAP_SIZE; u8 *extras_dir[4]; u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0 /*, have_p = 0*/; @@ -287,10 +288,14 @@ int main(int argc, char **argv_orig, char **envp) { 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) { + "+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:Z")) > 0) { switch (opt) { + case 'Z': + afl->old_seed_selection = 1; + break; + case 'I': afl->infoexec = optarg; break; @@ -355,14 +360,16 @@ int main(int argc, char **argv_orig, char **envp) { afl->schedule = RARE; - } else if (!stricmp(optarg, "explore") || !stricmp(optarg, "afl")) { - - afl->schedule = EXPLORE; + } else if (!stricmp(optarg, "explore") || !stricmp(optarg, "afl") || - } else if (!stricmp(optarg, "seek") || !stricmp(optarg, "default") || + !stricmp(optarg, "default") || !stricmp(optarg, "normal")) { + afl->schedule = EXPLORE; + + } else if (!stricmp(optarg, "seek")) { + afl->schedule = SEEK; } else { @@ -404,7 +411,8 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); } afl->sync_id = ck_strdup(optarg); - afl->skip_deterministic = 0; + afl->skip_deterministic = 0; // force determinsitic fuzzing + afl->old_seed_selection = 1; // force old queue walking seed selection if ((c = strchr(afl->sync_id, ':'))) { @@ -1131,8 +1139,10 @@ int main(int argc, char **argv_orig, char **envp) { 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(3); + WARNF( + "no -M main node found. It is recommended to run exactly one main " + "instance."); + sleep(1); } @@ -1302,7 +1312,7 @@ int main(int argc, char **argv_orig, char **envp) { show_init_stats(afl); - seek_to = find_start_position(afl); + if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); @@ -1324,28 +1334,37 @@ int main(int argc, char **argv_orig, char **envp) { // real start time, we reset, so this works correctly with -V afl->start_time = get_cur_time(); + u32 runs_in_current_cycle = (u32)-1; + u32 prev_queued_paths = 0; + while (1) { u8 skipped_fuzz; cull_queue(afl); - if (!afl->queue_cur) { + if (unlikely((!afl->old_seed_selection && + runs_in_current_cycle > afl->queued_paths) || + (afl->old_seed_selection && !afl->queue_cur))) { ++afl->queue_cycle; - afl->current_entry = 0; + runs_in_current_cycle = 0; afl->cur_skipped_paths = 0; - afl->queue_cur = afl->queue; - if (seek_to) { + if (unlikely(afl->old_seed_selection)) { - afl->current_entry = seek_to; - afl->queue_cur = afl->queue_buf[seek_to]; - seek_to = 0; + afl->current_entry = 0; + afl->queue_cur = afl->queue; - } + if (unlikely(seek_to)) { - // show_stats(afl); + afl->current_entry = seek_to; + afl->queue_cur = afl->queue_buf[seek_to]; + seek_to = 0; + + } + + } if (unlikely(afl->not_on_tty)) { @@ -1366,9 +1385,11 @@ int main(int argc, char **argv_orig, char **envp) { switch (afl->expand_havoc) { case 0: + // this adds extra splicing mutation options to havoc mode afl->expand_havoc = 1; break; case 1: + // add MOpt mutator if (afl->limit_time_sig == 0 && !afl->custom_only && !afl->python_only) { @@ -1381,25 +1402,26 @@ int main(int argc, char **argv_orig, char **envp) { break; case 2: // if (!have_p) afl->schedule = EXPLOIT; + // increase havoc mutations per fuzz attempt afl->havoc_stack_pow2++; afl->expand_havoc = 3; break; case 3: + // further increase havoc mutations per fuzz attempt afl->havoc_stack_pow2++; afl->expand_havoc = 4; break; case 4: + // if not in sync mode, enable deterministic mode? + // if (!afl->sync_dir) afl->skip_deterministic = 0; + afl->expand_havoc = 5; + break; + case 5: // nothing else currently break; } - if (afl->expand_havoc) { - - } else - - afl->expand_havoc = 1; - } else { afl->use_splicing = 1; @@ -1470,6 +1492,22 @@ int main(int argc, char **argv_orig, char **envp) { } + if (likely(!afl->old_seed_selection)) { + + ++runs_in_current_cycle; + if (unlikely(prev_queued_paths < afl->queued_paths)) { + + // we have new queue entries since the last run, recreate alias table + prev_queued_paths = afl->queued_paths; + create_alias_table(afl); + + } + + afl->current_entry = select_next_queue_entry(afl); + afl->queue_cur = afl->queue_buf[afl->current_entry]; + + } + skipped_fuzz = fuzz_one(afl); if (!skipped_fuzz && !afl->stop_soon && afl->sync_id) { @@ -1490,8 +1528,12 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->stop_soon) { break; } - afl->queue_cur = afl->queue_cur->next; - ++afl->current_entry; + if (unlikely(afl->old_seed_selection)) { + + afl->queue_cur = afl->queue_cur->next; + ++afl->current_entry; + + } } -- cgit 1.4.1 From b7e0490bcdaa7fa792a9dccfa5983e03af92730e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 12 Oct 2020 03:44:34 +0200 Subject: Revert "Merge branch 'memcache_marc' into dev" This reverts commit c03fbcedaa68db5324423975a34331287426f7c2, reversing changes made to dab017dddaaab6d836a590f7bba3eea3549758d2. --- include/afl-fuzz.h | 16 ------ include/config.h | 9 --- src/afl-fuzz-one.c | 157 +++++++++++++++++++++++++++++++-------------------- src/afl-fuzz-queue.c | 87 ---------------------------- src/afl-fuzz.c | 5 +- 5 files changed, 97 insertions(+), 177 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index a3e87129..45de197d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -168,9 +168,6 @@ struct queue_entry { double perf_score; /* performance score */ - u8 *testcase_buf; /* The testcase buffer, if loaded. */ - u32 testcase_refs; /* count of users of testcase buf */ - struct queue_entry *next; /* Next element, if any */ }; @@ -689,12 +686,6 @@ typedef struct afl_state { /* queue entries ready for splicing count (len > 4) */ u32 ready_for_splicing_count; - /* How many queue entries currently have cached testcases */ - u32 q_testcase_cache_count; - /* Refs to each queue entry with cached testcase (for eviction, if cache_count - * is too large) */ - struct queue_entry *q_testcase_cache[TESTCASE_CACHE_SIZE]; - } afl_state_t; struct custom_mutator { @@ -1141,12 +1132,5 @@ static inline u64 next_p2(u64 val) { } -/* Returns the testcase buf from the file behind this queue entry. - Increases the refcount. */ -u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q); - -/* Tell afl that this testcase may be evicted from the cache */ -void queue_testcase_release(afl_state_t *afl, struct queue_entry *q); - #endif diff --git a/include/config.h b/include/config.h index 3f498275..7dd045e3 100644 --- a/include/config.h +++ b/include/config.h @@ -295,15 +295,6 @@ #define RESEED_RNG 100000 -/* The amount of entries in the testcase cache, held in memory. -Decrease if RAM usage is high. */ -#define TESTCASE_CACHE_SIZE 3072 - -#if TESTCASE_CACHE_SIZE < 4 - #error \ - "Dangerously low cache size: Set TESTCASE_CACHE_SIZE to 4 or more in config.h!" -#endif - /* Maximum line length passed from GCC to 'as' and used for parsing configuration files: */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ebe541a2..6ef728e0 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -370,7 +370,7 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { u8 fuzz_one_original(afl_state_t *afl) { - s32 len, temp_len; + s32 len, fd, temp_len; u32 j; u32 i; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -453,9 +453,28 @@ u8 fuzz_one_original(afl_state_t *afl) { } - orig_in = in_buf = queue_testcase_take(afl, afl->queue_cur); + /* Map the test case into memory. */ + + fd = open(afl->queue_cur->fname, O_RDONLY); + + if (unlikely(fd < 0)) { + + PFATAL("Unable to open '%s'", afl->queue_cur->fname); + + } + len = afl->queue_cur->len; + orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (unlikely(orig_in == MAP_FAILED)) { + + PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); + + } + + close(fd); + /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ @@ -1678,7 +1697,7 @@ custom_mutator_stage: for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - struct queue_entry *target = NULL; + struct queue_entry *target; u32 tid; u8 * new_buf = NULL; u32 target_len = 0; @@ -1701,7 +1720,17 @@ custom_mutator_stage: afl->splicing_with = tid; /* Read the additional testcase into a new buffer. */ - new_buf = queue_testcase_take(afl, target); + fd = open(target->fname, O_RDONLY); + if (unlikely(fd < 0)) { + + PFATAL("Unable to open '%s'", target->fname); + + } + + new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + ck_read(fd, new_buf, target->len, target->fname); + close(fd); target_len = target->len; } @@ -1712,13 +1741,6 @@ custom_mutator_stage: el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf, target_len, max_seed_size); - if (new_buf) { - - queue_testcase_release(afl, target); - new_buf = NULL; - - } - if (unlikely(!mutated_buf)) { FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); @@ -2301,53 +2323,52 @@ havoc_stage: /* Overwrite bytes with a randomly selected chunk from another testcase or insert that chunk. */ - if (afl->queued_paths < 4) { break; } + if (afl->queued_paths < 4) break; /* Pick a random queue entry and seek to it. */ u32 tid; - do { - + do tid = rand_below(afl, afl->queued_paths); - - } while (tid == afl->current_entry); + 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)) { - + while (target && (target->len < 2 || target == afl->queue_cur)) target = target->next; - } + if (!target) break; - if (!target) { break; } + /* Read the testcase into a new buffer. */ - u32 new_len = target->len; + fd = open(target->fname, O_RDONLY); - /* Get the testcase contents for splicing. */ - u8 *new_buf = queue_testcase_take(afl, target); + if (unlikely(fd < 0)) { - u8 overwrite = 0; - if (temp_len >= 2 && rand_below(afl, 2)) { + PFATAL("Unable to open '%s'", target->fname); - overwrite = 1; + } - } else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { + u32 new_len = target->len; + u8 *new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), new_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } - if (temp_len >= 2) { + ck_read(fd, new_buf, new_len, target->fname); - overwrite = 1; + close(fd); - } else { + u8 overwrite = 0; + if (temp_len >= 2 && rand_below(afl, 2)) + overwrite = 1; + else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { - queue_testcase_release(afl, target); - new_buf = NULL; + if (temp_len >= 2) + overwrite = 1; + else break; - } - } if (overwrite) { @@ -2393,9 +2414,6 @@ havoc_stage: } - /* We don't need this splice testcase anymore */ - queue_testcase_release(afl, target); - new_buf = NULL; break; } @@ -2501,17 +2519,24 @@ retry_splicing: if (!target) { goto retry_splicing; } - /* Get the testcase buffer */ - u8 *splice_buf = queue_testcase_take(afl, target); + /* Read the testcase into a new buffer. */ + + fd = open(target->fname, O_RDONLY); + + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } + new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); if (unlikely(!new_buf)) { PFATAL("alloc"); } + ck_read(fd, new_buf, target->len, target->fname); + + close(fd); + /* Find a suitable splicing location, somewhere between the first and the last differing byte. Bail out if the difference is just a single byte or so. */ - locate_diffs(in_buf, splice_buf, MIN(len, (s64)target->len), &f_diff, - &l_diff); + locate_diffs(in_buf, new_buf, MIN(len, (s64)target->len), &f_diff, &l_diff); if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; } @@ -2523,7 +2548,6 @@ retry_splicing: len = target->len; memcpy(new_buf, in_buf, split_at); - memcpy(new_buf + split_at, splice_buf + split_at, target->len - split_at); afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; @@ -2531,9 +2555,6 @@ retry_splicing: if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); - queue_testcase_release(afl, target); - splice_buf = NULL; - goto custom_mutator_stage; /* ???: While integrating Python module, the author decided to jump to python stage, but the reason behind this is not clear.*/ @@ -2564,8 +2585,7 @@ abandon_entry: ++afl->queue_cur->fuzz_level; - queue_testcase_release(afl, afl->queue_cur); - orig_in = NULL; + munmap(orig_in, afl->queue_cur->len); return ret_val; @@ -2587,7 +2607,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } - s32 len, temp_len; + s32 len, fd, temp_len; u32 i; u32 j; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -2652,9 +2672,23 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } /* Map the test case into memory. */ - orig_in = in_buf = queue_testcase_take(afl, afl->queue_cur); + + fd = open(afl->queue_cur->fname, O_RDONLY); + + if (fd < 0) { PFATAL("Unable to open '%s'", afl->queue_cur->fname); } + len = afl->queue_cur->len; + orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (orig_in == MAP_FAILED) { + + PFATAL("Unable to mmap '%s'", afl->queue_cur->fname); + + } + + close(fd); + /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ @@ -4494,24 +4528,31 @@ pacemaker_fuzzing: if (!target) { goto retry_splicing_puppet; } /* Read the testcase into a new buffer. */ - u8 *splicing_buf = queue_testcase_take(afl, target); + + fd = open(target->fname, O_RDONLY); + + if (fd < 0) { PFATAL("Unable to open '%s'", target->fname); } + + new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + + ck_read(fd, new_buf, target->len, target->fname); + + close(fd); /* Find a suitable splicin g location, somewhere between the first and the last differing byte. Bail out if the difference is just a single byte or so. */ - locate_diffs(in_buf, splicing_buf, MIN(len, (s32)target->len), &f_diff, + locate_diffs(in_buf, new_buf, MIN(len, (s32)target->len), &f_diff, &l_diff); if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { - queue_testcase_release(afl, target); goto retry_splicing_puppet; } - new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); - /* Split somewhere between the first and last differing byte. */ split_at = f_diff + rand_below(afl, l_diff - f_diff); @@ -4520,17 +4561,12 @@ pacemaker_fuzzing: len = target->len; memcpy(new_buf, in_buf, split_at); - memcpy(new_buf + split_at, splicing_buf + split_at, - target->len - split_at); afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = new_buf; out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); - queue_testcase_release(afl, target); - splicing_buf = NULL; - goto havoc_stage_puppet; } /* if splice_cycle */ @@ -4564,8 +4600,7 @@ pacemaker_fuzzing: // if (afl->queue_cur->favored) --afl->pending_favored; // } - queue_testcase_release(afl, afl->queue_cur); - orig_in = NULL; + munmap(orig_in, afl->queue_cur->len); if (afl->key_puppet == 1) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index a034b168..d608e890 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -343,7 +343,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->depth = afl->cur_depth + 1; q->passed_det = passed_det; q->trace_mini = NULL; - q->testcase_buf = NULL; if (q->depth > afl->max_depth) { afl->max_depth = q->depth; } @@ -892,89 +891,3 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } -/* Tell afl that this testcase may be evicted from the cache */ -inline void queue_testcase_release(afl_state_t *afl, struct queue_entry *q) { - - (void)afl; - if (unlikely(q->testcase_refs == 0)) { - - FATAL("Testcase refcount reduced past 0"); - - } - - q->testcase_refs--; - -} - -/* Returns the testcase buf from the file behind this queue entry. - Increases the refcount. */ -u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q) { - - if (!q->testcase_buf) { - - u32 tid = 0; - /* Buf not cached, let's do that now */ - - if (likely(afl->q_testcase_cache_count == TESTCASE_CACHE_SIZE)) { - - /* Cache full. We neet to evict one to map one. - Get a random one which is not in use */ - do { - - tid = rand_below(afl, afl->q_testcase_cache_count); - - } while (afl->q_testcase_cache[tid]->testcase_refs > 0); - - struct queue_entry *old_cached = afl->q_testcase_cache[tid]; - /* free the current buf from cache */ - munmap(old_cached->testcase_buf, old_cached->len); - old_cached->testcase_buf = NULL; - - } else { - - tid = afl->q_testcase_cache_count; - afl->q_testcase_cache_count++; - - } - - /* Map the test case into memory. */ - - int fd = open(q->fname, O_RDONLY); - - if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); } - - u32 len = q->len; - - q->testcase_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (unlikely(q->testcase_buf == MAP_FAILED)) { - - PFATAL("Unable to mmap '%s' with len %d", q->fname, len); - - } - - close(fd); - - /* Register us as cached */ - afl->q_testcase_cache[tid] = q; - - } - - q->testcase_refs++; - if (unlikely(!q->testcase_buf || !q->testcase_refs)) { - if (!q->testcase_buf) { - - FATAL("Testcase buf is NULL, this should never happen"); - - } - if (!q->testcase_refs) { - - FATAL("Testcase ref overflow. Missing a testcase release somwhere?"); - - } - } - - return q->testcase_buf; - -} - diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index cb5eb37a..d42a0d36 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1174,12 +1174,9 @@ int main(int argc, char **argv_orig, char **envp) { if (extras_dir_cnt) { - for (i = 0; i < extras_dir_cnt; i++) { - + for (i = 0; i < extras_dir_cnt; i++) load_extras(afl, extras_dir[i]); - } - dedup_extras(afl); OKF("Loaded a total of %u extras.", afl->extras_cnt); -- cgit 1.4.1 From d9b63766dfdb8feeb1dc6f7c51c17abf07ee4086 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 12 Oct 2020 11:12:16 +0200 Subject: fix new seed selection algo --- include/afl-fuzz.h | 3 +++ src/afl-fuzz-queue.c | 59 ++++++++++++--------------------------------------- src/afl-performance.c | 10 ++++++++- 3 files changed, 26 insertions(+), 46 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 45de197d..85597150 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1045,6 +1045,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, /* xoshiro256** */ uint64_t rand_next(afl_state_t *afl); +/* probability between 0.0 and 1.0 */ +double rand_next_percent(afl_state_t *afl); + /**** Inline routines ****/ /* Generate a random number (from 0 to limit - 1). This may diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index d608e890..f224d851 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -27,17 +27,22 @@ #include #include +/* select next queue entry based on alias algo - fast! */ + inline u32 select_next_queue_entry(afl_state_t *afl) { - u32 r = rand_below(afl, 0xffffffff); - u32 s = r % afl->queued_paths; - // fprintf(stderr, "select: r=%u s=%u ... r < prob[s]=%f ? s=%u : - // alias[%u]=%u\n", r, s, afl->alias_probability[s], s, s, - // afl->alias_table[s]); - return (r < afl->alias_probability[s] ? s : afl->alias_table[s]); + u32 s = rand_below(afl, afl->queued_paths); + double p = rand_next_percent(afl); + /* + fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u" + " ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p < afl->alias_probability[s] ? s : afl->alias_table[s]); + */ + return (p < afl->alias_probability[s] ? s : afl->alias_table[s]); } +/* create the alias table that allows weighted random selection - expensive */ + void create_alias_table(afl_state_t *afl) { u32 n = afl->queued_paths, i = 0, a, g; @@ -63,11 +68,6 @@ void create_alias_table(afl_state_t *afl) { if (!q->disabled) q->perf_score = calculate_score(afl, q); sum += q->perf_score; - /* - if (afl->debug) - fprintf(stderr, "entry %u: score=%f %s (sum: %f)\n", i, q->perf_score, - q->disabled ? "disabled" : "", sum); - */ } @@ -110,41 +110,10 @@ void create_alias_table(afl_state_t *afl) { afl->alias_probability[S[--nS]] = 1; /* - if (afl->debug) { - - fprintf(stderr, " %-3s %-3s %-9s\n", "entry", "alias", "prob"); + fprintf(stderr, " %-3s %-3s %-9s %-9s\n", "entry", "alias", "prob", "perf"); for (u32 i = 0; i < n; ++i) - fprintf(stderr, " %3i %3i %9.7f\n", i, afl->alias_table[i], - afl->alias_probability[i]); - - } - - int prob = 0; - fprintf(stderr, "Alias:"); - for (i = 0; i < n; i++) { - - fprintf(stderr, " [%u]=%u", i, afl->alias_table[i]); - if (afl->alias_table[i] >= n) - prob = i; - - } - - fprintf(stderr, "\n"); - - if (prob) { - - fprintf(stderr, "PROBLEM! alias[%u] = %u\n", prob, - afl->alias_table[prob]); - - for (i = 0; i < n; i++) { - - struct queue_entry *q = afl->queue_buf[i]; - - fprintf(stderr, "%u: score=%f\n", i, q->perf_score); - - } - - } + fprintf(stderr, " %3i %3i %9.7f %9.7f\n", i, afl->alias_table[i], + afl->alias_probability[i], afl->queue_buf[i]->perf_score); */ diff --git a/src/afl-performance.c b/src/afl-performance.c index 7a80ac4b..6fa95dea 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -47,7 +47,7 @@ void rand_set_seed(afl_state_t *afl, s64 init_seed) { } -uint64_t rand_next(afl_state_t *afl) { +inline uint64_t rand_next(afl_state_t *afl) { const uint64_t result = rotl(afl->rand_seed[0] + afl->rand_seed[3], 23) + afl->rand_seed[0]; @@ -67,6 +67,14 @@ uint64_t rand_next(afl_state_t *afl) { } +/* returns a double between 0.000000000 and 1.000000000 */ + +inline double rand_next_percent(afl_state_t *afl) { + + return (double)(((double)rand_next(afl)) / (double) 0xffffffffffffffff); + +} + /* This is the jump function for the generator. It is equivalent to 2^128 calls to rand_next(); it can be used to generate 2^128 non-overlapping subsequences for parallel computations. */ -- cgit 1.4.1 From 56ac3fcdc511d124ad058412021ead21bbbcf4bf Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 14 Oct 2020 15:30:30 +0200 Subject: configurable testcache with malloc (#581) * cache item number to cache memory size * reload testcase if trimming changed the size * fix splicing selection * slim splicing * import sync fix * write testcache stats to fuzzer_stats * fix new seed selection algo * malloc+read instead of mmap * fix * testcache is configurable now and no reference counts * fixes compilation, test script * fixes * switch TEST_CC to afl-cc in makefile * code format * fix * fix crash * fix crash * fix env help output * remove unnecessary pointer resets * fix endless loop bug * actually use the cache if set * one more fix * increase default cache entries, add default cache size value to config.h Co-authored-by: hexcoder- --- GNUmakefile | 4 +- include/afl-fuzz.h | 31 +++++++- include/config.h | 9 +++ include/envs.h | 1 + src/afl-fuzz-init.c | 4 +- src/afl-fuzz-one.c | 169 +++++++++---------------------------------- src/afl-fuzz-queue.c | 167 ++++++++++++++++++++++++++++++++++++++---- src/afl-fuzz-run.c | 6 ++ src/afl-fuzz-state.c | 8 ++ src/afl-fuzz-stats.c | 7 +- src/afl-fuzz.c | 29 ++++++-- src/afl-performance.c | 2 +- test/test-custom-mutators.sh | 2 +- 13 files changed, 276 insertions(+), 163 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index c885a935..80b7b68b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -223,8 +223,6 @@ ifneq "$(findstring OpenBSD, $(shell uname))" "" LDFLAGS += -lpthread endif -TEST_CC = afl-gcc - COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h ifeq "$(shell echo '$(HASH)include @int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" @@ -488,7 +486,7 @@ code-format: ifndef AFL_NO_X86 test_build: afl-cc afl-as afl-showmap @echo "[*] Testing the CC wrapper and instrumentation output..." - @unset AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_DEBUG=1 AFL_INST_RATIO=100 AFL_PATH=. ./$(TEST_CC) $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 | grep 'afl-as' >/dev/null || (echo "Oops, afl-as did not get called from "$(TEST_CC)". This is normally achieved by "$(CC)" honoring the -B option."; exit 1 ) + @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN AFL_CC; AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc $(CFLAGS) test-instr.c -o test-instr $(LDFLAGS) 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 85597150..940c5602 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -168,6 +168,8 @@ struct queue_entry { double perf_score; /* performance score */ + u8 *testcase_buf; /* The testcase buffer, if loaded. */ + struct queue_entry *next; /* Next element, if any */ }; @@ -363,7 +365,7 @@ typedef struct afl_env_vars { u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, - *afl_statsd_tags_flavor; + *afl_statsd_tags_flavor, *afl_testcache_size; } afl_env_vars_t; @@ -675,6 +677,9 @@ typedef struct afl_state { u8 *in_scratch_buf; u8 *ex_buf; + + u8 *testcase_buf, *splicecase_buf; + u32 custom_mutators_count; list_t custom_mutator_list; @@ -686,6 +691,22 @@ typedef struct afl_state { /* queue entries ready for splicing count (len > 4) */ u32 ready_for_splicing_count; + /* This is the user specified maximum size to use for the testcase cache */ + u64 q_testcase_max_cache_size; + + /* How much of the testcase cache is used so far */ + u64 q_testcase_cache_size; + + /* highest cache count so far */ + u32 q_testcase_max_cache_count; + + /* How many queue entries currently have cached testcases */ + u32 q_testcase_cache_count; + + /* Refs to each queue entry with cached testcase (for eviction, if cache_count + * is too large) */ + struct queue_entry *q_testcase_cache[TESTCASE_ENTRIES]; + } afl_state_t; struct custom_mutator { @@ -1135,5 +1156,13 @@ static inline u64 next_p2(u64 val) { } +/* Returns the testcase buf from the file behind this queue entry. + Increases the refcount. */ +u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q); + +/* If trimming changes the testcase size we have to reload it */ +void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, + u32 old_len); + #endif diff --git a/include/config.h b/include/config.h index 7dd045e3..b4f3a775 100644 --- a/include/config.h +++ b/include/config.h @@ -295,6 +295,15 @@ #define RESEED_RNG 100000 +/* The maximum number of testcases to cache */ + +#define TESTCASE_ENTRIES 16384 + +/* The default maximum testcase cache size in MB, 0 = disable. + A value between 50 and 250 is a good default value. */ + +#define TESTCASE_CACHE 0 + /* Maximum line length passed from GCC to 'as' and used for parsing configuration files: */ diff --git a/include/envs.h b/include/envs.h index 51520312..a1b3ad12 100644 --- a/include/envs.h +++ b/include/envs.h @@ -139,6 +139,7 @@ static char *afl_environment_variables[] = { "AFL_STATSD_HOST", "AFL_STATSD_PORT", "AFL_STATSD_TAGS_FLAVOR", + "AFL_TESTCACHE_SIZE", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 881bf10f..607b652f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1045,7 +1045,7 @@ restart_outer_cull_loop: while (q) { - if (q->cal_failed || !q->exec_cksum) continue; + if (q->cal_failed || !q->exec_cksum) { goto next_entry; } restart_inner_cull_loop: @@ -1090,6 +1090,8 @@ restart_outer_cull_loop: } + next_entry: + prev = q; q = q->next; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index fc092f8d..154e4b45 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -370,7 +370,7 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { u8 fuzz_one_original(afl_state_t *afl) { - s32 len, fd, temp_len; + s32 len, temp_len; u32 j; u32 i; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -453,32 +453,9 @@ u8 fuzz_one_original(afl_state_t *afl) { } - /* Map the test case into memory. */ - - fd = open(afl->queue_cur->fname, O_RDONLY); - - if (unlikely(fd < 0)) { - - PFATAL("Unable to open '%s'", afl->queue_cur->fname); - - } - + orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); len = afl->queue_cur->len; - orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (unlikely(orig_in == MAP_FAILED)) { - - PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); - - } - - close(fd); - - /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every - single byte anyway, so it wouldn't give us any performance or memory usage - benefits. */ - out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } @@ -526,6 +503,7 @@ u8 fuzz_one_original(afl_state_t *afl) { !afl->disable_trim)) { u8 res = trim_case(afl, afl->queue_cur, in_buf); + orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); if (unlikely(res == FSRV_RUN_ERROR)) { @@ -1720,17 +1698,7 @@ custom_mutator_stage: afl->splicing_with = tid; /* Read the additional testcase into a new buffer. */ - fd = open(target->fname, O_RDONLY); - if (unlikely(fd < 0)) { - - PFATAL("Unable to open '%s'", target->fname); - - } - - new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - ck_read(fd, new_buf, target->len, target->fname); - close(fd); + new_buf = queue_testcase_get(afl, target); target_len = target->len; } @@ -2182,7 +2150,6 @@ havoc_stage: afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); out_buf = new_buf; - new_buf = NULL; temp_len += clone_len; } @@ -2326,43 +2293,21 @@ havoc_stage: /* Pick a random queue entry and seek to it. */ u32 tid; - do - tid = rand_below(afl, afl->queued_paths); - while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); - - struct queue_entry *target = afl->queue_buf[tid]; - - /* 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 = afl_realloc(AFL_BUF_PARAM(in_scratch), new_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - ck_read(fd, new_buf, new_len, target->fname); + do { - close(fd); + tid = rand_below(afl, afl->queued_paths); - u8 overwrite = 0; - if (temp_len >= 2 && rand_below(afl, 2)) - overwrite = 1; - else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { + } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); - if (temp_len >= 2) - overwrite = 1; - else - break; + /* Get the testcase for splicing. */ + struct queue_entry *target = afl->queue_buf[tid]; + u32 new_len = target->len; + u8 * new_buf = queue_testcase_get(afl, target); - } + if ((temp_len >= 2 && rand_below(afl, 2)) || + temp_len + HAVOC_BLK_XL >= MAX_FILE) { - if (overwrite) { + /* overwrite mode */ u32 copy_from, copy_to, copy_len; @@ -2376,15 +2321,16 @@ havoc_stage: } else { + /* insert mode */ + 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 + 1); - clone_to = rand_below(afl, temp_len); - - u8 *temp_buf = - afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); + u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), + temp_len + clone_len + 1); if (unlikely(!temp_buf)) { PFATAL("alloc"); } /* Head */ @@ -2496,21 +2442,10 @@ retry_splicing: } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); + /* Get the testcase */ afl->splicing_with = tid; target = afl->queue_buf[tid]; - - /* Read the testcase into a new buffer. */ - - fd = open(target->fname, O_RDONLY); - - if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } - - new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - ck_read(fd, new_buf, target->len, target->fname); - - close(fd); + new_buf = queue_testcase_get(afl, target); /* Find a suitable splicing location, somewhere between the first and the last differing byte. Bail out if the difference is just a single @@ -2527,18 +2462,16 @@ retry_splicing: /* Do the thing. */ len = target->len; - memcpy(new_buf, in_buf, split_at); - afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); - in_buf = new_buf; + afl->in_scratch_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len); + memcpy(afl->in_scratch_buf, in_buf, split_at); + memcpy(afl->in_scratch_buf + split_at, new_buf, len - split_at); + in_buf = afl->in_scratch_buf; out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); goto custom_mutator_stage; - /* ???: While integrating Python module, the author decided to jump to - python stage, but the reason behind this is not clear.*/ - // goto havoc_stage; } @@ -2564,9 +2497,7 @@ abandon_entry: } ++afl->queue_cur->fuzz_level; - - munmap(orig_in, afl->queue_cur->len); - + orig_in = NULL; return ret_val; #undef FLIP_BIT @@ -2587,7 +2518,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } - s32 len, fd, temp_len; + s32 len, temp_len; u32 i; u32 j; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -2652,32 +2583,11 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } /* Map the test case into memory. */ - - fd = open(afl->queue_cur->fname, O_RDONLY); - - if (fd < 0) { PFATAL("Unable to open '%s'", afl->queue_cur->fname); } - + orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); len = afl->queue_cur->len; - - orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (orig_in == MAP_FAILED) { - - PFATAL("Unable to mmap '%s'", afl->queue_cur->fname); - - } - - close(fd); - - /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every - single byte anyway, so it wouldn't give us any performance or memory usage - benefits. */ - out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } - afl->subseq_tmouts = 0; - afl->cur_depth = afl->queue_cur->depth; /******************************************* @@ -2721,6 +2631,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u32 old_len = afl->queue_cur->len; u8 res = trim_case(afl, afl->queue_cur, in_buf); + orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); if (res == FSRV_RUN_ERROR) { @@ -4497,17 +4408,7 @@ pacemaker_fuzzing: target = afl->queue_buf[tid]; /* Read the testcase into a new buffer. */ - - fd = open(target->fname, O_RDONLY); - - if (fd < 0) { PFATAL("Unable to open '%s'", target->fname); } - - new_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), target->len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - ck_read(fd, new_buf, target->len, target->fname); - - close(fd); + new_buf = queue_testcase_get(afl, target); /* Find a suitable splicin g location, somewhere between the first and the last differing byte. Bail out if the difference is just a single @@ -4529,9 +4430,11 @@ pacemaker_fuzzing: /* Do the thing. */ len = target->len; - memcpy(new_buf, in_buf, split_at); - afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); - in_buf = new_buf; + afl->in_scratch_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len); + memcpy(afl->in_scratch_buf, in_buf, split_at); + memcpy(afl->in_scratch_buf + split_at, new_buf, len - split_at); + in_buf = afl->in_scratch_buf; + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } memcpy(out_buf, in_buf, len); @@ -4569,7 +4472,7 @@ pacemaker_fuzzing: // if (afl->queue_cur->favored) --afl->pending_favored; // } - munmap(orig_in, afl->queue_cur->len); + orig_in = NULL; if (afl->key_puppet == 1) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f224d851..c634328f 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -31,11 +31,12 @@ inline u32 select_next_queue_entry(afl_state_t *afl) { - u32 s = rand_below(afl, afl->queued_paths); + u32 s = rand_below(afl, afl->queued_paths); double p = rand_next_percent(afl); /* fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u" - " ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p < afl->alias_probability[s] ? s : afl->alias_table[s]); + " ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p < + afl->alias_probability[s] ? s : afl->alias_table[s]); */ return (p < afl->alias_probability[s] ? s : afl->alias_table[s]); @@ -55,7 +56,7 @@ void create_alias_table(afl_state_t *afl) { int * S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32)); int * L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32)); - if (!P || !S || !L) FATAL("could not aquire memory for alias table"); + if (!P || !S || !L) { FATAL("could not aquire memory for alias table"); } memset((void *)afl->alias_table, 0, n * sizeof(u32)); memset((void *)afl->alias_probability, 0, n * sizeof(double)); @@ -65,7 +66,7 @@ void create_alias_table(afl_state_t *afl) { struct queue_entry *q = afl->queue_buf[i]; - if (!q->disabled) q->perf_score = calculate_score(afl, q); + if (!q->disabled) { q->perf_score = calculate_score(afl, q); } sum += q->perf_score; @@ -74,19 +75,23 @@ void create_alias_table(afl_state_t *afl) { for (i = 0; i < n; i++) { struct queue_entry *q = afl->queue_buf[i]; - - P[i] = q->perf_score * n / sum; + P[i] = (q->perf_score * n) / sum; } int nS = 0, nL = 0, s; for (s = (s32)n - 1; s >= 0; --s) { - if (P[s] < 1) + if (P[s] < 1) { + S[nS++] = s; - else + + } else { + L[nL++] = s; + } + } while (nS && nL) { @@ -96,11 +101,16 @@ void create_alias_table(afl_state_t *afl) { afl->alias_probability[a] = P[a]; afl->alias_table[a] = g; P[g] = P[g] + P[a] - 1; - if (P[g] < 1) + if (P[g] < 1) { + S[nS++] = g; - else + + } else { + L[nL++] = g; + } + } while (nL) @@ -110,11 +120,10 @@ void create_alias_table(afl_state_t *afl) { afl->alias_probability[S[--nS]] = 1; /* - fprintf(stderr, " %-3s %-3s %-9s %-9s\n", "entry", "alias", "prob", "perf"); - for (u32 i = 0; i < n; ++i) - fprintf(stderr, " %3i %3i %9.7f %9.7f\n", i, afl->alias_table[i], - afl->alias_probability[i], afl->queue_buf[i]->perf_score); - + fprintf(stderr, " entry alias probability perf_score\n"); + for (u32 i = 0; i < n; ++i) + fprintf(stderr, " %5u %5u %11u %0.9f\n", i, afl->alias_table[i], + afl->alias_probability[i], afl->queue_buf[i]->perf_score); */ } @@ -860,3 +869,131 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } +void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, + u32 old_len) { + + if (likely(q->testcase_buf)) { + + free(q->testcase_buf); + int fd = open(q->fname, O_RDONLY); + + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); } + + u32 len = q->len; + q->testcase_buf = malloc(len); + + if (unlikely(!q->testcase_buf)) { + + PFATAL("Unable to mmap '%s' with len %d", q->fname, len); + + } + + close(fd); + afl->q_testcase_cache_size = afl->q_testcase_cache_size + q->len - old_len; + + } + +} + +/* Returns the testcase buf from the file behind this queue entry. + Increases the refcount. */ +inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { + + u32 len = q->len; + + /* first handle if no testcase cache is configured */ + + if (unlikely(!afl->q_testcase_max_cache_size)) { + + u8 *buf; + + if (q == afl->queue_cur) { + + buf = afl_realloc((void **)&afl->testcase_buf, len); + + } else { + + buf = afl_realloc((void **)&afl->splicecase_buf, len); + + } + + if (unlikely(!buf)) { + + PFATAL("Unable to malloc '%s' with len %u", q->fname, len); + + } + + int fd = open(q->fname, O_RDONLY); + + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); } + + ck_read(fd, buf, len, q->fname); + close(fd); + return buf; + + } + + /* now handle the testcase cache */ + + if (unlikely(!q->testcase_buf)) { + + /* Buf not cached, let's load it */ + u32 tid = 0; + + while (unlikely(afl->q_testcase_cache_size + len >= + afl->q_testcase_max_cache_size || + afl->q_testcase_cache_count >= TESTCASE_ENTRIES - 1)) { + + /* Cache full. We neet to evict one to map one. + Get a random one which is not in use */ + + do { + + tid = rand_below(afl, afl->q_testcase_max_cache_count); + + } while (afl->q_testcase_cache[tid] == NULL || + + afl->q_testcase_cache[tid] == afl->queue_cur); + + struct queue_entry *old_cached = afl->q_testcase_cache[tid]; + free(old_cached->testcase_buf); + old_cached->testcase_buf = NULL; + afl->q_testcase_cache_size -= old_cached->len; + afl->q_testcase_cache[tid] = NULL; + --afl->q_testcase_cache_count; + + } + + while (likely(afl->q_testcase_cache[tid] != NULL)) + ++tid; + + /* Map the test case into memory. */ + + int fd = open(q->fname, O_RDONLY); + + if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); } + + q->testcase_buf = malloc(len); + + if (unlikely(!q->testcase_buf)) { + + PFATAL("Unable to malloc '%s' with len %u", q->fname, len); + + } + + ck_read(fd, q->testcase_buf, len, q->fname); + close(fd); + + /* Register testcase as cached */ + afl->q_testcase_cache[tid] = q; + afl->q_testcase_cache_size += q->len; + ++afl->q_testcase_cache_count; + if (tid >= afl->q_testcase_max_cache_count) + afl->q_testcase_max_cache_count = tid + 1; + + } + + return q->testcase_buf; + +} + diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ee22b0f6..ab870319 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -692,6 +692,8 @@ void sync_fuzzers(afl_state_t *afl) { u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { + u32 orig_len = q->len; + /* Custom mutator trimmer */ if (afl->custom_mutators_count) { @@ -709,6 +711,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { }); + if (orig_len != q->len) { queue_testcase_retake(afl, q, orig_len); } + if (custom_trimmed) return trimmed_case; } @@ -842,6 +846,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { close(fd); + if (orig_len != q->len) queue_testcase_retake(afl, q, orig_len); + memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); update_bitmap_score(afl, q); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index a0a2795e..0824b77f 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -103,6 +103,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_avg_exec = -1; afl->skip_deterministic = 1; afl->use_splicing = 1; + afl->q_testcase_max_cache_size = TESTCASE_CACHE * 1024000; #ifdef HAVE_AFFINITY afl->cpu_aff = -1; /* Selected CPU core */ @@ -353,6 +354,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_forksrv_init_tmout = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_TESTCACHE_SIZE", + + afl_environment_variable_len)) { + + afl->afl_env.afl_testcache_size = + (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_STATSD_HOST", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 76f24977..4f0cab4c 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -165,6 +165,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, "edges_found : %u\n" "var_byte_count : %u\n" "havoc_expansion : %u\n" + "testcache_size : %llu\n" + "testcache_count : %u\n" "afl_banner : %s\n" "afl_version : " VERSION "\n" @@ -198,8 +200,9 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #else -1, #endif - t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner, - afl->unicorn_mode ? "unicorn" : "", + t_bytes, afl->var_byte_count, afl->expand_havoc, + afl->q_testcase_cache_size, afl->q_testcase_cache_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 " : "", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 6498eb30..a59abb7d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -196,11 +196,13 @@ static void usage(u8 *argv0, int more_help) { "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" - "AFL_STATSD: enables StatsD metrics collection" - "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)" - "AFL_STATSD_PORT: change default statsd port (default: 8125)" - "AFL_STATSD_TAGS_FLAVOR: change default statsd tags format (default will disable tags)." - " Supported formats are: 'dogstatsd', 'librato', 'signalfx' and 'influxdb'" + "AFL_STATSD: enables StatsD metrics collection\n" + "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n" + "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" + "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n" + " Supported formats are: 'dogstatsd', 'librato', 'signalfx'\n" + " and 'influxdb'\n" + "AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n" "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n" //"AFL_PERSISTENT: not supported anymore -> no effect, just a warning\n" //"AFL_DEFER_FORKSRV: not supported anymore -> no effect, just a warning\n" @@ -885,7 +887,7 @@ int main(int argc, char **argv_orig, char **envp) { auto_sync = 1; afl->sync_id = ck_strdup("default"); afl->is_secondary_node = 1; - OKF("no -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id); + OKF("No -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id); } @@ -1006,6 +1008,21 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_testcache_size) { + + afl->q_testcase_max_cache_size = + (u64)atoi(afl->afl_env.afl_testcache_size) * 1024000; + OKF("Enabled testcache with %llu MB", + afl->q_testcase_max_cache_size / 1024000); + + } else { + + ACTF( + "No testcache was configured. it is recommended to use a testcache, it " + "improves performance: set AFL_TESTCACHE_SIZE=(value in MB)"); + + } + if (afl->afl_env.afl_forksrv_init_tmout) { afl->fsrv.init_tmout = atoi(afl->afl_env.afl_forksrv_init_tmout); diff --git a/src/afl-performance.c b/src/afl-performance.c index 6fa95dea..e070a05e 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -71,7 +71,7 @@ inline uint64_t rand_next(afl_state_t *afl) { inline double rand_next_percent(afl_state_t *afl) { - return (double)(((double)rand_next(afl)) / (double) 0xffffffffffffffff); + return (double)(((double)rand_next(afl)) / (double)0xffffffffffffffff); } diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh index f7677ac5..d4d21048 100755 --- a/test/test-custom-mutators.sh +++ b/test/test-custom-mutators.sh @@ -1,4 +1,4 @@ -f#!/bin/sh +#!/bin/sh . ./test-pre.sh -- cgit 1.4.1 From 23872d6f2c0ae77beb832f44d392f86cc8530e1a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 14 Oct 2020 16:38:29 +0200 Subject: add documentation --- README.md | 12 ++++++++++-- docs/env_variables.md | 4 ++++ include/afl-fuzz.h | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/README.md b/README.md index 384ae830..c7793dff 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ behaviours and defaults: * -m none is now default, set memory limits (in MB) with e.g. -m 250 * deterministic fuzzing is now disabled by default (unless using -M) and can be enabled with -D + * a caching of testcases can now be performed and can be enabled by + editing config.h for TESTCASE_CACHE or by specifying the env variable + `AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500. ## Contents @@ -555,7 +558,7 @@ is: All labels are explained in [docs/status_screen.md](docs/status_screen.md). -#### b) Using multiple cores/threads +#### b) Using multiple cores If you want to seriously fuzz then use as many cores/threads as possible to fuzz your target. @@ -563,7 +566,12 @@ fuzz your target. On the same machine - due to the design of how afl++ works - there is a maximum number of CPU cores/threads that are useful, use more and the overall performance degrades instead. This value depends on the target, and the limit is between 32 -and 64 cores/threads per machine. +and 64 cores per machine. + +If you have the RAM, it is highly recommended run the instances with a caching +of the testcases. Depending on the average testcase size (and those found +during fuzzing) and their number, a value between 50-500MB is recommended. +You can set the cache size (in MB) by setting the environment variable `AFL_TESTCACHE_SIZE`. There should be one main fuzzer (`-M main` option) and as many secondary fuzzers (eg `-S variant1`) as you have cores that you use. diff --git a/docs/env_variables.md b/docs/env_variables.md index ebb7521e..49eadcaa 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -282,6 +282,10 @@ checks or alter some of the more exotic semantics of the tool: the target. This must be equal or larger than the size the target was compiled with. + - AFL_TESTCACHE_SIZE allows you to overrider the define in config.h for + TESTCASE_CACHE. Recommended values are 50-250MB - or more if your + fuzzing finds a huge amount of paths for large inputs. + - Setting AFL_DISABLE_TRIM tells afl-fuzz to no trim test cases. This is usually a bad idea! diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 940c5602..514d558b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1164,5 +1164,9 @@ u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q); void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, u32 old_len); +#if TESTCASE_CACHE == 1 +#error define of TESTCASE_CACHE must be zero or larger than 1 +#endif + #endif -- cgit 1.4.1 From 735e8c39561d3d4d8bae01251e025e52e05472e2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 14 Oct 2020 17:32:51 +0200 Subject: check for minimum cache size --- include/afl-fuzz.h | 2 +- src/afl-fuzz.c | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 514d558b..8bac1457 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1165,7 +1165,7 @@ void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, u32 old_len); #if TESTCASE_CACHE == 1 -#error define of TESTCASE_CACHE must be zero or larger than 1 + #error define of TESTCASE_CACHE must be zero or larger than 1 #endif #endif diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a59abb7d..3167b742 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -200,8 +200,8 @@ static void usage(u8 *argv0, int more_help) { "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n" "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n" - " Supported formats are: 'dogstatsd', 'librato', 'signalfx'\n" - " and 'influxdb'\n" + " Supported formats are: 'dogstatsd', 'librato',\n" + " 'signalfx' and 'influxdb'\n" "AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n" "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n" //"AFL_PERSISTENT: not supported anymore -> no effect, just a warning\n" @@ -1012,15 +1012,26 @@ int main(int argc, char **argv_orig, char **envp) { afl->q_testcase_max_cache_size = (u64)atoi(afl->afl_env.afl_testcache_size) * 1024000; - OKF("Enabled testcache with %llu MB", - afl->q_testcase_max_cache_size / 1024000); - } else { + } + + if (!afl->q_testcase_max_cache_size) { ACTF( "No testcache was configured. it is recommended to use a testcache, it " "improves performance: set AFL_TESTCACHE_SIZE=(value in MB)"); + } else if (afl->q_testcase_max_cache_size < 2 * MAX_FILE) { + + FATAL("AFL_TESTCACHE_SIZE must be set to %u or more, or 0 to disable", + (2 * MAX_FILE) % 1024000 ? 1 + ((2 * MAX_FILE) / 1024000) + : (2 * MAX_FILE) / 1024000); + + } else { + + OKF("Enabled testcache with %llu MB", + afl->q_testcase_max_cache_size / 1024000); + } if (afl->afl_env.afl_forksrv_init_tmout) { -- cgit 1.4.1 From 638bf19b651864bdc6ec801f87123d08f92af04e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 14 Oct 2020 17:14:36 +0100 Subject: DragonFlyBSD build fix proposal. --- GNUmakefile.gcc_plugin | 7 ++++++- include/afl-fuzz.h | 1 + src/afl-fuzz-init.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index d139387a..bf3a3288 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -56,7 +56,8 @@ ifeq "$(findstring Foundation,$(shell $(CC) --version))" "" CXX = g++ endif -PLUGIN_FLAGS = -fPIC -fno-rtti -I"$(shell $(CC) -print-file-name=plugin)/include" +PLUGIN_BASE = "$(shell $(CC) -print-file-name=plugin)" +PLUGIN_FLAGS = -fPIC -fno-rtti -I$(PLUGIN_BASE)/include -I$(PLUGIN_BASE) HASH=\# GCCVER = $(shell $(CC) --version 2>/dev/null | awk 'NR == 1 {print $$NF}') @@ -88,6 +89,10 @@ ifeq "$(shell uname -s)" "OpenBSD" PLUGIN_FLAGS += -I/usr/local/include endif +ifeq "$(shell uname -s)" "DragonFly" + PLUGIN_FLAGS += -I/usr/local/include +endif + ifeq "$(shell uname -s)" "SunOS" PLUGIN_FLAGS += -I/usr/include/gmp endif diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 940c5602..972d2a60 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -66,6 +66,7 @@ #include #include +#include #include #include diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 607b652f..13e42e03 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -272,7 +272,7 @@ void bind_to_free_cpu(afl_state_t *afl) { #elif defined(__DragonFly__) - if (procs[i].kp_lwp.kl_cpuid < sizeof(cpu_used) && + if (procs[i].kp_lwp.kl_cpuid < (s32)sizeof(cpu_used) && procs[i].kp_lwp.kl_pctcpu > 10) cpu_used[procs[i].kp_lwp.kl_cpuid] = 1; -- cgit 1.4.1 From f41aafa4f7aa446c3cb1cbe6d77364cf32a6c6cb Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 15 Oct 2020 15:48:39 +0200 Subject: retake from mem if possible --- include/afl-fuzz.h | 4 ++++ src/afl-fuzz-queue.c | 39 ++++++++++++++++++++++++++++++++++----- src/afl-fuzz-run.c | 8 ++++++-- 3 files changed, 44 insertions(+), 7 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index acded98f..6204c81b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1165,6 +1165,10 @@ u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q); void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, u32 old_len); +/* If trimming changes the testcase size we have to replace it */ +void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q, u8 *in, + u32 len, u32 old_len); + #if TESTCASE_CACHE == 1 #error define of TESTCASE_CACHE must be zero or larger than 1 #endif diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 095a391f..92b722f6 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -870,8 +870,10 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { } -void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, - u32 old_len) { +/* after a custom trim we need to reload the testcase from disk */ + +inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, + u32 old_len) { if (likely(q->testcase_buf)) { @@ -879,9 +881,9 @@ void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, if (len != old_len) { - afl->q_testcase_cache_size = - afl->q_testcase_cache_size + q->len - old_len; + afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len; q->testcase_buf = realloc(q->testcase_buf, len); + if (unlikely(!q->testcase_buf)) { PFATAL("Unable to malloc '%s' with len %d", q->fname, len); @@ -901,8 +903,35 @@ void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, } +/* after a normal trim we need to replace the testcase with the new data */ + +inline void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q, + u8 *in, u32 len, u32 old_len) { + + if (likely(q->testcase_buf)) { + + if (len != old_len) { + + afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len; + q->testcase_buf = realloc(q->testcase_buf, len); + + if (unlikely(!q->testcase_buf)) { + + PFATAL("Unable to malloc '%s' with len %d", q->fname, len); + + } + + } + + memcpy(q->testcase_buf, in, len); + + } + +} + /* Returns the testcase buf from the file behind this queue entry. Increases the refcount. */ + inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { u32 len = q->len; @@ -913,7 +942,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { u8 *buf; - if (q == afl->queue_cur) { + if (unlikely(q == afl->queue_cur)) { buf = afl_realloc((void **)&afl->testcase_buf, len); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ab870319..dfd3abfb 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -711,7 +711,11 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { }); - if (orig_len != q->len) { queue_testcase_retake(afl, q, orig_len); } + if (orig_len != q->len || custom_trimmed) { + + queue_testcase_retake(afl, q, orig_len); + + } if (custom_trimmed) return trimmed_case; @@ -846,7 +850,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { close(fd); - if (orig_len != q->len) queue_testcase_retake(afl, q, orig_len); + queue_testcase_retake_mem(afl, q, in_buf, q->len, orig_len); memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); update_bitmap_score(afl, q); -- cgit 1.4.1 From d5c3b4bafdae8a68e7f63c0afdd1cc5820636f2d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 16 Oct 2020 09:35:35 +0200 Subject: directly add new queue to cache --- include/afl-fuzz.h | 4 ++++ src/afl-fuzz-bitmap.c | 6 ++++++ src/afl-fuzz-queue.c | 43 ++++++++++++++++++++++++++++++++++++++++++- src/afl-showmap.c | 2 +- 4 files changed, 53 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 6204c81b..e94f389a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1169,6 +1169,10 @@ void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q, u8 *in, u32 len, u32 old_len); +/* Add a new queue entry directly to the cache */ + +void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, u8 *mem); + #if TESTCASE_CACHE == 1 #error define of TESTCASE_CACHE must be zero or larger than 1 #endif diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index a22223b9..2653b9fd 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -623,6 +623,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { ck_write(fd, mem, len, queue_fn); close(fd); + if (likely(afl->q_testcase_max_cache_size)) { + + queue_testcase_store_mem(afl, afl->queue_top, mem); + + } + keeping = 1; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 92b722f6..f8034ebd 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -1021,7 +1021,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { /* Register testcase as cached */ afl->q_testcase_cache[tid] = q; - afl->q_testcase_cache_size += q->len; + afl->q_testcase_cache_size += len; ++afl->q_testcase_cache_count; if (tid >= afl->q_testcase_max_cache_count) afl->q_testcase_max_cache_count = tid + 1; @@ -1032,3 +1032,44 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { } +/* Adds the new queue entry to the cache. */ + +inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, + u8 *mem) { + + u32 len = q->len; + + if (unlikely(afl->q_testcase_cache_size + len >= + afl->q_testcase_max_cache_size || + afl->q_testcase_cache_count >= TESTCASE_ENTRIES - 1)) { + + return; + + } + + u32 tid = 0; + + while (likely(afl->q_testcase_cache[tid] != NULL)) + ++tid; + + /* Map the test case into memory. */ + + q->testcase_buf = malloc(len); + + if (unlikely(!q->testcase_buf)) { + + PFATAL("Unable to malloc '%s' with len %u", q->fname, len); + + } + + memcpy(q->testcase_buf, mem, len); + + /* Register testcase as cached */ + afl->q_testcase_cache[tid] = q; + afl->q_testcase_cache_size += len; + ++afl->q_testcase_cache_count; + if (tid >= afl->q_testcase_max_cache_count) + afl->q_testcase_max_cache_count = tid + 1; + +} + diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 822e62df..6213c447 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1017,7 +1017,7 @@ int main(int argc, char **argv_orig, char **envp) { alloc_printf("%s/.afl-showmap-temp-%u", use_dir, (u32)getpid()); unlink(stdin_file); atexit(at_exit_handler); - afl->fsrv.out_file = stdin_file; + fsrv->out_file = stdin_file; fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600); if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } -- cgit 1.4.1 From fcea01a8ea7ec507b675d839035eb0fed2f06867 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 17 Oct 2020 11:38:55 +0200 Subject: add eviction stat --- include/afl-fuzz.h | 3 +++ src/afl-fuzz-queue.c | 1 + src/afl-fuzz-stats.c | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e94f389a..880b8d50 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -704,6 +704,9 @@ typedef struct afl_state { /* How many queue entries currently have cached testcases */ u32 q_testcase_cache_count; + /* How often did we evict from the cache */ + u32 q_testcase_evictions; + /* Refs to each queue entry with cached testcase (for eviction, if cache_count * is too large) */ struct queue_entry *q_testcase_cache[TESTCASE_ENTRIES]; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f8034ebd..e0df7206 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -996,6 +996,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { afl->q_testcase_cache_size -= old_cached->len; afl->q_testcase_cache[tid] = NULL; --afl->q_testcase_cache_count; + ++afl->q_testcase_evictions; } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 4f0cab4c..d213d054 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -167,6 +167,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, "havoc_expansion : %u\n" "testcache_size : %llu\n" "testcache_count : %u\n" + "testcache_evict : %u\n" "afl_banner : %s\n" "afl_version : " VERSION "\n" @@ -202,7 +203,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #endif t_bytes, afl->var_byte_count, afl->expand_havoc, afl->q_testcase_cache_size, afl->q_testcase_cache_count, - afl->use_banner, afl->unicorn_mode ? "unicorn" : "", + afl->q_testcase_evictions, afl->use_banner, + afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", afl->non_instrumented_mode ? " non_instrumented " : "", afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", -- cgit 1.4.1 From c866aef37fcf799506d93b9a47d4eb2b77c75f5b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 22 Oct 2020 21:07:37 +0200 Subject: maybe enhancement to cache algo --- include/afl-fuzz.h | 5 ++++- src/afl-fuzz-queue.c | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 880b8d50..220380b9 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -704,7 +704,10 @@ typedef struct afl_state { /* How many queue entries currently have cached testcases */ u32 q_testcase_cache_count; - /* How often did we evict from the cache */ + /* the smallest id currently known free entry */ + u32 q_testcase_smallest_free; + + /* How often did we evict from the cache (for statistics only) */ u32 q_testcase_evictions; /* Refs to each queue entry with cached testcase (for eviction, if cache_count diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 3e6deb0c..db387c33 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -1004,13 +1004,15 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { afl->q_testcase_cache[tid] = NULL; --afl->q_testcase_cache_count; ++afl->q_testcase_evictions; + if (tid < afl->q_testcase_smallest_free) + afl->q_testcase_smallest_free = tid; } - if (tid >= TESTCASE_ENTRIES) { + if (unlikely(tid >= TESTCASE_ENTRIES)) { // uh we were full, so now we have to search from start - tid = 0; + tid = afl->q_testcase_smallest_free; } @@ -1042,6 +1044,8 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { ++afl->q_testcase_cache_count; if (tid >= afl->q_testcase_max_cache_count) afl->q_testcase_max_cache_count = tid + 1; + if (tid == afl->q_testcase_smallest_free) + afl->q_testcase_smallest_free = tid + 1; } -- cgit 1.4.1 From 0e748ccda713708de6a501d23a58788aba9d0b03 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 23 Oct 2020 14:05:34 +0200 Subject: set max testcache entries automated if not specified by the user --- include/afl-fuzz.h | 7 ++++-- include/config.h | 10 ++++---- include/envs.h | 1 + src/afl-fuzz-queue.c | 11 +++++---- src/afl-fuzz-state.c | 10 +++++++- src/afl-fuzz-stats.c | 2 +- src/afl-fuzz.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 91 insertions(+), 18 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 220380b9..11feb9f7 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -366,7 +366,7 @@ typedef struct afl_env_vars { u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, - *afl_statsd_tags_flavor, *afl_testcache_size; + *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries; } afl_env_vars_t; @@ -695,6 +695,9 @@ typedef struct afl_state { /* This is the user specified maximum size to use for the testcase cache */ u64 q_testcase_max_cache_size; + /* This is the user specified maximum entries in the testcase cache */ + u32 q_testcase_max_cache_entries; + /* How much of the testcase cache is used so far */ u64 q_testcase_cache_size; @@ -712,7 +715,7 @@ typedef struct afl_state { /* Refs to each queue entry with cached testcase (for eviction, if cache_count * is too large) */ - struct queue_entry *q_testcase_cache[TESTCASE_ENTRIES]; + struct queue_entry **q_testcase_cache; } afl_state_t; diff --git a/include/config.h b/include/config.h index b4f3a775..491d8132 100644 --- a/include/config.h +++ b/include/config.h @@ -295,14 +295,12 @@ #define RESEED_RNG 100000 -/* The maximum number of testcases to cache */ - -#define TESTCASE_ENTRIES 16384 - /* The default maximum testcase cache size in MB, 0 = disable. - A value between 50 and 250 is a good default value. */ + A value between 50 and 250 is a good default value. Note that the + number of entries will be auto assigned if not specified via the + AFL_TESTCACHE_ENTRIES env variable */ -#define TESTCASE_CACHE 0 +#define TESTCASE_CACHE_SIZE 50 /* Maximum line length passed from GCC to 'as' and used for parsing configuration files: */ diff --git a/include/envs.h b/include/envs.h index a1b3ad12..b753d5f8 100644 --- a/include/envs.h +++ b/include/envs.h @@ -140,6 +140,7 @@ static char *afl_environment_variables[] = { "AFL_STATSD_PORT", "AFL_STATSD_TAGS_FLAVOR", "AFL_TESTCACHE_SIZE", + "AFL_TESTCACHE_ENTRIES", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index db387c33..baa80e61 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -978,9 +978,9 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { /* Buf not cached, let's load it */ u32 tid = afl->q_testcase_max_cache_count; - while (unlikely(afl->q_testcase_cache_size + len >= - afl->q_testcase_max_cache_size || - afl->q_testcase_cache_count >= TESTCASE_ENTRIES - 1)) { + while (unlikely( + afl->q_testcase_cache_size + len >= afl->q_testcase_max_cache_size || + afl->q_testcase_cache_count >= afl->q_testcase_max_cache_entries - 1)) { /* Cache full. We neet to evict one or more to map one. Get a random one which is not in use */ @@ -1009,7 +1009,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) { } - if (unlikely(tid >= TESTCASE_ENTRIES)) { + if (unlikely(tid >= afl->q_testcase_max_cache_entries)) { // uh we were full, so now we have to search from start tid = afl->q_testcase_smallest_free; @@ -1062,7 +1062,8 @@ inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q, if (unlikely(afl->q_testcase_cache_size + len >= afl->q_testcase_max_cache_size || - afl->q_testcase_cache_count >= TESTCASE_ENTRIES - 1)) { + afl->q_testcase_cache_count >= + afl->q_testcase_max_cache_entries - 1)) { // no space? will be loaded regularly later. return; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 0824b77f..ae7d410b 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -103,7 +103,8 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_avg_exec = -1; afl->skip_deterministic = 1; afl->use_splicing = 1; - afl->q_testcase_max_cache_size = TESTCASE_CACHE * 1024000; + afl->q_testcase_max_cache_size = TESTCASE_CACHE_SIZE * 1048576UL; + afl->q_testcase_max_cache_entries = 4096; #ifdef HAVE_AFFINITY afl->cpu_aff = -1; /* Selected CPU core */ @@ -361,6 +362,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_testcache_size = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_TESTCACHE_ENTRIES", + + afl_environment_variable_len)) { + + afl->afl_env.afl_testcache_entries = + (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_STATSD_HOST", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d213d054..bec90519 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1028,7 +1028,7 @@ void show_init_stats(afl_state_t *afl) { } - SAYF("\n"); + // SAYF("\n"); if (avg_us > ((afl->fsrv.qemu_mode || afl->unicorn_mode) ? 50000 : 10000)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 7215ecec..637e1985 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -251,7 +251,7 @@ static int stricmp(char const *a, char const *b) { int main(int argc, char **argv_orig, char **envp) { - s32 opt, i, auto_sync = 0; + s32 opt, i, auto_sync = 0, user_set_cache = 0; u64 prev_queued = 0; u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = MAP_SIZE; u8 *extras_dir[4]; @@ -1015,6 +1015,22 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_testcache_entries) { + + afl->q_testcase_max_cache_entries = + (u32)atoi(afl->afl_env.afl_testcache_entries); + + user_set_cache = 1; + + } + + if (!afl->afl_env.afl_testcache_size || !afl->afl_env.afl_testcache_entries) { + + afl->afl_env.afl_testcache_entries = 0; + afl->afl_env.afl_testcache_size = 0; + + } + if (!afl->q_testcase_max_cache_size) { ACTF( @@ -1347,6 +1363,52 @@ int main(int argc, char **argv_orig, char **envp) { perform_dry_run(afl); + if (!user_set_cache && afl->q_testcase_max_cache_size) { + + /* The user defined not a fixed number of entries for the cache. + Hence we autodetect a good value. After the dry run inputs are + trimmed and we know the average and max size of the input seeds. + We use this information to set a fitting size to max entries + based on the cache size. */ + + struct queue_entry *q = afl->queue; + u64 size = 0, count = 0, avg = 0, max = 0; + + while (q) { + + ++count; + size += q->len; + if (max < q->len) { max = q->len; } + q = q->next; + + } + + if (count) { + + avg = size / count; + avg = ((avg + max) / 2) + 1; + + } + + if (avg < 10240) { avg = 10240; } + + afl->q_testcase_max_cache_entries = afl->q_testcase_max_cache_size / avg; + + if (afl->q_testcase_max_cache_entries > 32768) + afl->q_testcase_max_cache_entries = 32768; + + } + + if (afl->q_testcase_max_cache_entries) { + + OKF("Setting %u maximum entries for the testcase cache", + afl->q_testcase_max_cache_entries); + afl->q_testcase_cache = + ck_alloc(afl->q_testcase_max_cache_entries * sizeof(size_t)); + if (!afl->q_testcase_cache) { PFATAL("malloc failed for cache entries"); } + + } + cull_queue(afl); if (!afl->pending_not_fuzzed) @@ -1366,8 +1428,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->not_on_tty) { - sleep(4); - afl->start_time += 4000; + sleep(1); if (afl->stop_soon) { goto stop_fuzzing; } } @@ -1654,6 +1715,7 @@ stop_fuzzing: ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); ck_free(afl->sync_id); + if (afl->q_testcase_cache) { ck_free(afl->q_testcase_cache); } afl_state_deinit(afl); free(afl); /* not tracked */ -- cgit 1.4.1 From 2e8ec1e33943c5067637361a8c182d13412a307c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 23 Oct 2020 22:49:20 +0200 Subject: allow symbolize=1 for asan/debug --- GNUmakefile | 2 +- include/afl-fuzz.h | 2 +- src/afl-fuzz-init.c | 8 ++++++-- src/afl-fuzz.c | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index 80b7b68b..c576ae67 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -247,7 +247,7 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1 endif ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" - ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer + ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer endif diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 11feb9f7..85b31795 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1057,7 +1057,7 @@ void check_crash_handling(void); void check_cpu_governor(afl_state_t *); void get_core_count(afl_state_t *); void fix_up_sync(afl_state_t *); -void check_asan_opts(void); +void check_asan_opts(afl_state_t *); void check_binary(afl_state_t *, u8 *); void fix_up_banner(afl_state_t *, u8 *); void check_if_tty(afl_state_t *); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 13e42e03..1bccff8f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2338,10 +2338,12 @@ static void handle_resize(int sig) { /* Check ASAN options. */ -void check_asan_opts(void) { +void check_asan_opts(afl_state_t *afl) { u8 *x = get_afl_env("ASAN_OPTIONS"); + (void)(afl); + if (x) { if (!strstr(x, "abort_on_error=1")) { @@ -2350,11 +2352,13 @@ void check_asan_opts(void) { } - if (!strstr(x, "symbolize=0")) { +#ifndef ASAN_BUILD + if (!afl->debug && !strstr(x, "symbolize=0")) { FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); } +#endif } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 70e21c0f..22e6d577 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -878,7 +878,7 @@ int main(int argc, char **argv_orig, char **envp) { #endif setup_signal_handlers(); - check_asan_opts(); + check_asan_opts(afl); afl->power_name = power_names[afl->schedule]; -- cgit 1.4.1 From 0fd98ae8b070b05a72b2c47a76f4ea145f9d51c2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 1 Nov 2020 21:34:08 +0100 Subject: added mutation introspection make target --- GNUmakefile | 6 + README.md | 1 + docs/Changelog.md | 2 + include/afl-fuzz.h | 6 + include/alloc-inl.h | 36 ++ instrumentation/SanitizerCoveragePCGUARD.so.cc | 14 +- src/afl-fuzz-bitmap.c | 11 + src/afl-fuzz-extras.c | 16 +- src/afl-fuzz-one.c | 503 ++++++++++++++++++++++++- src/afl-fuzz.c | 17 + 10 files changed, 592 insertions(+), 20 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index c8d155e4..764c9baa 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -110,6 +110,11 @@ ifdef PROFILING LDFLAGS += -pg endif +ifdef INTROSPECTION + $(info Compiling with introspection documentation) + CFLAGS_OPT += -DINTROSPECTION=1 +endif + ifneq "$(shell uname -m)" "x86_64" ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386" ifneq "$(shell uname -m)" "amd64" @@ -348,6 +353,7 @@ help: @echo ASAN_BUILD - compiles with memory sanitizer for debug purposes @echo DEBUG - no optimization, -ggdb3, all warnings and -Werror @echo PROFILING - compile afl-fuzz with profiling information + @echo INTROSPECTION - compile afl-fuzz with mutation introspection @echo NO_PYTHON - disable python support @echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing @echo AFL_NO_X86 - if compiling on non-intel/amd platforms diff --git a/README.md b/README.md index 7c3b6ecf..d954a236 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,7 @@ These build options exist: * ASAN_BUILD - compiles with memory sanitizer for debug purposes * DEBUG - no optimization, -ggdb3, all warnings and -Werror * PROFILING - compile with profiling information (gprof) +* INTROSPECTION - compile afl-fuzz with mutation introspection * NO_PYTHON - disable python support * NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing * AFL_NO_X86 - if compiling on non-intel/amd platforms diff --git a/docs/Changelog.md b/docs/Changelog.md index 798a056f..f11a1178 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,8 @@ sending a mail to . skipped. They are used for splicing though. - set the default power schedule to the superiour "seek" schedule - added NO_SPLICING compile option and makefile define + - added INTROSPECTION make target that writes all mutations to + out/NAME/introspection.txt - print special compile time options used in help output - instrumentation - We received an enhanced gcc_plugin module from AdaCore, thank you diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 85b31795..5ff7672b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -717,6 +717,12 @@ typedef struct afl_state { * is too large) */ struct queue_entry **q_testcase_cache; +#ifdef INTROSPECTION + char mutation[8072]; + char m_tmp[4096]; + FILE *introspection_file; +#endif + } afl_state_t; struct custom_mutator { diff --git a/include/alloc-inl.h b/include/alloc-inl.h index 36e47810..d7aa51a7 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -708,6 +708,42 @@ static inline void *afl_realloc(void **buf, size_t size_needed) { } +/* afl_realloc_exact uses afl alloc buffers but sets it to a specific size */ + +static inline void *afl_realloc_exact(void **buf, size_t size_needed) { + + struct afl_alloc_buf *new_buf = NULL; + + size_t current_size = 0; + + if (likely(*buf)) { + + /* the size is always stored at buf - 1*size_t */ + new_buf = (struct afl_alloc_buf *)afl_alloc_bufptr(*buf); + current_size = new_buf->complete_size; + + } + + size_needed += AFL_ALLOC_SIZE_OFFSET; + + /* No need to realloc */ + if (unlikely(current_size == size_needed)) { return *buf; } + + /* alloc */ + new_buf = (struct afl_alloc_buf *)realloc(new_buf, size_needed); + if (unlikely(!new_buf)) { + + *buf = NULL; + return NULL; + + } + + new_buf->complete_size = size_needed; + *buf = (void *)(new_buf->buf); + return *buf; + +} + static inline void afl_free(void *buf) { if (buf) { free(afl_alloc_bufptr(buf)); } diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 97e8d32b..2f87e4f9 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -247,13 +247,13 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { Options.CoverageType = SanitizerCoverageOptions::SCK_Edge; // std::max(Options.CoverageType, // CLOpts.CoverageType); - Options.IndirectCalls = true; // CLOpts.IndirectCalls; - Options.TraceCmp = false; //|= ClCMPTracing; - Options.TraceDiv = false; //|= ClDIVTracing; - Options.TraceGep = false; //|= ClGEPTracing; - Options.TracePC = false; //|= ClTracePC; - Options.TracePCGuard = true; // |= ClTracePCGuard; - Options.Inline8bitCounters = 0; //|= ClInline8bitCounters; + Options.IndirectCalls = true; // CLOpts.IndirectCalls; + Options.TraceCmp = false; //|= ClCMPTracing; + Options.TraceDiv = false; //|= ClDIVTracing; + Options.TraceGep = false; //|= ClGEPTracing; + Options.TracePC = false; //|= ClTracePC; + Options.TracePCGuard = true; // |= ClTracePCGuard; + Options.Inline8bitCounters = 0; //|= ClInline8bitCounters; // Options.InlineBoolFlag = 0; //|= ClInlineBoolFlag; Options.PCTable = false; //|= ClCreatePCTable; Options.NoPrune = false; //|= !ClPruneBlocks; diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 2653b9fd..735420c3 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -587,6 +587,11 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { add_to_queue(afl, queue_fn, len, 0); +#ifdef INTROSPECTION + fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation, + afl->queue_top->fname); +#endif + if (hnb == 2) { afl->queue_top->has_new_cov = 1; @@ -659,6 +664,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { } ++afl->unique_tmouts; +#ifdef INTROSPECTION + fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation); +#endif /* Before saving, we make sure that it's a genuine hang by re-running the target with a more generous timeout (unless the default timeout @@ -742,6 +750,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #endif /* ^!SIMPLE_FILES */ ++afl->unique_crashes; +#ifdef INTROSPECTION + fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation); +#endif if (unlikely(afl->infoexec)) { // if the user wants to be informed on new crashes - do that diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index adec986e..171cce96 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -423,8 +423,8 @@ void dedup_extras(afl_state_t *afl) { } if (afl->extras_cnt != orig_cnt) - afl->extras = ck_realloc((void **)&afl->extras, - afl->extras_cnt * sizeof(struct extra_data)); + afl->extras = afl_realloc_exact( + (void **)&afl->extras, afl->extras_cnt * sizeof(struct extra_data)); } @@ -462,16 +462,8 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { } - if (afl->extras) { - - afl->extras = ck_realloc((void **)&afl->extras, - (afl->extras_cnt + 1) * sizeof(struct extra_data)); - - } else { - - afl->extras = ck_alloc((afl->extras_cnt + 1) * sizeof(struct extra_data)); - - } + afl->extras = afl_realloc((void **)&afl->extras, + (afl->extras_cnt + 1) * sizeof(struct extra_data)); if (unlikely(!afl->extras)) { PFATAL("alloc"); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 0f3393d2..5337b7f8 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -609,6 +609,11 @@ u8 fuzz_one_original(afl_state_t *afl) { FLIP_BIT(out_buf, afl->stage_cur); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT1 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } FLIP_BIT(out_buf, afl->stage_cur); @@ -718,6 +723,11 @@ u8 fuzz_one_original(afl_state_t *afl) { FLIP_BIT(out_buf, afl->stage_cur); FLIP_BIT(out_buf, afl->stage_cur + 1); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT2 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } FLIP_BIT(out_buf, afl->stage_cur); @@ -747,6 +757,11 @@ u8 fuzz_one_original(afl_state_t *afl) { FLIP_BIT(out_buf, afl->stage_cur + 2); FLIP_BIT(out_buf, afl->stage_cur + 3); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT4 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } FLIP_BIT(out_buf, afl->stage_cur); @@ -802,6 +817,11 @@ u8 fuzz_one_original(afl_state_t *afl) { out_buf[afl->stage_cur] ^= 0xFF; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT8 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } /* We also use this stage to pull off a simple trick: we identify @@ -889,6 +909,11 @@ u8 fuzz_one_original(afl_state_t *afl) { *(u16 *)(out_buf + i) ^= 0xFFFF; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT16 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -927,6 +952,11 @@ u8 fuzz_one_original(afl_state_t *afl) { *(u32 *)(out_buf + i) ^= 0xFFFFFFFF; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT32 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -985,6 +1015,11 @@ skip_bitflip: afl->stage_cur_val = j; out_buf[i] = orig + j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH8+ %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1001,6 +1036,11 @@ skip_bitflip: afl->stage_cur_val = -j; out_buf[i] = orig - j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH8- %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1065,6 +1105,11 @@ skip_bitflip: afl->stage_cur_val = j; *(u16 *)(out_buf + i) = orig + j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16+ %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1079,6 +1124,11 @@ skip_bitflip: afl->stage_cur_val = -j; *(u16 *)(out_buf + i) = orig - j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16- %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1097,6 +1147,11 @@ skip_bitflip: afl->stage_cur_val = j; *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) + j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16+BE %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1111,6 +1166,11 @@ skip_bitflip: afl->stage_cur_val = -j; *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) - j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16-BE %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1174,6 +1234,11 @@ skip_bitflip: afl->stage_cur_val = j; *(u32 *)(out_buf + i) = orig + j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+ %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1188,6 +1253,11 @@ skip_bitflip: afl->stage_cur_val = -j; *(u32 *)(out_buf + i) = orig - j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32- %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1206,6 +1276,11 @@ skip_bitflip: afl->stage_cur_val = j; *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) + j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+BE %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1220,6 +1295,11 @@ skip_bitflip: afl->stage_cur_val = -j; *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) - j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32-BE %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1287,6 +1367,11 @@ skip_arith: afl->stage_cur_val = interesting_8[j]; out_buf[i] = interesting_8[j]; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING8 %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } out_buf[i] = orig; @@ -1342,6 +1427,11 @@ skip_arith: *(u16 *)(out_buf + i) = interesting_16[j]; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING16 %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1358,6 +1448,11 @@ skip_arith: afl->stage_val_type = STAGE_VAL_BE; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s INTERESTING16BE %u %u", afl->queue_cur->fname, i, j); +#endif + *(u16 *)(out_buf + i) = SWAP16(interesting_16[j]); if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1421,6 +1516,11 @@ skip_arith: *(u32 *)(out_buf + i) = interesting_32[j]; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING32 %u %u", + afl->queue_cur->fname, i, j); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1437,6 +1537,11 @@ skip_arith: afl->stage_val_type = STAGE_VAL_BE; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s INTERESTING32BE %u %u", afl->queue_cur->fname, i, j); +#endif + *(u32 *)(out_buf + i) = SWAP32(interesting_32[j]); if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1510,6 +1615,12 @@ skip_interest: last_len = afl->extras[j].len; memcpy(out_buf + i, afl->extras[j].data, last_len); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s EXTRAS overwrite %u %u:%s", afl->queue_cur->fname, i, j, + afl->extras[j].data); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1557,6 +1668,12 @@ skip_interest: /* Copy tail */ memcpy(ex_tmp + i + afl->extras[j].len, out_buf + i, len - i); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s EXTRAS insert %u %u:%s", afl->queue_cur->fname, i, j, + afl->extras[j].data); +#endif + if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) { goto abandon_entry; @@ -1614,6 +1731,12 @@ skip_user_extras: last_len = afl->a_extras[j].len; memcpy(out_buf + i, afl->a_extras[j].data, last_len); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s AUTO_EXTRAS overwrite %u %u:%s", afl->queue_cur->fname, i, j, + afl->a_extras[j].data); +#endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1675,7 +1798,7 @@ custom_mutator_stage: for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - struct queue_entry *target; + struct queue_entry *target = NULL; u32 tid; u8 * new_buf = NULL; u32 target_len = 0; @@ -1717,6 +1840,12 @@ custom_mutator_stage: if (mutated_size > 0) { +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s CUSTOM %s", + afl->queue_cur->fname, + target != NULL ? (char *)target->fname : "none"); +#endif + if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { goto abandon_entry; @@ -1866,6 +1995,11 @@ havoc_stage: afl->stage_cur_val = use_stacking; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s HAVOC %u", + afl->queue_cur->fname, use_stacking); +#endif + for (i = 0; i < use_stacking; ++i) { if (afl->custom_mutators_count) { @@ -1909,6 +2043,10 @@ havoc_stage: /* Flip a single bit somewhere. Spooky! */ +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1"); + strcat(afl->mutation, afl->m_tmp); +#endif FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); break; @@ -1916,6 +2054,10 @@ havoc_stage: /* Set byte to interesting value. */ +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8"); + strcat(afl->mutation, afl->m_tmp); +#endif out_buf[rand_below(afl, temp_len)] = interesting_8[rand_below(afl, sizeof(interesting_8))]; break; @@ -1928,11 +2070,19 @@ havoc_stage: if (rand_below(afl, 2)) { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; } else { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); @@ -1948,11 +2098,19 @@ havoc_stage: if (rand_below(afl, 2)) { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; } else { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32( interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]); @@ -1964,6 +2122,10 @@ havoc_stage: /* Randomly subtract from byte. */ +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8-"); + strcat(afl->mutation, afl->m_tmp); +#endif out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX); break; @@ -1971,6 +2133,10 @@ havoc_stage: /* Randomly add to byte. */ +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8+"); + strcat(afl->mutation, afl->m_tmp); +#endif out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); break; @@ -1984,6 +2150,10 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16-_%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { @@ -1991,6 +2161,11 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 1); u16 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16-BE_%u_%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); @@ -2008,6 +2183,10 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+_%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { @@ -2015,6 +2194,11 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 1); u16 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE_%u_%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); @@ -2032,6 +2216,10 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 3); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32-_%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { @@ -2039,6 +2227,11 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 3); u32 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32-BE_%u_%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); @@ -2056,6 +2249,10 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 3); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+_%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { @@ -2063,6 +2260,11 @@ havoc_stage: u32 pos = rand_below(afl, temp_len - 3); u32 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE_%u_%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); @@ -2076,6 +2278,10 @@ havoc_stage: why not. We use XOR with 1-255 to eliminate the possibility of a no-op. */ +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8"); + strcat(afl->mutation, afl->m_tmp); +#endif out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); break; @@ -2095,6 +2301,11 @@ havoc_stage: del_from = rand_below(afl, temp_len - del_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL_%u_%u", del_from, + del_len); + strcat(afl->mutation, afl->m_tmp); +#endif memmove(out_buf + del_from, out_buf + del_from + del_len, temp_len - del_from - del_len); @@ -2128,6 +2339,12 @@ havoc_stage: clone_to = rand_below(afl, temp_len); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE_%s_%u_%u_%u", + actually_clone ? "clone" : "insert", clone_from, clone_to, + clone_len); + strcat(afl->mutation, afl->m_tmp); +#endif new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); if (unlikely(!new_buf)) { PFATAL("alloc"); } @@ -2181,12 +2398,23 @@ havoc_stage: if (copy_from != copy_to) { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " OVERWRITE_COPY_%u_%u_%u", copy_from, copy_to, + copy_len); + strcat(afl->mutation, afl->m_tmp); +#endif memmove(out_buf + copy_to, out_buf + copy_from, copy_len); } } else { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " OVERWRITE_FIXED_%u_%u_%u", copy_from, copy_to, copy_len); + strcat(afl->mutation, afl->m_tmp); +#endif memset(out_buf + copy_to, rand_below(afl, 2) ? rand_below(afl, 256) : out_buf[rand_below(afl, temp_len)], @@ -2222,6 +2450,12 @@ havoc_stage: if ((s32)extra_len > temp_len) { break; } insert_at = rand_below(afl, temp_len - extra_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_OVERWRITE_%u_%u_%s", insert_at, extra_len, + afl->a_extras[use_extra].data); + strcat(afl->mutation, afl->m_tmp); +#endif memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, extra_len); @@ -2236,6 +2470,12 @@ havoc_stage: if ((s32)extra_len > temp_len) { break; } insert_at = rand_below(afl, temp_len - extra_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " EXTRA_OVERWRITE_%u_%u_%s", insert_at, extra_len, + afl->a_extras[use_extra].data); + strcat(afl->mutation, afl->m_tmp); +#endif memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); @@ -2258,12 +2498,23 @@ havoc_stage: use_extra = rand_below(afl, afl->a_extras_cnt); extra_len = afl->a_extras[use_extra].len; ptr = afl->a_extras[use_extra].data; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_INSERT_%u_%u_%s", insert_at, extra_len, + ptr); + strcat(afl->mutation, afl->m_tmp); +#endif } else { use_extra = rand_below(afl, afl->extras_cnt); extra_len = afl->extras[use_extra].len; ptr = afl->extras[use_extra].data; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " EXTRA_INSERT_%u_%u_%s", insert_at, extra_len, ptr); + strcat(afl->mutation, afl->m_tmp); +#endif } @@ -2324,6 +2575,12 @@ havoc_stage: copy_from = rand_below(afl, new_len - copy_len + 1); copy_to = rand_below(afl, temp_len - copy_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_OVERWRITE_%u_%u_%u_%s", copy_from, copy_to, + copy_len, target->fname); + strcat(afl->mutation, afl->m_tmp); +#endif memmove(out_buf + copy_to, new_buf + copy_from, copy_len); } else { @@ -2340,6 +2597,12 @@ havoc_stage: temp_len + clone_len + 1); if (unlikely(!temp_buf)) { PFATAL("alloc"); } +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_INSERT_%u_%u_%u_%s", clone_from, clone_to, + clone_len, target->fname); + strcat(afl->mutation, afl->m_tmp); +#endif /* Head */ memcpy(temp_buf, out_buf, clone_to); @@ -2755,6 +3018,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { FLIP_BIT(out_buf, afl->stage_cur); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT1 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } FLIP_BIT(out_buf, afl->stage_cur); @@ -2864,6 +3131,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { FLIP_BIT(out_buf, afl->stage_cur); FLIP_BIT(out_buf, afl->stage_cur + 1); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT2 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } FLIP_BIT(out_buf, afl->stage_cur); @@ -2893,6 +3164,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { FLIP_BIT(out_buf, afl->stage_cur + 2); FLIP_BIT(out_buf, afl->stage_cur + 3); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT4 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } FLIP_BIT(out_buf, afl->stage_cur); @@ -2948,6 +3223,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { out_buf[afl->stage_cur] ^= 0xFF; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT8 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } /* We also use this stage to pull off a simple trick: we identify @@ -3035,6 +3314,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { *(u16 *)(out_buf + i) ^= 0xFFFF; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT16 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3073,6 +3356,10 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { *(u32 *)(out_buf + i) ^= 0xFFFFFFFF; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_FLIP_BIT32 %u", + afl->queue_cur->fname, afl->stage_cur); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3131,6 +3418,10 @@ skip_bitflip: afl->stage_cur_val = j; out_buf[i] = orig + j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH8+ %u %u", + afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3147,6 +3438,10 @@ skip_bitflip: afl->stage_cur_val = -j; out_buf[i] = orig - j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH8- %u %u", + afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3211,6 +3506,10 @@ skip_bitflip: afl->stage_cur_val = j; *(u16 *)(out_buf + i) = orig + j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH16+ %u %u", + afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3225,6 +3524,10 @@ skip_bitflip: afl->stage_cur_val = -j; *(u16 *)(out_buf + i) = orig - j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH16- %u %u", + afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3243,6 +3546,10 @@ skip_bitflip: afl->stage_cur_val = j; *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) + j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_ARITH16+BE %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3257,6 +3564,10 @@ skip_bitflip: afl->stage_cur_val = -j; *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) - j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_ARITH16-BE %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3320,6 +3631,10 @@ skip_bitflip: afl->stage_cur_val = j; *(u32 *)(out_buf + i) = orig + j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH32+ %u %u", + afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3334,6 +3649,10 @@ skip_bitflip: afl->stage_cur_val = -j; *(u32 *)(out_buf + i) = orig - j; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_ARITH32- %u %u", + afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3352,6 +3671,10 @@ skip_bitflip: afl->stage_cur_val = j; *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) + j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_ARITH32+BE %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3366,6 +3689,10 @@ skip_bitflip: afl->stage_cur_val = -j; *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) - j); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_ARITH32-BE %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3433,6 +3760,10 @@ skip_arith: afl->stage_cur_val = interesting_8[j]; out_buf[i] = interesting_8[j]; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_INTERESTING8 %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } out_buf[i] = orig; @@ -3488,6 +3819,10 @@ skip_arith: *(u16 *)(out_buf + i) = interesting_16[j]; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_INTERESTING16 %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3504,6 +3839,10 @@ skip_arith: afl->stage_val_type = STAGE_VAL_BE; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_INTERESTING16BE %u %u", afl->queue_cur->fname, i, j); +#endif *(u16 *)(out_buf + i) = SWAP16(interesting_16[j]); if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3567,6 +3906,10 @@ skip_arith: *(u32 *)(out_buf + i) = interesting_32[j]; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_INTERESTING32 %u %u", afl->queue_cur->fname, i, j); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3583,6 +3926,10 @@ skip_arith: afl->stage_val_type = STAGE_VAL_BE; +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_INTERESTING32BE %u %u", afl->queue_cur->fname, i, j); +#endif *(u32 *)(out_buf + i) = SWAP32(interesting_32[j]); if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3656,6 +4003,11 @@ skip_interest: last_len = afl->extras[j].len; memcpy(out_buf + i, afl->extras[j].data, last_len); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_EXTRAS overwrite %u %u:%s", afl->queue_cur->fname, i, j, + afl->extras[j].data); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3703,6 +4055,11 @@ skip_interest: /* Copy tail */ memcpy(ex_tmp + i + afl->extras[j].len, out_buf + i, len - i); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_EXTRAS insert %u %u:%s", afl->queue_cur->fname, i, j, + afl->extras[j].data); +#endif if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) { goto abandon_entry; @@ -3759,6 +4116,11 @@ skip_user_extras: last_len = afl->a_extras[j].len; memcpy(out_buf + i, afl->a_extras[j].data, last_len); +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_AUTO_EXTRAS overwrite %u %u:%s", afl->queue_cur->fname, + i, j, afl->a_extras[j].data); +#endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -3885,6 +4247,11 @@ pacemaker_fuzzing: } +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), "%s MOPT_HAVOC %u", + afl->queue_cur->fname, use_stacking); +#endif + for (i = 0; i < use_stacking; ++i) { switch (select_algorithm(afl)) { @@ -3893,6 +4260,10 @@ pacemaker_fuzzing: /* Flip a single bit somewhere. Spooky! */ FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); MOpt_globals.cycles_v2[STAGE_FLIP1] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 1: @@ -3901,6 +4272,10 @@ pacemaker_fuzzing: FLIP_BIT(out_buf, temp_len_puppet); FLIP_BIT(out_buf, temp_len_puppet + 1); MOpt_globals.cycles_v2[STAGE_FLIP2] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT2"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 2: @@ -3911,24 +4286,40 @@ pacemaker_fuzzing: FLIP_BIT(out_buf, temp_len_puppet + 2); FLIP_BIT(out_buf, temp_len_puppet + 3); MOpt_globals.cycles_v2[STAGE_FLIP4] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT4"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 3: if (temp_len < 4) { break; } out_buf[rand_below(afl, temp_len)] ^= 0xFF; MOpt_globals.cycles_v2[STAGE_FLIP8] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT8"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 4: if (temp_len < 8) { break; } *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) ^= 0xFFFF; MOpt_globals.cycles_v2[STAGE_FLIP16] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT16"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 5: if (temp_len < 8) { break; } *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) ^= 0xFFFFFFFF; MOpt_globals.cycles_v2[STAGE_FLIP32] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT32"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 6: @@ -3937,6 +4328,10 @@ pacemaker_fuzzing: out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); MOpt_globals.cycles_v2[STAGE_ARITH8] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH+-"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 7: @@ -3946,11 +4341,20 @@ pacemaker_fuzzing: u32 pos = rand_below(afl, temp_len - 1); *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16-%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif } else { u32 pos = rand_below(afl, temp_len - 1); u16 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16BE-%u-%u", + pos, num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); @@ -3960,12 +4364,21 @@ pacemaker_fuzzing: if (rand_below(afl, 2)) { u32 pos = rand_below(afl, temp_len - 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { u32 pos = rand_below(afl, temp_len - 1); u16 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16BE+%u-%u", + pos, num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); @@ -3980,12 +4393,21 @@ pacemaker_fuzzing: if (rand_below(afl, 2)) { u32 pos = rand_below(afl, temp_len - 3); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32-%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { u32 pos = rand_below(afl, temp_len - 3); u32 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32BE-%u-%u", + pos, num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); @@ -3996,12 +4418,21 @@ pacemaker_fuzzing: if (rand_below(afl, 2)) { u32 pos = rand_below(afl, temp_len - 3); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+%u", pos); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { u32 pos = rand_below(afl, temp_len - 3); u32 num = 1 + rand_below(afl, ARITH_MAX); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32BE+%u-%u", + pos, num); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); @@ -4016,6 +4447,10 @@ pacemaker_fuzzing: out_buf[rand_below(afl, temp_len)] = interesting_8[rand_below(afl, sizeof(interesting_8))]; MOpt_globals.cycles_v2[STAGE_INTEREST8] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 10: @@ -4023,12 +4458,20 @@ pacemaker_fuzzing: if (temp_len < 8) { break; } if (rand_below(afl, 2)) { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; } else { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16(interesting_16[rand_below( afl, sizeof(interesting_16) >> 1)]); @@ -4045,12 +4488,20 @@ pacemaker_fuzzing: if (rand_below(afl, 2)) { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; } else { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE"); + strcat(afl->mutation, afl->m_tmp); +#endif *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32(interesting_32[rand_below( afl, sizeof(interesting_32) >> 2)]); @@ -4068,6 +4519,10 @@ pacemaker_fuzzing: out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); MOpt_globals.cycles_v2[STAGE_RANDOMBYTE] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8"); + strcat(afl->mutation, afl->m_tmp); +#endif break; case 13: { @@ -4091,6 +4546,11 @@ pacemaker_fuzzing: temp_len -= del_len; MOpt_globals.cycles_v2[STAGE_DELETEBYTE] += 1; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u%u", del_from, + del_len); + strcat(afl->mutation, afl->m_tmp); +#endif break; } @@ -4120,6 +4580,12 @@ pacemaker_fuzzing: clone_to = rand_below(afl, temp_len); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE_%s_%u_%u_%u", + actually_clone ? "clone" : "insert", clone_from, + clone_to, clone_len); + strcat(afl->mutation, afl->m_tmp); +#endif new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); if (unlikely(!new_buf)) { PFATAL("alloc"); } @@ -4175,12 +4641,24 @@ pacemaker_fuzzing: if (copy_from != copy_to) { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " OVERWRITE_COPY_%u_%u_%u", copy_from, copy_to, + copy_len); + strcat(afl->mutation, afl->m_tmp); +#endif memmove(out_buf + copy_to, out_buf + copy_from, copy_len); } } else { +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " OVERWRITE_FIXED_%u_%u_%u", copy_from, copy_to, + copy_len); + strcat(afl->mutation, afl->m_tmp); +#endif memset(out_buf + copy_to, rand_below(afl, 2) ? rand_below(afl, 256) : out_buf[rand_below(afl, temp_len)], @@ -4212,6 +4690,12 @@ pacemaker_fuzzing: if (extra_len > (u32)temp_len) break; u32 insert_at = rand_below(afl, temp_len - extra_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_OVERWRITE_%u_%u_%s", insert_at, extra_len, + afl->a_extras[use_extra].data); + strcat(afl->mutation, afl->m_tmp); +#endif memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, extra_len); @@ -4225,6 +4709,12 @@ pacemaker_fuzzing: if (extra_len > (u32)temp_len) break; u32 insert_at = rand_below(afl, temp_len - extra_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " EXTRA_OVERWRITE_%u_%u_%s", insert_at, extra_len, + afl->a_extras[use_extra].data); + strcat(afl->mutation, afl->m_tmp); +#endif memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); @@ -4254,12 +4744,23 @@ pacemaker_fuzzing: use_extra = rand_below(afl, afl->a_extras_cnt); extra_len = afl->a_extras[use_extra].len; ptr = afl->a_extras[use_extra].data; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_INSERT_%u_%u_%s", insert_at, extra_len, + ptr); + strcat(afl->mutation, afl->m_tmp); +#endif } else { use_extra = rand_below(afl, afl->extras_cnt); extra_len = afl->extras[use_extra].len; ptr = afl->extras[use_extra].data; +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " EXTRA_INSERT_%u_%u_%s", insert_at, extra_len, ptr); + strcat(afl->mutation, afl->m_tmp); +#endif } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index cad26841..575e6b74 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -236,6 +236,10 @@ static void usage(u8 *argv0, int more_help) { SAYF("Compiled with PROFILING\n\n"); #endif +#ifdef INTROSPECTION + SAYF("Compiled with INTROSPECTION\n\n"); +#endif + #ifdef _DEBUG SAYF("Compiled with _DEBUG\n\n"); #endif @@ -1462,6 +1466,19 @@ int main(int argc, char **argv_orig, char **envp) { u32 prev_queued_paths = 0; u8 skipped_fuzz; + #ifdef INTROSPECTION + char ifn[4096]; + snprintf(ifn, sizeof(ifn), "%s/introspection.txt", afl->out_dir); + if ((afl->introspection_file = fopen(ifn, "w")) == NULL) { + + PFATAL("could not create '%s'", ifn); + + } + + setvbuf(afl->introspection_file, NULL, _IONBF, 0); + OKF("Writing mutation introspection to '%s'", ifn); + #endif + while (likely(!afl->stop_soon)) { cull_queue(afl); -- cgit 1.4.1 From 416e01d3c6277988ed39e67f9404bd7a6034820b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 2 Nov 2020 11:04:35 +0100 Subject: match mopt to havoc --- docs/Changelog.md | 6 +- include/afl-fuzz.h | 3 +- src/afl-fuzz-one.c | 209 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 164 insertions(+), 54 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index f11a1178..50c1d48a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -21,11 +21,11 @@ sending a mail to . a schedule performance score, which is much better that the previous walk the whole queue approach. Select the old mode with -Z (auto enabled with -M) - - statsd support by Edznux, thanks a lot! + - rpc.statsd support by Edznux, thanks a lot! - Marcel Boehme submitted a patch that improves all AFFast schedules :) - not specifying -M or -S will now auto-set "-S default" - reading testcases from -i now descends into subdirectories - - allow up to 4 -x command line options + - allow up to 4 times the -x command line option - loaded extras now have a duplicate protection - If test cases are too large we do a partial read on the maximum supported size @@ -33,7 +33,7 @@ sending a mail to . for fuzzing but still be used for splicing - crashing seeds are now not prohibiting a run anymore but are skipped. They are used for splicing though. - - set the default power schedule to the superiour "seek" schedule + - update MOpt for expanded havoc modes - added NO_SPLICING compile option and makefile define - added INTROSPECTION make target that writes all mutations to out/NAME/introspection.txt diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5ff7672b..e59d5f90 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -231,7 +231,7 @@ enum { }; -#define operator_num 18 +#define operator_num 19 #define swarm_num 5 #define period_core 500000 @@ -247,6 +247,7 @@ enum { #define STAGE_OverWrite75 15 #define STAGE_OverWriteExtra 16 #define STAGE_InsertExtra 17 +#define STAGE_Splice 18 #define period_pilot 50000 enum { diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 5337b7f8..e4016773 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -29,11 +29,9 @@ /* MOpt */ -static int select_algorithm(afl_state_t *afl) { +static int select_algorithm(afl_state_t *afl, u32 max_algorithm) { - int i_puppet, j_puppet = 0, operator_number = operator_num; - - if (!afl->extras_cnt && !afl->a_extras_cnt) operator_number -= 2; + int i_puppet, j_puppet = 0, operator_number = max_algorithm; double range_sele = (double)afl->probability_now[afl->swarm_now][operator_number - 1]; @@ -502,6 +500,8 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done && !afl->disable_trim)) { + u32 old_len = afl->queue_cur->len; + u8 res = trim_case(afl, afl->queue_cur, in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); @@ -524,6 +524,9 @@ u8 fuzz_one_original(afl_state_t *afl) { len = afl->queue_cur->len; + /* maybe current entry is not ready for splicing anymore */ + if (unlikely(len <= 4 && old_len > 4)) afl->ready_for_splicing_count--; + } memcpy(out_buf, in_buf, len); @@ -537,7 +540,7 @@ u8 fuzz_one_original(afl_state_t *afl) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score == 0)) { goto abandon_entry; } + if (unlikely(perf_score <= 0)) { goto abandon_entry; } if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { @@ -1976,7 +1979,7 @@ havoc_stage: /* add expensive havoc cases here, they are activated after a full cycle without finds happened */ - r_max += 1; + r_max++; } @@ -1985,7 +1988,7 @@ havoc_stage: /* add expensive havoc cases here if there is no findings in the last 5s */ - r_max += 1; + r_max++; } @@ -2396,7 +2399,7 @@ havoc_stage: if (likely(rand_below(afl, 4))) { - if (copy_from != copy_to) { + if (likely(copy_from != copy_to)) { #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), @@ -2445,11 +2448,10 @@ havoc_stage: u32 use_extra = rand_below(afl, afl->a_extras_cnt); u32 extra_len = afl->a_extras[use_extra].len; - u32 insert_at; if ((s32)extra_len > temp_len) { break; } - insert_at = rand_below(afl, temp_len - extra_len + 1); + u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " AUTO_EXTRA_OVERWRITE_%u_%u_%s", insert_at, extra_len, @@ -2465,11 +2467,10 @@ havoc_stage: u32 use_extra = rand_below(afl, afl->extras_cnt); u32 extra_len = afl->extras[use_extra].len; - u32 insert_at; if ((s32)extra_len > temp_len) { break; } - insert_at = rand_below(afl, temp_len - extra_len + 1); + u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_OVERWRITE_%u_%u_%s", insert_at, extra_len, @@ -2816,7 +2817,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { possibly skip to them at the expense of already-fuzzed or non-favored cases. */ - if ((afl->queue_cur->was_fuzzed || !afl->queue_cur->favored) && + if (((afl->queue_cur->was_fuzzed > 0 || afl->queue_cur->fuzz_level > 0) || + !afl->queue_cur->favored) && rand_below(afl, 100) < SKIP_TO_NEW_PROB) { return 1; @@ -2831,13 +2833,14 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { The odds of skipping stuff are higher for already-fuzzed inputs and lower for never-fuzzed entries. */ - if (afl->queue_cycle > 1 && !afl->queue_cur->was_fuzzed) { + if (afl->queue_cycle > 1 && + (afl->queue_cur->fuzz_level == 0 || afl->queue_cur->was_fuzzed)) { - if (rand_below(afl, 100) < SKIP_NFAV_NEW_PROB) { return 1; } + if (likely(rand_below(afl, 100) < SKIP_NFAV_NEW_PROB)) { return 1; } } else { - if (rand_below(afl, 100) < SKIP_NFAV_OLD_PROB) { return 1; } + if (likely(rand_below(afl, 100) < SKIP_NFAV_OLD_PROB)) { return 1; } } @@ -2856,16 +2859,19 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { /* Map the test case into memory. */ orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); len = afl->queue_cur->len; + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } + afl->subseq_tmouts = 0; + afl->cur_depth = afl->queue_cur->depth; /******************************************* * CALIBRATION (only if failed earlier on) * *******************************************/ - if (afl->queue_cur->cal_failed) { + if (unlikely(afl->queue_cur->cal_failed)) { u8 res = FSRV_RUN_TMOUT; @@ -2897,7 +2903,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { * TRIMMING * ************/ - if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done) { + if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done && + !afl->disable_trim)) { u32 old_len = afl->queue_cur->len; @@ -2939,6 +2946,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); + if (unlikely(perf_score <= 0)) { goto abandon_entry; } + if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { if (input_to_state_stage(afl, in_buf, out_buf, len, @@ -2968,8 +2977,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { this entry ourselves (was_fuzzed), or if it has gone through deterministic testing in earlier, resumed runs (passed_det). */ - if (afl->skip_deterministic || afl->queue_cur->was_fuzzed || - afl->queue_cur->passed_det) { + if (likely(afl->skip_deterministic || afl->queue_cur->was_fuzzed || + afl->queue_cur->passed_det)) { goto havoc_stage; @@ -2978,8 +2987,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { /* Skip deterministic fuzzing if exec path checksum puts this out of scope for this main instance. */ - if (afl->main_node_max && (afl->queue_cur->exec_cksum % afl->main_node_max) != - afl->main_node_id - 1) { + if (unlikely(afl->main_node_max && + (afl->queue_cur->exec_cksum % afl->main_node_max) != + afl->main_node_id - 1)) { goto havoc_stage; @@ -4008,6 +4018,7 @@ skip_interest: "%s MOPT_EXTRAS overwrite %u %u:%s", afl->queue_cur->fname, i, j, afl->extras[j].data); #endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -4060,6 +4071,7 @@ skip_interest: "%s MOPT_EXTRAS insert %u %u:%s", afl->queue_cur->fname, i, j, afl->extras[j].data); #endif + if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) { goto abandon_entry; @@ -4099,7 +4111,8 @@ skip_user_extras: afl->stage_cur_byte = i; - for (j = 0; j < MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS); ++j) { + u32 min_extra_len = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS); + for (j = 0; j < min_extra_len; ++j) { /* See the comment in the earlier code; extras are sorted by size. */ @@ -4121,6 +4134,7 @@ skip_user_extras: "%s MOPT_AUTO_EXTRAS overwrite %u %u:%s", afl->queue_cur->fname, i, j, afl->a_extras[j].data); #endif + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -4234,6 +4248,19 @@ pacemaker_fuzzing: havoc_queued = afl->queued_paths; + u32 r_max; + + r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + + if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) { + + /* add expensive havoc cases here, they are activated after a full + cycle without finds happened */ + + ++r_max; + + } + for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { @@ -4254,12 +4281,12 @@ pacemaker_fuzzing: for (i = 0; i < use_stacking; ++i) { - switch (select_algorithm(afl)) { + switch (select_algorithm(afl, r_max)) { case 0: /* Flip a single bit somewhere. Spooky! */ FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); - MOpt_globals.cycles_v2[STAGE_FLIP1] += 1; + MOpt_globals.cycles_v2[STAGE_FLIP1]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1"); strcat(afl->mutation, afl->m_tmp); @@ -4271,7 +4298,7 @@ pacemaker_fuzzing: temp_len_puppet = rand_below(afl, (temp_len << 3) - 1); FLIP_BIT(out_buf, temp_len_puppet); FLIP_BIT(out_buf, temp_len_puppet + 1); - MOpt_globals.cycles_v2[STAGE_FLIP2] += 1; + MOpt_globals.cycles_v2[STAGE_FLIP2]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT2"); strcat(afl->mutation, afl->m_tmp); @@ -4285,7 +4312,7 @@ pacemaker_fuzzing: FLIP_BIT(out_buf, temp_len_puppet + 1); FLIP_BIT(out_buf, temp_len_puppet + 2); FLIP_BIT(out_buf, temp_len_puppet + 3); - MOpt_globals.cycles_v2[STAGE_FLIP4] += 1; + MOpt_globals.cycles_v2[STAGE_FLIP4]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT4"); strcat(afl->mutation, afl->m_tmp); @@ -4295,7 +4322,7 @@ pacemaker_fuzzing: case 3: if (temp_len < 4) { break; } out_buf[rand_below(afl, temp_len)] ^= 0xFF; - MOpt_globals.cycles_v2[STAGE_FLIP8] += 1; + MOpt_globals.cycles_v2[STAGE_FLIP8]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT8"); strcat(afl->mutation, afl->m_tmp); @@ -4305,7 +4332,7 @@ pacemaker_fuzzing: case 4: if (temp_len < 8) { break; } *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) ^= 0xFFFF; - MOpt_globals.cycles_v2[STAGE_FLIP16] += 1; + MOpt_globals.cycles_v2[STAGE_FLIP16]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT16"); strcat(afl->mutation, afl->m_tmp); @@ -4315,7 +4342,7 @@ pacemaker_fuzzing: case 5: if (temp_len < 8) { break; } *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) ^= 0xFFFFFFFF; - MOpt_globals.cycles_v2[STAGE_FLIP32] += 1; + MOpt_globals.cycles_v2[STAGE_FLIP32]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT32"); strcat(afl->mutation, afl->m_tmp); @@ -4327,7 +4354,7 @@ pacemaker_fuzzing: 1 + rand_below(afl, ARITH_MAX); out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); - MOpt_globals.cycles_v2[STAGE_ARITH8] += 1; + MOpt_globals.cycles_v2[STAGE_ARITH8]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH+-"); strcat(afl->mutation, afl->m_tmp); @@ -4384,7 +4411,7 @@ pacemaker_fuzzing: } - MOpt_globals.cycles_v2[STAGE_ARITH16] += 1; + MOpt_globals.cycles_v2[STAGE_ARITH16]++; break; case 8: @@ -4438,7 +4465,7 @@ pacemaker_fuzzing: } - MOpt_globals.cycles_v2[STAGE_ARITH32] += 1; + MOpt_globals.cycles_v2[STAGE_ARITH32]++; break; case 9: @@ -4446,7 +4473,7 @@ pacemaker_fuzzing: if (temp_len < 4) { break; } out_buf[rand_below(afl, temp_len)] = interesting_8[rand_below(afl, sizeof(interesting_8))]; - MOpt_globals.cycles_v2[STAGE_INTEREST8] += 1; + MOpt_globals.cycles_v2[STAGE_INTEREST8]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8"); strcat(afl->mutation, afl->m_tmp); @@ -4478,7 +4505,7 @@ pacemaker_fuzzing: } - MOpt_globals.cycles_v2[STAGE_INTEREST16] += 1; + MOpt_globals.cycles_v2[STAGE_INTEREST16]++; break; case 11: @@ -4508,7 +4535,7 @@ pacemaker_fuzzing: } - MOpt_globals.cycles_v2[STAGE_INTEREST32] += 1; + MOpt_globals.cycles_v2[STAGE_INTEREST32]++; break; case 12: @@ -4518,7 +4545,7 @@ pacemaker_fuzzing: possibility of a no-op. */ out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); - MOpt_globals.cycles_v2[STAGE_RANDOMBYTE] += 1; + MOpt_globals.cycles_v2[STAGE_RANDOMBYTE]++; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8"); strcat(afl->mutation, afl->m_tmp); @@ -4541,16 +4568,16 @@ pacemaker_fuzzing: del_from = rand_below(afl, temp_len - del_len + 1); - memmove(out_buf + del_from, out_buf + del_from + del_len, - temp_len - del_from - del_len); - - temp_len -= del_len; - MOpt_globals.cycles_v2[STAGE_DELETEBYTE] += 1; #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u%u", del_from, del_len); strcat(afl->mutation, afl->m_tmp); #endif + memmove(out_buf + del_from, out_buf + del_from + del_len, + temp_len - del_from - del_len); + + temp_len -= del_len; + MOpt_globals.cycles_v2[STAGE_DELETEBYTE]++; break; } @@ -4566,7 +4593,7 @@ pacemaker_fuzzing: u32 clone_from, clone_to, clone_len; u8 *new_buf; - if (actually_clone) { + if (likely(actually_clone)) { clone_len = choose_block_len(afl, temp_len); clone_from = rand_below(afl, temp_len - clone_len + 1); @@ -4617,7 +4644,7 @@ pacemaker_fuzzing: out_buf = new_buf; afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); temp_len += clone_len; - MOpt_globals.cycles_v2[STAGE_Clone75] += 1; + MOpt_globals.cycles_v2[STAGE_Clone75]++; } @@ -4637,9 +4664,9 @@ pacemaker_fuzzing: copy_from = rand_below(afl, temp_len - copy_len + 1); copy_to = rand_below(afl, temp_len - copy_len + 1); - if (rand_below(afl, 4)) { + if (likely(rand_below(afl, 4))) { - if (copy_from != copy_to) { + if (likely(copy_from != copy_to)) { #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), @@ -4666,7 +4693,7 @@ pacemaker_fuzzing: } - MOpt_globals.cycles_v2[STAGE_OverWrite75] += 1; + MOpt_globals.cycles_v2[STAGE_OverWrite75]++; break; } /* case 15 */ @@ -4721,7 +4748,7 @@ pacemaker_fuzzing: } afl->stage_cycles_puppet_v2[afl->swarm_now] - [STAGE_OverWriteExtra] += 1; + [STAGE_OverWriteExtra]++; break; @@ -4783,11 +4810,93 @@ pacemaker_fuzzing: } + default: { + + if (unlikely(afl->ready_for_splicing_count < 2)) break; + + u32 tid; + do { + + tid = rand_below(afl, afl->queued_paths); + + } while (tid == afl->current_entry || + + afl->queue_buf[tid]->len < 4); + + /* Get the testcase for splicing. */ + struct queue_entry *target = afl->queue_buf[tid]; + u32 new_len = target->len; + u8 * new_buf = queue_testcase_get(afl, target); + + if ((temp_len >= 2 && rand_below(afl, 2)) || + temp_len + HAVOC_BLK_XL >= MAX_FILE) { + + /* overwrite mode */ + + u32 copy_from, copy_to, copy_len; + + copy_len = choose_block_len(afl, new_len - 1); + if ((s32)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); + +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_OVERWRITE_%u_%u_%u_%s", copy_from, copy_to, + copy_len, target->fname); + strcat(afl->mutation, afl->m_tmp); +#endif + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); + + } else { + + /* insert mode */ + + 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 + 1); + + u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), + temp_len + clone_len + 1); + if (unlikely(!temp_buf)) { PFATAL("alloc"); } + +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_INSERT_%u_%u_%u_%s", clone_from, clone_to, + clone_len, target->fname); + strcat(afl->mutation, afl->m_tmp); +#endif + /* 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); + + out_buf = temp_buf; + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); + temp_len += clone_len; + + } + + afl->stage_cycles_puppet_v2[afl->swarm_now][STAGE_Splice]++; + break; + + } // end of default: + } /* switch select_algorithm() */ } /* for i=0; i < use_stacking */ - *MOpt_globals.pTime += 1; + ++*MOpt_globals.pTime; u64 temp_total_found = afl->queued_paths + afl->unique_crashes; @@ -5138,7 +5247,7 @@ u8 pilot_fuzzing(afl_state_t *afl) { void pso_updating(afl_state_t *afl) { - afl->g_now += 1; + afl->g_now++; if (afl->g_now > afl->g_max) { afl->g_now = 0; } afl->w_now = (afl->w_init - afl->w_end) * (afl->g_max - afl->g_now) / (afl->g_max) + -- cgit 1.4.1 From 8e1047f5efaece663bba9b8ef86d181198db5101 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 10 Nov 2020 14:08:21 +0100 Subject: support custom mutator introspection --- docs/Changelog.md | 1 + docs/custom_mutators.md | 10 ++++++ include/afl-fuzz.h | 33 ++++++++++++++------ src/afl-fuzz-bitmap.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++--- src/afl-fuzz-mutators.c | 7 +++++ src/afl-fuzz-one.c | 8 +++++ src/afl-fuzz-python.c | 33 ++++++++++++++++++++ 7 files changed, 159 insertions(+), 14 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index 50c1d48a..a69f2ff4 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -37,6 +37,7 @@ sending a mail to . - added NO_SPLICING compile option and makefile define - added INTROSPECTION make target that writes all mutations to out/NAME/introspection.txt + - added INTROSPECTION support for custom modules - print special compile time options used in help output - instrumentation - We received an enhanced gcc_plugin module from AdaCore, thank you diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 81ee9de4..2516e511 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -42,6 +42,7 @@ size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size unsigned char afl_custom_havoc_mutation_probability(void *data); unsigned char afl_custom_queue_get(void *data, const unsigned char *filename); void afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue); +const char* afl_custom_introspection(my_mutator_t *data); void afl_custom_deinit(void *data); ``` @@ -81,6 +82,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): pass ``` +def introspection(): + return string + ### Custom Mutation - `init`: @@ -130,6 +134,12 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): This methods is called after adding a new test case to the queue. +- `introspection` (optional): + + This method is called after a new queue entry, crash or timeout is + discovered if compiled with INTROSPECTION. The custom mutator can then + return a string (const char *) that reports the exact mutations used. + - `deinit`: The last method to be called, deinitializing the state. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e59d5f90..c355263b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -310,6 +310,7 @@ enum { /* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY, /* 10 */ PY_FUNC_QUEUE_GET, /* 11 */ PY_FUNC_QUEUE_NEW_ENTRY, + /* 12 */ PY_FUNC_INTROSPECTION, PY_FUNC_COUNT }; @@ -684,6 +685,8 @@ typedef struct afl_state { u32 custom_mutators_count; + struct custom_mutator *current_custom_fuzz; + list_t custom_mutator_list; /* this is a fixed buffer of size map_size that can be used by any function if @@ -747,6 +750,15 @@ struct custom_mutator { */ void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed); + /** + * When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can + * also give introspection information back with this function. + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @return pointer to a text string (const char*) + */ + const char *(*afl_custom_introspection)(void *data); + /** * This method is called just before fuzzing a queue entry with the custom * mutator, and receives the initial buffer. It should return the number of @@ -953,16 +965,17 @@ u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf, struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *); void finalize_py_module(void *); -u32 fuzz_count_py(void *, const u8 *, size_t); -size_t post_process_py(void *, u8 *, size_t, u8 **); -s32 init_trim_py(void *, u8 *, size_t); -s32 post_trim_py(void *, u8); -size_t trim_py(void *, u8 **); -size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t); -u8 havoc_mutation_probability_py(void *); -u8 queue_get_py(void *, const u8 *); -void queue_new_entry_py(void *, const u8 *, const u8 *); -void deinit_py(void *); +u32 fuzz_count_py(void *, const u8 *, size_t); +size_t post_process_py(void *, u8 *, size_t, u8 **); +s32 init_trim_py(void *, u8 *, size_t); +s32 post_trim_py(void *, u8); +size_t trim_py(void *, u8 **); +size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t); +u8 havoc_mutation_probability_py(void *); +u8 queue_get_py(void *, const u8 *); +const char *introspection_py(void *); +void queue_new_entry_py(void *, const u8 *, const u8 *); +void deinit_py(void *); #endif diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 735420c3..132499d6 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -588,8 +588,32 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { add_to_queue(afl, queue_fn, len, 0); #ifdef INTROSPECTION - fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation, - afl->queue_top->fname); + if (afl->mutation[0] != 0) { + + fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation, + afl->queue_top->fname); + + } else if (afl->custom_mutators_count && afl->current_custom_fuzz) { + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (afl->current_custom_fuzz == el && el->afl_custom_introspection) { + + const char *ptr = el->afl_custom_introspection(el->data); + + if (ptr != NULL && *ptr != 0) { + + fprintf(afl->introspection_file, "QUEUE CUSTOM %s = %s\n", ptr, + afl->queue_top->fname); + + } + + } + + }); + + } + #endif if (hnb == 2) { @@ -665,7 +689,32 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { ++afl->unique_tmouts; #ifdef INTROSPECTION - fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation); + if (afl->mutation[0] != 0) { + + fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation); + + } else if (afl->custom_mutators_count && afl->current_custom_fuzz) { + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (afl->current_custom_fuzz == el && el->afl_custom_introspection) { + + const char *ptr = el->afl_custom_introspection(el->data); + + if (ptr != NULL && *ptr != 0) { + + fprintf(afl->introspection_file, + "UNIQUE_TIMEOUT CUSTOM %s = %s\n", ptr, + afl->queue_top->fname); + + } + + } + + }); + + } + #endif /* Before saving, we make sure that it's a genuine hang by re-running @@ -751,7 +800,31 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { ++afl->unique_crashes; #ifdef INTROSPECTION - fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation); + if (afl->mutation[0] != 0) { + + fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation); + + } else if (afl->custom_mutators_count && afl->current_custom_fuzz) { + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (afl->current_custom_fuzz == el && el->afl_custom_introspection) { + + const char *ptr = el->afl_custom_introspection(el->data); + + if (ptr != NULL && *ptr != 0) { + + fprintf(afl->introspection_file, "UNIQUE_CRASH CUSTOM %s = %s\n", + ptr, afl->queue_top->fname); + + } + + } + + }); + + } + #endif if (unlikely(afl->infoexec)) { diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index c4d7233c..1d14f657 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -166,6 +166,13 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { } + /* "afl_custom_introspection", optional */ +#ifdef INTROSPECTION + mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection"); + if (!mutator->afl_custom_introspection) + ACTF("optional symbol 'afl_custom_introspection' not found."); +#endif + /* "afl_custom_fuzz_count", optional */ mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count"); if (!mutator->afl_custom_fuzz_count) diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 91bbced6..64365ebb 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1780,10 +1780,16 @@ custom_mutator_stage: orig_hit_cnt = afl->queued_paths + afl->unique_crashes; +#ifdef INTROSPECTION + afl->mutation[0] = 0; +#endif + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { if (el->afl_custom_fuzz) { + afl->current_custom_fuzz = el; + if (el->afl_custom_fuzz_count) afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len); else @@ -1889,6 +1895,8 @@ custom_mutator_stage: }); + afl->current_custom_fuzz = NULL; + if (!has_custom_fuzz) goto havoc_stage; new_hit_cnt = afl->queued_paths + afl->unique_crashes; diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index adb92649..fe16bc46 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -163,6 +163,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "queue_get"); py_functions[PY_FUNC_QUEUE_NEW_ENTRY] = PyObject_GetAttrString(py_module, "queue_new_entry"); + py_functions[PY_FUNC_INTROSPECTION] = + PyObject_GetAttrString(py_module, "introspection"); py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); if (!py_functions[PY_FUNC_DEINIT]) FATAL("deinit function not found in python module"); @@ -381,6 +383,15 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, } + #ifdef INTROSPECTION + if (py_functions[PY_FUNC_INTROSPECTION]) { + + mutator->afl_custom_introspection = introspection_py; + + } + + #endif + OKF("Python mutator '%s' installed successfully.", module_name); /* Initialize the custom mutator */ @@ -679,6 +690,28 @@ u8 havoc_mutation_probability_py(void *py_mutator) { } +const char *introspection_py(void *py_mutator) { + + PyObject *py_args, *py_value; + + py_args = PyTuple_New(0); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INTROSPECTION], + py_args); + Py_DECREF(py_args); + + if (py_value == NULL) { + + return NULL; + + } else { + + return PyByteArray_AsString(py_value); + + } + +} + u8 queue_get_py(void *py_mutator, const u8 *filename) { PyObject *py_args, *py_value; -- cgit 1.4.1 From f80f62f14bb5222344925a7ec51c81aa2f95d86e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 18 Nov 2020 03:02:13 +0100 Subject: renamed env var to AFL_DEBUG_CHILD --- docs/Changelog.md | 1 + docs/env_variables.md | 2 +- examples/afl_network_proxy/afl-network-server.c | 7 +++++-- include/afl-fuzz.h | 4 ++-- include/envs.h | 3 ++- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-fuzz-run.c | 2 +- src/afl-fuzz-state.c | 6 ++++-- src/afl-fuzz.c | 4 ++-- src/afl-showmap.c | 6 +++++- src/afl-tmin.c | 7 +++++-- test/test-unicorn-mode.sh | 6 +++--- 12 files changed, 32 insertions(+), 18 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index baa2667b..9426ed54 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -58,6 +58,7 @@ sending a mail to . - added INTROSPECTION support for custom modules - python fuzz function was not optional, fixed - unicornafl synced with upstream (arm64 fix, better rust bindings) + - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD ### Version ++2.68c (release) diff --git a/docs/env_variables.md b/docs/env_variables.md index 469fc957..1ce6f206 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -388,7 +388,7 @@ checks or alter some of the more exotic semantics of the tool: processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to exit soon after the first crash is found. - - Setting `AFL_DEBUG_CHILD_OUTPUT` will not suppress the child output. + - Setting `AFL_DEBUG_CHILD` will not suppress the child output. Not pretty but good for debugging purposes. - Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color. diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index 3831f985..513dc8f2 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -636,8 +636,11 @@ int main(int argc, char **argv_orig, char **envp) { if (listen(sock, 1) < 0) { PFATAL("listen() failed"); } - afl_fsrv_start(fsrv, use_argv, &stop_soon, - get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + afl_fsrv_start( + fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); #ifdef USE_DEFLATE compressor = libdeflate_alloc_compressor(1); diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c355263b..b484b93e 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -362,8 +362,8 @@ typedef struct afl_env_vars { u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check, afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, - afl_bench_until_crash, afl_debug_child_output, afl_autoresume, - afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd; + afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, + afl_cycle_schedules, afl_expand_havoc, afl_statsd; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/envs.h b/include/envs.h index b753d5f8..8255cf4f 100644 --- a/include/envs.h +++ b/include/envs.h @@ -6,6 +6,7 @@ static char *afl_environment_deprecated[] = { "AFL_LLVM_WHITELIST", "AFL_GCC_WHITELIST", + "AFL_DEBUG_CHILD_OUTPUT", "AFL_DEFER_FORKSRV", "AFL_POST_LIBRARY", "AFL_PERSISTENT", @@ -36,7 +37,7 @@ static char *afl_environment_variables[] = { "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", - "AFL_DEBUG_CHILD_OUTPUT", + "AFL_DEBUG_CHILD", "AFL_DEBUG_GDB", "AFL_DISABLE_TRIM", "AFL_DONT_OPTIMIZE", diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 18501b65..485f500c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -992,7 +992,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { // For stability analysis, if you want to know to which function unstable // edge IDs belong - uncomment, recompile+install llvm_mode, recompile // the target. libunwind and libbacktrace are better solutions. - // Set AFL_DEBUG_CHILD_OUTPUT=1 and run afl-fuzz with 2>file to capture + // Set AFL_DEBUG_CHILD=1 and run afl-fuzz with 2>file to capture // the backtrace output /* uint32_t unstable[] = { ... unstable edge IDs }; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index b96fe71a..95b3ee8a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -332,7 +332,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, - afl->afl_env.afl_debug_child_output); + afl->afl_env.afl_debug_child); if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 61bd06b7..489d4e53 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -268,11 +268,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_bench_until_crash = get_afl_env(afl_environment_variables[i]) ? 1 : 0; - } else if (!strncmp(env, "AFL_DEBUG_CHILD_OUTPUT", + } else if (!strncmp(env, "AFL_DEBUG_CHILD", + afl_environment_variable_len) || + !strncmp(env, "AFL_DEBUG_CHILD_OUTPUT", afl_environment_variable_len)) { - afl->afl_env.afl_debug_child_output = + afl->afl_env.afl_debug_child = get_afl_env(afl_environment_variables[i]) ? 1 : 0; } else if (!strncmp(env, "AFL_AUTORESUME", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ac77bb1f..e04ae649 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -166,7 +166,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n" "AFL_DEBUG: extra debugging output for Python mode trimming\n" - "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n" + "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n" "AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" @@ -1426,7 +1426,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.init_child_func = cmplog_exec_child; afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, - afl->afl_env.afl_debug_child_output); + afl->afl_env.afl_debug_child); OKF("Cmplog forkserver successfully started"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 4b357254..69527007 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1091,7 +1091,11 @@ int main(int argc, char **argv_orig, char **envp) { } afl_fsrv_start(fsrv, use_argv, &stop_soon, - get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + (get_afl_env("AFL_DEBUG_CHILD") || + get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); + map_size = fsrv->map_size; if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 06037d61..e4fb068d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1141,8 +1141,11 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv, &stop_soon, - get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + afl_fsrv_start( + fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); diff --git a/test/test-unicorn-mode.sh b/test/test-unicorn-mode.sh index 7ac4cdd2..b4c6eb3e 100755 --- a/test/test-unicorn-mode.sh +++ b/test/test-unicorn-mode.sh @@ -7,7 +7,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel test -e ../unicorn_mode/samples/simple/simple_target.bin -a -e ../unicorn_mode/samples/compcov_x64/compcov_target.bin && { { # We want to see python errors etc. in logs, in case something doesn't work - export AFL_DEBUG_CHILD_OUTPUT=1 + export AFL_DEBUG_CHILD=1 # some python version should be available now PYTHONS="`command -v python3` `command -v python` `command -v python2`" @@ -34,7 +34,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel cd ../unicorn_mode/samples/persistent make >>errors 2>&1 $ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds" - AFL_DEBUG_CHILD_OUTPUT=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1 + AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1 test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)" } || { @@ -96,7 +96,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel } fi - unset AFL_DEBUG_CHILD_OUTPUT + unset AFL_DEBUG_CHILD } } || { -- cgit 1.4.1 From b260204b728efcc4ba13dfa77692cfc5721db606 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Wed, 18 Nov 2020 18:13:03 +0000 Subject: Solaris/Illumos build fix. (#609) --- include/afl-fuzz.h | 1 + src/afl-cc.c | 2 +- src/afl-fuzz-init.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index b484b93e..423230f1 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -113,6 +113,7 @@ #include #include #include + #include #endif #endif /* __linux__ */ diff --git a/src/afl-cc.c b/src/afl-cc.c index 9c23c18b..19dc9a6a 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -837,7 +837,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - #ifndef __APPLE__ + #if !defined(__APPLE__) && !defined(__sun) if (!shared_linking) cc_params[cc_par_cnt++] = alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 6884bb1d..0360cdb0 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -355,7 +355,7 @@ void bind_to_free_cpu(afl_state_t *afl) { if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used); - for (i = 0; i < ncpus; i++) { + for (i = 0; i < (s32)ncpus; i++) { k = kstat_lookup(m, "cpu_stat", i, NULL); if (kstat_read(m, k, &cs)) { -- cgit 1.4.1 From cd0a25be5e9b05a2ab6a11592cd95e7f653bf42d Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Wed, 18 Nov 2020 14:29:17 -0500 Subject: Use buffer protocol to retrieve result from python post_process (#605) Saves an extra copy, gives post processing functions more flexibility --- docs/custom_mutators.md | 3 +++ include/afl-fuzz.h | 3 +-- src/afl-fuzz-python.c | 34 ++++++++++++++++++++++++---------- 3 files changed, 28 insertions(+), 12 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 2516e511..53f783fe 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -130,6 +130,9 @@ def introspection(): `post_process` function. This function is then transforming the data into the format expected by the API before executing the target. + This can return any python object that implements the buffer protocol and + supports PyBUF_SIMPLE. These include bytes, bytearray, etc. + - `queue_new_entry` (optional): This methods is called after adding a new test case to the queue. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 423230f1..933af65d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -326,8 +326,7 @@ typedef struct py_mutator { u8 * fuzz_buf; size_t fuzz_size; - u8 * post_process_buf; - size_t post_process_size; + Py_buffer post_process_buf; u8 * trim_buf; size_t trim_size; diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 80532774..9ac4403b 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -134,6 +134,18 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject * py_module = py->py_module; PyObject **py_functions = py->py_functions; + // initialize the post process buffer; ensures it's always valid + PyObject *unused_bytes = PyByteArray_FromStringAndSize("OHAI", 4); + if (!unused_bytes) { FATAL("allocation failed!"); } + if (PyObject_GetBuffer(unused_bytes, &py->post_process_buf, PyBUF_SIMPLE) == + -1) { + + FATAL("buffer initialization failed"); + + } + + Py_DECREF(unused_bytes); + if (py_module != NULL) { u8 py_notrim = 0, py_idx; @@ -313,7 +325,6 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, struct custom_mutator *mutator; mutator = ck_alloc(sizeof(struct custom_mutator)); - mutator->post_process_buf = NULL; mutator->name = module_name; ACTF("Loading Python mutator library from '%s'...", module_name); @@ -403,10 +414,13 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { - size_t py_out_buf_size; PyObject * py_args, *py_value; py_mutator_t *py = (py_mutator_t *)py_mutator; + // buffer returned previously must be released; initialized during init + // so we don't need to do comparisons + PyBuffer_Release(&py->post_process_buf); + py_args = PyTuple_New(1); py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { @@ -426,20 +440,20 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size, if (py_value != NULL) { - py_out_buf_size = PyByteArray_Size(py_value); + if (PyObject_GetBuffer(py_value, &py->post_process_buf, PyBUF_SIMPLE) == + -1) { - if (unlikely(!afl_realloc(BUF_PARAMS(post_process), py_out_buf_size))) { - - PFATAL("alloc"); + PyErr_Print(); + FATAL( + "Python custom mutator: post_process call return value not a " + "bytes-like object"); } - memcpy(py->post_process_buf, PyByteArray_AsString(py_value), - py_out_buf_size); Py_DECREF(py_value); - *out_buf = py->post_process_buf; - return py_out_buf_size; + *out_buf = (u8 *)py->post_process_buf.buf; + return py->post_process_buf.len; } else { -- cgit 1.4.1 From a2e2fae840e9946c7994ac6807bed8496d71af56 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 3 Dec 2020 14:43:06 +0100 Subject: AFL_CRASH_EXITCODE env var added, u8->bool --- .gitignore | 1 + afl-cmin | 5 +++-- docs/Changelog.md | 4 +++- docs/env_variables.md | 7 +++++++ include/afl-fuzz.h | 7 ++++--- include/common.h | 2 +- include/envs.h | 1 + include/forkserver.h | 21 +++++++++++++-------- src/afl-analyze.c | 4 ++-- src/afl-common.c | 4 ++-- src/afl-forkserver.c | 22 +++++++++++++++------- src/afl-fuzz-init.c | 27 +++++++++++++++++++++++++-- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 26 ++++++++++++++++++++++++-- src/afl-showmap.c | 19 +++++++++++++++++++ src/afl-tmin.c | 32 +++++++++++++++++++++++++------- 16 files changed, 152 insertions(+), 37 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/.gitignore b/.gitignore index 97f99bf6..82a81605 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.pyc *.dSYM as +a.out ld in out diff --git a/afl-cmin b/afl-cmin index 91ed8d6d..b3b1ead8 100755 --- a/afl-cmin +++ b/afl-cmin @@ -116,11 +116,12 @@ function usage() { "For additional tips, please consult README.md\n" \ "\n" \ "Environment variables used:\n" \ +"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ +"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ +"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_PATH: path for the afl-showmap binary\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" \ -"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" -"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" exit 1 } diff --git a/docs/Changelog.md b/docs/Changelog.md index fd30c7b0..02728f10 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -60,8 +60,10 @@ sending a mail to . - Our afl++ Grammar-Mutator is now better integrated into custom_mutators/ - added INTROSPECTION support for custom modules - python fuzz function was not optional, fixed - - unicornafl synced with upstream (arm64 fix, better rust bindings) + - some python mutator speed improvements + - unicornafl synced with upstream version 1.02 (fixes, better rust bindings) - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD + - added AFL_CRASH_EXITCODE env variable to treat a child exitcode as crash ### Version ++2.68c (release) diff --git a/docs/env_variables.md b/docs/env_variables.md index ada89257..e203055f 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -428,6 +428,13 @@ checks or alter some of the more exotic semantics of the tool: matches your StatsD server. Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. + - Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash. + For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting + in an `-1` return code (i.e. `exit(-1)` got called), will be treated + as if a crash had ocurred. + This may be beneficial if you look for higher-level faulty conditions in which your + target still exits gracefully. + - Outdated environment variables that are not supported anymore: `AFL_DEFER_FORKSRV` `AFL_PERSISTENT` diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 933af65d..62d76323 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -144,8 +144,8 @@ struct queue_entry { u8 *fname; /* File name for the test case */ u32 len; /* Input length */ - u8 cal_failed, /* Calibration failed? */ - trim_done, /* Trimmed? */ + u8 cal_failed; /* Calibration failed? */ + bool trim_done, /* Trimmed? */ was_fuzzed, /* historical, but needed for MOpt */ passed_det, /* Deterministic stages passed? */ has_new_cov, /* Triggers new coverage? */ @@ -368,7 +368,8 @@ typedef struct afl_env_vars { u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, - *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries; + *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, + *afl_testcache_entries; } afl_env_vars_t; diff --git a/include/common.h b/include/common.h index c364ade0..6e5039d8 100644 --- a/include/common.h +++ b/include/common.h @@ -38,7 +38,7 @@ #define STRINGIFY_VAL_SIZE_MAX (16) -void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin); +void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin); void check_environment_vars(char **env); char **argv_cpy_dup(int argc, char **argv); diff --git a/include/envs.h b/include/envs.h index 3aa05cb5..43c87148 100644 --- a/include/envs.h +++ b/include/envs.h @@ -32,6 +32,7 @@ static char *afl_environment_variables[] = { "AFL_CODE_START", "AFL_COMPCOV_BINNAME", "AFL_COMPCOV_LEVEL", + "AFL_CRASH_EXITCODE", "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CXX", diff --git a/include/forkserver.h b/include/forkserver.h index 300ecffc..5d5c728f 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -37,9 +37,7 @@ typedef struct afl_forkserver { /* a program that includes afl-forkserver needs to define these */ - u8 uses_asan; /* Target uses ASAN? */ u8 *trace_bits; /* SHM with instrumentation bitmap */ - u8 use_stdin; /* use stdin for sending data */ s32 fsrv_pid, /* PID of the fork server */ child_pid, /* PID of the fuzzed program */ @@ -53,8 +51,6 @@ typedef struct afl_forkserver { fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_st_fd; /* Fork server status pipe (read) */ - u8 no_unlink; /* do not unlink cur_input */ - u32 exec_tmout; /* Configurable exec timeout (ms) */ u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ @@ -73,13 +69,22 @@ typedef struct afl_forkserver { u8 last_kill_signal; /* Signal that killed the child */ - u8 use_shmem_fuzz; /* use shared mem for test cases */ + bool use_shmem_fuzz; /* use shared mem for test cases */ + + bool support_shmem_fuzz; /* set by afl-fuzz */ + + bool use_fauxsrv; /* Fauxsrv for non-forking targets? */ + + bool qemu_mode; /* if running in qemu mode or not */ + + bool use_stdin; /* use stdin for sending data */ - u8 support_shmem_fuzz; /* set by afl-fuzz */ + bool no_unlink; /* do not unlink cur_input */ - u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ + bool uses_asan; /* Target uses ASAN? */ - u8 qemu_mode; /* if running in qemu mode or not */ + bool uses_crash_exitcode; /* Custom crash exitcode specified? */ + u8 crash_exitcode; /* The crash exitcode specified */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index c8acebb3..2780deff 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -78,9 +78,9 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static s32 dev_null_fd = -1; /* FD to /dev/null */ -static u8 edges_only, /* Ignore hit counts? */ +static bool edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ - use_stdin = 1; /* Use stdin for program input? */ + use_stdin = true; /* Use stdin for program input? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ diff --git a/src/afl-common.c b/src/afl-common.c index 8cf1a444..ed0b0e53 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -46,7 +46,7 @@ u8 be_quiet = 0; u8 *doc_path = ""; u8 last_intr = 0; -void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { +void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) { u32 i = 0; u8 cwd[PATH_MAX]; @@ -63,7 +63,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); } - *use_stdin = 0; + *use_stdin = false; if (prog_in[0] != 0) { // not afl-showmap special case diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 01ef1d9e..20117c1d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -76,8 +76,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->dev_urandom_fd = -1; /* Settings */ - fsrv->use_stdin = 1; - fsrv->no_unlink = 0; + fsrv->use_stdin = true; + fsrv->no_unlink = false; fsrv->exec_tmout = EXEC_TIMEOUT; fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT; fsrv->mem_limit = MEM_LIMIT; @@ -86,8 +86,11 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { /* exec related stuff */ fsrv->child_pid = -1; fsrv->map_size = get_map_size(); - fsrv->use_fauxsrv = 0; - fsrv->last_run_timed_out = 0; + fsrv->use_fauxsrv = false; + fsrv->last_run_timed_out = false; + + fsrv->uses_crash_exitcode = false; + fsrv->uses_asan = false; fsrv->init_child_func = fsrv_exec_child; @@ -109,6 +112,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->dev_urandom_fd = from->dev_urandom_fd; fsrv_to->out_fd = from->out_fd; // not sure this is a good idea fsrv_to->no_unlink = from->no_unlink; + fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode; + fsrv_to->crash_exitcode = from->crash_exitcode; // These are forkserver specific. fsrv_to->out_dir_fd = -1; @@ -1136,10 +1141,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ + /* MSAN in uses_asan mode uses a special exit code as it doesn't support + abort_on_error. + On top, a user may specify a custom AFL_CRASH_EXITCODE. Handle both here. */ - if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) { + if ((fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + (fsrv->uses_crash_exitcode && + WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode)) { fsrv->last_kill_signal = 0; return FSRV_RUN_CRASH; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 0360cdb0..6707340b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -868,7 +868,19 @@ void perform_dry_run(afl_state_t *afl) { if (skip_crashes) { - WARNF("Test case results in a crash (skipping)"); + if (afl->fsrv.uses_crash_exitcode) { + + WARNF( + "Test case results in a crash or AFL_CRASH_EXITCODE %d " + "(skipping)", + (int)(s8)afl->fsrv.crash_exitcode); + + } else { + + WARNF("Test case results in a crash (skipping)"); + + } + q->cal_failed = CAL_CHANCES; ++cal_failures; break; @@ -954,7 +966,18 @@ void perform_dry_run(afl_state_t *afl) { #undef MSG_ULIMIT_USAGE #undef MSG_FORK_ON_APPLE - WARNF("Test case '%s' results in a crash, skipping", fn); + if (afl->fsrv.uses_crash_exitcode) { + + WARNF( + "Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, " + "skipping", + fn, (int)(s8)afl->fsrv.crash_exitcode); + + } else { + + WARNF("Test case '%s' results in a crash, skipping", fn); + + } /* Remove from fuzzing queue but keep for splicing */ diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 489d4e53..73b94466 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -394,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_statsd_tags_flavor = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_CRASH_EXITCODE", + + afl_environment_variable_len)) { + + afl->afl_env.afl_crash_exitcode = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b91d862d..eb5e9307 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -26,6 +26,7 @@ #include "afl-fuzz.h" #include "cmplog.h" #include +#include #ifndef USEMMAP #include #include @@ -165,6 +166,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_BENCH_JUST_ONE: run the target just once\n" "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" + "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n" @@ -702,7 +704,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'N': /* Unicorn mode */ if (afl->no_unlink) { FATAL("Multiple -N options not supported"); } - afl->fsrv.no_unlink = afl->no_unlink = 1; + afl->fsrv.no_unlink = (afl->no_unlink = true); break; @@ -1135,6 +1137,23 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_crash_exitcode) { + + long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10); + if ((!exitcode && (errno == EINVAL || errno == ERANGE)) || + exitcode < -127 || exitcode > 128) { + + FATAL("Invalid crash exitcode, expected -127 to 128, but got %s", + afl->afl_env.afl_crash_exitcode); + + } + + afl->fsrv.uses_crash_exitcode = true; + // WEXITSTATUS is 8 bit unsigned + afl->fsrv.crash_exitcode = (u8)exitcode; + + } + if (afl->non_instrumented_mode == 2 && afl->no_forkserver) { FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); @@ -1486,9 +1505,12 @@ int main(int argc, char **argv_orig, char **envp) { cull_queue(afl); - if (!afl->pending_not_fuzzed) + if (!afl->pending_not_fuzzed) { + FATAL("We need at least on valid input seed that does not crash!"); + } + show_init_stats(afl); if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index a8e7d3f9..e07e76c8 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -667,6 +667,8 @@ static void usage(u8 *argv0) { "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " "inputs\n" "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n" + "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as " + "crash\n" "AFL_DEBUG: enable extra developer output\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size\n" @@ -1090,6 +1092,23 @@ int main(int argc, char **argv_orig, char **envp) { } + if (getenv("AFL_CRASH_EXITCODE")) { + + long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); + if ((!exitcode && (errno == EINVAL || errno == ERANGE)) || + exitcode < -127 || exitcode > 128) { + + FATAL("Invalid crash exitcode, expected -127 to 128, but got %s", + getenv("AFL_CRASH_EXITCODE")); + + } + + fsrv->uses_crash_exitcode = true; + // WEXITSTATUS is 8 bit unsigned + fsrv->crash_exitcode = (u8)exitcode; + + } + afl_fsrv_start(fsrv, use_argv, &stop_soon, (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) diff --git a/src/afl-tmin.c b/src/afl-tmin.c index e4fb068d..b9045551 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -841,17 +842,17 @@ static void usage(u8 *argv0) { "For additional tips, please consult %s/README.md.\n\n" "Environment variables used:\n" - "TMPDIR: directory to use for temporary input files\n" - "ASAN_OPTIONS: custom settings for ASAN\n" - " (must contain abort_on_error=1 and symbolize=0)\n" - "MSAN_OPTIONS: custom settings for MSAN\n" - " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" + "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" " the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n" - "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" - + "ASAN_OPTIONS: custom settings for ASAN\n" + " (must contain abort_on_error=1 and symbolize=0)\n" + "MSAN_OPTIONS: custom settings for MSAN\n" + " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "TMPDIR: directory to use for temporary input files\n" , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); exit(1); @@ -1122,6 +1123,23 @@ int main(int argc, char **argv_orig, char **envp) { } + if (getenv("AFL_CRASH_EXITCODE")) { + + long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); + if ((!exitcode && (errno == EINVAL || errno == ERANGE)) || + exitcode < -127 || exitcode > 128) { + + FATAL("Invalid crash exitcode, expected -127 to 128, but got %s", + getenv("AFL_CRASH_EXITCODE")); + + } + + fsrv->uses_crash_exitcode = true; + // WEXITSTATUS is 8 bit unsigned + fsrv->crash_exitcode = (u8)exitcode; + + } + shm_fuzz = ck_alloc(sizeof(sharedmem_t)); /* initialize cmplog_mode */ -- cgit 1.4.1 From a19b3022d93195d3703817c728817d7e071e89fe Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 3 Dec 2020 19:22:44 +0100 Subject: afl_custom_describe api added --- docs/Changelog.md | 10 ++++--- include/afl-fuzz.h | 14 +++++++++ src/afl-fuzz-bitmap.c | 63 +++++++++++++++++++++++++++++--------- src/afl-fuzz-mutators.c | 80 ++++++++++++++++++++++++++++++++++++++++--------- src/afl-fuzz-one.c | 9 ++++-- unicorn_mode/unicornafl | 2 +- 6 files changed, 143 insertions(+), 35 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index 02728f10..5201eb8b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -22,18 +22,18 @@ sending a mail to . a schedule performance score, which is much better that the previous walk the whole queue approach. Select the old mode with -Z (auto enabled with -M) - - rpc.statsd support by Edznux, thanks a lot! + - rpc.statsd support, for stats and charts, by Edznux, thanks a lot! - Marcel Boehme submitted a patch that improves all AFFast schedules :) - not specifying -M or -S will now auto-set "-S default" - reading testcases from -i now descends into subdirectories - - allow up to 4 times the -x command line option - - loaded extras now have a duplicate protection + - allow the -x command line option up to 4 times + - loaded extras now have a duplication protection - If test cases are too large we do a partial read on the maximum supported size - longer seeds with the same trace information will now be ignored for fuzzing but still be used for splicing - crashing seeds are now not prohibiting a run anymore but are - skipped. They are used for splicing though. + skipped - they are used for splicing, though - update MOpt for expanded havoc modes - setting the env var AFL_NO_AUTODICT will not load an LTO autodictionary - added NO_SPLICING compile option and makefile define @@ -42,6 +42,8 @@ sending a mail to . - print special compile time options used in help output - when using -c cmplog, one of the childs was not killed, fixed - somewhere we broke -n dumb fuzzing, fixed + - added afl_custom_describe to the custom mutator API to allow for easy + mutation reproduction on crashing inputs - instrumentation - We received an enhanced gcc_plugin module from AdaCore, thank you very much!! diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 62d76323..92465e7e 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -798,6 +798,20 @@ struct custom_mutator { size_t (*afl_custom_fuzz)(void *data, u8 *buf, size_t buf_size, u8 **out_buf, u8 *add_buf, size_t add_buf_size, size_t max_size); + /** + * Describe the current testcase, generated by the last mutation. + * This will be called, for example, to give the written testcase a name + * after a crash ocurred. It can help to reproduce crashing mutations. + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param[in] max_size Maximum size of the mutated output. The mutation must + * not produce data larger than max_size. + * @return A valid ptr to a 0-terminated string, or NULL on error. + */ + const char *(*afl_custom_describe)(void *data, size_t max_size); + /** * A post-processing function to use right before AFL writes the test case to * disk in order to execute the target. diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 2d14b04e..a78bf374 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -425,7 +425,7 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { /* Construct a file name for a new test case, capturing the operation that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */ -u8 *describe_op(afl_state_t *afl, u8 hnb) { +u8 *describe_op(afl_state_t *afl, u8 new_bits) { u8 *ret = afl->describe_op_buf_256; @@ -445,29 +445,64 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) { sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time); - sprintf(ret + strlen(ret), ",op:%s", afl->stage_short); + if (afl->current_custom_fuzz && + afl->current_custom_fuzz->afl_custom_describe) { - if (afl->stage_cur_byte >= 0) { + /* We are currently in a custom mutator that supports afl_custom_describe, + * use it! */ - sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte); + size_t len_current = strlen(ret); + ret[len_current++] = ','; + ret[len_current++] = '\0'; - if (afl->stage_val_type != STAGE_VAL_NONE) { + size_t size_left = + sizeof(afl->describe_op_buf_256) - len_current - strlen(",+cov") - 2; + assert(size_left > 0); - sprintf(ret + strlen(ret), ",val:%s%+d", - (afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "", - afl->stage_cur_val); + const char *custom_description = + afl->current_custom_fuzz->afl_custom_describe( + afl->current_custom_fuzz->data, size_left); + if (!custom_description || !custom_description[0]) { + + DEBUGF("Error getting a description from afl_custom_describe"); + /* Take the stage name as description fallback */ + sprintf(ret + len_current, "op:%s", afl->stage_short); + + } else { + + /* We got a proper custom description, use it */ + strncat(ret + len_current, custom_description, size_left); } } else { - sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val); + /* Normal testcase descriptions start here */ + sprintf(ret + strlen(ret), ",op:%s", afl->stage_short); + + if (afl->stage_cur_byte >= 0) { + + sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte); + + if (afl->stage_val_type != STAGE_VAL_NONE) { + + sprintf(ret + strlen(ret), ",val:%s%+d", + (afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "", + afl->stage_cur_val); + + } + + } else { + + sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val); + + } } } - if (hnb == 2) { strcat(ret, ",+cov"); } + if (new_bits == 2) { strcat(ret, ",+cov"); } return ret; @@ -540,7 +575,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (unlikely(len == 0)) { return 0; } u8 *queue_fn = ""; - u8 hnb = '\0'; + u8 new_bits = '\0'; s32 fd; u8 keeping = 0, res; u64 cksum = 0; @@ -566,7 +601,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { /* Keep only if there are new bits in the map, add to queue for future fuzzing, etc. */ - if (!(hnb = has_new_bits(afl, afl->virgin_bits))) { + if (!(new_bits = has_new_bits(afl, afl->virgin_bits))) { if (unlikely(afl->crash_mode)) { ++afl->total_crashes; } return 0; @@ -576,7 +611,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, - afl->queued_paths, describe_op(afl, hnb)); + afl->queued_paths, describe_op(afl, new_bits)); #else @@ -619,7 +654,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #endif - if (hnb == 2) { + if (new_bits == 2) { afl->queue_top->has_new_cov = 1; ++afl->queued_with_cov; diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 1d14f657..0c85458e 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -151,7 +151,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { /* Mutator */ /* "afl_custom_init", optional for backward compatibility */ mutator->afl_custom_init = dlsym(dh, "afl_custom_init"); - if (!mutator->afl_custom_init) FATAL("Symbol 'afl_custom_init' not found."); + if (!mutator->afl_custom_init) { + + FATAL("Symbol 'afl_custom_init' not found."); + + } /* "afl_custom_fuzz" or "afl_custom_mutator", required */ mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz"); @@ -161,49 +165,74 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'."); mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator"); - if (!mutator->afl_custom_fuzz) + if (!mutator->afl_custom_fuzz) { + WARNF("Symbol 'afl_custom_mutator' not found."); + } + } /* "afl_custom_introspection", optional */ #ifdef INTROSPECTION mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection"); - if (!mutator->afl_custom_introspection) + if (!mutator->afl_custom_introspection) { + ACTF("optional symbol 'afl_custom_introspection' not found."); + + } + #endif /* "afl_custom_fuzz_count", optional */ mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count"); - if (!mutator->afl_custom_fuzz_count) + if (!mutator->afl_custom_fuzz_count) { + ACTF("optional symbol 'afl_custom_fuzz_count' not found."); + } + /* "afl_custom_deinit", optional for backward compatibility */ mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit"); - if (!mutator->afl_custom_deinit) + 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"); - if (!mutator->afl_custom_post_process) + if (!mutator->afl_custom_post_process) { + ACTF("optional symbol 'afl_custom_post_process' not found."); + } + u8 notrim = 0; /* "afl_custom_init_trim", optional */ mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); - if (!mutator->afl_custom_init_trim) + if (!mutator->afl_custom_init_trim) { + ACTF("optional symbol 'afl_custom_init_trim' not found."); + } + /* "afl_custom_trim", optional */ mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim"); - if (!mutator->afl_custom_trim) + if (!mutator->afl_custom_trim) { + ACTF("optional symbol 'afl_custom_trim' not found."); + } + /* "afl_custom_post_trim", optional */ mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim"); - if (!mutator->afl_custom_post_trim) + if (!mutator->afl_custom_post_trim) { + ACTF("optional symbol 'afl_custom_post_trim' not found."); + } + if (notrim) { mutator->afl_custom_init_trim = NULL; @@ -217,31 +246,54 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { /* "afl_custom_havoc_mutation", optional */ mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation"); - if (!mutator->afl_custom_havoc_mutation) + if (!mutator->afl_custom_havoc_mutation) { + ACTF("optional symbol 'afl_custom_havoc_mutation' not found."); + } + /* "afl_custom_havoc_mutation", optional */ mutator->afl_custom_havoc_mutation_probability = dlsym(dh, "afl_custom_havoc_mutation_probability"); - if (!mutator->afl_custom_havoc_mutation_probability) + if (!mutator->afl_custom_havoc_mutation_probability) { + ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found."); + } + /* "afl_custom_queue_get", optional */ mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get"); - if (!mutator->afl_custom_queue_get) + if (!mutator->afl_custom_queue_get) { + ACTF("optional symbol 'afl_custom_queue_get' not found."); + } + /* "afl_custom_queue_new_entry", optional */ mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry"); - if (!mutator->afl_custom_queue_new_entry) + if (!mutator->afl_custom_queue_new_entry) { + ACTF("optional symbol 'afl_custom_queue_new_entry' not found"); + } + + /* "afl_custom_describe", optional */ + mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe"); + if (!mutator->afl_custom_describe) { + + ACTF("Symbol 'afl_custom_describe' not found."); + + } + OKF("Custom mutator '%s' installed successfully.", fn); /* Initialize the custom mutator */ - if (mutator->afl_custom_init) + if (mutator->afl_custom_init) { + mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); + } + mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation); mutator->stacked_custom_prob = 6; // like one of the default mutations in havoc diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 0adc3719..ca48f72a 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1790,11 +1790,16 @@ custom_mutator_stage: afl->current_custom_fuzz = el; - if (el->afl_custom_fuzz_count) + if (el->afl_custom_fuzz_count) { + afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len); - else + + } else { + afl->stage_max = saved_max; + } + has_custom_fuzz = true; afl->stage_short = el->name_short; diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index f44ec48f..8cca4801 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit f44ec48f8d5929f243522c1152b5b3c0985a5548 +Subproject commit 8cca4801adb767dce7cf72202d7d25bdb420cf7d -- cgit 1.4.1 From 1f34b9f8e185998e4c9c4b96b0c1878b6615115a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 4 Dec 2020 05:28:36 +0100 Subject: added python mutator, documentation --- docs/custom_mutators.md | 11 +++++++++++ include/afl-fuzz.h | 36 +++++++++++++++++++----------------- src/afl-fuzz-python.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 17 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 6e16ba0f..6d3c9f38 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -34,6 +34,7 @@ C/C++: void *afl_custom_init(afl_state_t *afl, unsigned int seed); unsigned int afl_custom_fuzz_count(void *data, const unsigned char *buf, size_t buf_size); size_t afl_custom_fuzz(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf, unsigned char *add_buf, size_t add_buf_size, size_t max_size); +const char *afl_custom_describe(void *data, size_t max_description_len); size_t afl_custom_post_process(void *data, unsigned char *buf, size_t buf_size, unsigned char **out_buf); int afl_custom_init_trim(void *data, unsigned char *buf, size_t buf_size); size_t afl_custom_trim(void *data, unsigned char **out_buf); @@ -57,6 +58,9 @@ def fuzz_count(buf, add_buf, max_size): def fuzz(buf, add_buf, max_size): return mutated_out +def describe(max_description_length): + return "description_of_current_mutation" + def post_process(buf): return out_buf @@ -112,6 +116,13 @@ def introspection(): You would only skip this if `post_process` is used to fix checksums etc. so you are using it e.g. as a post processing library. +- `describe` (optional): + + When this function is called, is shall describe the current testcase, + generated by the last mutation. This will be called, for example, + to give the written testcase a name after a crash ocurred. + Using it can help to reproduce crashing mutations. + - `havoc_mutation` and `havoc_mutation_probability` (optional): `havoc_mutation` performs a single custom mutation on a given input. This diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 92465e7e..4efa1a6c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -312,6 +312,7 @@ enum { /* 10 */ PY_FUNC_QUEUE_GET, /* 11 */ PY_FUNC_QUEUE_NEW_ENTRY, /* 12 */ PY_FUNC_INTROSPECTION, + /* 13 */ PY_FUNC_DESCRIBE, PY_FUNC_COUNT }; @@ -755,7 +756,7 @@ struct custom_mutator { * When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can * also give introspection information back with this function. * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @return pointer to a text string (const char*) */ const char *(*afl_custom_introspection)(void *data); @@ -771,7 +772,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param buf Buffer containing the test case * @param buf_size Size of the test case * @return The amount of fuzzes to perform on this queue entry, 0 = skip @@ -783,7 +784,7 @@ struct custom_mutator { * * (Optional for now. Required in the future) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param[in] buf Pointer to the input data to be mutated and the mutated * output * @param[in] buf_size Size of the input/output data @@ -805,12 +806,13 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param[in] max_size Maximum size of the mutated output. The mutation must - * not produce data larger than max_size. - * @return A valid ptr to a 0-terminated string, or NULL on error. + * @param data pointer returned by afl_customm_init for this custom mutator + * @paramp[in] max_description_len maximum size avaliable for the description. + * A longer return string is legal, but will be truncated. + * @return A valid ptr to a 0-terminated string. + * An empty or NULL return will result in a default description */ - const char *(*afl_custom_describe)(void *data, size_t max_size); + const char *(*afl_custom_describe)(void *data, size_t max_description_len); /** * A post-processing function to use right before AFL writes the test case to @@ -819,7 +821,7 @@ struct custom_mutator { * (Optional) If this functionality is not needed, simply don't define this * function. * - * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] data pointer returned in afl_custom_init by this custom mutator * @param[in] buf Buffer containing the test case to be executed * @param[in] buf_size Size of the test case * @param[out] out_buf Pointer to the buffer storing the test case after @@ -846,7 +848,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param buf Buffer containing the test case * @param buf_size Size of the test case * @return The amount of possible iteration steps to trim the input. @@ -865,7 +867,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param[out] out_buf Pointer to the buffer containing the trimmed test case. * The library can reuse a buffer for each call * and will have to free the buf (for example in deinit) @@ -880,7 +882,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param success Indicates if the last trim operation was successful. * @return The next trim iteration index (from 0 to the maximum amount of * steps returned in init_trim). Negative on error. @@ -893,7 +895,7 @@ struct custom_mutator { * * (Optional) * - * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] data pointer returned in afl_custom_init by this custom mutator * @param[in] buf Pointer to the input data to be mutated and the mutated * output * @param[in] buf_size Size of input data @@ -912,7 +914,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @return The probability (0-100). */ u8 (*afl_custom_havoc_mutation_probability)(void *data); @@ -922,7 +924,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param filename File name of the test case in the queue entry * @return Return True(1) if the fuzzer will fuzz the queue entry, and * False(0) otherwise. @@ -935,7 +937,7 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator * @param filename_new_queue File name of the new queue entry * @param filename_orig_queue File name of the original queue entry. This * argument can be NULL while initializing the fuzzer @@ -945,7 +947,7 @@ struct custom_mutator { /** * Deinitialize the custom mutator. * - * @param data pointer returned in afl_custom_init for this fuzz case + * @param data pointer returned in afl_custom_init by this custom mutator */ void (*afl_custom_deinit)(void *data); diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 9ac4403b..8760194c 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -111,6 +111,37 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, } +static const char *custom_describe_py(void * py_mutator, + size_t max_description_len) { + + PyObject *py_args, *py_value; + + py_args = PyTuple_New(1); + + PyLong_FromSize_t(max_description_len); + + /* add_buf */ + py_value = PyLong_FromSize_t(max_description_len); + if (!py_value) { + + Py_DECREF(py_args); + FATAL("Failed to convert arguments"); + + } + + PyTuple_SetItem(py_args, 0, py_value); + + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DESCRIBE], py_args); + + Py_DECREF(py_args); + + if (py_value != NULL) { return PyBytes_AsString(py_value); } + + return NULL; + +} + static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { (void)afl; @@ -156,6 +187,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); if (!py_functions[PY_FUNC_FUZZ]) py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate"); + py_functions[PY_FUNC_DESCRIBE] = + PyObject_GetAttrString(py_module, "describe"); py_functions[PY_FUNC_FUZZ_COUNT] = PyObject_GetAttrString(py_module, "fuzz_count"); if (!py_functions[PY_FUNC_FUZZ]) @@ -342,6 +375,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, if (py_functions[PY_FUNC_FUZZ]) { mutator->afl_custom_fuzz = fuzz_py; } + if (py_functions[PY_FUNC_DESCRIBE]) { + + mutator->afl_custom_describe = custom_describe_py; + + } + if (py_functions[PY_FUNC_POST_PROCESS]) { mutator->afl_custom_post_process = post_process_py; -- cgit 1.4.1 From 1dbefc14eae4f7a189851785aa3f0982af4236f2 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 4 Dec 2020 14:25:18 +0100 Subject: fixed bugs in custom_describe, reported by wizche --- include/afl-fuzz.h | 2 +- src/afl-fuzz-bitmap.c | 21 +++++++++++++-------- src/afl-fuzz-run.c | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4efa1a6c..bdf44def 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1023,7 +1023,7 @@ void classify_counts(afl_forkserver_t *); void init_count_class16(void); void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES -u8 *describe_op(afl_state_t *, u8); +u8 *describe_op(afl_state_t *, u8, size_t); #endif u8 save_if_interesting(afl_state_t *, void *, u32, u8); u8 has_new_bits(afl_state_t *, u8 *); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index a78bf374..f920efa4 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -425,8 +425,10 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { /* Construct a file name for a new test case, capturing the operation that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */ -u8 *describe_op(afl_state_t *afl, u8 new_bits) { +u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { + size_t real_max_len = + MIN(max_description_len, sizeof(afl->describe_op_buf_256)); u8 *ret = afl->describe_op_buf_256; if (unlikely(afl->syncing_party)) { @@ -453,10 +455,9 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits) { size_t len_current = strlen(ret); ret[len_current++] = ','; - ret[len_current++] = '\0'; + ret[len_current] = '\0'; - size_t size_left = - sizeof(afl->describe_op_buf_256) - len_current - strlen(",+cov") - 2; + size_t size_left = real_max_len - len_current - strlen(",+cov") - 2; assert(size_left > 0); const char *custom_description = @@ -504,6 +505,8 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits) { if (new_bits == 2) { strcat(ret, ",+cov"); } + assert(strlen(ret) <= max_description_len); + return ret; } @@ -610,8 +613,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, - afl->queued_paths, describe_op(afl, new_bits)); + queue_fn = alloc_printf( + "%s/queue/id:%06u,%s", afl->out_dir, afl->queued_paths, + describe_op(afl, new_bits, NAME_MAX - strlen("id:000000,"))); #else @@ -777,7 +781,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir, - afl->unique_hangs, describe_op(afl, 0)); + afl->unique_hangs, + describe_op(afl, 0, NAME_MAX - strlen("id:000000,"))); #else @@ -822,7 +827,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, afl->unique_crashes, afl->fsrv.last_kill_signal, - describe_op(afl, 0)); + describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,"))); #else diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index b716b8c8..5948d83a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -79,7 +79,8 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) { s32 doc_fd; char fn[PATH_MAX]; snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir, - afl->document_counter++, describe_op(afl, 0)); + afl->document_counter++, + describe_op(afl, 0, NAME_MAX - strlen("000000000:"))); if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) { -- cgit 1.4.1 From 06ec5ab3d723bf7f0a2ee76be8b12c09fa870a9d Mon Sep 17 00:00:00 2001 From: Marcel Boehme Date: Mon, 7 Dec 2020 21:32:25 +0000 Subject: Sampling next seed by weight (hit_count, bitmap_size, exec_us) --- include/afl-fuzz.h | 3 ++- src/afl-fuzz-one.c | 6 ++++-- src/afl-fuzz-queue.c | 39 ++++++++++++++++++++++++++++++++------- 3 files changed, 38 insertions(+), 10 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index bdf44def..6ce032df 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -168,7 +168,8 @@ struct queue_entry { u8 *trace_mini; /* Trace bytes, if kept */ u32 tc_ref; /* Trace bytes ref count */ - double perf_score; /* performance score */ + double perf_score, /* performance score */ + weight; u8 *testcase_buf; /* The testcase buffer, if loaded. */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ca48f72a..a48afffb 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -445,8 +445,10 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(afl->not_on_tty)) { - ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found)...", - afl->current_entry, afl->queued_paths, afl->unique_crashes); + ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found, perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u)...", + afl->current_entry, afl->queued_paths, afl->unique_crashes, + afl->queue_cur->perf_score, afl->queue_cur->exec_us, + afl->n_fuzz[afl->queue_cur->n_fuzz_entry], afl->queue_cur->bitmap_size); fflush(stdout); } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f35b4f57..1e997c55 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -42,6 +42,21 @@ inline u32 select_next_queue_entry(afl_state_t *afl) { } +double compute_weight(afl_state_t *afl, struct queue_entry *q, double avg_exec_us, double avg_bitmap_size) { + + u32 hits = afl->n_fuzz[q->n_fuzz_entry]; + if (hits == 0) hits = 1; + + double weight = 1.0; + weight *= avg_exec_us / q->exec_us; + weight *= log(q->bitmap_size) / avg_bitmap_size; + weight /= log10(hits) + 1; + + if (q->favored) weight *= 5; + + return weight; +} + /* create the alias table that allows weighted random selection - expensive */ void create_alias_table(afl_state_t *afl) { @@ -65,25 +80,35 @@ void create_alias_table(afl_state_t *afl) { memset((void *)afl->alias_table, 0, n * sizeof(u32)); memset((void *)afl->alias_probability, 0, n * sizeof(double)); - double sum = 0; - + double avg_exec_us = 0.0; + double avg_bitmap_size = 0.0; for (i = 0; i < n; i++) { struct queue_entry *q = afl->queue_buf[i]; - - if (!q->disabled) { q->perf_score = calculate_score(afl, q); } - - sum += q->perf_score; + avg_exec_us += q->exec_us; + avg_bitmap_size += log(q->bitmap_size); } + avg_exec_us /= afl->queued_paths; + avg_bitmap_size /= afl->queued_paths; + double sum = 0; for (i = 0; i < n; i++) { struct queue_entry *q = afl->queue_buf[i]; - P[i] = (q->perf_score * n) / sum; + + if (!q->disabled) { + q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size); + q->perf_score = calculate_score(afl, q); + } + + sum += q->weight; } + for (i = 0; i < n; i++) + P[i] = (afl->queue_buf[i]->weight * n) / sum; + int nS = 0, nL = 0, s; for (s = (s32)n - 1; s >= 0; --s) { -- cgit 1.4.1 From 46156957bd120dc8d8bcd9da72f83574902c654f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 8 Dec 2020 11:07:11 +0100 Subject: fix aflfast changes --- include/afl-fuzz.h | 2 +- src/afl-fuzz-one.c | 11 +++-- src/afl-fuzz-queue.c | 73 ++++++++++++++++++++++++---------- utils/aflpp_driver/aflpp_qemu_driver.c | 2 +- 4 files changed, 61 insertions(+), 27 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 6ce032df..2f2d31d3 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -169,7 +169,7 @@ struct queue_entry { u32 tc_ref; /* Trace bytes ref count */ double perf_score, /* performance score */ - weight; + weight; u8 *testcase_buf; /* The testcase buffer, if loaded. */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index a48afffb..e6fa6064 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -445,10 +445,13 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(afl->not_on_tty)) { - ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found, perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u)...", - afl->current_entry, afl->queued_paths, afl->unique_crashes, - afl->queue_cur->perf_score, afl->queue_cur->exec_us, - afl->n_fuzz[afl->queue_cur->n_fuzz_entry], afl->queue_cur->bitmap_size); + ACTF( + "Fuzzing test case #%u (%u total, %llu uniq crashes found, " + "perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u)...", + afl->current_entry, afl->queued_paths, afl->unique_crashes, + afl->queue_cur->perf_score, afl->queue_cur->exec_us, + likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0, + afl->queue_cur->bitmap_size); fflush(stdout); } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 1e997c55..071e4a4c 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -42,7 +42,8 @@ inline u32 select_next_queue_entry(afl_state_t *afl) { } -double compute_weight(afl_state_t *afl, struct queue_entry *q, double avg_exec_us, double avg_bitmap_size) { +double compute_weight(afl_state_t *afl, struct queue_entry *q, + double avg_exec_us, double avg_bitmap_size) { u32 hits = afl->n_fuzz[q->n_fuzz_entry]; if (hits == 0) hits = 1; @@ -55,13 +56,15 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, double avg_exec_u if (q->favored) weight *= 5; return weight; + } /* create the alias table that allows weighted random selection - expensive */ void create_alias_table(afl_state_t *afl) { - u32 n = afl->queued_paths, i = 0, a, g; + u32 n = afl->queued_paths, i = 0, a, g; + double sum = 0; afl->alias_table = (u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32)); @@ -80,34 +83,62 @@ void create_alias_table(afl_state_t *afl) { memset((void *)afl->alias_table, 0, n * sizeof(u32)); memset((void *)afl->alias_probability, 0, n * sizeof(double)); - double avg_exec_us = 0.0; - double avg_bitmap_size = 0.0; - for (i = 0; i < n; i++) { + if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) { - struct queue_entry *q = afl->queue_buf[i]; - avg_exec_us += q->exec_us; - avg_bitmap_size += log(q->bitmap_size); + double avg_exec_us = 0.0; + double avg_bitmap_size = 0.0; + for (i = 0; i < n; i++) { - } - avg_exec_us /= afl->queued_paths; - avg_bitmap_size /= afl->queued_paths; + struct queue_entry *q = afl->queue_buf[i]; + avg_exec_us += q->exec_us; + avg_bitmap_size += log(q->bitmap_size); - double sum = 0; - for (i = 0; i < n; i++) { + } + + avg_exec_us /= afl->queued_paths; + avg_bitmap_size /= afl->queued_paths; + + for (i = 0; i < n; i++) { - struct queue_entry *q = afl->queue_buf[i]; + struct queue_entry *q = afl->queue_buf[i]; + + if (!q->disabled) { + + q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size); + q->perf_score = calculate_score(afl, q); + + } + + sum += q->weight; - if (!q->disabled) { - q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size); - q->perf_score = calculate_score(afl, q); } - sum += q->weight; + for (i = 0; i < n; i++) { - } + P[i] = (afl->queue_buf[i]->weight * n) / sum; + + } + + } else { + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + + if (!q->disabled) { q->perf_score = calculate_score(afl, q); } + + sum += q->perf_score; - for (i = 0; i < n; i++) - P[i] = (afl->queue_buf[i]->weight * n) / sum; + } + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + P[i] = (q->perf_score * n) / sum; + + } + + } int nS = 0, nL = 0, s; for (s = (s32)n - 1; s >= 0; --s) { diff --git a/utils/aflpp_driver/aflpp_qemu_driver.c b/utils/aflpp_driver/aflpp_qemu_driver.c index cb3b86d0..a0c02833 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver.c +++ b/utils/aflpp_driver/aflpp_qemu_driver.c @@ -7,7 +7,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); #define kMaxAflInputSize (1 * 1024 * 1024); -static uint8_t AflInputBuf[kMaxAflInputSize]; +static uint8_t AflInputBuf[kMaxAflInputSize]; void __attribute__((noinline)) afl_qemu_driver_stdin_input(void) { -- cgit 1.4.1 From d07b0169cb6137e4620db63b144e46e140b7437d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 17 Dec 2020 10:55:33 +0100 Subject: skim import --- GNUmakefile | 37 ++++--- include/afl-fuzz.h | 9 +- src/afl-fuzz-bitmap.c | 284 ++++++++++++++------------------------------------ src/afl-fuzz-run.c | 6 +- 4 files changed, 105 insertions(+), 231 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index 5c82279b..af85be06 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -42,8 +42,8 @@ endif ifdef ASAN_BUILD $(info Compiling ASAN version of binaries) - override CFLAGS+=$(ASAN_CFLAGS) - LDFLAGS+=$(ASAN_LDFLAGS) + override CFLAGS += $(ASAN_CFLAGS) + LDFLAGS += $(ASAN_LDFLAGS) endif ifdef UBSAN_BUILD $(info Compiling UBSAN version of binaries) @@ -77,30 +77,34 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants - SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli endif +ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + ifndef SOURCE_DATE_EPOCH + HAVE_MARCHNATIVE = 1 + CFLAGS_OPT += -march=native + endif +endif + ifneq "$(shell uname)" "Darwin" - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -march=native -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" - ifndef SOURCE_DATE_EPOCH - #CFLAGS_OPT += -march=native - SPECIAL_PERFORMANCE += -march=native - endif - endif + ifeq "$(HAVE_MARCHNATIVE)" "1" + SPECIAL_PERFORMANCE += -march=native + endif # OS X does not like _FORTIFY_SOURCE=2 - ifndef DEBUG - CFLAGS_OPT += -D_FORTIFY_SOURCE=2 - endif + ifndef DEBUG + CFLAGS_OPT += -D_FORTIFY_SOURCE=2 + endif endif ifeq "$(shell uname)" "SunOS" - CFLAGS_OPT += -Wno-format-truncation - LDFLAGS=-lkstat -lrt + CFLAGS_OPT += -Wno-format-truncation + LDFLAGS = -lkstat -lrt endif ifdef STATIC $(info Compiling static version of binaries, disabling python though) # Disable python for static compilation to simplify things - PYTHON_OK=0 + PYTHON_OK = 0 PYFLAGS= - PYTHON_INCLUDE=/ + PYTHON_INCLUDE = / CFLAGS_OPT += -static LDFLAGS += -lm -lpthread -lz -lutil @@ -117,6 +121,7 @@ ifdef INTROSPECTION CFLAGS_OPT += -DINTROSPECTION=1 endif + ifneq "$(shell uname -m)" "x86_64" ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386" ifneq "$(shell uname -m)" "amd64" @@ -131,7 +136,7 @@ ifdef DEBUG $(info Compiling DEBUG version of binaries) CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror else - CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) + CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) endif override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \ diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 2f2d31d3..6e695a97 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1014,14 +1014,9 @@ void write_bitmap(afl_state_t *); u32 count_bits(afl_state_t *, u8 *); u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); -#ifdef WORD_SIZE_64 -void simplify_trace(afl_state_t *, u64 *); -void classify_counts(afl_forkserver_t *); -#else -void simplify_trace(afl_state_t *, u32 *); -void classify_counts(afl_forkserver_t *); -#endif +void simplify_trace(afl_state_t *, u8 *); void init_count_class16(void); +void classify_counts(afl_forkserver_t *fsrv); void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES u8 *describe_op(afl_state_t *, u8, size_t); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index f1ca7400..738ba986 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -49,101 +49,6 @@ void write_bitmap(afl_state_t *afl) { } -/* Check if the current execution path brings anything new to the table. - Update virgin bits to reflect the finds. Returns 1 if the only change is - the hit-count for a particular tuple; 2 if there are new tuples seen. - Updates the map, so subsequent calls will always return 0. - - This function is called after every exec() on a fairly large buffer, so - it needs to be fast. We do this in 32-bit and 64-bit flavors. */ - -u8 __attribute__((hot)) has_new_bits(afl_state_t *afl, u8 *virgin_map) { - -#ifdef WORD_SIZE_64 - - u64 *current = (u64 *)afl->fsrv.trace_bits; - u64 *virgin = (u64 *)virgin_map; - - u32 i = (afl->fsrv.map_size >> 3); - -#else - - u32 *current = (u32 *)afl->fsrv.trace_bits; - u32 *virgin = (u32 *)virgin_map; - - u32 i = (afl->fsrv.map_size >> 2); - -#endif /* ^WORD_SIZE_64 */ - // the map size must be a minimum of 8 bytes. - // for variable/dynamic map sizes this is ensured in the forkserver - - u8 ret = 0; - - while (i--) { - - /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap - that have not been already cleared from the virgin map - since this will - almost always be the case. */ - - // the (*current) is unnecessary but speeds up the overall comparison - if (unlikely(*current) && unlikely(*current & *virgin)) { - - if (likely(ret < 2)) { - - u8 *cur = (u8 *)current; - u8 *vir = (u8 *)virgin; - - /* Looks like we have not found any new bytes yet; see if any non-zero - bytes in current[] are pristine in virgin[]. */ - -#ifdef WORD_SIZE_64 - - if (*virgin == 0xffffffffffffffff || (cur[0] && vir[0] == 0xff) || - (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) || - (cur[3] && vir[3] == 0xff) || (cur[4] && vir[4] == 0xff) || - (cur[5] && vir[5] == 0xff) || (cur[6] && vir[6] == 0xff) || - (cur[7] && vir[7] == 0xff)) { - - ret = 2; - - } else { - - ret = 1; - - } - -#else - - if (*virgin == 0xffffffff || (cur[0] && vir[0] == 0xff) || - (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) || - (cur[3] && vir[3] == 0xff)) - ret = 2; - else - ret = 1; - -#endif /* ^WORD_SIZE_64 */ - - } - - *virgin &= ~*current; - - } - - ++current; - ++virgin; - - } - - if (unlikely(ret) && likely(virgin_map == afl->virgin_bits)) { - - afl->bitmap_changed = 1; - - } - - return ret; - -} - /* Count the number of bits set in the provided bitmap. Used for the status screen several times every second, does not have to be fast. */ @@ -242,77 +147,11 @@ const u8 simplify_lookup[256] = { }; -#ifdef WORD_SIZE_64 - -void simplify_trace(afl_state_t *afl, u64 *mem) { - - u32 i = (afl->fsrv.map_size >> 3); - - while (i--) { - - /* Optimize for sparse bitmaps. */ - - if (unlikely(*mem)) { - - u8 *mem8 = (u8 *)mem; - - mem8[0] = simplify_lookup[mem8[0]]; - mem8[1] = simplify_lookup[mem8[1]]; - mem8[2] = simplify_lookup[mem8[2]]; - mem8[3] = simplify_lookup[mem8[3]]; - mem8[4] = simplify_lookup[mem8[4]]; - mem8[5] = simplify_lookup[mem8[5]]; - mem8[6] = simplify_lookup[mem8[6]]; - mem8[7] = simplify_lookup[mem8[7]]; - - } else { - - *mem = 0x0101010101010101ULL; - - } - - ++mem; - - } - -} - -#else - -void simplify_trace(afl_state_t *afl, u32 *mem) { - - u32 i = (afl->fsrv.map_size >> 2); - - while (i--) { - - /* Optimize for sparse bitmaps. */ - - if (unlikely(*mem)) { - - u8 *mem8 = (u8 *)mem; - - mem8[0] = simplify_lookup[mem8[0]]; - mem8[1] = simplify_lookup[mem8[1]]; - mem8[2] = simplify_lookup[mem8[2]]; - mem8[3] = simplify_lookup[mem8[3]]; - - } else - - *mem = 0x01010101; - - ++mem; - - } - -} - -#endif /* ^WORD_SIZE_64 */ - /* Destructively classify execution counts in a trace. This is used as a preprocessing step for any newly acquired traces. Called on every exec, must be fast. */ -static const u8 count_class_lookup8[256] = { +const u8 count_class_lookup8[256] = { [0] = 0, [1] = 1, @@ -326,7 +165,7 @@ static const u8 count_class_lookup8[256] = { }; -static u16 count_class_lookup16[65536]; +u16 count_class_lookup16[65536]; void init_count_class16(void) { @@ -345,63 +184,87 @@ void init_count_class16(void) { } -#ifdef WORD_SIZE_64 +/* Import coverage processing routines. */ -void __attribute__((hot)) classify_counts(afl_forkserver_t *fsrv) { +#ifdef WORD_SIZE_64 + #include "coverage-64.h" +#else + #include "coverage-32.h" +#endif - u64 *mem = (u64 *)fsrv->trace_bits; +/* Check if the current execution path brings anything new to the table. + Update virgin bits to reflect the finds. Returns 1 if the only change is + the hit-count for a particular tuple; 2 if there are new tuples seen. + Updates the map, so subsequent calls will always return 0. - u32 i = (fsrv->map_size >> 3); + This function is called after every exec() on a fairly large buffer, so + it needs to be fast. We do this in 32-bit and 64-bit flavors. */ - while (i--) { +inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { - /* Optimize for sparse bitmaps. */ +#ifdef WORD_SIZE_64 - if (unlikely(*mem)) { + u64 *current = (u64 *)afl->fsrv.trace_bits; + u64 *virgin = (u64 *)virgin_map; - u16 *mem16 = (u16 *)mem; + u32 i = (afl->fsrv.map_size >> 3); - mem16[0] = count_class_lookup16[mem16[0]]; - mem16[1] = count_class_lookup16[mem16[1]]; - mem16[2] = count_class_lookup16[mem16[2]]; - mem16[3] = count_class_lookup16[mem16[3]]; +#else - } + u32 *current = (u32 *)afl->fsrv.trace_bits; + u32 *virgin = (u32 *)virgin_map; - ++mem; + u32 i = (afl->fsrv.map_size >> 2); - } +#endif /* ^WORD_SIZE_64 */ -} + u8 ret = 0; + while (i--) { -#else + if (unlikely(*current)) discover_word(&ret, current, virgin); -void __attribute__((hot)) classify_counts(afl_forkserver_t *fsrv) { + current++; + virgin++; - u32 *mem = (u32 *)fsrv->trace_bits; + } - u32 i = (fsrv->map_size >> 2); + if (unlikely(ret) && likely(virgin_map == afl->virgin_bits)) + afl->bitmap_changed = 1; - while (i--) { + return ret; - /* Optimize for sparse bitmaps. */ +} - if (unlikely(*mem)) { +/* A combination of classify_counts and has_new_bits. If 0 is returned, then the + * trace bits are kept as-is. Otherwise, the trace bits are overwritten with + * classified values. + * + * This accelerates the processing: in most cases, no interesting behavior + * happen, and the trace bits will be discarded soon. This function optimizes + * for such cases: one-pass scan on trace bits without modifying anything. Only + * on rare cases it fall backs to the slow path: classify_counts() first, then + * return has_new_bits(). */ - u16 *mem16 = (u16 *)mem; +inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) { - mem16[0] = count_class_lookup16[mem16[0]]; - mem16[1] = count_class_lookup16[mem16[1]]; + /* Handle the hot path first: no new coverage */ + u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size; - } +#ifdef WORD_SIZE_64 - ++mem; + if (!skim((u64 *)virgin_map, (u64 *)afl->fsrv.trace_bits, (u64 *)end)) + return 0; - } +#else -} + if (!skim((u32 *)virgin_map, (u32 *)afl->fsrv.trace_bits, (u32 *)end)) + return 0; #endif /* ^WORD_SIZE_64 */ + classify_counts(&afl->fsrv); + return has_new_bits(afl, virgin_map); + +} /* Compact trace bytes into a smaller bitmap. We effectively just drop the count information here. This is called only sporadically, for some @@ -581,7 +444,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 *queue_fn = ""; u8 new_bits = '\0'; s32 fd; - u8 keeping = 0, res; + u8 keeping = 0, res, classified = 0; u64 cksum = 0; u8 fn[PATH_MAX]; @@ -605,13 +468,17 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { /* Keep only if there are new bits in the map, add to queue for future fuzzing, etc. */ - if (!(new_bits = has_new_bits(afl, afl->virgin_bits))) { + new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); + + if (likely(!new_bits)) { if (unlikely(afl->crash_mode)) { ++afl->total_crashes; } return 0; } + classified = new_bits; + #ifndef SIMPLE_FILES queue_fn = alloc_printf( @@ -715,11 +582,14 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (likely(!afl->non_instrumented_mode)) { -#ifdef WORD_SIZE_64 - simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); -#else - simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); -#endif /* ^WORD_SIZE_64 */ + if (!classified) { + + classify_counts(&afl->fsrv); + classified = 1; + + } + + simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_tmout)) { return keeping; } @@ -764,6 +634,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 new_fault; write_to_testcase(afl, mem, len); new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout); + classify_counts(&afl->fsrv); /* A corner case that one user reported bumping into: increasing the timeout actually uncovers a crash. Make sure we don't discard it if @@ -812,11 +683,14 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (likely(!afl->non_instrumented_mode)) { -#ifdef WORD_SIZE_64 - simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); -#else - simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); -#endif /* ^WORD_SIZE_64 */ + if (!classified) { + + classify_counts(&afl->fsrv); + classified = 1; + + } + + simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a97ceb89..60086bd6 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -62,8 +62,6 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { time_spent_start = (spec.tv_sec * 1000000000) + spec.tv_nsec; #endif - // TODO: Don't classify for faults? - classify_counts(fsrv); return res; } @@ -379,6 +377,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } + classify_counts(&afl->fsrv); cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (q->exec_cksum != cksum) { @@ -767,13 +766,14 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); - ++afl->trim_execs; if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ + ++afl->trim_execs; + classify_counts(&afl->fsrv); cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); /* If the deletion had no impact on the trace, make it permanent. This -- cgit 1.4.1 From 0011f2047bdd3e1adc25de4388edd609dc27bc85 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 18 Dec 2020 09:33:52 +0100 Subject: merge romu and skim --- include/afl-fuzz.h | 13 ++-- include/coverage-32.h | 109 +++++++++++++++++++++++++++++ include/coverage-64.h | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/afl-performance.c | 124 ++++++++------------------------- 4 files changed, 331 insertions(+), 101 deletions(-) create mode 100644 include/coverage-32.h create mode 100644 include/coverage-64.h (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 6e695a97..31c19287 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -134,6 +134,12 @@ // Little helper to access the ptr to afl->##name_buf - for use in afl_realloc. #define AFL_BUF_PARAM(name) ((void **)&afl->name##_buf) +#ifdef WORD_SIZE_64 + #define AFL_RAND_RETURN u64 +#else + #define AFL_RAND_RETURN u32 +#endif + extern s8 interesting_8[INTERESTING_8_LEN]; extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN]; extern s32 @@ -580,7 +586,7 @@ typedef struct afl_state { u32 rand_cnt; /* Random number counter */ - u64 rand_seed[4]; + u64 rand_seed[3]; s64 init_seed; u64 total_cal_us, /* Total calibration time (us) */ @@ -1015,8 +1021,8 @@ u32 count_bits(afl_state_t *, u8 *); u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); void simplify_trace(afl_state_t *, u8 *); +void classify_counts(afl_forkserver_t *); void init_count_class16(void); -void classify_counts(afl_forkserver_t *fsrv); void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES u8 *describe_op(afl_state_t *, u8, size_t); @@ -1106,8 +1112,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, u64 exec_cksum); -/* xoshiro256** */ -uint64_t rand_next(afl_state_t *afl); +AFL_RAND_RETURN rand_next(afl_state_t *afl); /* probability between 0.0 and 1.0 */ double rand_next_percent(afl_state_t *afl); diff --git a/include/coverage-32.h b/include/coverage-32.h new file mode 100644 index 00000000..710ff0cf --- /dev/null +++ b/include/coverage-32.h @@ -0,0 +1,109 @@ +#include "config.h" +#include "types.h" + +inline u32 classify_word(u32 word) { + + u16 mem16[2]; + memcpy(mem16, &word, sizeof(mem16)); + + mem16[0] = count_class_lookup16[mem16[0]]; + mem16[1] = count_class_lookup16[mem16[1]]; + + memcpy(&word, mem16, sizeof(mem16)); + return word; + +} + +void simplify_trace(afl_state_t *afl, u8 *bytes) { + + u32 *mem = (u32 *)fsrv->trace_bits; + u32 i = (fsrv->map_size >> 2); + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { + + u8 *mem8 = (u8 *)mem; + + mem8[0] = simplify_lookup[mem8[0]]; + mem8[1] = simplify_lookup[mem8[1]]; + mem8[2] = simplify_lookup[mem8[2]]; + mem8[3] = simplify_lookup[mem8[3]]; + + } else + + *mem = 0x01010101; + + mem++; + + } + +} + +inline void classify_counts(u8 *bytes) { + + u64 *mem = (u64 *)bytes; + u32 i = MAP_SIZE >> 2; + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { *mem = classify_word(*mem); } + + mem++; + + } + +} + +/* Updates the virgin bits, then reflects whether a new count or a new tuple is + * seen in ret. */ +inline void discover_word(u8 *ret, u32 *current, u32 *virgin) { + + /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap + that have not been already cleared from the virgin map - since this will + almost always be the case. */ + + if (*current & *virgin) { + + if (likely(*ret < 2)) { + + u8 *cur = (u8 *)current; + u8 *vir = (u8 *)virgin; + + /* Looks like we have not found any new bytes yet; see if any non-zero + bytes in current[] are pristine in virgin[]. */ + + if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || + (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff)) + *ret = 2; + else + *ret = 1; + + } + + *virgin &= ~*current; + + } + +} + +#define PACK_SIZE 16 +inline u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end) { + + for (; current != current_end; virgin += 4, current += 4) { + + if (current[0] && classify_word(current[0]) & virgin[0]) return 1; + if (current[1] && classify_word(current[1]) & virgin[1]) return 1; + if (current[2] && classify_word(current[2]) & virgin[2]) return 1; + if (current[3] && classify_word(current[3]) & virgin[3]) return 1; + + } + + return 0; + +} + diff --git a/include/coverage-64.h b/include/coverage-64.h new file mode 100644 index 00000000..54cf0073 --- /dev/null +++ b/include/coverage-64.h @@ -0,0 +1,186 @@ +#include "config.h" +#include "types.h" + +#if (defined(__AVX512F__) && defined(__AVX512DQ__)) || defined(__AVX2__) + #include +#endif + +inline u64 classify_word(u64 word) { + + u16 mem16[4]; + memcpy(mem16, &word, sizeof(mem16)); + + mem16[0] = count_class_lookup16[mem16[0]]; + mem16[1] = count_class_lookup16[mem16[1]]; + mem16[2] = count_class_lookup16[mem16[2]]; + mem16[3] = count_class_lookup16[mem16[3]]; + + memcpy(&word, mem16, sizeof(mem16)); + return word; + +} + +void simplify_trace(afl_state_t *afl, u8 *bytes) { + + u64 *mem = (u64 *)bytes; + u32 i = (afl->fsrv.map_size >> 3); + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { + + u8 *mem8 = (u8 *)mem; + + mem8[0] = simplify_lookup[mem8[0]]; + mem8[1] = simplify_lookup[mem8[1]]; + mem8[2] = simplify_lookup[mem8[2]]; + mem8[3] = simplify_lookup[mem8[3]]; + mem8[4] = simplify_lookup[mem8[4]]; + mem8[5] = simplify_lookup[mem8[5]]; + mem8[6] = simplify_lookup[mem8[6]]; + mem8[7] = simplify_lookup[mem8[7]]; + + } else + + *mem = 0x0101010101010101ULL; + + mem++; + + } + +} + +inline void classify_counts(afl_forkserver_t *fsrv) { + + u64 *mem = (u64 *)fsrv->trace_bits; + u32 i = (fsrv->map_size >> 3); + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { *mem = classify_word(*mem); } + + mem++; + + } + +} + +/* Updates the virgin bits, then reflects whether a new count or a new tuple is + * seen in ret. */ +inline void discover_word(u8 *ret, u64 *current, u64 *virgin) { + + /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap + that have not been already cleared from the virgin map - since this will + almost always be the case. */ + + if (*current & *virgin) { + + if (likely(*ret < 2)) { + + u8 *cur = (u8 *)current; + u8 *vir = (u8 *)virgin; + + /* Looks like we have not found any new bytes yet; see if any non-zero + bytes in current[] are pristine in virgin[]. */ + + if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || + (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) || + (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) || + (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff)) + *ret = 2; + else + *ret = 1; + + } + + *virgin &= ~*current; + + } + +} + +#if defined(__AVX512F__) && defined(__AVX512DQ__) + #define PACK_SIZE 64 +inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) { + + for (; current != current_end; virgin += 8, current += 8) { + + __m512i value = *(__m512i *)current; + __mmask8 mask = _mm512_testn_epi64_mask(value, value); + + /* All bytes are zero. */ + if (mask == 0xff) continue; + + /* Look for nonzero bytes and check for new bits. */ + #define UNROLL(x) \ + if (!(mask & (1 << x)) && classify_word(current[x]) & virgin[x]) return 1 + UNROLL(0); + UNROLL(1); + UNROLL(2); + UNROLL(3); + UNROLL(4); + UNROLL(5); + UNROLL(6); + UNROLL(7); + #undef UNROLL + + } + + return 0; + +} + +#endif + +#if !defined(PACK_SIZE) && defined(__AVX2__) + #define PACK_SIZE 32 +inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) { + + __m256i zeroes = _mm256_setzero_si256(); + + for (; current != current_end; virgin += 4, current += 4) { + + __m256i value = *(__m256i *)current; + __m256i cmp = _mm256_cmpeq_epi64(value, zeroes); + u32 mask = _mm256_movemask_epi8(cmp); + + /* All bytes are zero. */ + if (mask == (u32)-1) continue; + + /* Look for nonzero bytes and check for new bits. */ + if (!(mask & 0xff) && classify_word(current[0]) & virgin[0]) return 1; + if (!(mask & 0xff00) && classify_word(current[1]) & virgin[1]) return 1; + if (!(mask & 0xff0000) && classify_word(current[2]) & virgin[2]) return 1; + if (!(mask & 0xff000000) && classify_word(current[3]) & virgin[3]) return 1; + + } + + return 0; + +} + +#endif + +#if !defined(PACK_SIZE) + #define PACK_SIZE 32 +inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) { + + for (; current != current_end; virgin += 4, current += 4) { + + if (current[0] && classify_word(current[0]) & virgin[0]) return 1; + if (current[1] && classify_word(current[1]) & virgin[1]) return 1; + if (current[2] && classify_word(current[2]) & virgin[2]) return 1; + if (current[3] && classify_word(current[3]) & virgin[3]) return 1; + + } + + return 0; + +} + +#endif + diff --git a/src/afl-performance.c b/src/afl-performance.c index e070a05e..89b170eb 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -27,45 +27,49 @@ #include "xxhash.h" #undef XXH_INLINE_ALL -/* we use xoshiro256** instead of rand/random because it is 10x faster and has - better randomness properties. */ - -static inline uint64_t rotl(const uint64_t x, int k) { - - return (x << k) | (x >> (64 - k)); - -} - void rand_set_seed(afl_state_t *afl, s64 init_seed) { afl->init_seed = init_seed; afl->rand_seed[0] = hash64((u8 *)&afl->init_seed, sizeof(afl->init_seed), HASH_CONST); afl->rand_seed[1] = afl->rand_seed[0] ^ 0x1234567890abcdef; - afl->rand_seed[2] = afl->rand_seed[0] & 0x0123456789abcdef; - afl->rand_seed[3] = afl->rand_seed[0] | 0x01abcde43f567908; + afl->rand_seed[2] = (afl->rand_seed[0] & 0x1234567890abcdef) ^ + (afl->rand_seed[1] | 0xfedcba9876543210); } -inline uint64_t rand_next(afl_state_t *afl) { +#define ROTL(d, lrot) ((d << (lrot)) | (d >> (8 * sizeof(d) - (lrot)))) - const uint64_t result = - rotl(afl->rand_seed[0] + afl->rand_seed[3], 23) + afl->rand_seed[0]; +#ifdef WORD_SIZE_64 +// romuDuoJr +inline AFL_RAND_RETURN rand_next(afl_state_t *afl) { - const uint64_t t = afl->rand_seed[1] << 17; + AFL_RAND_RETURN xp = afl->rand_seed[0]; + afl->rand_seed[0] = 15241094284759029579u * afl->rand_seed[1]; + afl->rand_seed[1] = afl->rand_seed[1] - xp; + afl->rand_seed[1] = ROTL(afl->rand_seed[1], 27); + return xp; - afl->rand_seed[2] ^= afl->rand_seed[0]; - afl->rand_seed[3] ^= afl->rand_seed[1]; - afl->rand_seed[1] ^= afl->rand_seed[2]; - afl->rand_seed[0] ^= afl->rand_seed[3]; +} - afl->rand_seed[2] ^= t; +#else +// RomuTrio32 +inline AFL_RAND_RETURN rand_next(afl_state_t *afl) { + + AFL_RAND_RETURN xp = afl->rand_seed[0], yp = afl->rand_seed[1], + zp = afl->rand_seed[2]; + afl->rand_seed[0] = 3323815723u * zp; + afl->rand_seed[1] = yp - xp; + afl->rand_seed[1] = ROTL(afl->rand_seed[1], 6); + afl->rand_seed[2] = zp - yp; + afl->rand_seed[2] = ROTL(afl->rand_seed[2], 22); + return xp; - afl->rand_seed[3] = rotl(afl->rand_seed[3], 45); +} - return result; +#endif -} +#undef ROTL /* returns a double between 0.000000000 and 1.000000000 */ @@ -75,80 +79,6 @@ inline double rand_next_percent(afl_state_t *afl) { } -/* This is the jump function for the generator. It is equivalent - to 2^128 calls to rand_next(); it can be used to generate 2^128 - non-overlapping subsequences for parallel computations. */ - -void jump(afl_state_t *afl) { - - static const uint64_t JUMP[] = {0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, - 0xa9582618e03fc9aa, 0x39abdc4529b1661c}; - size_t i, b; - uint64_t s0 = 0; - uint64_t s1 = 0; - uint64_t s2 = 0; - uint64_t s3 = 0; - for (i = 0; i < (sizeof(JUMP) / sizeof(*JUMP)); i++) - for (b = 0; b < 64; b++) { - - if (JUMP[i] & UINT64_C(1) << b) { - - s0 ^= afl->rand_seed[0]; - s1 ^= afl->rand_seed[1]; - s2 ^= afl->rand_seed[2]; - s3 ^= afl->rand_seed[3]; - - } - - rand_next(afl); - - } - - afl->rand_seed[0] = s0; - afl->rand_seed[1] = s1; - afl->rand_seed[2] = s2; - afl->rand_seed[3] = s3; - -} - -/* This is the long-jump function for the generator. It is equivalent to - 2^192 calls to rand_next(); it can be used to generate 2^64 starting points, - from each of which jump() will generate 2^64 non-overlapping - subsequences for parallel distributed computations. */ - -void long_jump(afl_state_t *afl) { - - static const uint64_t LONG_JUMP[] = {0x76e15d3efefdcbbf, 0xc5004e441c522fb3, - 0x77710069854ee241, 0x39109bb02acbe635}; - - size_t i, b; - uint64_t s0 = 0; - uint64_t s1 = 0; - uint64_t s2 = 0; - uint64_t s3 = 0; - for (i = 0; i < (sizeof(LONG_JUMP) / sizeof(*LONG_JUMP)); i++) - for (b = 0; b < 64; b++) { - - if (LONG_JUMP[i] & UINT64_C(1) << b) { - - s0 ^= afl->rand_seed[0]; - s1 ^= afl->rand_seed[1]; - s2 ^= afl->rand_seed[2]; - s3 ^= afl->rand_seed[3]; - - } - - rand_next(afl); - - } - - afl->rand_seed[0] = s0; - afl->rand_seed[1] = s1; - afl->rand_seed[2] = s2; - afl->rand_seed[3] = s3; - -} - /* we switch from afl's murmur implementation to xxh3 as it is 30% faster - and get 64 bit hashes instead of just 32 bit. Less collisions! :-) */ -- cgit 1.4.1 From f0b6576f977d9130285159dff90f5b31b950cb07 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 18 Dec 2020 09:55:47 +0100 Subject: fix --- include/afl-fuzz.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 31c19287..3acb6b93 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1022,6 +1022,7 @@ u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); void simplify_trace(afl_state_t *, u8 *); void classify_counts(afl_forkserver_t *); +u8 has_new_bits_unclassified(afl_state_t *, u8 *); void init_count_class16(void); void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES -- cgit 1.4.1 From ea9db86bb86341e4e2b53c46204e3f86496e6ab9 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 18 Dec 2020 10:20:43 +0100 Subject: mem error fix --- include/afl-fuzz.h | 3 ++- instrumentation/afl-compiler-rt.o.c | 4 ++-- src/afl-forkserver.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 3acb6b93..99647c5b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1022,7 +1022,7 @@ u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); void simplify_trace(afl_state_t *, u8 *); void classify_counts(afl_forkserver_t *); -u8 has_new_bits_unclassified(afl_state_t *, u8 *); +void discover_word(u8 *ret, u64 *current, u64 *virgin); void init_count_class16(void); void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES @@ -1030,6 +1030,7 @@ u8 *describe_op(afl_state_t *, u8, size_t); #endif u8 save_if_interesting(afl_state_t *, void *, u32, u8); u8 has_new_bits(afl_state_t *, u8 *); +u8 has_new_bits_unclassified(afl_state_t *, u8 *); /* Extras */ diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index b1df26db..cddde87c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -236,8 +236,8 @@ static void __afl_map_shm(void) { if (__afl_final_loc) { - if (__afl_final_loc % 8) - __afl_final_loc = (((__afl_final_loc + 7) >> 3) << 3); + if (__afl_final_loc % 32) + __afl_final_loc = (((__afl_final_loc + 31) >> 5) << 5); __afl_map_size = __afl_final_loc; if (__afl_final_loc > MAP_SIZE) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3afb94be..90fa55e9 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -641,11 +641,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } - if (unlikely(tmp_map_size % 8)) { + if (unlikely(tmp_map_size % 32)) { // should not happen WARNF("Target reported non-aligned map size of %u", tmp_map_size); - tmp_map_size = (((tmp_map_size + 8) >> 3) << 3); + tmp_map_size = (((tmp_map_size + 31) >> 5) << 5); } -- cgit 1.4.1 From 7e27448dac2191060320831904f32fe9d572bc3d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 21 Dec 2020 12:19:22 +0100 Subject: another 32 bit fix --- include/afl-fuzz.h | 4 ++++ include/coverage-32.h | 2 +- src/afl-cc.c | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 99647c5b..e2fb0344 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1022,7 +1022,11 @@ u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); void simplify_trace(afl_state_t *, u8 *); void classify_counts(afl_forkserver_t *); +#ifdef WORD_SIZE_64 void discover_word(u8 *ret, u64 *current, u64 *virgin); +#else +void discover_word(u8 *ret, u32 *current, u32 *virgin); +#endif void init_count_class16(void); void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES diff --git a/include/coverage-32.h b/include/coverage-32.h index 124d6ee5..a5cc498c 100644 --- a/include/coverage-32.h +++ b/include/coverage-32.h @@ -47,7 +47,7 @@ void simplify_trace(afl_state_t *afl, u8 *bytes) { inline void classify_counts(afl_forkserver_t *fsrv) { - u64 *mem = (u32 *)fsrv->trace_bits; + u32 *mem = (u32 *)fsrv->trace_bits; u32 i = (fsrv->map_size >> 2); while (i--) { diff --git a/src/afl-cc.c b/src/afl-cc.c index 6f4801de..3b8092a9 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1347,7 +1347,8 @@ int main(int argc, char **argv, char **envp) { "available)\n" " PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n" #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) - " NATIVE: use llvm's native PCGUARD instrumentation (less performant)\n" + " NATIVE: use llvm's native PCGUARD instrumentation (less " + "performant)\n" #endif " CLASSIC: decision target instrumentation (README.llvm.md)\n" " CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n" -- cgit 1.4.1 From 688f4ffb89ebf41a497070e8fcf2927510b66874 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 28 Dec 2020 14:01:48 +0100 Subject: added corpus introspection --- docs/Changelog.md | 1 + include/afl-fuzz.h | 5 +++++ src/afl-fuzz-queue.c | 30 ++++++++++++++++++++++++++++++ src/afl-fuzz-run.c | 4 ++++ 4 files changed, 40 insertions(+) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index a8b8f0af..71846535 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,7 @@ sending a mail to . ### Version ++3.01a (release) + - Mac OS ARM64 support - afl-fuzz - fix crash for very, very fast targets+systems (thanks to mhlakhani for reporting) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e2fb0344..57b0e6cc 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -174,6 +174,10 @@ struct queue_entry { u8 *trace_mini; /* Trace bytes, if kept */ u32 tc_ref; /* Trace bytes ref count */ +#ifdef INTROSPECTION + u32 bitsmap_size; +#endif + double perf_score, /* performance score */ weight; @@ -734,6 +738,7 @@ typedef struct afl_state { char mutation[8072]; char m_tmp[4096]; FILE *introspection_file; + u32 bitsmap_size; #endif } afl_state_t; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 54afa17c..5dc2d70b 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -190,6 +190,32 @@ void create_alias_table(afl_state_t *afl) { while (nS) afl->alias_probability[S[--nS]] = 1; +#ifdef INTROSPECTION + u8 fn[PATH_MAX]; + snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir); + FILE *f = fopen(fn, "a"); + if (f) { + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + fprintf( + f, + "entry=%u name=%s variable=%s disabled=%s len=%u exec_us=%u " + "bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n", + i, q->fname, q->var_behavior ? "true" : "false", + q->disabled ? "true" : "false", q->len, (u32)q->exec_us, + q->bitmap_size, q->bitsmap_size, q->tc_ref, q->weight, q->perf_score); + + } + + fprintf(f, "\n"); + fclose(f); + + } + +#endif + /* fprintf(stderr, " entry alias probability perf_score filename\n"); for (u32 i = 0; i < n; ++i) @@ -398,6 +424,10 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->trace_mini = NULL; q->testcase_buf = NULL; +#ifdef INTROSPECTION + q->bitsmap_size = afl->bitsmap_size; +#endif + if (q->depth > afl->max_depth) { afl->max_depth = q->depth; } if (afl->queue_top) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index d53ba546..339fb9c3 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -380,6 +380,10 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } +#ifdef INTROSPECTION + if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size; +#endif + classify_counts(&afl->fsrv); cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (q->exec_cksum != cksum) { -- cgit 1.4.1 From b0d69f1b6995a9ddc0aebb0c289da79ebd3fc5e9 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Wed, 30 Dec 2020 13:02:11 +0100 Subject: cleanup of hot fix for -s on 32-bit --- include/afl-fuzz.h | 3 ++- src/afl-performance.c | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 57b0e6cc..0bf0aebe 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -590,7 +590,8 @@ typedef struct afl_state { u32 rand_cnt; /* Random number counter */ - u64 rand_seed[3]; +/* unsigned long rand_seed[3]; would also work */ + AFL_RAND_RETURN rand_seed[3]; s64 init_seed; u64 total_cal_us, /* Total calibration time (us) */ diff --git a/src/afl-performance.c b/src/afl-performance.c index 4bca95d6..89b170eb 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -56,13 +56,13 @@ inline AFL_RAND_RETURN rand_next(afl_state_t *afl) { // RomuTrio32 inline AFL_RAND_RETURN rand_next(afl_state_t *afl) { - AFL_RAND_RETURN xp = (u32)afl->rand_seed[0], yp = (u32)afl->rand_seed[1], - zp = (u32)afl->rand_seed[2]; + AFL_RAND_RETURN xp = afl->rand_seed[0], yp = afl->rand_seed[1], + zp = afl->rand_seed[2]; afl->rand_seed[0] = 3323815723u * zp; afl->rand_seed[1] = yp - xp; - afl->rand_seed[1] = ROTL((u32)afl->rand_seed[1], 6); + afl->rand_seed[1] = ROTL(afl->rand_seed[1], 6); afl->rand_seed[2] = zp - yp; - afl->rand_seed[2] = ROTL((u32)afl->rand_seed[2], 22); + afl->rand_seed[2] = ROTL(afl->rand_seed[2], 22); return xp; } -- cgit 1.4.1 From 7e6645d5a25b874b978430eeb7d1ddce1f681d98 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 31 Dec 2020 11:51:10 +0100 Subject: float2double --- include/afl-fuzz.h | 2 +- src/afl-fuzz-stats.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 0bf0aebe..a99e4991 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -645,7 +645,7 @@ typedef struct afl_state { unsigned long long int last_avg_exec_update; u32 last_avg_execs; - float last_avg_execs_saved; + double last_avg_execs_saved; /* foreign sync */ #define FOREIGN_SYNCS_MAX 32 diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index cb0d3dcd..1c211da6 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -120,8 +120,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, 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); + (double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) / + (double)(cur_time - afl->last_avg_exec_update); afl->last_avg_execs = afl->fsrv.total_execs; afl->last_avg_exec_update = cur_time; -- cgit 1.4.1 From 880513651d271db538eeb3f04d046cf9ce6021f8 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 3 Jan 2021 10:13:55 +0100 Subject: cmplog cleanup --- include/afl-fuzz.h | 4 ++-- src/afl-fuzz-redqueen.c | 40 +++------------------------------- utils/libdislocator/libdislocator.so.c | 2 +- 3 files changed, 6 insertions(+), 40 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index a99e4991..d6a322cc 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -590,9 +590,9 @@ typedef struct afl_state { u32 rand_cnt; /* Random number counter */ -/* unsigned long rand_seed[3]; would also work */ + /* unsigned long rand_seed[3]; would also work */ AFL_RAND_RETURN rand_seed[3]; - s64 init_seed; + s64 init_seed; u64 total_cal_us, /* Total calibration time (us) */ total_cal_cycles; /* Total calibration cycles */ diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index df215e9c..bbd47ab2 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -99,12 +99,12 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) { } -static void rand_replace(afl_state_t *afl, u8 *buf, u32 len) { +static void xor_replace(u8 *buf, u32 len) { u32 i; for (i = 0; i < len; ++i) { - buf[i] = rand_below(afl, 256); + buf[i] ^= 0xff; } @@ -115,8 +115,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { struct range *ranges = add_range(NULL, 0, len); u8 * backup = ck_alloc_nozero(len); - u8 needs_write = 0; - u64 orig_hit_cnt, new_hit_cnt; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -136,7 +134,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { /* Range not empty */ memcpy(backup, buf + rng->start, s); - rand_replace(afl, buf + rng->start, s); + xor_replace(buf + rng->start, s); u64 cksum; u64 start_us = get_cur_time_us(); @@ -158,10 +156,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); memcpy(buf + rng->start, backup, s); - } else { - - needs_write = 1; - } } @@ -191,32 +185,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { } - // save the input with the high entropy - - if (needs_write) { - - s32 fd; - - if (afl->no_unlink) { - - fd = open(afl->queue_cur->fname, O_WRONLY | O_CREAT | O_TRUNC, 0600); - - } else { - - unlink(afl->queue_cur->fname); /* ignore errors */ - fd = open(afl->queue_cur->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); - - } - - if (fd < 0) { PFATAL("Unable to create '%s'", afl->queue_cur->fname); } - - ck_write(fd, buf, len, afl->queue_cur->fname); - afl->queue_cur->len = len; // no-op, just to be 100% safe - - close(fd); - - } - return 0; checksum_fail: @@ -232,8 +200,6 @@ checksum_fail: } - // TODO: clang notices a _potential_ leak of mem pointed to by rng - return 1; } diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c index c2b200cb..c041fec6 100644 --- a/utils/libdislocator/libdislocator.so.c +++ b/utils/libdislocator/libdislocator.so.c @@ -345,7 +345,7 @@ void free(void *ptr) { len = PTR_L(ptr); total_mem -= len; - u8 * ptr_ = ptr; + u8 *ptr_ = ptr; if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1))) { -- cgit 1.4.1 From c6e038fe25789caa8da777f53154de1bd7b4e178 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Mon, 4 Jan 2021 20:40:53 +0100 Subject: code cleanups (shadowed vars, (un)signed type mismatches, format types, etc.) --- include/afl-fuzz.h | 4 +-- include/config.h | 46 +++++++++++++++--------------- src/afl-analyze.c | 4 +-- src/afl-cc.c | 74 ++++++++++++++++++++++++++++--------------------- src/afl-common.c | 20 ++++++------- src/afl-forkserver.c | 4 +-- src/afl-fuzz-bitmap.c | 2 +- src/afl-fuzz-extras.c | 6 ++-- src/afl-fuzz-mutators.c | 28 ++++++++++++------- src/afl-fuzz-one.c | 24 ++++++++-------- src/afl-fuzz-queue.c | 5 ++-- src/afl-fuzz-redqueen.c | 9 ++++-- src/afl-fuzz-run.c | 2 +- src/afl-fuzz-stats.c | 8 +++--- src/afl-fuzz.c | 8 +++--- src/afl-ld-lto.c | 6 ++-- src/afl-showmap.c | 12 ++++---- src/afl-tmin.c | 4 +-- 18 files changed, 144 insertions(+), 122 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index d6a322cc..ede54f0e 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -573,7 +573,7 @@ typedef struct afl_state { u8 stage_name_buf[STAGE_BUF_SIZE]; /* reused stagename buf with len 64 */ - s32 stage_cur, stage_max; /* Stage progression */ + u32 stage_cur, stage_max; /* Stage progression */ s32 splicing_with; /* Splicing with which test case? */ u32 main_node_id, main_node_max; /* Main instance job splitting */ @@ -648,7 +648,7 @@ typedef struct afl_state { double last_avg_execs_saved; /* foreign sync */ -#define FOREIGN_SYNCS_MAX 32 +#define FOREIGN_SYNCS_MAX 32U u8 foreign_sync_cnt; struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX]; diff --git a/include/config.h b/include/config.h index e8a49270..7c75e9c9 100644 --- a/include/config.h +++ b/include/config.h @@ -80,11 +80,11 @@ /* Default timeout for fuzzed code (milliseconds). This is the upper bound, also used for detecting hangs; the actual value is auto-scaled: */ -#define EXEC_TIMEOUT 1000 +#define EXEC_TIMEOUT 1000U /* Timeout rounding factor when auto-scaling (milliseconds): */ -#define EXEC_TM_ROUND 20 +#define EXEC_TM_ROUND 20U /* 64bit arch MACRO */ #if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__)) @@ -93,48 +93,48 @@ /* Default memory limit for child process (MB) 0 = disabled : */ -#define MEM_LIMIT 0 +#define MEM_LIMIT 0U /* Default memory limit when running in QEMU mode (MB) 0 = disabled : */ -#define MEM_LIMIT_QEMU 0 +#define MEM_LIMIT_QEMU 0U /* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */ -#define MEM_LIMIT_UNICORN 0 +#define MEM_LIMIT_UNICORN 0U /* Number of calibration cycles per every new test case (and for test cases that show variable behavior): */ -#define CAL_CYCLES 8 -#define CAL_CYCLES_LONG 40 +#define CAL_CYCLES 8U +#define CAL_CYCLES_LONG 40U /* Number of subsequent timeouts before abandoning an input file: */ -#define TMOUT_LIMIT 250 +#define TMOUT_LIMIT 250U /* Maximum number of unique hangs or crashes to record: */ -#define KEEP_UNIQUE_HANG 500 -#define KEEP_UNIQUE_CRASH 5000 +#define KEEP_UNIQUE_HANG 500U +#define KEEP_UNIQUE_CRASH 5000U /* Baseline number of random tweaks during a single 'havoc' stage: */ -#define HAVOC_CYCLES 256 -#define HAVOC_CYCLES_INIT 1024 +#define HAVOC_CYCLES 256U +#define HAVOC_CYCLES_INIT 1024U /* Maximum multiplier for the above (should be a power of two, beware of 32-bit int overflows): */ -#define HAVOC_MAX_MULT 64 -#define HAVOC_MAX_MULT_MOPT 64 +#define HAVOC_MAX_MULT 64U +#define HAVOC_MAX_MULT_MOPT 64U /* Absolute minimum number of havoc cycles (after all adjustments): */ -#define HAVOC_MIN 12 +#define HAVOC_MIN 12U /* Power Schedule Divisor */ -#define POWER_BETA 1 +#define POWER_BETA 1U #define MAX_FACTOR (POWER_BETA * 32) /* Maximum stacking for havoc-stage tweaks. The actual value is calculated @@ -146,19 +146,19 @@ In other words, the default (n = 4) produces 2, 4, 8, 16 stacked tweaks: */ -#define HAVOC_STACK_POW2 4 +#define HAVOC_STACK_POW2 4U /* Caps on block sizes for cloning and deletion operations. Each of these ranges has a 33% probability of getting picked, except for the first two cycles where smaller blocks are favored: */ -#define HAVOC_BLK_SMALL 32 -#define HAVOC_BLK_MEDIUM 128 -#define HAVOC_BLK_LARGE 1500 +#define HAVOC_BLK_SMALL 32U +#define HAVOC_BLK_MEDIUM 128U +#define HAVOC_BLK_LARGE 1500U /* Extra-large blocks, selected very rarely (<5% of the time): */ -#define HAVOC_BLK_XL 32768 +#define HAVOC_BLK_XL 32768U /* Probabilities of skipping non-favored entries in the queue, expressed as percentages: */ @@ -188,11 +188,11 @@ /* Maximum size of input file, in bytes (keep under 100MB): */ -#define MAX_FILE (1 * 1024 * 1024) +#define MAX_FILE (1 * 1024 * 1024U) /* The same, for the test case minimizer: */ -#define TMIN_MAX_FILE (10 * 1024 * 1024) +#define TMIN_MAX_FILE (10 * 1024 * 1024U) /* Block normalization steps for afl-tmin: */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 6dac415b..8fc4434a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -903,8 +903,8 @@ static void usage(u8 *argv0) { "Execution control settings:\n" " -f file - input file read by the tested program (stdin)\n" - " -t msec - timeout for each run (%d ms)\n" - " -m megs - memory limit for child process (%d MB)\n" + " -t msec - timeout for each run (%u ms)\n" + " -m megs - memory limit for child process (%u MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " diff --git a/src/afl-cc.c b/src/afl-cc.c index e6a6718e..180ab3c4 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -120,8 +120,10 @@ char compiler_mode_string[7][12] = { u8 *getthecwd() { - static u8 fail[] = ""; - if (getcwd(cwd, sizeof(cwd)) == NULL) return fail; + if (getcwd(cwd, sizeof(cwd)) == NULL) { + static u8 fail[] = ""; + return fail; + } return cwd; } @@ -654,9 +656,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - u32 idx; if (lto_mode && argc > 1) { + u32 idx; for (idx = 1; idx < argc; idx++) { if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1; @@ -1208,12 +1210,12 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRUMENT")) { - u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); + u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); - while (ptr) { + while (ptr2) { - if (strncasecmp(ptr, "afl", strlen("afl")) == 0 || - strncasecmp(ptr, "classic", strlen("classic")) == 0) { + if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 || + strncasecmp(ptr2, "classic", strlen("classic")) == 0) { if (instrument_mode == INSTRUMENT_LTO) { @@ -1229,8 +1231,8 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || - strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) { + if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 || + strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD) instrument_mode = INSTRUMENT_PCGUARD; @@ -1241,8 +1243,8 @@ int main(int argc, char **argv, char **envp) { } // this is a hidden option - if (strncasecmp(ptr, "llvmnative", strlen("llvmnative")) == 0 || - strncasecmp(ptr, "llvm-native", strlen("llvm-native")) == 0) { + if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 || + strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) instrument_mode = INSTRUMENT_LLVMNATIVE; @@ -1252,8 +1254,8 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || - strncasecmp(ptr, "instrim", strlen("instrim")) == 0) { + if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || + strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { if (instrument_mode == INSTRUMENT_LTO) { @@ -1269,7 +1271,7 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "lto", strlen("lto")) == 0) { + if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) { lto_mode = 1; if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) @@ -1280,7 +1282,7 @@ int main(int argc, char **argv, char **envp) { } - if (strcasecmp(ptr, "gcc") == 0) { + if (strcasecmp(ptr2, "gcc") == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_GCC) instrument_mode = INSTRUMENT_GCC; @@ -1291,7 +1293,7 @@ int main(int argc, char **argv, char **envp) { } - if (strcasecmp(ptr, "clang") == 0) { + if (strcasecmp(ptr2, "clang") == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_CLANG) instrument_mode = INSTRUMENT_CLANG; @@ -1302,29 +1304,29 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { + if (strncasecmp(ptr2, "ctx", strlen("ctx")) == 0) { instrument_opt_mode |= INSTRUMENT_OPT_CTX; setenv("AFL_LLVM_CTX", "1", 1); } - if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) { + if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) { - ptr += strlen("ngram"); - while (*ptr && (*ptr < '0' || *ptr > '9')) - ptr++; + ptr2 += strlen("ngram"); + while (*ptr2 && (*ptr2 < '0' || *ptr2 > '9')) + ptr2++; - if (!*ptr) { + if (!*ptr2) { - if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL) + if ((ptr2 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL) FATAL( "you must set the NGRAM size with (e.g. for value 2) " "AFL_LLVM_INSTRUMENT=ngram-2"); } - ngram_size = atoi(ptr); + ngram_size = atoi(ptr2); if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) FATAL( "NGRAM instrumentation option must be between 2 and " @@ -1332,12 +1334,12 @@ int main(int argc, char **argv, char **envp) { "(%u)", NGRAM_SIZE_MAX); instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM); - ptr = alloc_printf("%u", ngram_size); - setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1); + ptr2 = alloc_printf("%u", ngram_size); + setenv("AFL_LLVM_NGRAM_SIZE", ptr2, 1); } - ptr = strtok(NULL, ":,;"); + ptr2 = strtok(NULL, ":,;"); } @@ -1448,20 +1450,28 @@ int main(int argc, char **argv, char **envp) { " The best is LTO but it often needs RANLIB and AR settings outside " "of afl-cc.\n\n"); +#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) +#define NATIVE_MSG \ + " NATIVE: use llvm's native PCGUARD instrumentation (less " \ + "performant)\n" +#else +#define NATIVE_MSG "" +#endif + SAYF( "Sub-Modes: (set via env AFL_LLVM_INSTRUMENT, afl-cc selects the best " "available)\n" " PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n" -#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) - " NATIVE: use llvm's native PCGUARD instrumentation (less " - "performant)\n" -#endif + + NATIVE_MSG + " CLASSIC: decision target instrumentation (README.llvm.md)\n" " CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n" " NGRAM-x: CLASSIC + previous path " "((instrumentation/README.ngram.md)\n" " INSTRIM: Dominator tree (for LLVM <= 6.0) " "(instrumentation/README.instrim.md)\n\n"); +#undef NATIVE_MSG SAYF( "Features: (see documentation links)\n" @@ -1625,7 +1635,7 @@ int main(int argc, char **argv, char **envp) { if (!instrument_mode) { instrument_mode = INSTRUMENT_CFG; - ptr = instrument_mode_string[instrument_mode]; + //ptr = instrument_mode_string[instrument_mode]; } diff --git a/src/afl-common.c b/src/afl-common.c index 1928663d..21cb6ab4 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -696,16 +696,16 @@ u8 *stringify_mem_size(u8 *buf, size_t len, u64 val) { u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms) { - u64 delta; - s32 t_d, t_h, t_m, t_s; - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - if (!event_ms) { snprintf(buf, len, "none seen yet"); } else { + u64 delta; + s32 t_d, t_h, t_m, t_s; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + delta = cur_ms - event_ms; t_d = delta / 1000 / 60 / 60 / 24; @@ -858,16 +858,16 @@ u8 *u_stringify_mem_size(u8 *buf, u64 val) { u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) { - u64 delta; - s32 t_d, t_h, t_m, t_s; - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - if (!event_ms) { sprintf(buf, "none seen yet"); } else { + u64 delta; + s32 t_d, t_h, t_m, t_s; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + delta = cur_ms - event_ms; t_d = delta / 1000 / 60 / 60 / 24; @@ -895,8 +895,8 @@ u32 get_map_size(void) { map_size = atoi(ptr); if (map_size < 8 || map_size > (1 << 29)) { - FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 8, - 1 << 29); + FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 8U, + 1U << 29); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 90fa55e9..d6195cb5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -213,7 +213,7 @@ restart_select: static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { unsigned char tmp[4] = {0, 0, 0, 0}; - pid_t child_pid = -1; + pid_t child_pid; if (!be_quiet) { ACTF("Using Fauxserver:"); } @@ -1104,7 +1104,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, "Unable to communicate with fork server. Some possible reasons:\n\n" " - You've run out of memory. Use -m to increase the the memory " "limit\n" - " to something higher than %lld.\n" + " to something higher than %llu.\n" " - The binary or one of the libraries it uses manages to " "create\n" " threads before the forkserver initializes.\n" diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 62a8211c..85a01f98 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -703,7 +703,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (!classified) { classify_counts(&afl->fsrv); - classified = 1; +// classified = 1; } diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 171cce96..04f0878c 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -266,7 +266,7 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, if (afl->extras_cnt > afl->max_det_extras) { - WARNF("More than %d tokens - will use them probabilistically.", + WARNF("More than %u tokens - will use them probabilistically.", afl->max_det_extras); } @@ -431,7 +431,6 @@ void dedup_extras(afl_state_t *afl) { /* Adds a new extra / dict entry. */ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { - u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; u32 i, found = 0; for (i = 0; i < afl->extras_cnt; i++) { @@ -451,6 +450,7 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { if (len > MAX_DICT_FILE) { + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; WARNF("Extra '%.*s' is too big (%s, limit is %s), skipping file!", (int)len, mem, stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len), stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); @@ -481,7 +481,7 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { if (afl->extras_cnt == afl->max_det_extras + 1) { - WARNF("More than %d tokens - will use them probabilistically.", + WARNF("More than %u tokens - will use them probabilistically.", afl->max_det_extras); } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 0c85458e..5da692d3 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -316,16 +316,20 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, /* Initialize trimming in the custom mutator */ afl->stage_cur = 0; - afl->stage_max = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len); - if (unlikely(afl->stage_max) < 0) { + s32 retval = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len); + if (unlikely(retval) < 0) { - FATAL("custom_init_trim error ret: %d", afl->stage_max); + FATAL("custom_init_trim error ret: %d", retval); + } else { + + afl->stage_max = retval; + } if (afl->not_on_tty && afl->debug) { - SAYF("[Custom Trimming] START: Max %d iterations, %u bytes", afl->stage_max, + SAYF("[Custom Trimming] START: Max %u iterations, %u bytes", afl->stage_max, q->len); } @@ -343,7 +347,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (unlikely(!retbuf)) { - FATAL("custom_trim failed (ret %zd)", retlen); + FATAL("custom_trim failed (ret %zu)", retlen); } else if (unlikely(retlen > orig_len)) { @@ -409,7 +413,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (afl->not_on_tty && afl->debug) { - SAYF("[Custom Trimming] SUCCESS: %d/%d iterations (now at %u bytes)", + SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)", afl->stage_cur, afl->stage_max, q->len); } @@ -417,16 +421,20 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, } else { /* Tell the custom mutator that the trimming was unsuccessful */ - afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 0); - if (unlikely(afl->stage_cur < 0)) { + s32 retval2 = mutator->afl_custom_post_trim(mutator->data, 0); + if (unlikely(retval2 < 0)) { + + FATAL("Error ret in custom_post_trim: %d", retval2); + + } else { - FATAL("Error ret in custom_post_trim: %d", afl->stage_cur); + afl->stage_cur = retval2; } if (afl->not_on_tty && afl->debug) { - SAYF("[Custom Trimming] FAILURE: %d/%d iterations", afl->stage_cur, + SAYF("[Custom Trimming] FAILURE: %u/%u iterations", afl->stage_cur, afl->stage_max); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index e6fa6064..f9509e86 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -368,7 +368,7 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { u8 fuzz_one_original(afl_state_t *afl) { - s32 len, temp_len; + u32 len, temp_len; u32 j; u32 i; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -545,7 +545,7 @@ u8 fuzz_one_original(afl_state_t *afl) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score <= 0)) { goto abandon_entry; } + if (unlikely(perf_score == 0)) { goto abandon_entry; } if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { @@ -902,7 +902,7 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { /* Let's consult the effector map... */ @@ -945,7 +945,7 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; ++i) { + for (i = 0; i < len - 3; ++i) { /* Let's consult the effector map... */ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && @@ -1405,7 +1405,7 @@ skip_arith: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { u16 orig = *(u16 *)(out_buf + i); @@ -1493,7 +1493,7 @@ skip_arith: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; i++) { + for (i = 0; i < len - 3; i++) { u32 orig = *(u32 *)(out_buf + i); @@ -1850,7 +1850,7 @@ custom_mutator_stage: if (unlikely(!mutated_buf)) { - FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); + FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size); } @@ -2026,7 +2026,7 @@ havoc_stage: el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE); if (unlikely(!custom_havoc_buf)) { - FATAL("Error in custom_havoc (return %zd)", new_len); + FATAL("Error in custom_havoc (return %zu)", new_len); } @@ -2458,7 +2458,7 @@ havoc_stage: u32 use_extra = rand_below(afl, afl->a_extras_cnt); u32 extra_len = afl->a_extras[use_extra].len; - if ((s32)extra_len > temp_len) { break; } + if (extra_len > temp_len) { break; } u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION @@ -2476,7 +2476,7 @@ havoc_stage: u32 use_extra = rand_below(afl, afl->extras_cnt); u32 extra_len = afl->extras[use_extra].len; - if ((s32)extra_len > temp_len) { break; } + if (extra_len > temp_len) { break; } u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION @@ -2577,7 +2577,7 @@ havoc_stage: u32 copy_from, copy_to, copy_len; copy_len = choose_block_len(afl, new_len - 1); - if ((s32)copy_len > temp_len) copy_len = temp_len; + 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); @@ -2952,7 +2952,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score <= 0)) { goto abandon_entry; } + if (unlikely(perf_score == 0)) { goto abandon_entry; } if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 9a0d199e..cd41bafc 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -489,11 +489,12 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { void destroy_queue(afl_state_t *afl) { - struct queue_entry *q; u32 i; for (i = 0; i < afl->queued_paths; i++) { + struct queue_entry *q; + q = afl->queue_buf[i]; ck_free(q->fname); ck_free(q->trace_mini); @@ -996,7 +997,7 @@ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, if (unlikely(!q->testcase_buf)) { - PFATAL("Unable to malloc '%s' with len %d", q->fname, len); + PFATAL("Unable to malloc '%s' with len %u", q->fname, len); } diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index c5db8fa1..7dba1caa 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -445,6 +445,9 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { u32 k; u8 cons_ff = 0, cons_0 = 0; + + if (shape > sizeof(v)) FATAL("shape is greater than %zu, please report!", sizeof(v)); + for (k = 0; k < shape; ++k) { if (b[k] == 0) { @@ -453,7 +456,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } else if (b[k] == 0xff) { - ++cons_0; + ++cons_ff; } else { @@ -667,12 +670,12 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { u8 status = 0; // opt not in the paper - u32 fails = 0; +// u32 fails = 0; u8 found_one = 0; for (i = 0; i < loggeds; ++i) { - fails = 0; + u32 fails = 0; struct cmpfn_operands *o = &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i]; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 339fb9c3..11d8204b 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -682,7 +682,7 @@ void sync_fuzzers(afl_state_t *afl) { // same time. If so, the first temporary main node running again will demote // themselves so this is not an issue - u8 path[PATH_MAX]; +// u8 path2[PATH_MAX]; afl->is_main_node = 1; sprintf(path, "%s/is_main_node", afl->out_dir); int fd = open(path, O_CREAT | O_RDWR, 0644); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 1c211da6..c8366174 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -31,7 +31,6 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { - char *val; u8 fn[PATH_MAX]; snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); FILE *f = create_ffile(fn); @@ -44,6 +43,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { for (i = 0; i < s_afl_env; ++i) { + char *val; if ((val = getenv(afl_environment_variables[i])) != NULL) { fprintf(f, "%s=%s\n", afl_environment_variables[i], val); @@ -228,7 +228,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, if (afl->virgin_bits[i] != 0xff) { - fprintf(f, " %d[%02x]", i, afl->virgin_bits[i]); + fprintf(f, " %u[%02x]", i, afl->virgin_bits[i]); } @@ -238,7 +238,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, fprintf(f, "var_bytes :"); for (i = 0; i < afl->fsrv.map_size; i++) { - if (afl->var_bytes[i]) { fprintf(f, " %d", i); } + if (afl->var_bytes[i]) { fprintf(f, " %u", i); } } @@ -1163,7 +1163,7 @@ void show_init_stats(afl_state_t *afl) { } else { - ACTF("-t option specified. We'll use an exec timeout of %d ms.", + ACTF("-t option specified. We'll use an exec timeout of %u ms.", afl->fsrv.exec_tmout); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 897c2f1e..e239b47f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -99,8 +99,8 @@ static void usage(u8 *argv0, int more_help) { " lin, quad> -- see docs/power_schedules.md\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" - " -t msec - timeout for each run (auto-scaled, 50-%d ms)\n" - " -m megs - memory limit for child process (%d MB, 0 = no limit)\n" + " -t msec - timeout for each run (auto-scaled, 50-%u ms)\n" + " -m megs - memory limit for child process (%u MB, 0 = no limit)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -299,7 +299,7 @@ int main(int argc, char **argv_orig, char **envp) { s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/; u64 prev_queued = 0; - u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = MAP_SIZE; + u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = get_map_size(); u8 *extras_dir[4]; u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0 /*, have_p = 0*/; @@ -326,7 +326,7 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; } - map_size = get_map_size(); +// map_size = get_map_size(); afl_state_init(afl, map_size); afl->debug = debug; afl_fsrv_init(&afl->fsrv); diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index fccdb1a5..1d54fda0 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -187,7 +187,7 @@ static void edit_params(int argc, char **argv) { if (debug) DEBUGF( - "passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s " + "passthrough=%s instrim=%u, gold_pos=%u, gold_present=%s " "inst_present=%s rt_present=%s rt_lto_present=%s\n", passthrough ? "true" : "false", instrim, gold_pos, gold_present ? "true" : "false", inst_present ? "true" : "false", @@ -253,10 +253,10 @@ static void edit_params(int argc, char **argv) { int main(int argc, char **argv) { s32 pid, i, status; - u8 * ptr; +// u8 * ptr; char thecwd[PATH_MAX]; - if ((ptr = getenv("AFL_LD_CALLER")) != NULL) { + if (getenv("AFL_LD_CALLER") != NULL) { FATAL("ld loop detected! Set AFL_REAL_LD!\n"); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 355b2dc3..c0223a07 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -662,7 +662,7 @@ static void usage(u8 *argv0) { "Execution control settings:\n" " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%d MB)\n" + " -m megs - memory limit for child process (%u MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine mode)\n" @@ -1014,7 +1014,7 @@ int main(int argc, char **argv_orig, char **envp) { DIR * dir_in, *dir_out = NULL; struct dirent *dir_ent; - int done = 0; +// int done = 0; u8 infile[PATH_MAX], outfile[PATH_MAX]; u8 wait_for_gdb = 0; #if !defined(DT_REG) @@ -1090,11 +1090,11 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) { - int i = optind; + int j = optind; DEBUGF("%s:", fsrv->target_path); - while (argv[i] != NULL) { + while (argv[j] != NULL) { - SAYF(" \"%s\"", argv[i++]); + SAYF(" \"%s\"", argv[j++]); } @@ -1143,7 +1143,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - while (done == 0 && (dir_ent = readdir(dir_in))) { + while ((dir_ent = readdir(dir_in))) { if (dir_ent->d_name[0] == '.') { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index ed928c7c..09d97f58 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -835,8 +835,8 @@ static void usage(u8 *argv0) { "Execution control settings:\n" " -f file - input file read by the tested program (stdin)\n" - " -t msec - timeout for each run (%d ms)\n" - " -m megs - memory limit for child process (%d MB)\n" + " -t msec - timeout for each run (%u ms)\n" + " -m megs - memory limit for child process (%u MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " -- cgit 1.4.1 From 9cdf5c415015e4e80b577c021b8b9fcf8a3d58fb Mon Sep 17 00:00:00 2001 From: buherator Date: Thu, 7 Jan 2021 22:35:34 +0100 Subject: User defined kill signal value (#678) * Adding AFL_KILL_SIGNAL environment variable Controlling the kill signal used to end forked processes. * Checking validity of AFL_KILL_SIGNAL env variable This commit also sets a valid value in the environment to avoid duplicating code in at_exit(). Changing data type of fsrv->kill_signal to u8 to match last_kill_signal. * Adding afl_kill_signal to AFL (environment) state This commit simply introduces a struct member for future use. The env variable is not used from the afl struct but from fsrv, where its validity is checked, resulting in a FATAL in case of errors. --- include/afl-fuzz.h | 2 +- include/envs.h | 1 + include/forkserver.h | 2 ++ src/afl-forkserver.c | 44 +++++++++++++++++++++++++++++++++++++++----- src/afl-fuzz-state.c | 11 +++++++++-- src/afl-fuzz.c | 13 +++++++++++-- 6 files changed, 63 insertions(+), 10 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index ede54f0e..988a907d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -381,7 +381,7 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries; + *afl_testcache_entries, *afl_kill_signal; } afl_env_vars_t; diff --git a/include/envs.h b/include/envs.h index e4e49c4d..97367fae 100644 --- a/include/envs.h +++ b/include/envs.h @@ -61,6 +61,7 @@ static char *afl_environment_variables[] = { "AFL_IMPORT_FIRST", "AFL_INST_LIBS", "AFL_INST_RATIO", + "AFL_KILL_SIGNAL", "AFL_KEEP_TRACES", "AFL_KEEP_ASSEMBLY", "AFL_LD_HARD_FAIL", diff --git a/include/forkserver.h b/include/forkserver.h index 8e029266..3019e289 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -99,6 +99,8 @@ typedef struct afl_forkserver { void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len); + u8 kill_signal; + } afl_forkserver_t; typedef enum fsrv_run_result { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d6195cb5..70fb9572 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -95,6 +95,29 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->uses_asan = false; fsrv->init_child_func = fsrv_exec_child; + fsrv->kill_signal = SIGKILL; + + char *kill_signal_env = get_afl_env("AFL_KILL_SIGNAL"); + if (kill_signal_env) { + + char *endptr; + u8 signal_code; + signal_code = (u8)strtoul(kill_signal_env, &endptr, 10); + /* Did we manage to parse the full string? */ + if (*endptr != '\0' || endptr == kill_signal_env) { + + FATAL("Invalid kill signal value!"); + + } + + fsrv->kill_signal = signal_code; + + } else { + + /* Using hardcoded code for SIGKILL for the sake of simplicity */ + setenv("AFL_KILL_SIGNAL", "9", 1); + + } list_append(&fsrv_list, fsrv); @@ -126,6 +149,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->init_child_func = from->init_child_func; // Note: do not copy ->add_extra_func + fsrv_to->kill_signal = from->kill_signal; + list_append(&fsrv_list, fsrv_to); } @@ -559,12 +584,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!time_ms) { - kill(fsrv->fsrv_pid, SIGKILL); + kill(fsrv->fsrv_pid, fsrv->kill_signal); } else if (time_ms > fsrv->init_tmout) { fsrv->last_run_timed_out = 1; - kill(fsrv->fsrv_pid, SIGKILL); + kill(fsrv->fsrv_pid, fsrv->kill_signal); } else { @@ -944,10 +969,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, static void afl_fsrv_kill(afl_forkserver_t *fsrv) { - if (fsrv->child_pid > 0) { kill(fsrv->child_pid, SIGKILL); } + if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->kill_signal); } if (fsrv->fsrv_pid > 0) { - kill(fsrv->fsrv_pid, SIGKILL); + kill(fsrv->fsrv_pid, fsrv->kill_signal); if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } } @@ -1091,7 +1116,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* If there was no response from forkserver after timeout seconds, we kill the child. The forkserver should inform us afterwards */ - kill(fsrv->child_pid, SIGKILL); + kill(fsrv->child_pid, fsrv->kill_signal); fsrv->last_run_timed_out = 1; if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; } @@ -1137,6 +1162,15 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* Report outcome to caller. */ + /* TODO We use SIGTERM here as an indicator of Xen mode, + although it's not equivalent! */ + if (fsrv->kill_signal == SIGTERM && !*stop_soon_p && + fsrv->last_run_timed_out) { + + return FSRV_RUN_TMOUT; + + } + if (WIFSIGNALED(fsrv->child_status) && !*stop_soon_p) { fsrv->last_kill_signal = WTERMSIG(fsrv->child_status); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 34456c0d..60c9684c 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -418,6 +418,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { (u8 *)get_afl_env(afl_environment_variables[i]); #endif + } else if (!strncmp(env, "AFL_KILL_SIGNAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_kill_signal = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { @@ -524,8 +531,8 @@ void afl_states_stop(void) { LIST_FOREACH(&afl_states, afl_state_t, { - if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL); - if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL); + if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, el->fsrv.kill_signal); + if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, el->fsrv.kill_signal); }); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 063134fb..00625f2e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -76,8 +76,17 @@ static void at_exit() { } - if (pid1 > 0) { kill(pid1, SIGKILL); } - if (pid2 > 0) { kill(pid2, SIGKILL); } + u8 kill_signal = SIGKILL; + + /* AFL_KILL_SIGNAL should already be initialized by afl_fsrv_init() */ + if (getenv("AFL_KILL_SIGNAL")) { + + kill_signal = atoi(getenv("AFL_KILL_SIGNAL")); + + } + + if (pid1 > 0) { kill(pid1, kill_signal); } + if (pid2 > 0) { kill(pid2, kill_signal); } } -- cgit 1.4.1 From a0e884cf8bffe1a0394d106375f6a23edd2b60e6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 15 Jan 2021 16:56:40 +0100 Subject: merge cmplog --- include/afl-fuzz.h | 21 +- include/cmplog.h | 17 +- include/debug.h | 24 +- include/types.h | 43 +- instrumentation/afl-compiler-rt.o.c | 89 +- instrumentation/cmplog-instructions-pass.cc | 586 +++++++++-- src/afl-cc.c | 49 +- src/afl-fuzz-init.c | 38 + src/afl-fuzz-one.c | 81 +- src/afl-fuzz-queue.c | 1 + src/afl-fuzz-redqueen.c | 1437 +++++++++++++++++++++++---- src/afl-fuzz-state.c | 1 + src/afl-fuzz.c | 60 +- 13 files changed, 2055 insertions(+), 392 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 988a907d..8a2122dc 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -145,12 +145,22 @@ extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN]; extern s32 interesting_32[INTERESTING_8_LEN + INTERESTING_16_LEN + INTERESTING_32_LEN]; +struct tainted { + + u32 pos; + u32 len; + struct tainted *next; + struct tainted *prev; + +}; + struct queue_entry { u8 *fname; /* File name for the test case */ u32 len; /* Input length */ - u8 cal_failed; /* Calibration failed? */ + u8 colorized, /* Do not run redqueen stage again */ + cal_failed; /* Calibration failed? */ bool trim_done, /* Trimmed? */ was_fuzzed, /* historical, but needed for MOpt */ passed_det, /* Deterministic stages passed? */ @@ -158,7 +168,6 @@ 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 */ is_ascii, /* Is the input just ascii text? */ disabled; /* Is disabled from fuzz selection */ @@ -183,7 +192,11 @@ struct queue_entry { u8 *testcase_buf; /* The testcase buffer, if loaded. */ - struct queue_entry *next; /* Next element, if any */ + u8 * cmplog_colorinput; /* the result buf of colorization */ + struct tainted *taint; /* Taint information from CmpLog */ + + struct queue_entry *mother, /* queue entry this based on */ + *next; /* Next element, if any */ }; @@ -636,6 +649,8 @@ typedef struct afl_state { /* cmplog forkserver ids */ s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd; u32 cmplog_prev_timed_out; + u32 cmplog_max_filesize; + u32 cmplog_lvl; struct afl_pass_stat *pass_stats; struct cmp_map * orig_cmp_map; diff --git a/include/cmplog.h b/include/cmplog.h index bf557785..6392c503 100644 --- a/include/cmplog.h +++ b/include/cmplog.h @@ -30,8 +30,10 @@ #include "config.h" +#define CMPLOG_LVL_MAX 3 + #define CMP_MAP_W 65536 -#define CMP_MAP_H 256 +#define CMP_MAP_H 32 #define CMP_MAP_RTN_H (CMP_MAP_H / 4) #define SHAPE_BYTES(x) (x + 1) @@ -41,13 +43,12 @@ struct cmp_header { - unsigned hits : 20; - - unsigned cnt : 20; - unsigned id : 16; - - unsigned shape : 5; // from 0 to 31 + unsigned hits : 24; + unsigned id : 24; + unsigned shape : 5; unsigned type : 1; + unsigned attribute : 4; + unsigned reserved : 6; } __attribute__((packed)); @@ -55,6 +56,8 @@ struct cmp_operands { u64 v0; u64 v1; + u64 v0_128; + u64 v1_128; }; diff --git a/include/debug.h b/include/debug.h index ef5b195b..fc1f39cb 100644 --- a/include/debug.h +++ b/include/debug.h @@ -295,8 +295,8 @@ static inline const char *colorfilter(const char *x) { \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ "\n[-] PROGRAM ABORT : " cRST x); \ - SAYF(cLRD "\n Location : " cRST "%s(), %s:%d\n\n", __func__, \ - __FILE__, __LINE__); \ + SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \ + __FILE__, (u32)__LINE__); \ exit(1); \ \ } while (0) @@ -308,8 +308,8 @@ static inline const char *colorfilter(const char *x) { \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ "\n[-] PROGRAM ABORT : " cRST x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%d\n\n", __func__, \ - __FILE__, __LINE__); \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \ + __FILE__, (u32)__LINE__); \ abort(); \ \ } while (0) @@ -322,8 +322,8 @@ static inline const char *colorfilter(const char *x) { fflush(stdout); \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ "\n[-] SYSTEM ERROR : " cRST x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%d\n", __func__, \ - __FILE__, __LINE__); \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \ + __FILE__, (u32)__LINE__); \ SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ exit(1); \ \ @@ -344,12 +344,12 @@ static inline const char *colorfilter(const char *x) { /* Show a prefixed debug output. */ -#define DEBUGF(x...) \ - do { \ - \ - SAYF(cMGN "[D] " cBRI "DEBUG: " cRST x); \ - SAYF(cRST ""); \ - \ +#define DEBUGF(x...) \ + do { \ + \ + fprintf(stderr, cMGN "[D] " cBRI "DEBUG: " cRST x); \ + fprintf(stderr, cRST ""); \ + \ } while (0) /* Error-checking versions of read() and write() that call RPFATAL() as diff --git a/include/types.h b/include/types.h index 3e3bc953..d5c31597 100644 --- a/include/types.h +++ b/include/types.h @@ -26,9 +26,11 @@ #include #include -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef unsigned __int128 uint128_t; +typedef uint128_t u128; /* Extended forkserver option values */ @@ -57,10 +59,12 @@ typedef uint32_t u32; typedef unsigned long long u64; -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef __int128 int128_t; +typedef int128_t s128; #ifndef MIN #define MIN(a, b) \ @@ -114,6 +118,31 @@ typedef int64_t s64; \ }) +// It is impossible to define 128 bit constants, so ... +#define SWAPN(_x, _l) \ + ({ \ + \ + u128 _res = (_x), _ret; \ + char *d = (char *)&_ret, *s = (char *)&_res; \ + int i; \ + for (i = 0; i < 16; i++) \ + d[15 - i] = s[i]; \ + u32 sr = 128U - ((_l) << 3U); \ + (_ret >>= sr); \ + (u128) _ret; \ + \ + }) + +#define SWAPNN(_x, _y, _l) \ + ({ \ + \ + char *d = (char *)(_x), *s = (char *)(_y); \ + u32 i, l = (_l)-1; \ + for (i = 0; i <= l; i++) \ + d[l - i] = s[i]; \ + \ + }) + #ifdef AFL_LLVM_PASS #if defined(__linux__) || !defined(__ANDROID__) #define AFL_SR(s) (srandom(s)) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index b735d8df..5d75af78 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -161,7 +161,7 @@ void send_forkserver_error(int error) { u32 status; if (!error || error > 0xffff) return; status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); - if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; } } @@ -544,11 +544,11 @@ static void __afl_start_snapshots(void) { if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT; memcpy(tmp, &status, 4); - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); } if (getenv("AFL_DEBUG")) { @@ -1207,7 +1207,9 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { ///// CmpLog instrumentation -void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) { +void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) { + + // fprintf(stderr, "hook1 arg0=%02x arg1=%02x attr=%u\n", arg1, arg2, attr); if (unlikely(!__afl_cmp_map)) return; @@ -1216,6 +1218,7 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) { k &= CMP_MAP_W - 1; __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + __afl_cmp_map->headers[k].attribute = attr; u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; @@ -1230,7 +1233,7 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) { } -void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) { +void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) { if (unlikely(!__afl_cmp_map)) return; @@ -1239,6 +1242,7 @@ void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) { k &= CMP_MAP_W - 1; __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + __afl_cmp_map->headers[k].attribute = attr; u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; @@ -1251,7 +1255,9 @@ void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) { } -void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) { +void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr) { + + // fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr); if (unlikely(!__afl_cmp_map)) return; @@ -1260,6 +1266,7 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) { k &= CMP_MAP_W - 1; __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + __afl_cmp_map->headers[k].attribute = attr; u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; @@ -1272,7 +1279,9 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) { } -void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) { +void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) { + + // fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr); if (unlikely(!__afl_cmp_map)) return; @@ -1281,6 +1290,7 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) { k &= CMP_MAP_W - 1; __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + __afl_cmp_map->headers[k].attribute = attr; u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; @@ -1293,16 +1303,77 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) { } +// support for u24 to u120 via llvm _ExitInt(). size is in bytes minus 1 +void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr, + uint8_t size) { + + // fprintf(stderr, "hookN arg0=%llx:%llx arg1=%llx:%llx bytes=%u attr=%u\n", + // (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1, + // attr); + + if (unlikely(!__afl_cmp_map)) return; + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + __afl_cmp_map->headers[k].attribute = attr; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = size; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = (u64)arg1; + __afl_cmp_map->log[k][hits].v1 = (u64)arg2; + + if (size > 7) { + + __afl_cmp_map->log[k][hits].v0_128 = (u64)(arg1 >> 64); + __afl_cmp_map->log[k][hits].v1_128 = (u64)(arg2 >> 64); + + } + +} + +void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) { + + if (unlikely(!__afl_cmp_map)) return; + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + __afl_cmp_map->headers[k].attribute = attr; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 15; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = (u64)arg1; + __afl_cmp_map->log[k][hits].v1 = (u64)arg2; + __afl_cmp_map->log[k][hits].v0_128 = (u64)(arg1 >> 64); + __afl_cmp_map->log[k][hits].v1_128 = (u64)(arg2 >> 64); + +} + #if defined(__APPLE__) #pragma weak __sanitizer_cov_trace_const_cmp1 = __cmplog_ins_hook1 #pragma weak __sanitizer_cov_trace_const_cmp2 = __cmplog_ins_hook2 #pragma weak __sanitizer_cov_trace_const_cmp4 = __cmplog_ins_hook4 #pragma weak __sanitizer_cov_trace_const_cmp8 = __cmplog_ins_hook8 + #pragma weak __sanitizer_cov_trace_const_cmp16 = __cmplog_ins_hook16 #pragma weak __sanitizer_cov_trace_cmp1 = __cmplog_ins_hook1 #pragma weak __sanitizer_cov_trace_cmp2 = __cmplog_ins_hook2 #pragma weak __sanitizer_cov_trace_cmp4 = __cmplog_ins_hook4 #pragma weak __sanitizer_cov_trace_cmp8 = __cmplog_ins_hook8 + #pragma weak __sanitizer_cov_trace_cmp16 = __cmplog_ins_hook16 #else void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__cmplog_ins_hook1"))); @@ -1312,6 +1383,8 @@ void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) __attribute__((alias("__cmplog_ins_hook4"))); void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) __attribute__((alias("__cmplog_ins_hook8"))); +void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) + __attribute__((alias("__cmplog_ins_hook16"))); void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__cmplog_ins_hook1"))); @@ -1321,6 +1394,8 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) __attribute__((alias("__cmplog_ins_hook4"))); void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) __attribute__((alias("__cmplog_ins_hook8"))); +void __sanitizer_cov_trace_cmp16(uint128_t arg1, uint128_t arg2) + __attribute__((alias("__cmplog_ins_hook16"))); #endif /* defined(__APPLE__) */ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index 3499ccf0..a74fb6c8 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -85,9 +85,25 @@ class CmpLogInstructions : public ModulePass { char CmpLogInstructions::ID = 0; +template +Iterator Unique(Iterator first, Iterator last) { + + while (first != last) { + + Iterator next(first); + last = std::remove(++next, last, *first); + first = next; + + } + + return last; + +} + bool CmpLogInstructions::hookInstrs(Module &M) { std::vector icomps; + std::vector switches; LLVMContext & C = M.getContext(); Type * VoidTy = Type::getVoidTy(C); @@ -95,13 +111,15 @@ bool CmpLogInstructions::hookInstrs(Module &M) { IntegerType *Int16Ty = IntegerType::getInt16Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); IntegerType *Int64Ty = IntegerType::getInt64Ty(C); + IntegerType *Int128Ty = IntegerType::getInt128Ty(C); #if LLVM_VERSION_MAJOR < 9 Constant * #else FunctionCallee #endif - c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty + c1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty, Int8Ty, + Int8Ty #if LLVM_VERSION_MAJOR < 5 , NULL @@ -118,7 +136,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) { #else FunctionCallee #endif - c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty + c2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy, Int16Ty, Int16Ty, + Int8Ty #if LLVM_VERSION_MAJOR < 5 , NULL @@ -135,7 +154,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) { #else FunctionCallee #endif - c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty + c4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy, Int32Ty, Int32Ty, + Int8Ty #if LLVM_VERSION_MAJOR < 5 , NULL @@ -152,7 +172,8 @@ bool CmpLogInstructions::hookInstrs(Module &M) { #else FunctionCallee #endif - c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty + c8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy, Int64Ty, Int64Ty, + Int8Ty #if LLVM_VERSION_MAJOR < 5 , NULL @@ -164,6 +185,42 @@ bool CmpLogInstructions::hookInstrs(Module &M) { FunctionCallee cmplogHookIns8 = c8; #endif +#if LLVM_VERSION_MAJOR < 9 + Constant * +#else + FunctionCallee +#endif + c16 = M.getOrInsertFunction("__cmplog_ins_hook16", VoidTy, Int128Ty, + Int128Ty, Int8Ty +#if LLVM_VERSION_MAJOR < 5 + , + NULL +#endif + ); +#if LLVM_VERSION_MAJOR < 9 + Function *cmplogHookIns16 = cast(c16); +#else + FunctionCallee cmplogHookIns16 = c16; +#endif + +#if LLVM_VERSION_MAJOR < 9 + Constant * +#else + FunctionCallee +#endif + cN = M.getOrInsertFunction("__cmplog_ins_hookN", VoidTy, Int128Ty, + Int128Ty, Int8Ty, Int8Ty +#if LLVM_VERSION_MAJOR < 5 + , + NULL +#endif + ); +#if LLVM_VERSION_MAJOR < 9 + Function *cmplogHookInsN = cast(cN); +#else + FunctionCallee cmplogHookInsN = cN; +#endif + /* iterate over all functions, bbs and instruction and add suitable calls */ for (auto &F : M) { @@ -174,35 +231,16 @@ bool CmpLogInstructions::hookInstrs(Module &M) { for (auto &IN : BB) { CmpInst *selectcmpInst = nullptr; - if ((selectcmpInst = dyn_cast(&IN))) { - if (selectcmpInst->getPredicate() == CmpInst::ICMP_EQ || - selectcmpInst->getPredicate() == CmpInst::ICMP_NE || - selectcmpInst->getPredicate() == CmpInst::ICMP_UGT || - selectcmpInst->getPredicate() == CmpInst::ICMP_SGT || - selectcmpInst->getPredicate() == CmpInst::ICMP_ULT || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLT || - selectcmpInst->getPredicate() == CmpInst::ICMP_UGE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SGE || - selectcmpInst->getPredicate() == CmpInst::ICMP_ULE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLE || - selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || - selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || - selectcmpInst->getPredicate() == CmpInst::FCMP_OLE || - selectcmpInst->getPredicate() == CmpInst::FCMP_ULE || - selectcmpInst->getPredicate() == CmpInst::FCMP_OGT || - selectcmpInst->getPredicate() == CmpInst::FCMP_UGT || - selectcmpInst->getPredicate() == CmpInst::FCMP_OLT || - selectcmpInst->getPredicate() == CmpInst::FCMP_ULT || - selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || - selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || - selectcmpInst->getPredicate() == CmpInst::FCMP_UNE || - selectcmpInst->getPredicate() == CmpInst::FCMP_ONE) { - - icomps.push_back(selectcmpInst); + icomps.push_back(selectcmpInst); - } + } + + SwitchInst *switchInst = nullptr; + if ((switchInst = dyn_cast(BB.getTerminator()))) { + + if (switchInst->getNumCases() > 1) { switches.push_back(switchInst); } } @@ -212,101 +250,473 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } - if (!icomps.size()) return false; - // if (!be_quiet) errs() << "Hooking " << icomps.size() << " cmp - // instructions\n"; + // unique the collected switches + switches.erase(Unique(switches.begin(), switches.end()), switches.end()); + + // Instrument switch values for cmplog + if (switches.size()) { + + if (!be_quiet) + errs() << "Hooking " << switches.size() << " switch instructions\n"; - for (auto &selectcmpInst : icomps) { + for (auto &SI : switches) { - IRBuilder<> IRB(selectcmpInst->getParent()); - IRB.SetInsertPoint(selectcmpInst); + Value * Val = SI->getCondition(); + unsigned int max_size = Val->getType()->getIntegerBitWidth(), cast_size; + unsigned char do_cast = 0; - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); + if (!SI->getNumCases() || max_size <= 8) { - IntegerType * intTyOp0 = NULL; - IntegerType * intTyOp1 = NULL; - unsigned max_size = 0; - std::vector args; + // if (!be_quiet) errs() << "skip trivial switch..\n"; + continue; - if (selectcmpInst->getOpcode() == Instruction::FCmp) { + } + + IRBuilder<> IRB(SI->getParent()); + IRB.SetInsertPoint(SI); + + if (max_size % 8) { + + max_size = (((max_size / 8) + 1) * 8); + do_cast = 1; + + } + + if (max_size > 128) { + + if (!be_quiet) { + + fprintf(stderr, + "Cannot handle this switch bit size: %u (truncating)\n", + max_size); + + } + + max_size = 128; + do_cast = 1; + + } + + // do we need to cast? + switch (max_size) { + + case 8: + case 16: + case 32: + case 64: + case 128: + cast_size = max_size; + break; + default: + cast_size = 128; + do_cast = 1; + + } + + Value *CompareTo = Val; + + if (do_cast) { + + ConstantInt *cint = dyn_cast(Val); + if (cint) { + + uint64_t val = cint->getZExtValue(); + // fprintf(stderr, "ConstantInt: %lu\n", val); + switch (cast_size) { + + case 8: + CompareTo = ConstantInt::get(Int8Ty, val); + break; + case 16: + CompareTo = ConstantInt::get(Int16Ty, val); + break; + case 32: + CompareTo = ConstantInt::get(Int32Ty, val); + break; + case 64: + CompareTo = ConstantInt::get(Int64Ty, val); + break; + case 128: + CompareTo = ConstantInt::get(Int128Ty, val); + break; + + } - auto ty0 = op0->getType(); - if (ty0->isHalfTy() + } else { + + CompareTo = IRB.CreateBitCast(Val, IntegerType::get(C, cast_size)); + + } + + } + + for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e; + ++i) { + +#if LLVM_VERSION_MAJOR < 5 + ConstantInt *cint = i.getCaseValue(); +#else + ConstantInt *cint = i->getCaseValue(); +#endif + + if (cint) { + + std::vector args; + args.push_back(CompareTo); + + Value *new_param = cint; + + if (do_cast) { + + uint64_t val = cint->getZExtValue(); + // fprintf(stderr, "ConstantInt: %lu\n", val); + switch (cast_size) { + + case 8: + new_param = ConstantInt::get(Int8Ty, val); + break; + case 16: + new_param = ConstantInt::get(Int16Ty, val); + break; + case 32: + new_param = ConstantInt::get(Int32Ty, val); + break; + case 64: + new_param = ConstantInt::get(Int64Ty, val); + break; + case 128: + new_param = ConstantInt::get(Int128Ty, val); + break; + + } + + } + + if (new_param) { + + args.push_back(new_param); + ConstantInt *attribute = ConstantInt::get(Int8Ty, 1); + args.push_back(attribute); + if (cast_size != max_size) { + + ConstantInt *bitsize = + ConstantInt::get(Int8Ty, (max_size / 8) - 1); + args.push_back(bitsize); + + } + + switch (cast_size) { + + case 8: + IRB.CreateCall(cmplogHookIns1, args); + break; + case 16: + IRB.CreateCall(cmplogHookIns2, args); + break; + case 32: + IRB.CreateCall(cmplogHookIns4, args); + break; + case 64: + IRB.CreateCall(cmplogHookIns8, args); + break; + case 128: + if (max_size == 128) { + + IRB.CreateCall(cmplogHookIns16, args); + + } else { + + IRB.CreateCall(cmplogHookInsN, args); + + } + + break; + + } + + } + + } + + } + + } + + } + + if (icomps.size()) { + + // if (!be_quiet) errs() << "Hooking " << icomps.size() << + // " cmp instructions\n"; + + for (auto &selectcmpInst : icomps) { + + IRBuilder<> IRB(selectcmpInst->getParent()); + IRB.SetInsertPoint(selectcmpInst); + + Value *op0 = selectcmpInst->getOperand(0); + Value *op1 = selectcmpInst->getOperand(1); + + IntegerType * intTyOp0 = NULL; + IntegerType * intTyOp1 = NULL; + unsigned max_size = 0, cast_size = 0; + unsigned char attr = 0, do_cast = 0; + std::vector args; + + CmpInst *cmpInst = dyn_cast(selectcmpInst); + + if (!cmpInst) { continue; } + + switch (cmpInst->getPredicate()) { + + case CmpInst::ICMP_NE: + case CmpInst::FCMP_UNE: + case CmpInst::FCMP_ONE: + break; + case CmpInst::ICMP_EQ: + case CmpInst::FCMP_UEQ: + case CmpInst::FCMP_OEQ: + attr += 1; + break; + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_SGT: + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_UGT: + attr += 2; + break; + case CmpInst::ICMP_UGE: + case CmpInst::ICMP_SGE: + case CmpInst::FCMP_OGE: + case CmpInst::FCMP_UGE: + attr += 3; + break; + case CmpInst::ICMP_ULT: + case CmpInst::ICMP_SLT: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_ULT: + attr += 4; + break; + case CmpInst::ICMP_ULE: + case CmpInst::ICMP_SLE: + case CmpInst::FCMP_OLE: + case CmpInst::FCMP_ULE: + attr += 5; + break; + default: + break; + + } + + if (selectcmpInst->getOpcode() == Instruction::FCmp) { + + auto ty0 = op0->getType(); + if (ty0->isHalfTy() #if LLVM_VERSION_MAJOR >= 11 - || ty0->isBFloatTy() + || ty0->isBFloatTy() #endif - ) - max_size = 16; - else if (ty0->isFloatTy()) - max_size = 32; - else if (ty0->isDoubleTy()) - max_size = 64; + ) + max_size = 16; + else if (ty0->isFloatTy()) + max_size = 32; + else if (ty0->isDoubleTy()) + max_size = 64; + else if (ty0->isX86_FP80Ty()) + max_size = 80; + else if (ty0->isFP128Ty() || ty0->isPPC_FP128Ty()) + max_size = 128; + + attr += 8; + do_cast = 1; - if (max_size) { + } else { - Value *V0 = IRB.CreateBitCast(op0, IntegerType::get(C, max_size)); - intTyOp0 = dyn_cast(V0->getType()); - Value *V1 = IRB.CreateBitCast(op1, IntegerType::get(C, max_size)); - intTyOp1 = dyn_cast(V1->getType()); + intTyOp0 = dyn_cast(op0->getType()); + intTyOp1 = dyn_cast(op1->getType()); if (intTyOp0 && intTyOp1) { max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() ? intTyOp0->getBitWidth() : intTyOp1->getBitWidth(); - args.push_back(V0); - args.push_back(V1); - } else { + } + + } + + if (!max_size) { continue; } + + // _ExtInt() with non-8th values + if (max_size % 8) { + + max_size = (((max_size / 8) + 1) * 8); + do_cast = 1; + + } + + if (max_size > 128) { + + if (!be_quiet) { - max_size = 0; + fprintf(stderr, + "Cannot handle this compare bit size: %u (truncating)\n", + max_size); } + max_size = 128; + do_cast = 1; + + } + + // do we need to cast? + switch (max_size) { + + case 8: + case 16: + case 32: + case 64: + case 128: + cast_size = max_size; + break; + default: + cast_size = 128; + do_cast = 1; + } - } else { + if (do_cast) { + + // F*cking LLVM optimized out any kind of bitcasts of ConstantInt values + // creating illegal calls. WTF. So we have to work around this. + + ConstantInt *cint = dyn_cast(op0); + if (cint) { + + uint64_t val = cint->getZExtValue(); + // fprintf(stderr, "ConstantInt: %lu\n", val); + ConstantInt *new_param = NULL; + switch (cast_size) { + + case 8: + new_param = ConstantInt::get(Int8Ty, val); + break; + case 16: + new_param = ConstantInt::get(Int16Ty, val); + break; + case 32: + new_param = ConstantInt::get(Int32Ty, val); + break; + case 64: + new_param = ConstantInt::get(Int64Ty, val); + break; + case 128: + new_param = ConstantInt::get(Int128Ty, val); + break; + + } + + if (!new_param) { continue; } + args.push_back(new_param); + + } else { + + Value *V0 = IRB.CreateBitCast(op0, IntegerType::get(C, cast_size)); + args.push_back(V0); + + } + + cint = dyn_cast(op1); + if (cint) { + + uint64_t val = cint->getZExtValue(); + ConstantInt *new_param = NULL; + switch (cast_size) { + + case 8: + new_param = ConstantInt::get(Int8Ty, val); + break; + case 16: + new_param = ConstantInt::get(Int16Ty, val); + break; + case 32: + new_param = ConstantInt::get(Int32Ty, val); + break; + case 64: + new_param = ConstantInt::get(Int64Ty, val); + break; + case 128: + new_param = ConstantInt::get(Int128Ty, val); + break; + + } + + if (!new_param) { continue; } + args.push_back(new_param); + + } else { + + Value *V1 = IRB.CreateBitCast(op1, IntegerType::get(C, cast_size)); + args.push_back(V1); - intTyOp0 = dyn_cast(op0->getType()); - intTyOp1 = dyn_cast(op1->getType()); + } - if (intTyOp0 && intTyOp1) { + } else { - max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() - ? intTyOp0->getBitWidth() - : intTyOp1->getBitWidth(); args.push_back(op0); args.push_back(op1); } - } + ConstantInt *attribute = ConstantInt::get(Int8Ty, attr); + args.push_back(attribute); + + if (cast_size != max_size) { + + ConstantInt *bitsize = ConstantInt::get(Int8Ty, (max_size / 8) - 1); + args.push_back(bitsize); + + } + + // fprintf(stderr, "_ExtInt(%u) castTo %u with attr %u didcast %u\n", + // max_size, cast_size, attr, do_cast); + + switch (cast_size) { - if (max_size < 8 || max_size > 64 || !intTyOp0 || !intTyOp1) continue; - - switch (max_size) { - - case 8: - IRB.CreateCall(cmplogHookIns1, args); - break; - case 16: - IRB.CreateCall(cmplogHookIns2, args); - break; - case 32: - IRB.CreateCall(cmplogHookIns4, args); - break; - case 64: - IRB.CreateCall(cmplogHookIns8, args); - break; - default: - break; + case 8: + IRB.CreateCall(cmplogHookIns1, args); + break; + case 16: + IRB.CreateCall(cmplogHookIns2, args); + break; + case 32: + IRB.CreateCall(cmplogHookIns4, args); + break; + case 64: + IRB.CreateCall(cmplogHookIns8, args); + break; + case 128: + if (max_size == 128) { + + IRB.CreateCall(cmplogHookIns16, args); + + } else { + + IRB.CreateCall(cmplogHookInsN, args); + + } + + break; + + } } } - return true; + if (switches.size() || icomps.size()) + return true; + else + return false; } diff --git a/src/afl-cc.c b/src/afl-cc.c index 8fb42718..02c9c7c5 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -528,10 +528,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = alloc_printf( "-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path); - cc_params[cc_par_cnt++] = alloc_printf( - "-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); cc_params[cc_par_cnt++] = alloc_printf( "-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); } else { @@ -541,18 +541,18 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = alloc_printf("%s/cmplog-routines-pass.so", obj_path); - // reuse split switches from laf cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = - alloc_printf("%s/split-switches-pass.so", obj_path); + alloc_printf("%s/cmplog-instructions-pass.so", obj_path); + // reuse split switches from laf cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = - alloc_printf("%s/cmplog-instructions-pass.so", obj_path); + alloc_printf("%s/split-switches-pass.so", obj_path); } @@ -792,10 +792,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { } -#if defined(USEMMAP) - #if !defined(__HAIKU__) +#if defined(USEMMAP) && !defined(__HAIKU__) cc_params[cc_par_cnt++] = "-lrt"; - #endif #endif cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; @@ -858,6 +856,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()"; cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_ABORT()=__afl_coverage_abort()"; + cc_params[cc_par_cnt++] = "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : " "__afl_fuzz_alt_ptr)"; @@ -967,10 +966,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); #endif - #if defined(USEMMAP) - #if !defined(__HAIKU__) + #if defined(USEMMAP) && !defined(__HAIKU__) cc_params[cc_par_cnt++] = "-lrt"; - #endif #endif } @@ -1278,7 +1275,6 @@ int main(int argc, char **argv, char **envp) { } - // this is a hidden option if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 || strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) { @@ -1349,29 +1345,28 @@ int main(int argc, char **argv, char **envp) { if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) { - ptr2 += strlen("ngram"); - while (*ptr2 && (*ptr2 < '0' || *ptr2 > '9')) - ptr2++; + u8 *ptr3 = ptr2 + strlen("ngram"); + while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9')) + ptr3++; - if (!*ptr2) { + if (!*ptr3) { - if ((ptr2 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL) + if ((ptr3 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL) FATAL( "you must set the NGRAM size with (e.g. for value 2) " "AFL_LLVM_INSTRUMENT=ngram-2"); } - ngram_size = atoi(ptr2); + ngram_size = atoi(ptr3); if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) FATAL( "NGRAM instrumentation option must be between 2 and " - "NGRAM_SIZE_MAX " - "(%u)", + "NGRAM_SIZE_MAX (%u)", NGRAM_SIZE_MAX); instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM); - ptr2 = alloc_printf("%u", ngram_size); - setenv("AFL_LLVM_NGRAM_SIZE", ptr2, 1); + u8 *ptr4 = alloc_printf("%u", ngram_size); + setenv("AFL_LLVM_NGRAM_SIZE", ptr4, 1); } @@ -1507,6 +1502,7 @@ int main(int argc, char **argv, char **envp) { "((instrumentation/README.ngram.md)\n" " INSTRIM: Dominator tree (for LLVM <= 6.0) " "(instrumentation/README.instrim.md)\n\n"); + #undef NATIVE_MSG SAYF( @@ -1641,16 +1637,15 @@ int main(int argc, char **argv, char **envp) { if (have_lto) SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO); if (have_llvm) - SAYF("afl-cc LLVM version %d using binary path \"%s\".\n", LLVM_MAJOR, + SAYF("afl-cc LLVM version %d using the binary path \"%s\".\n", LLVM_MAJOR, LLVM_BINDIR); #endif -#if defined(USEMMAP) +#ifdef USEMMAP #if !defined(__HAIKU__) - cc_params[cc_par_cnt++] = "-lrt"; - SAYF("Compiled with shm_open support (adds -lrt when linking).\n"); - #else SAYF("Compiled with shm_open support.\n"); + #else + SAYF("Compiled with shm_open support (adds -lrt when linking).\n"); #endif #else SAYF("Compiled with shmat support.\n"); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index dbffa4f9..cbff6d7e 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -729,6 +729,30 @@ void read_testcases(afl_state_t *afl, u8 *directory) { add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size, passed_det); + if (unlikely(afl->shm.cmplog_mode)) { + + if (afl->cmplog_lvl == 1) { + + if (!afl->cmplog_max_filesize || + afl->cmplog_max_filesize < st.st_size) { + + afl->cmplog_max_filesize = st.st_size; + + } + + } else if (afl->cmplog_lvl == 2) { + + if (!afl->cmplog_max_filesize || + afl->cmplog_max_filesize > st.st_size) { + + afl->cmplog_max_filesize = st.st_size; + + } + + } + + } + if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); @@ -756,6 +780,20 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } + if (unlikely(afl->shm.cmplog_mode)) { + + if (afl->cmplog_max_filesize < 1024) { + + afl->cmplog_max_filesize = 1024; + + } else { + + afl->cmplog_max_filesize = (((afl->cmplog_max_filesize >> 10) + 1) << 10); + + } + + } + afl->last_path_time = 0; afl->queued_at_start = afl->queued_paths; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index f9509e86..596bae22 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -165,7 +165,7 @@ static u8 could_be_arith(u32 old_val, u32 new_val, u8 blen) { /* See if one-byte adjustments to any byte could produce this result. */ - for (i = 0; i < blen; ++i) { + for (i = 0; (u8)i < blen; ++i) { u8 a = old_val >> (8 * i), b = new_val >> (8 * i); @@ -193,7 +193,7 @@ static u8 could_be_arith(u32 old_val, u32 new_val, u8 blen) { diffs = 0; - for (i = 0; i < blen / 2; ++i) { + for (i = 0; (u8)i < blen / 2; ++i) { u16 a = old_val >> (16 * i), b = new_val >> (16 * i); @@ -290,7 +290,7 @@ static u8 could_be_interest(u32 old_val, u32 new_val, u8 blen, u8 check_le) { /* See if two-byte insertions over old_val could give us new_val. */ - for (i = 0; (s32)i < blen - 1; ++i) { + for (i = 0; (u8)i < blen - 1; ++i) { for (j = 0; j < sizeof(interesting_16) / 2; ++j) { @@ -545,14 +545,31 @@ u8 fuzz_one_original(afl_state_t *afl) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score == 0)) { goto abandon_entry; } + if (unlikely(perf_score <= 0)) { goto abandon_entry; } - if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { + if (unlikely(afl->shm.cmplog_mode && + afl->queue_cur->colorized < afl->cmplog_lvl && + (u32)len <= afl->cmplog_max_filesize)) { - if (input_to_state_stage(afl, in_buf, out_buf, len, - afl->queue_cur->exec_cksum)) { + if (unlikely(len < 4)) { - goto abandon_entry; + afl->queue_cur->colorized = 0xff; + + } else { + + if (afl->cmplog_lvl == 3 || + (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || + !(afl->fsrv.total_execs % afl->queued_paths) || + get_cur_time() - afl->last_path_time > 15000) { + + if (input_to_state_stage(afl, in_buf, out_buf, len, + afl->queue_cur->exec_cksum)) { + + goto abandon_entry; + + } + + } } @@ -2796,7 +2813,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } - s32 len, temp_len; + u32 len, temp_len; u32 i; u32 j; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -2952,14 +2969,31 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score == 0)) { goto abandon_entry; } + if (unlikely(perf_score <= 0)) { goto abandon_entry; } - if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { + if (unlikely(afl->shm.cmplog_mode && + afl->queue_cur->colorized < afl->cmplog_lvl && + (u32)len <= afl->cmplog_max_filesize)) { - if (input_to_state_stage(afl, in_buf, out_buf, len, - afl->queue_cur->exec_cksum)) { + if (unlikely(len < 4)) { - goto abandon_entry; + afl->queue_cur->colorized = 0xff; + + } else { + + if (afl->cmplog_lvl == 3 || + (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || + !(afl->fsrv.total_execs % afl->queued_paths) || + get_cur_time() - afl->last_path_time > 15000) { + + if (input_to_state_stage(afl, in_buf, out_buf, len, + afl->queue_cur->exec_cksum)) { + + goto abandon_entry; + + } + + } } @@ -3315,7 +3349,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { /* Let's consult the effector map... */ @@ -3357,7 +3391,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; ++i) { + for (i = 0; i < len - 3; ++i) { /* Let's consult the effector map... */ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && @@ -3489,7 +3523,7 @@ skip_bitflip: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { u16 orig = *(u16 *)(out_buf + i); @@ -3615,7 +3649,7 @@ skip_bitflip: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; ++i) { + for (i = 0; i < len - 3; ++i) { u32 orig = *(u32 *)(out_buf + i); @@ -3805,7 +3839,7 @@ skip_arith: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { u16 orig = *(u16 *)(out_buf + i); @@ -3891,7 +3925,7 @@ skip_arith: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; ++i) { + for (i = 0; i < len - 3; ++i) { u32 orig = *(u32 *)(out_buf + i); @@ -4120,7 +4154,7 @@ skip_user_extras: /* See the comment in the earlier code; extras are sorted by size. */ - if ((s32)(afl->a_extras[j].len) > (s32)(len - i) || + if ((afl->a_extras[j].len) > (len - i) || !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len) || !memchr(eff_map + EFF_APOS(i), 1, EFF_SPAN_ALEN(i, afl->a_extras[j].len))) { @@ -4837,7 +4871,7 @@ pacemaker_fuzzing: u32 copy_from, copy_to, copy_len; copy_len = choose_block_len(afl, new_len - 1); - if ((s32)copy_len > temp_len) copy_len = temp_len; + 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); @@ -5033,8 +5067,7 @@ pacemaker_fuzzing: the last differing byte. Bail out if the difference is just a single byte or so. */ - locate_diffs(in_buf, new_buf, MIN(len, (s32)target->len), &f_diff, - &l_diff); + locate_diffs(in_buf, new_buf, MIN(len, target->len), &f_diff, &l_diff); if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 66938635..aec57a6e 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -433,6 +433,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->passed_det = passed_det; q->trace_mini = NULL; q->testcase_buf = NULL; + q->mother = afl->queue_cur; #ifdef INTROSPECTION q->bitsmap_size = afl->bitsmap_size; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 28585afe..955a9232 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -28,6 +28,8 @@ #include "afl-fuzz.h" #include "cmplog.h" +//#define _DEBUG + ///// Colorization struct range { @@ -35,6 +37,8 @@ struct range { u32 start; u32 end; struct range *next; + struct range *prev; + u8 ok; }; @@ -44,6 +48,8 @@ static struct range *add_range(struct range *ranges, u32 start, u32 end) { r->start = start; r->end = end; r->next = ranges; + r->ok = 0; + if (likely(ranges)) ranges->prev = r; return r; } @@ -51,45 +57,61 @@ static struct range *add_range(struct range *ranges, u32 start, u32 end) { static struct range *pop_biggest_range(struct range **ranges) { struct range *r = *ranges; - struct range *prev = NULL; struct range *rmax = NULL; - struct range *prev_rmax = NULL; u32 max_size = 0; while (r) { - u32 s = r->end - r->start; - if (s >= max_size) { + if (!r->ok) { + + u32 s = 1 + r->end - r->start; + + if (s >= max_size) { + + max_size = s; + rmax = r; - max_size = s; - prev_rmax = prev; - rmax = r; + } } - prev = r; r = r->next; } - if (rmax) { + return rmax; - if (prev_rmax) { +} - prev_rmax->next = rmax->next; +#ifdef _DEBUG +// static int logging = 0; +static void dump(char *txt, u8 *buf, u32 len) { - } else { + u32 i; + fprintf(stderr, "DUMP %s %llx ", txt, hash64(buf, len, 0)); + for (i = 0; i < len; i++) + fprintf(stderr, "%02x", buf[i]); + fprintf(stderr, "\n"); - *ranges = rmax->next; +} - } +static void dump_file(char *path, char *name, u32 counter, u8 *buf, u32 len) { - } + char fn[4096]; + if (!path) path = "."; + snprintf(fn, sizeof(fn), "%s/%s%d", path, name, counter); + int fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (fd >= 0) { - return rmax; + write(fd, buf, len); + close(fd); + + } } +#endif + static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) { if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; } @@ -99,107 +121,270 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) { } -static void xor_replace(u8 *buf, u32 len) { +/* replace everything with different values but stay in the same type */ +static void type_replace(afl_state_t *afl, u8 *buf, u32 len) { u32 i; + u8 c; for (i = 0; i < len; ++i) { - buf[i] ^= 0xff; + // wont help for UTF or non-latin charsets + do { + + switch (buf[i]) { + + case 'A' ... 'F': + c = 'A' + rand_below(afl, 1 + 'F' - 'A'); + break; + case 'a' ... 'f': + c = 'a' + rand_below(afl, 1 + 'f' - 'a'); + break; + case '0': + c = '1'; + break; + case '1': + c = '0'; + break; + case '2' ... '9': + c = '2' + rand_below(afl, 1 + '9' - '2'); + break; + case 'G' ... 'Z': + c = 'G' + rand_below(afl, 1 + 'Z' - 'G'); + break; + case 'g' ... 'z': + c = 'g' + rand_below(afl, 1 + 'z' - 'g'); + break; + case '!' ... '*': + c = '!' + rand_below(afl, 1 + '*' - '!'); + break; + case ',' ... '.': + c = ',' + rand_below(afl, 1 + '.' - ','); + break; + case ':' ... '@': + c = ':' + rand_below(afl, 1 + '@' - ':'); + break; + case '[' ... '`': + c = '[' + rand_below(afl, 1 + '`' - '['); + break; + case '{' ... '~': + c = '{' + rand_below(afl, 1 + '~' - '{'); + break; + case '+': + c = '/'; + break; + case '/': + c = '+'; + break; + case ' ': + c = '\t'; + break; + case '\t': + c = ' '; + break; + /* + case '\r': + case '\n': + // nothing ... + break; + */ + default: + c = (buf[i] ^ 0xff); + + } + + } while (c == buf[i]); + + buf[i] = c; } } -static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { +static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum, + struct tainted **taints) { - struct range *ranges = add_range(NULL, 0, len); - u8 * backup = ck_alloc_nozero(len); + struct range * ranges = add_range(NULL, 0, len - 1), *rng; + struct tainted *taint = NULL; + u8 * backup = ck_alloc_nozero(len); + u8 * changed = ck_alloc_nozero(len); u64 orig_hit_cnt, new_hit_cnt; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_name = "colorization"; afl->stage_short = "colorization"; - afl->stage_max = 1000; + afl->stage_max = (len << 1); - struct range *rng = NULL; afl->stage_cur = 0; + memcpy(backup, buf, len); + memcpy(changed, buf, len); + type_replace(afl, changed, len); + while ((rng = pop_biggest_range(&ranges)) != NULL && afl->stage_cur < afl->stage_max) { - u32 s = rng->end - rng->start; + u32 s = 1 + rng->end - rng->start; + + memcpy(buf + rng->start, changed + rng->start, s); - if (s != 0) { + u64 cksum; + u64 start_us = get_cur_time_us(); + if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) { - /* Range not empty */ + goto checksum_fail; - memcpy(backup, buf + rng->start, s); - xor_replace(buf + rng->start, s); + } + + u64 stop_us = get_cur_time_us(); + + /* Discard if the mutations change the path or if it is too decremental + in speed - how could the same path have a much different speed + though ...*/ + if (cksum != exec_cksum || + (unlikely(stop_us - start_us > 3 * afl->queue_cur->exec_us) && + likely(!afl->fixed_seed))) { + + memcpy(buf + rng->start, backup + rng->start, s); - u64 cksum; - u64 start_us = get_cur_time_us(); - if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) { + if (s > 1) { // to not add 0 size ranges - goto checksum_fail; + ranges = add_range(ranges, rng->start, rng->start - 1 + s / 2); + ranges = add_range(ranges, rng->start + s / 2, rng->end); } - u64 stop_us = get_cur_time_us(); + if (ranges == rng) { + + ranges = rng->next; + if (ranges) { ranges->prev = NULL; } + + } else if (rng->next) { + + rng->prev->next = rng->next; + rng->next->prev = rng->prev; - /* Discard if the mutations change the paths or if it is too decremental - in speed */ - if (cksum != exec_cksum || - ((stop_us - start_us > 2 * afl->queue_cur->exec_us) && - likely(!afl->fixed_seed))) { + } else { - ranges = add_range(ranges, rng->start, rng->start + s / 2); - ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); - memcpy(buf + rng->start, backup, s); + if (rng->prev) { rng->prev->next = NULL; } } + free(rng); + + } else { + + rng->ok = 1; + } - ck_free(rng); - rng = NULL; ++afl->stage_cur; } - if (afl->stage_cur < afl->stage_max) { afl->queue_cur->fully_colorized = 1; } + rng = ranges; + while (rng) { - new_hit_cnt = afl->queued_paths + afl->unique_crashes; - afl->stage_finds[STAGE_COLORIZATION] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur; - ck_free(backup); + rng = rng->next; - ck_free(rng); - rng = NULL; + } - while (ranges) { + u32 i = 1; + u32 positions = 0; + while (i) { + restart: + i = 0; + struct range *r = NULL; + u32 pos = (u32)-1; rng = ranges; - ranges = rng->next; - ck_free(rng); - rng = NULL; - } + while (rng) { - return 0; + if (rng->ok == 1 && rng->start < pos) { -checksum_fail: - if (rng) { ck_free(rng); } - ck_free(backup); + if (taint && taint->pos + taint->len == rng->start) { + + taint->len += (1 + rng->end - rng->start); + positions += (1 + rng->end - rng->start); + rng->ok = 2; + goto restart; + + } else { + + r = rng; + pos = rng->start; + + } + + } + + rng = rng->next; + + } + + if (r) { + + struct tainted *t = ck_alloc_nozero(sizeof(struct tainted)); + t->pos = r->start; + t->len = 1 + r->end - r->start; + positions += (1 + r->end - r->start); + if (likely(taint)) { taint->prev = t; } + t->next = taint; + t->prev = NULL; + taint = t; + r->ok = 2; + i = 1; + } + + } + + *taints = taint; + + /* temporary: clean ranges */ while (ranges) { rng = ranges; ranges = rng->next; ck_free(rng); - rng = NULL; } + new_hit_cnt = afl->queued_paths + afl->unique_crashes; + +#ifdef _DEBUG + /* + char fn[4096]; + snprintf(fn, sizeof(fn), "%s/introspection_color.txt", afl->out_dir); + FILE *f = fopen(fn, "a"); + if (f) { + + */ + FILE *f = stderr; + fprintf(f, + "Colorization: fname=%s len=%u result=%u execs=%u found=%llu " + "taint=%u\n", + afl->queue_cur->fname, len, afl->queue_cur->colorized, afl->stage_cur, + new_hit_cnt - orig_hit_cnt, positions); +/* + fclose(f); + + } + +*/ +#endif + + afl->stage_finds[STAGE_COLORIZATION] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur; + ck_free(backup); + ck_free(changed); + + return 0; + +checksum_fail: + ck_free(backup); + ck_free(changed); + return 1; } @@ -212,12 +397,19 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { orig_hit_cnt = afl->queued_paths + afl->unique_crashes; +#ifdef _DEBUG + dump("DATA", buf, len); +#endif + if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; } new_hit_cnt = afl->queued_paths + afl->unique_crashes; if (unlikely(new_hit_cnt != orig_hit_cnt)) { +#ifdef _DEBUG + fprintf(stderr, "NEW FIND\n"); +#endif *status = 1; } else { @@ -278,11 +470,33 @@ static int strntoull(const char *str, size_t sz, char **end, int base, } static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, - u64 pattern, u64 repl, u64 o_pattern, u32 idx, - u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse, - u8 *status) { - - if (!buf) { FATAL("BUG: buf was NULL. Please report this.\n"); } + u64 pattern, u64 repl, u64 o_pattern, + u64 changed_val, u8 attr, u32 idx, u32 taint_len, + u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len, + u8 do_reverse, u8 lvl, u8 *status) { + + // (void)(changed_val); // TODO + // we can use the information in changed_val to see if there is a + // computable i2s transformation. + // if (pattern != o_pattern && repl != changed_val) { + + // u64 in_diff = pattern - o_pattern, out_diff = repl - changed_val; + // if (in_diff != out_diff) { + + // switch(in_diff) { + + // detect uppercase <-> lowercase, base64, hex encoding, etc.: + // repl = reverse_transform(TYPE, pattern); + // } + // } + // } + // not 100% but would have a chance to be detected + + // fprintf(stderr, + // "Encode: %llx->%llx into %llx(<-%llx) at pos=%u " + // "taint_len=%u shape=%u attr=%u\n", + // o_pattern, pattern, repl, changed_val, idx, taint_len, + // h->shape + 1, attr); u64 *buf_64 = (u64 *)&buf[idx]; u32 *buf_32 = (u32 *)&buf[idx]; @@ -293,76 +507,215 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u16 *o_buf_16 = (u16 *)&orig_buf[idx]; u8 * o_buf_8 = &orig_buf[idx]; - u32 its_len = len - idx; - // *status = 0; + u32 its_len = MIN(len - idx, taint_len); u8 * endptr; u8 use_num = 0, use_unum = 0; unsigned long long unum; long long num; - if (afl->queue_cur->is_ascii) { + // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl == 3 + if (lvl & 4) { - endptr = buf_8; - if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) { + if (afl->queue_cur->is_ascii) { - if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum)) - use_unum = 1; + endptr = buf_8; + if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) { - } else + if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum)) + use_unum = 1; - use_num = 1; + } else - } + use_num = 1; - if (use_num && (u64)num == pattern) { + } - size_t old_len = endptr - buf_8; - size_t num_len = snprintf(NULL, 0, "%lld", num); +#ifdef _DEBUG + if (idx == 0) + fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n", + afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern); +#endif - u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - memcpy(new_buf, buf, idx); + // num is likely not pattern as atoi("AAA") will be zero... + if (use_num && ((u64)num == pattern || !num)) { - snprintf(new_buf + idx, num_len, "%lld", num); - memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + u8 tmp_buf[32]; + size_t num_len = snprintf(tmp_buf, sizeof(tmp_buf), "%lld", repl); + size_t old_len = endptr - buf_8; - if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } + u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } - } else if (use_unum && unum == pattern) { + memcpy(new_buf, buf, idx); + memcpy(new_buf + idx, tmp_buf, num_len); + memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); - size_t old_len = endptr - buf_8; - size_t num_len = snprintf(NULL, 0, "%llu", unum); + if (new_buf[idx + num_len] >= '0' && new_buf[idx + num_len] <= '9') { + + new_buf[idx + num_len] = ' '; + + } - u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - memcpy(new_buf, buf, idx); + if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } - snprintf(new_buf + idx, num_len, "%llu", unum); - memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + } else if (use_unum && (unum == pattern || !unum)) { - if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } + u8 tmp_buf[32]; + size_t num_len = snprintf(tmp_buf, sizeof(tmp_buf), "%llu", repl); + size_t old_len = endptr - buf_8; + + u8 *new_buf = afl_realloc((void **)&afl->out_scratch_buf, len + num_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + + memcpy(new_buf, buf, idx); + memcpy(new_buf + idx, tmp_buf, num_len); + memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len); + + if (new_buf[idx + num_len] >= '0' && new_buf[idx + num_len] <= '9') { + + new_buf[idx + num_len] = ' '; + + } + + if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; } + + } } - if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) { + // we only allow this for ascii2integer (above) + if (unlikely(pattern == o_pattern)) { return 0; } - if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) { + if ((lvl & 1) || ((lvl & 2) && (attr >= 8 && attr <= 15)) || attr >= 16) { - *buf_64 = repl; - if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_64 = pattern; + if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) { + + // if (its_len >= 8 && (attr == 0 || attr >= 8)) + // fprintf(stderr, + // "TestU64: %u>=4 %x==%llx" + // " %x==%llx (idx=%u attr=%u) <= %llx<-%llx\n", + // its_len, *buf_32, pattern, *o_buf_32, o_pattern, idx, attr, + // repl, changed_val); + + // if this is an fcmp (attr & 8 == 8) then do not compare the patterns - + // due to a bug in llvm dynamic float bitcasts do not work :( + // the value 16 means this is a +- 1.0 test case + if (its_len >= 8 && + ((*buf_64 == pattern && *o_buf_64 == o_pattern) || attr >= 16)) { + + u64 tmp_64 = *buf_64; + *buf_64 = repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + if (*status == 1) { memcpy(cbuf + idx, buf_64, 8); } + *buf_64 = tmp_64; + + // fprintf(stderr, "Status=%u\n", *status); + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), + SWAP64(o_pattern), SWAP64(changed_val), + attr, idx, taint_len, orig_buf, buf, + cbuf, len, 0, lvl, status))) { + + return 1; + + } + + } } - // reverse encoding - if (do_reverse && *status != 1) { + if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) { - if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), - SWAP64(o_pattern), idx, orig_buf, buf, - len, 0, status))) { + // if (its_len >= 4 && (attr <= 1 || attr >= 8)) + // fprintf(stderr, + // "TestU32: %u>=4 %x==%llx" + // " %x==%llx (idx=%u attr=%u) <= %llx<-%llx\n", + // its_len, *buf_32, pattern, *o_buf_32, o_pattern, idx, attr, + // repl, changed_val); - return 1; + if (its_len >= 4 && + ((*buf_32 == (u32)pattern && *o_buf_32 == (u32)o_pattern) || + attr >= 16)) { + + u32 tmp_32 = *buf_32; + *buf_32 = (u32)repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + if (*status == 1) { memcpy(cbuf + idx, buf_32, 4); } + *buf_32 = tmp_32; + + // fprintf(stderr, "Status=%u\n", *status); + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), + SWAP32(o_pattern), SWAP32(changed_val), + attr, idx, taint_len, orig_buf, buf, + cbuf, len, 0, lvl, status))) { + + return 1; + + } + + } + + } + + if (SHAPE_BYTES(h->shape) >= 2 && *status != 1) { + + if (its_len >= 2 && + ((*buf_16 == (u16)pattern && *o_buf_16 == (u16)o_pattern) || + attr >= 16)) { + + u16 tmp_16 = *buf_16; + *buf_16 = (u16)repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + if (*status == 1) { memcpy(cbuf + idx, buf_16, 2); } + *buf_16 = tmp_16; + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), + SWAP16(o_pattern), SWAP16(changed_val), + attr, idx, taint_len, orig_buf, buf, + cbuf, len, 0, lvl, status))) { + + return 1; + + } + + } + + } + + if (*status != 1) { // u8 + + // if (its_len >= 1 && (attr <= 1 || attr >= 8)) + // fprintf(stderr, + // "TestU8: %u>=1 %x==%x %x==%x (idx=%u attr=%u) <= %x<-%x\n", + // its_len, *buf_8, pattern, *o_buf_8, o_pattern, idx, attr, + // repl, changed_val); + + if (its_len >= 1 && + ((*buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) || + attr >= 16)) { + + u8 tmp_8 = *buf_8; + *buf_8 = (u8)repl; + if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + if (*status == 1) { cbuf[idx] = *buf_8; } + *buf_8 = tmp_8; } @@ -370,49 +723,205 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) { + // here we add and subract 1 from the value, but only if it is not an + // == or != comparison + // Bits: 1 = Equal, 2 = Greater, 3 = Lesser, 4 = Float - if (its_len >= 4 && *buf_32 == (u32)pattern && - *o_buf_32 == (u32)o_pattern) { + if (lvl < 4) { return 0; } - *buf_32 = (u32)repl; - if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_32 = pattern; + if (attr >= 8 && attr < 16) { // lesser/greater integer comparison + + u64 repl_new; + if (SHAPE_BYTES(h->shape) == 4 && its_len >= 4) { + + float *f = (float *)&repl; + float g = *f; + g += 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; + + } else if (SHAPE_BYTES(h->shape) == 8 && its_len >= 8) { + + double *f = (double *)&repl; + double g = *f; + g += 1.0; + + u64 *r = (u64 *)&g; + repl_new = *r; + + } else { + + return 0; } - // reverse encoding - if (do_reverse && *status != 1) { + changed_val = repl_new; + + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 16, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + if (SHAPE_BYTES(h->shape) == 4) { + + float *f = (float *)&repl; + float g = *f; + g -= 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; + + } else if (SHAPE_BYTES(h->shape) == 8) { + + double *f = (double *)&repl; + double g = *f; + g -= 1.0; + u64 *r = (u64 *)&g; + repl_new = *r; + + } else { + + return 0; + + } + + changed_val = repl_new; + + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 16, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + // transform double to float, llvm likes to do that internally ... + if (SHAPE_BYTES(h->shape) == 8 && its_len >= 4) { + + double *f = (double *)&repl; + float g = (float)*f; + repl_new = 0; +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + memcpy((char *)&repl_new, (char *)&g, 4); +#else + memcpy(((char *)&repl_new) + 4, (char *)&g, 4); +#endif + changed_val = repl_new; + h->shape = 3; // modify shape - if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), - SWAP32(o_pattern), idx, orig_buf, buf, - len, 0, status))) { + // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new); + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + + h->shape = 7; return 1; } + h->shape = 7; // recover shape + + } + + } else if (attr > 1 && attr < 8) { // lesser/greater integer comparison + + u64 repl_new; + + repl_new = repl + 1; + changed_val = repl_new; + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 32, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + + } + + repl_new = repl - 1; + changed_val = repl_new; + if (unlikely(cmp_extend_encoding(afl, h, pattern, repl_new, o_pattern, + changed_val, 32, idx, taint_len, orig_buf, + buf, cbuf, len, 1, lvl, status))) { + + return 1; + } } - if (SHAPE_BYTES(h->shape) >= 2 && *status != 1) { + return 0; - if (its_len >= 2 && *buf_16 == (u16)pattern && - *o_buf_16 == (u16)o_pattern) { +} - *buf_16 = (u16)repl; +static u8 cmp_extend_encoding128(afl_state_t *afl, struct cmp_header *h, + u128 pattern, u128 repl, u128 o_pattern, + u128 changed_val, u8 attr, u32 idx, + u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u8 do_reverse, u8 lvl, u8 *status) { + + u128 *buf_128 = (u128 *)&buf[idx]; + u64 * buf0 = (u64 *)&buf[idx]; + u64 * buf1 = (u64 *)(buf + idx + 8); + u128 *o_buf_128 = (u128 *)&orig_buf[idx]; + u32 its_len = MIN(len - idx, taint_len); + u64 v10 = (u64)repl; + u64 v11 = (u64)(repl >> 64); + + // if this is an fcmp (attr & 8 == 8) then do not compare the patterns - + // due to a bug in llvm dynamic float bitcasts do not work :( + // the value 16 means this is a +- 1.0 test case + if (its_len >= 16) { + +#ifdef _DEBUG + fprintf(stderr, "TestU128: %u>=16 (idx=%u attr=%u) (%u)\n", its_len, idx, + attr, do_reverse); + u64 v00 = (u64)pattern; + u64 v01 = pattern >> 64; + u64 ov00 = (u64)o_pattern; + u64 ov01 = o_pattern >> 64; + u64 ov10 = (u64)changed_val; + u64 ov11 = changed_val >> 64; + u64 b00 = (u64)*buf_128; + u64 b01 = *buf_128 >> 64; + u64 ob00 = (u64)*o_buf_128; + u64 ob01 = *o_buf_128 >> 64; + fprintf(stderr, + "TestU128: %llx:%llx==%llx:%llx" + " %llx:%llx==%llx:%llx <= %llx:%llx<-%llx:%llx\n", + b01, b00, v01, v00, ob01, ob00, ov01, ov00, v11, v10, ov11, ov10); +#endif + + if (*buf_128 == pattern && *o_buf_128 == o_pattern) { + + u128 tmp_128 = *buf_128; + // *buf_128 = repl; <- this crashes +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + *buf0 = v10; + *buf1 = v11; +#else + *buf1 = v10; + *buf0 = v11; +#endif if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_16 = (u16)pattern; + if (*status == 1) { memcpy(cbuf + idx, buf_128, 16); } + *buf_128 = tmp_128; + +#ifdef _DEBUG + fprintf(stderr, "Status=%u\n", *status); +#endif } // reverse encoding if (do_reverse && *status != 1) { - if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), - SWAP16(o_pattern), idx, orig_buf, buf, - len, 0, status))) { + if (unlikely(cmp_extend_encoding128( + afl, h, SWAPN(pattern, 128), SWAPN(repl, 128), + SWAPN(o_pattern, 128), SWAPN(changed_val, 128), attr, idx, + taint_len, orig_buf, buf, cbuf, len, 0, lvl, status))) { return 1; @@ -422,14 +931,82 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* avoid CodeQL warning on unsigned overflow */ - if (/* SHAPE_BYTES(h->shape) >= 1 && */ *status != 1) { + return 0; - if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) { +} - *buf_8 = (u8)repl; +// uh a pointer read from (long double*) reads 12 bytes, not 10 ... +// so lets make this complicated. +static u8 cmp_extend_encoding_ld(afl_state_t *afl, struct cmp_header *h, + u8 *pattern, u8 *repl, u8 *o_pattern, + u8 *changed_val, u8 attr, u32 idx, + u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u8 do_reverse, u8 lvl, u8 *status) { + + u8 *buf_ld = &buf[idx], *o_buf_ld = &orig_buf[idx], backup[10]; + u32 its_len = MIN(len - idx, taint_len); + + if (its_len >= 10) { + +#ifdef _DEBUG + fprintf(stderr, "TestUld: %u>=10 (len=%u idx=%u attr=%u) (%u)\n", its_len, + len, idx, attr, do_reverse); + fprintf(stderr, "TestUld: "); + u32 i; + for (i = 0; i < 10; i++) + fprintf(stderr, "%02x", pattern[i]); + fprintf(stderr, "=="); + for (i = 0; i < 10; i++) + fprintf(stderr, "%02x", buf_ld[i]); + fprintf(stderr, " "); + for (i = 0; i < 10; i++) + fprintf(stderr, "%02x", o_pattern[i]); + fprintf(stderr, "=="); + for (i = 0; i < 10; i++) + fprintf(stderr, "%02x", o_buf_ld[i]); + fprintf(stderr, " <= "); + for (i = 0; i < 10; i++) + fprintf(stderr, "%02x", repl[i]); + fprintf(stderr, "=="); + for (i = 0; i < 10; i++) + fprintf(stderr, "%02x", changed_val[i]); + fprintf(stderr, "\n"); +#endif + + if (!memcmp(pattern, buf_ld, 10) && !memcmp(o_pattern, o_buf_ld, 10)) { + + // if this is an fcmp (attr & 8 == 8) then do not compare the patterns - + // due to a bug in llvm dynamic float bitcasts do not work :( + // the value 16 means this is a +- 1.0 test case + + memcpy(backup, buf_ld, 10); + memcpy(buf_ld, repl, 10); if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - *buf_8 = (u8)pattern; + if (*status == 1) { memcpy(cbuf + idx, repl, 10); } + memcpy(buf_ld, backup, 10); + +#ifdef _DEBUG + fprintf(stderr, "Status=%u\n", *status); +#endif + + } + + } + + // reverse encoding + if (do_reverse && *status != 1) { + + u8 sp[10], sr[10], osp[10], osr[10]; + SWAPNN(sp, pattern, 10); + SWAPNN(sr, repl, 10); + SWAPNN(osp, o_pattern, 10); + SWAPNN(osr, changed_val, 10); + + if (unlikely(cmp_extend_encoding_ld(afl, h, sp, sr, osp, osr, attr, idx, + taint_len, orig_buf, buf, cbuf, len, 0, + lvl, status))) { + + return 1; } @@ -445,10 +1022,6 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { u32 k; u8 cons_ff = 0, cons_0 = 0; - - if (shape > sizeof(v)) - FATAL("shape is greater than %zu, please report!", sizeof(v)); - for (k = 0; k < shape; ++k) { if (b[k] == 0) { @@ -457,7 +1030,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } else if (b[k] == 0xff) { - ++cons_ff; + ++cons_0; } else { @@ -493,28 +1066,126 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } -static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { +static void try_to_add_to_dict128(afl_state_t *afl, u128 v) { - struct cmp_header *h = &afl->shm.cmp_map->headers[key]; - u32 i, j, idx; + u8 *b = (u8 *)&v; - u32 loggeds = h->hits; + u32 k; + u8 cons_ff = 0, cons_0 = 0; + for (k = 0; k < 16; ++k) { + + if (b[k] == 0) { + + ++cons_0; + + } else if (b[k] == 0xff) { + + ++cons_0; + + } else { + + cons_0 = cons_ff = 0; + + } + + // too many uninteresting values? try adding 2 64-bit values + if (cons_0 > 6 || cons_ff > 6) { + + u64 v64 = (u64)v; + try_to_add_to_dict(afl, v64, 8); + v64 = (u64)(v >> 64); + try_to_add_to_dict(afl, v64, 8); + + return; + + } + + } + + maybe_add_auto(afl, (u8 *)&v, 16); + u128 rev = SWAPN(v, 128); + maybe_add_auto(afl, (u8 *)&rev, 16); + +} + +static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) { + + u8 *b = (u8 *)&v; + + u32 k; + u8 cons_ff = 0, cons_0 = 0; +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + for (k = 0; k < size; ++k) { + +#else + for (k = 16 - size; k < 16; ++k) { + +#endif + if (b[k] == 0) { + + ++cons_0; + + } else if (b[k] == 0xff) { + + ++cons_0; + + } else { + + cons_0 = cons_ff = 0; + + } + + } + + maybe_add_auto(afl, (u8 *)&v, size); + u128 rev = SWAPN(v, size); + maybe_add_auto(afl, (u8 *)&rev, size); + +} + +static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, u32 lvl, struct tainted *taint) { + + struct cmp_header *h = &afl->shm.cmp_map->headers[key]; + struct tainted * t; + u32 i, j, idx, taint_len; + u32 have_taint = 1, is_128 = 0, is_n = 0, is_ld = 0; + u32 loggeds = h->hits; if (h->hits > CMP_MAP_H) { loggeds = CMP_MAP_H; } u8 status = 0; - // opt not in the paper - u32 fails; - u8 found_one = 0; + u8 found_one = 0; /* loop cmps are useless, detect and ignore them */ - u64 s_v0, s_v1; - u8 s_v0_fixed = 1, s_v1_fixed = 1; - u8 s_v0_inc = 1, s_v1_inc = 1; - u8 s_v0_dec = 1, s_v1_dec = 1; + u128 s128_v0 = 0, s128_v1 = 0, orig_s128_v0 = 0, orig_s128_v1 = 0; + long double ld0, ld1, o_ld0, o_ld1; + u64 s_v0, s_v1; + u8 s_v0_fixed = 1, s_v1_fixed = 1; + u8 s_v0_inc = 1, s_v1_inc = 1; + u8 s_v0_dec = 1, s_v1_dec = 1; - for (i = 0; i < loggeds; ++i) { + switch (SHAPE_BYTES(h->shape)) { + + case 1: + case 2: + case 4: + case 8: + break; + case 16: + is_128 = 1; + break; + case 10: + if (h->attribute & 8) { is_ld = 1; } + // fall through + default: + is_n = 1; - fails = 0; + } + + // FCmp not in if level 1 only + if ((h->attribute & 8) && lvl < 2) return 0; + + for (i = 0; i < loggeds; ++i) { struct cmp_operands *o = &afl->shm.cmp_map->log[key][i]; @@ -551,55 +1222,242 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } - for (idx = 0; idx < len && fails < 8; ++idx) { +#ifdef _DEBUG + fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n", + orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, + SHAPE_BYTES(h->shape)); +#endif + + if (taint) { + + t = taint; + + while (t->next) { + + t = t->next; + + } + + } else { + + have_taint = 0; + t = NULL; + + } + + if (unlikely(is_128 || is_n)) { + + s128_v0 = ((u128)o->v0) + (((u128)o->v0_128) << 64); + s128_v1 = ((u128)o->v1) + (((u128)o->v1_128) << 64); + orig_s128_v0 = ((u128)orig_o->v0) + (((u128)orig_o->v0_128) << 64); + orig_s128_v1 = ((u128)orig_o->v1) + (((u128)orig_o->v1_128) << 64); + + if (is_ld) { + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + memcpy((char *)&ld0, (char *)&s128_v0, sizeof(long double)); + memcpy((char *)&ld1, (char *)&s128_v1, sizeof(long double)); + memcpy((char *)&o_ld0, (char *)&orig_s128_v0, sizeof(long double)); + memcpy((char *)&o_ld1, (char *)&orig_s128_v1, sizeof(long double)); +#else + memcpy((char *)&ld0, (char *)(&s128_v0) + 6, sizeof(long double)); + memcpy((char *)&ld1, (char *)(&s128_v1) + 6, sizeof(long double)); + memcpy((char *)&o_ld0, (char *)(&orig_s128_v0) + 6, + sizeof(long double)); + memcpy((char *)&o_ld1, (char *)(&orig_s128_v1) + 6, + sizeof(long double)); +#endif + + } + + } + + for (idx = 0; idx < len; ++idx) { + + if (have_taint) { + + if (!t || idx < t->pos) { + + continue; + + } else { + + taint_len = t->pos + t->len - idx; + + if (idx == t->pos + t->len - 1) { t = t->prev; } + + } + + } else { + + taint_len = len - idx; + + } status = 0; - if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, - orig_buf, buf, len, 1, &status))) { - return 1; + if (is_ld) { // long double special case + + if (ld0 != o_ld0 && o_ld1 != o_ld0) { + + if (unlikely(cmp_extend_encoding_ld( + afl, h, (u8 *)&ld0, (u8 *)&ld1, (u8 *)&o_ld0, (u8 *)&o_ld1, + h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1, + lvl, &status))) { + + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; + break; + + } + + if (ld1 != o_ld1 && o_ld0 != o_ld1) { + + if (unlikely(cmp_extend_encoding_ld( + afl, h, (u8 *)&ld1, (u8 *)&ld0, (u8 *)&o_ld1, (u8 *)&o_ld0, + h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1, + lvl, &status))) { + + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; + break; + + } + + } + + if (is_128) { // u128 special case + + if (s128_v0 != orig_s128_v0 && orig_s128_v0 != orig_s128_v1) { + + if (unlikely(cmp_extend_encoding128( + afl, h, s128_v0, s128_v1, orig_s128_v0, orig_s128_v1, + h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1, + lvl, &status))) { + + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; + break; + + } + + if (s128_v1 != orig_s128_v1 && orig_s128_v1 != orig_s128_v0) { + + if (unlikely(cmp_extend_encoding128( + afl, h, s128_v1, s128_v0, orig_s128_v1, orig_s128_v0, + h->attribute, idx, taint_len, orig_buf, buf, cbuf, len, 1, + lvl, &status))) { + + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; + break; + + } } - if (status == 2) { + // even for u128 and long double do cmp_extend_encoding() because + // if we got here their own special trials failed and it might just be + // a cast from e.g. u64 to u128 from the input data. - ++fails; + if ((o->v0 != orig_o->v0 || lvl >= 4) && orig_o->v0 != orig_o->v1) { - } else if (status == 1) { + if (unlikely(cmp_extend_encoding( + afl, h, o->v0, o->v1, orig_o->v0, orig_o->v1, h->attribute, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, &status))) { + return 1; + + } + + } + + if (status == 1) { + + found_one = 1; break; } status = 0; - if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, - orig_buf, buf, len, 1, &status))) { + if ((o->v1 != orig_o->v1 || lvl >= 4) && orig_o->v0 != orig_o->v1) { - return 1; + if (unlikely(cmp_extend_encoding( + afl, h, o->v1, o->v0, orig_o->v1, orig_o->v0, h->attribute, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, &status))) { - } + return 1; - if (status == 2) { + } - ++fails; + } - } else if (status == 1) { + if (status == 1) { + found_one = 1; break; } } - if (status == 1) { found_one = 1; } +#ifdef _DEBUG + fprintf(stderr, + "END: %llx->%llx vs %llx->%llx attr=%u i=%u found=%u is128=%u " + "isN=%u size=%u\n", + orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, i, found_one, + is_128, is_n, SHAPE_BYTES(h->shape)); +#endif // If failed, add to dictionary - if (fails == 8) { + if (!found_one) { if (afl->pass_stats[key].total == 0) { - try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape)); - try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape)); + if (unlikely(is_128)) { + + try_to_add_to_dict128(afl, s128_v0); + try_to_add_to_dict128(afl, s128_v1); + + } else if (unlikely(is_n)) { + + try_to_add_to_dictN(afl, s128_v0, SHAPE_BYTES(h->shape)); + try_to_add_to_dictN(afl, s128_v1, SHAPE_BYTES(h->shape)); + + } else { + + try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape)); + try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape)); + + } } @@ -630,20 +1488,19 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, - u8 *o_pattern, u32 idx, u8 *orig_buf, u8 *buf, - u32 len, u8 *status) { + u8 *o_pattern, u32 idx, u32 taint_len, + u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len, + u8 *status) { u32 i; u32 its_len = MIN((u32)32, len - idx); - + its_len = MIN(its_len, taint_len); u8 save[32]; memcpy(save, &buf[idx], its_len); - *status = 0; - for (i = 0; i < its_len; ++i) { - if (pattern[i] != buf[idx + i] || o_pattern[i] != orig_buf[idx + i] || + if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) || *status == 1) { break; @@ -654,6 +1511,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } + if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i); } + } memcpy(&buf[idx], save, i); @@ -661,23 +1520,21 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } -static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { +static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, + u32 len, struct tainted *taint) { + struct tainted * t; struct cmp_header *h = &afl->shm.cmp_map->headers[key]; - u32 i, j, idx; + u32 i, j, idx, have_taint = 1, taint_len; u32 loggeds = h->hits; if (h->hits > CMP_MAP_RTN_H) { loggeds = CMP_MAP_RTN_H; } u8 status = 0; - // opt not in the paper - // u32 fails = 0; u8 found_one = 0; for (i = 0; i < loggeds; ++i) { - u32 fails = 0; - struct cmpfn_operands *o = &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i]; @@ -696,50 +1553,84 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { } - for (idx = 0; idx < len && fails < 8; ++idx) { + if (taint) { - if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0, idx, - orig_buf, buf, len, &status))) { + t = taint; + while (t->next) { - return 1; + t = t->next; } - if (status == 2) { + } else { - ++fails; + have_taint = 0; + t = NULL; - } else if (status == 1) { + } - break; + for (idx = 0; idx < len; ++idx) { + + if (have_taint) { + + if (!t || idx < t->pos) { + + continue; + + } else { + + taint_len = t->pos + t->len - idx; + + if (idx == t->pos + t->len - 1) { t = t->prev; } + + } + + } else { + + taint_len = len - idx; } - if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1, idx, - orig_buf, buf, len, &status))) { + status = 0; + + if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0, idx, + taint_len, orig_buf, buf, cbuf, len, + &status))) { return 1; } - if (status == 2) { + if (status == 1) { + + found_one = 1; + break; + + } + + status = 0; + + if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1, idx, + taint_len, orig_buf, buf, cbuf, len, + &status))) { - ++fails; + return 1; - } else if (status == 1) { + } + if (status == 1) { + + found_one = 1; break; } } - if (status == 1) { found_one = 1; } - // If failed, add to dictionary - if (fails == 8) { + if (!found_one) { - if (afl->pass_stats[key].total == 0) { + if (unlikely(!afl->pass_stats[key].total)) { maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape)); maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape)); @@ -791,7 +1682,44 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map)); - if (unlikely(colorization(afl, buf, len, exec_cksum))) { return 1; } + struct tainted *taint = NULL; + + if (!afl->queue_cur->taint || !afl->queue_cur->cmplog_colorinput) { + + if (unlikely(colorization(afl, buf, len, exec_cksum, &taint))) { return 1; } + + // no taint? still try, create a dummy to prevent again colorization + if (!taint) { + + taint = ck_alloc(sizeof(struct tainted)); + taint->len = len; + + } + + } else { + + buf = afl->queue_cur->cmplog_colorinput; + taint = afl->queue_cur->taint; + // reget the cmplog information + if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) { return 1; } + + } + +#ifdef _DEBUG + dump("ORIG", orig_buf, len); + dump("NEW ", buf, len); +#endif + + struct tainted *t = taint; + + while (t) { + +#ifdef _DEBUG + fprintf(stderr, "T: pos=%u len=%u\n", t->pos, t->len); +#endif + t = t->next; + + } // do it manually, forkserver clear only afl->fsrv.trace_bits memset(afl->shm.cmp_map->headers, 0, sizeof(afl->shm.cmp_map->headers)); @@ -807,15 +1735,38 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, afl->stage_max = 0; afl->stage_cur = 0; + u32 lvl; + u32 cmplog_done = afl->queue_cur->colorized; + u32 cmplog_lvl = afl->cmplog_lvl; + if (!cmplog_done) { + + lvl = 1; + + } else { + + lvl = 0; + + } + + if (cmplog_lvl >= 2 && cmplog_done < 2) { lvl += 2; } + if (cmplog_lvl >= 3 && cmplog_done < 3) { lvl += 4; } + + u8 *cbuf = afl_realloc((void **)&afl->in_scratch_buf, len + 128); + memcpy(cbuf, orig_buf, len); + u8 *virgin_backup = afl_realloc((void **)&afl->ex_buf, afl->shm.map_size); + memcpy(virgin_backup, afl->virgin_bits, afl->shm.map_size); + u32 k; for (k = 0; k < CMP_MAP_W; ++k) { if (!afl->shm.cmp_map->headers[k].hits) { continue; } - if (afl->pass_stats[k].total && - (rand_below(afl, afl->pass_stats[k].total) >= - afl->pass_stats[k].faileds || - afl->pass_stats[k].total == 0xff)) { + if (afl->pass_stats[k].faileds == 0xff || + afl->pass_stats[k].total == 0xff) { + +#ifdef _DEBUG + fprintf(stderr, "DISABLED %u\n", k); +#endif afl->shm.cmp_map->headers[k].hits = 0; // ignore this cmp @@ -841,11 +1792,19 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) { - if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, len))) { goto exit_its; } + if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) { + + goto exit_its; + + } } else { - if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, len))) { goto exit_its; } + if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, taint))) { + + goto exit_its; + + } } @@ -854,12 +1813,86 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, r = 0; exit_its: + + afl->queue_cur->colorized = afl->cmplog_lvl; + if (afl->cmplog_lvl == CMPLOG_LVL_MAX) { + + ck_free(afl->queue_cur->cmplog_colorinput); + t = taint; + while (taint) { + + t = taint->next; + ck_free(taint); + taint = t; + + } + + afl->queue_cur->taint = NULL; + + } else { + + if (!afl->queue_cur->taint) { afl->queue_cur->taint = taint; } + + if (!afl->queue_cur->cmplog_colorinput) { + + afl->queue_cur->cmplog_colorinput = ck_alloc_nozero(len); + memcpy(afl->queue_cur->cmplog_colorinput, buf, len); + memcpy(buf, orig_buf, len); + + } + + } + + // copy the current virgin bits so we can recover the information + u8 *virgin_save = afl_realloc((void **)&afl->eff_buf, afl->shm.map_size); + memcpy(virgin_save, afl->virgin_bits, afl->shm.map_size); + // reset virgin bits to the backup previous to redqueen + memcpy(afl->virgin_bits, virgin_backup, afl->shm.map_size); + + u8 status = 0; + its_fuzz(afl, cbuf, len, &status); + + // now combine with the saved virgin bits +#ifdef WORD_SIZE_64 + u64 *v = (u64 *)afl->virgin_bits; + u64 *s = (u64 *)virgin_save; + u32 i; + for (i = 0; i < (afl->shm.map_size >> 3); i++) { + + v[i] &= s[i]; + + } + +#else + u32 *v = (u64 *)afl->virgin_bits; + u32 *s = (u64 *)virgin_save; + u32 i; + for (i = 0; i < (afl->shm.map_size >> 2); i++) { + + v[i] &= s[i]; + + } + +#endif + +#ifdef _DEBUG + dump("COMB", cbuf, len); + if (status == 1) { + + fprintf(stderr, "NEW COMBINED\n"); + + } else { + + fprintf(stderr, "NO new combined\n"); + + } + +#endif + new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs; - memcpy(buf, orig_buf, len); - return r; } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 60c9684c..8423a3d1 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -102,6 +102,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_update_freq = 1; afl->stats_avg_exec = 0; afl->skip_deterministic = 1; + afl->cmplog_lvl = 1; #ifndef NO_SPLICING afl->use_splicing = 1; #endif diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bb2674f0..1e914ca6 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -77,13 +77,8 @@ static void at_exit() { } int kill_signal = SIGKILL; - /* AFL_KILL_SIGNAL should already be a valid int at this point */ - if (getenv("AFL_KILL_SIGNAL")) { - - kill_signal = atoi(getenv("AFL_KILL_SIGNAL")); - - } + if ((ptr = getenv("AFL_KILL_SIGNAL"))) { kill_signal = atoi(ptr); } if (pid1 > 0) { kill(pid1, kill_signal); } if (pid2 > 0) { kill(pid2, kill_signal); } @@ -103,13 +98,14 @@ static void usage(u8 *argv0, int more_help) { "Execution control settings:\n" " -p schedule - power schedules compute a seed's performance score:\n" - " -- see docs/power_schedules.md\n" + " fast(default), explore, exploit, seek, rare, mmopt, " + "coe, lin\n" + " quad -- see docs/power_schedules.md\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" " -t msec - timeout for each run (auto-scaled, 50-%u ms)\n" - " -m megs - memory limit for child process (%u MB, 0 = no limit)\n" + " -m megs - memory limit for child process (%u MB, 0 = no limit " + "[default])\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -125,7 +121,9 @@ static void usage(u8 *argv0, int more_help) { " See docs/README.MOpt.md\n" " -c program - enable CmpLog by specifying a binary compiled for " "it.\n" - " if using QEMU, just use -c 0.\n\n" + " if using QEMU, just use -c 0.\n" + " -l cmplog_level - set the complexity/intensivity of CmpLog.\n" + " Values: 1 (default), 2 (intensive) and 3 (heavy)\n\n" "Fuzzing behavior settings:\n" " -Z - sequential queue selection instead of weighted " @@ -337,7 +335,6 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; } - // map_size = get_map_size(); afl_state_init(afl, map_size); afl->debug = debug; afl_fsrv_init(&afl->fsrv); @@ -358,7 +355,8 @@ int main(int argc, char **argv_orig, char **envp) { 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:Z")) > 0) { + "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:P:RQs:S:t:T:UV:Wx:Z")) > + 0) { switch (opt) { @@ -787,6 +785,26 @@ int main(int argc, char **argv_orig, char **envp) { } break; + case 'l': { + + afl->cmplog_lvl = atoi(optarg); + if (afl->cmplog_lvl < 1 || afl->cmplog_lvl > CMPLOG_LVL_MAX) { + + FATAL( + "Bad complog level value, accepted values are 1 (default), 2 and " + "%u.", + CMPLOG_LVL_MAX); + + } + + if (afl->cmplog_lvl == CMPLOG_LVL_MAX) { + + afl->cmplog_max_filesize = MAX_FILE; + + } + + } break; + case 'L': { /* MOpt mode */ if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); } @@ -1635,6 +1653,14 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->use_splicing) { ++afl->cycles_wo_finds; + + if (unlikely(afl->shm.cmplog_mode && + afl->cmplog_max_filesize < MAX_FILE)) { + + afl->cmplog_max_filesize <<= 4; + + } + switch (afl->expand_havoc) { case 0: @@ -1652,6 +1678,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl->expand_havoc = 2; + if (afl->cmplog_lvl < 2) afl->cmplog_lvl = 2; break; case 2: // if (!have_p) afl->schedule = EXPLOIT; @@ -1665,11 +1692,14 @@ int main(int argc, char **argv_orig, char **envp) { afl->expand_havoc = 4; break; case 4: - // if not in sync mode, enable deterministic mode? - // if (!afl->sync_id) afl->skip_deterministic = 0; afl->expand_havoc = 5; + if (afl->cmplog_lvl < 3) afl->cmplog_lvl = 3; break; case 5: + // if not in sync mode, enable deterministic mode? + if (!afl->sync_id) afl->skip_deterministic = 0; + afl->expand_havoc = 6; + case 6: // nothing else currently break; -- cgit 1.4.1 From c71ce79963ffd3e1203d1078b8a60f91c4ecebf1 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 17 Jan 2021 15:18:20 +0100 Subject: fix colorization --- GNUmakefile | 4 +-- include/afl-fuzz.h | 4 +-- instrumentation/afl-compiler-rt.o.c | 3 +- src/afl-fuzz-one.c | 6 ++-- src/afl-fuzz-redqueen.c | 56 ++++++++++++++++++++++--------------- src/afl-fuzz.c | 2 ++ src/afl-showmap.c | 25 ++++++++++++++--- 7 files changed, 65 insertions(+), 35 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/GNUmakefile b/GNUmakefile index 7b05a1d5..c71a7d47 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -428,8 +428,8 @@ src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm -afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o $@ $(LDFLAGS) +afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8a2122dc..621e8745 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1136,9 +1136,9 @@ void read_foreign_testcases(afl_state_t *, int); u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); /* RedQueen */ -u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, - u64 exec_cksum); +u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len); +/* our RNG wrapper */ AFL_RAND_RETURN rand_next(afl_state_t *afl); /* probability between 0.0 and 1.0 */ diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 5d75af78..bbec52f9 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1209,7 +1209,8 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) { - // fprintf(stderr, "hook1 arg0=%02x arg1=%02x attr=%u\n", arg1, arg2, attr); + // fprintf(stderr, "hook1 arg0=%02x arg1=%02x attr=%u\n", + // (u8) arg1, (u8) arg2, attr); if (unlikely(!__afl_cmp_map)) return; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 596bae22..4ce22c08 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,8 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { !(afl->fsrv.total_execs % afl->queued_paths) || get_cur_time() - afl->last_path_time > 15000) { - if (input_to_state_stage(afl, in_buf, out_buf, len, - afl->queue_cur->exec_cksum)) { + if (input_to_state_stage(afl, in_buf, out_buf, len)) { goto abandon_entry; @@ -2986,8 +2985,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { !(afl->fsrv.total_execs % afl->queued_paths) || get_cur_time() - afl->last_path_time > 15000) { - if (input_to_state_stage(afl, in_buf, out_buf, len, - afl->queue_cur->exec_cksum)) { + if (input_to_state_stage(afl, in_buf, out_buf, len)) { goto abandon_entry; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 955a9232..052f59f1 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -88,7 +88,7 @@ static struct range *pop_biggest_range(struct range **ranges) { static void dump(char *txt, u8 *buf, u32 len) { u32 i; - fprintf(stderr, "DUMP %s %llx ", txt, hash64(buf, len, 0)); + fprintf(stderr, "DUMP %s %llx ", txt, hash64(buf, len, HASH_CONST)); for (i = 0; i < len; i++) fprintf(stderr, "%02x", buf[i]); fprintf(stderr, "\n"); @@ -117,6 +117,7 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) { if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; } *cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + return 0; } @@ -200,7 +201,7 @@ static void type_replace(afl_state_t *afl, u8 *buf, u32 len) { } -static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum, +static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, struct tainted **taints) { struct range * ranges = add_range(NULL, 0, len - 1), *rng; @@ -208,18 +209,31 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum, u8 * backup = ck_alloc_nozero(len); u8 * changed = ck_alloc_nozero(len); - u64 orig_hit_cnt, new_hit_cnt; + u64 orig_hit_cnt, new_hit_cnt, exec_cksum; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_name = "colorization"; afl->stage_short = "colorization"; afl->stage_max = (len << 1); - afl->stage_cur = 0; + + // in colorization we do not classify counts, hence we have to calculate + // the original checksum! + if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) { + + goto checksum_fail; + + } + memcpy(backup, buf, len); memcpy(changed, buf, len); type_replace(afl, changed, len); +#ifdef _DEBUG + dump("ORIG", buf, len); + dump("CHAN", changed, len); +#endif + while ((rng = pop_biggest_range(&ranges)) != NULL && afl->stage_cur < afl->stage_max) { @@ -227,7 +241,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum, memcpy(buf + rng->start, changed + rng->start, s); - u64 cksum; + u64 cksum = 0; u64 start_us = get_cur_time_us(); if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) { @@ -633,11 +647,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) { // if (its_len >= 4 && (attr <= 1 || attr >= 8)) - // fprintf(stderr, - // "TestU32: %u>=4 %x==%llx" - // " %x==%llx (idx=%u attr=%u) <= %llx<-%llx\n", - // its_len, *buf_32, pattern, *o_buf_32, o_pattern, idx, attr, - // repl, changed_val); + // fprintf(stderr, + // "TestU32: %u>=4 %x==%llx" + // " %x==%llx (idx=%u attr=%u) <= %llx<-%llx\n", + // its_len, *buf_32, pattern, *o_buf_32, o_pattern, idx, attr, + // repl, changed_val); if (its_len >= 4 && ((*buf_32 == (u32)pattern && *o_buf_32 == (u32)o_pattern) || @@ -702,10 +716,10 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, if (*status != 1) { // u8 // if (its_len >= 1 && (attr <= 1 || attr >= 8)) - // fprintf(stderr, - // "TestU8: %u>=1 %x==%x %x==%x (idx=%u attr=%u) <= %x<-%x\n", - // its_len, *buf_8, pattern, *o_buf_8, o_pattern, idx, attr, - // repl, changed_val); + // fprintf(stderr, + // "TestU8: %u>=1 %x==%x %x==%x (idx=%u attr=%u) <= %x<-%x\n", + // its_len, *buf_8, (u8)pattern, *o_buf_8, (u8)o_pattern, idx, + // attr, (u8)repl, (u8)changed_val); if (its_len >= 1 && ((*buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) || @@ -1659,8 +1673,7 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, ///// Input to State stage // afl->queue_cur->exec_cksum -u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, - u64 exec_cksum) { +u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { u8 r = 1; if (unlikely(!afl->orig_cmp_map)) { @@ -1686,7 +1699,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, if (!afl->queue_cur->taint || !afl->queue_cur->cmplog_colorinput) { - if (unlikely(colorization(afl, buf, len, exec_cksum, &taint))) { return 1; } + if (unlikely(colorization(afl, buf, len, &taint))) { return 1; } // no taint? still try, create a dummy to prevent again colorization if (!taint) { @@ -1696,6 +1709,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, } +#ifdef _DEBUG + dump("NEW ", buf, len); +#endif + } else { buf = afl->queue_cur->cmplog_colorinput; @@ -1705,11 +1722,6 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, } -#ifdef _DEBUG - dump("ORIG", orig_buf, len); - dump("NEW ", buf, len); -#endif - struct tainted *t = taint; while (t) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 1e914ca6..88c40ee8 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1094,6 +1094,8 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->shm.cmplog_mode) { OKF("CmpLog level: %u", afl->cmplog_lvl); } + /* Dynamically allocate memory for AFLFast schedules */ if (afl->schedule >= FAST && afl->schedule <= RARE) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 5c9d38e0..5d98d646 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -42,6 +42,7 @@ #include "sharedmem.h" #include "forkserver.h" #include "common.h" +#include "hash.h" #include #include @@ -86,7 +87,8 @@ static u8 quiet_mode, /* Hide non-essential messages? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ remove_shm = 1, /* remove shmem? */ - collect_coverage; /* collect coverage */ + collect_coverage, /* collect coverage */ + no_classify; /* do not classify counts */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -317,7 +319,9 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, } - classify_counts(fsrv); + if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; } + + if (!no_classify) { classify_counts(fsrv); } if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); } @@ -490,7 +494,9 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { } - classify_counts(fsrv); + if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; } + + if (!no_classify) { classify_counts(fsrv); } if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); } @@ -680,6 +686,7 @@ static void usage(u8 *argv0) { " -q - sink program's output and don't show messages\n" " -e - show edge coverage only, ignore hit counts\n" " -r - show real tuple values instead of AFL filter values\n" + " -s - do not classify the map\n" " -c - allow core dumps\n\n" "This tool displays raw tuple data captured by AFL instrumentation.\n" @@ -729,10 +736,14 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrsh")) > 0) { switch (opt) { + case 's': + no_classify = 1; + break; + case 'C': collect_coverage = 1; quiet_mode = 1; @@ -1213,6 +1224,12 @@ int main(int argc, char **argv_orig, char **envp) { showmap_run_target(fsrv, use_argv); tcnt = write_results_to_file(fsrv, out_file); + if (!quiet_mode) { + + OKF("Hash of coverage map: %llx", + hash64(fsrv->trace_bits, fsrv->map_size, HASH_CONST)); + + } } -- cgit 1.4.1 From 0306261fec4c9ebc2b1361da1d0fbbe9bade8847 Mon Sep 17 00:00:00 2001 From: Joey Jiao Date: Wed, 13 Jan 2021 12:32:36 +0800 Subject: Fix build error for Android - LTO not work yet --- Android.bp | 304 +++++++++++++++++++++++++-- Android.mk | 1 - include/afl-fuzz.h | 4 - include/android-ashmem.h | 113 ++++------ src/afl-analyze.c | 3 - src/afl-fuzz-stats.c | 4 + src/afl-gotcpu.c | 3 - src/afl-showmap.c | 3 - src/afl-tmin.c | 4 - utils/afl_network_proxy/afl-network-server.c | 4 - 10 files changed, 332 insertions(+), 111 deletions(-) delete mode 120000 Android.mk (limited to 'include/afl-fuzz.h') diff --git a/Android.bp b/Android.bp index 2c2114b2..549577db 100644 --- a/Android.bp +++ b/Android.bp @@ -1,5 +1,13 @@ cc_defaults { name: "afl-defaults", + sanitize: { + never: true, + }, + + local_include_dirs: [ + "include", + "instrumentation", + ], cflags: [ "-funroll-loops", @@ -14,12 +22,17 @@ cc_defaults { "-DBIN_PATH=\"out/host/linux-x86/bin\"", "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"", "-D__USE_GNU", + "-D__aarch64__", + "-DDEBUG_BUILD", + "-U_FORTIFY_SOURCE", + "-g", + "-O0", + "-fno-omit-frame-pointer", ], } cc_binary { name: "afl-fuzz", - static_executable: true, host_supported: true, defaults: [ @@ -27,7 +40,11 @@ cc_binary { ], srcs: [ - "afl-fuzz.c", + "src/afl-fuzz*.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", ], } @@ -41,7 +58,10 @@ cc_binary { ], srcs: [ - "afl-showmap.c", + "src/afl-showmap.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", ], } @@ -55,7 +75,11 @@ cc_binary { ], srcs: [ - "afl-tmin.c", + "src/afl-tmin.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", ], } @@ -69,7 +93,10 @@ cc_binary { ], srcs: [ - "afl-analyze.c", + "src/afl-analyze.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-performance.c", ], } @@ -83,12 +110,13 @@ cc_binary { ], srcs: [ - "afl-gotcpu.c", + "src/afl-gotcpu.c", + "src/afl-common.c", ], } cc_binary_host { - name: "afl-clang-fast", + name: "afl-cc", static_executable: true, defaults: [ @@ -98,44 +126,286 @@ cc_binary_host { cflags: [ "-D__ANDROID__", "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + "-DAFL_CLANG_FLTO=\"-flto=full\"", + "-DUSE_BINDIR=1", + "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"", + "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"", + "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"", + "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"", + "-DLLVM_LTO=1", ], srcs: [ "src/afl-cc.c", + "src/afl-common.c", + ], + + symlinks: [ + "afl-clang-fast", + "afl-clang-fast++", + "afl-clang-lto", + "afl-clang-lto++", ], } -cc_binary_host { - name: "afl-clang-fast++", - static_executable: true, +cc_library_static { + name: "afl-llvm-rt", + compile_multilib: "both", + vendor_available: true, + host_supported: true, + recovery_available: true, + sdk_version: "9", + + apex_available: [ + "com.android.adbd", + "com.android.appsearch", + "com.android.art", + "com.android.bluetooth.updatable", + "com.android.cellbroadcast", + "com.android.conscrypt", + "com.android.extservices", + "com.android.cronet", + "com.android.neuralnetworks", + "com.android.media", + "com.android.media.swcodec", + "com.android.mediaprovider", + "com.android.permission", + "com.android.runtime", + "com.android.resolv", + "com.android.tethering", + "com.android.wifi", + "com.android.sdkext", + "com.android.os.statsd", + "//any", + ], defaults: [ "afl-defaults", ], - cflags: [ - "-D__ANDROID__", - "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + srcs: [ + "instrumentation/afl-compiler-rt.o.c", ], +} - srcs: [ - "src/afl-cc.c", +cc_defaults { + name: "afl-defaults-lto", + + include_dirs: [ + "prebuilts/clang/host/linux-x86/clang-r383902b/include", ], } +/*cc_library_host_shared { + name: "afl-llvm-lto-instrumentlist", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/afl-llvm-lto-instrumentlist.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "afl-llvm-dict2file", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/afl-llvm-dict2file.so.cc", + "instrumentation/afl-llvm-common.cc", + ], + + shared_libs: [ + "libLLVM-11git", + ], +}*/ + +/*cc_library_host_shared { + name: "cmplog-routines-pass", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/cmplog-routines-pass.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "cmplog-instructions-pass", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/cmplog-instructions-pass.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "split-switches-pass", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/split-switches-pass.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "compare-transform-pass", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/compare-transform-pass.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "split-compares-pass", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/split-compares-pass.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "libLLVMInsTrim", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/LLVMInsTrim.so.cc", + "instrumentation/MarkNodes.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "afl-llvm-pass", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/afl-llvm-pass.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "SanitizerCoveragePCGUARD", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/SanitizerCoveragePCGUARD.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "SanitizerCoverageLTO", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/SanitizerCoverageLTO.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + +/*cc_library_host_shared { + name: "afl-llvm-lto-instrumentation", + + defaults: [ + "afl-defaults", + "afl-defaults-lto", + ], + + srcs: [ + "instrumentation/afl-llvm-lto-instrumentation.so.cc", + "instrumentation/afl-llvm-common.cc", + ], +}*/ + cc_library_static { - name: "afl-llvm-rt", + name: "afl-llvm-rt-lto", compile_multilib: "both", vendor_available: true, host_supported: true, recovery_available: true, sdk_version: "9", + apex_available: [ + "com.android.adbd", + "com.android.appsearch", + "com.android.art", + "com.android.bluetooth.updatable", + "com.android.cellbroadcast", + "com.android.conscrypt", + "com.android.extservices", + "com.android.cronet", + "com.android.neuralnetworks", + "com.android.media", + "com.android.media.swcodec", + "com.android.mediaprovider", + "com.android.permission", + "com.android.runtime", + "com.android.resolv", + "com.android.tethering", + "com.android.wifi", + "com.android.sdkext", + "com.android.os.statsd", + "//any", + ], + defaults: [ "afl-defaults", + "afl-defaults-lto", ], srcs: [ - "instrumentation/afl-llvm-rt.o.c", + "instrumentation/afl-llvm-rt-lto.o.c", ], } diff --git a/Android.mk b/Android.mk deleted file mode 120000 index 33ceb8f0..00000000 --- a/Android.mk +++ /dev/null @@ -1 +0,0 @@ -Makefile \ No newline at end of file diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 988a907d..6342c8b6 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -37,10 +37,6 @@ #define _FILE_OFFSET_BITS 64 #endif -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 41d4d2da..6939e06d 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -1,112 +1,81 @@ -/* - american fuzzy lop++ - android shared memory compatibility layer - ---------------------------------------------------------------- - - Originally written by Michal Zalewski - - Now maintained by Marc Heuse , - Heiko Eißfeldt , - Andrea Fioraldi , - Dominik Maier - - Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This header re-defines the shared memory routines used by AFL++ - using the Andoid API. - - */ - +#ifdef __ANDROID__ #ifndef _ANDROID_ASHMEM_H #define _ANDROID_ASHMEM_H -#ifdef __ANDROID__ - - #include - #include - #include - #include - #include - - #if __ANDROID_API__ >= 26 - #define shmat bionic_shmat - #define shmctl bionic_shmctl - #define shmdt bionic_shmdt - #define shmget bionic_shmget - #endif - - #include - #undef shmat - #undef shmctl - #undef shmdt - #undef shmget - #include +#include +#include +#include +#include - #define ASHMEM_DEVICE "/dev/ashmem" +#if __ANDROID_API__ >= 26 +#define shmat bionic_shmat +#define shmctl bionic_shmctl +#define shmdt bionic_shmdt +#define shmget bionic_shmget +#endif +#include +#undef shmat +#undef shmctl +#undef shmdt +#undef shmget +#include -static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { +#define ASHMEM_DEVICE "/dev/ashmem" +int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - struct ashmem_pin pin = {0, (unsigned int)length}; + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); - } return ret; - } -static inline int shmget(key_t __key, size_t __size, int __shmflg) { - - (void)__shmflg; - int fd, ret; +int shmget(key_t __key, size_t __size, int __shmflg) { + (void) __shmflg; + int fd, ret; char ourkey[11]; fd = open(ASHMEM_DEVICE, O_RDWR); - if (fd < 0) return fd; + if (fd < 0) + return fd; sprintf(ourkey, "%d", __key); ret = ioctl(fd, ASHMEM_SET_NAME, ourkey); - if (ret < 0) goto error; + if (ret < 0) + goto error; ret = ioctl(fd, ASHMEM_SET_SIZE, __size); - if (ret < 0) goto error; + if (ret < 0) + goto error; return fd; error: close(fd); return ret; - } -static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { - - (void)__shmflg; - int size; +void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { + (void) __shmflg; + int size; void *ptr; size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - if (size < 0) { return NULL; } + if (size < 0) { + return NULL; + } ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0); - if (ptr == MAP_FAILED) { return NULL; } + if (ptr == MAP_FAILED) { + return NULL; + } return ptr; - } -#endif /* __ANDROID__ */ - -#endif - +#endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 8fc4434a..0af489fe 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -26,9 +26,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index e86f2aeb..e67bace9 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -58,7 +58,11 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { for (i = 0; i < argc; ++i) { if (i) fprintf(f, " "); +#ifdef __ANDROID__ + if (memchr(argv[i], '\'', sizeof(argv[i]))) { +#else if (index(argv[i], '\'')) { +#endif fprintf(f, "'"); for (j = 0; j < strlen(argv[i]); j++) diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c index 1aea3e40..ac002a93 100644 --- a/src/afl-gotcpu.c +++ b/src/afl-gotcpu.c @@ -35,9 +35,6 @@ #define _GNU_SOURCE #endif -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include #include #include diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 5c9d38e0..6d95fc1d 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -31,9 +31,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 6e2d7708..5fd60cd2 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -29,10 +29,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c index 513dc8f2..fe225416 100644 --- a/utils/afl_network_proxy/afl-network-server.c +++ b/utils/afl_network_proxy/afl-network-server.c @@ -24,10 +24,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" -- cgit 1.4.1 From 3b3565269d0453c9f4b5b2847f809cd5d315fff2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 30 Jan 2021 14:57:17 +0100 Subject: foreign sync from ctime to mtime (libfuzzer) --- include/afl-fuzz.h | 2 +- src/afl-fuzz-init.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f46d7707..12db9e4d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -404,7 +404,7 @@ struct afl_pass_stat { struct foreign_sync { u8 * dir; - time_t ctime; + time_t mtime; }; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 84f81112..1808f0a1 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -468,7 +468,7 @@ void read_foreign_testcases(afl_state_t *afl, int first) { afl->foreign_syncs[iter].dir[0] != 0) { if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir); - time_t ctime_max = 0; + time_t mtime_max = 0; u8 * name = strrchr(afl->foreign_syncs[iter].dir, '/'); if (!name) { name = afl->foreign_syncs[iter].dir; } if (!strcmp(name, "queue") || !strcmp(name, "out") || @@ -482,8 +482,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) { } - /* We do not use sorting yet and do a more expensive ctime check instead. - a ctimesort() implementation would be better though. */ + /* We do not use sorting yet and do a more expensive mtime check instead. + a mtimesort() implementation would be better though. */ nl_cnt = scandir(afl->foreign_syncs[iter].dir, &nl, NULL, NULL); @@ -537,8 +537,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) { } - /* we detect new files by their ctime */ - if (likely(st.st_ctime <= afl->foreign_syncs[iter].ctime)) { + /* we detect new files by their mtime */ + if (likely(st.st_mtime <= afl->foreign_syncs[iter].mtime)) { ck_free(fn2); continue; @@ -600,11 +600,11 @@ void read_foreign_testcases(afl_state_t *afl, int first) { munmap(mem, st.st_size); close(fd); - if (st.st_ctime > ctime_max) ctime_max = st.st_ctime; + if (st.st_mtime > mtime_max) mtime_max = st.st_mtime; } - afl->foreign_syncs[iter].ctime = ctime_max; + afl->foreign_syncs[iter].mtime = mtime_max; free(nl); /* not tracked */ } -- cgit 1.4.1 From 9d08f0d098c91e69b5fe41674e4c5d05363af604 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 30 Jan 2021 15:39:47 +0100 Subject: added AFL_CMPLOG_ONLY_NEW feature --- docs/Changelog.md | 2 + docs/env_variables.md | 5 ++ include/afl-fuzz.h | 2 +- include/common.h | 2 +- include/envs.h | 1 + src/afl-analyze.c | 22 ++++---- src/afl-common.c | 6 +-- src/afl-fuzz-init.c | 3 ++ src/afl-fuzz-one.c | 5 +- src/afl-fuzz-redqueen.c | 135 +++++++++++++++++++++++++----------------------- src/afl-fuzz-state.c | 7 +++ src/afl-fuzz.c | 35 +++++++------ src/afl-showmap.c | 24 ++++----- src/afl-tmin.c | 24 ++++----- 14 files changed, 147 insertions(+), 126 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index 329b7520..6e59961b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,8 @@ sending a mail to . transformations (e.g. toupper, tolower, to/from hex, xor, arithmetics, etc.). this is costly hence new command line option -l that sets the intensity (values 1 to 3). recommended is 1 or 2. + - added `AFL_CMPLOG_ONLY_NEW` to not use cmplog on initial testcases from + `-i` or resumes (as these have most likely already been done) - fix crash for very, very fast targets+systems (thanks to mhlakhani for reporting) - if determinstic mode is active (-D, or -M without -d) then we sync diff --git a/docs/env_variables.md b/docs/env_variables.md index 66d85749..4c3b1cfb 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -287,6 +287,11 @@ checks or alter some of the more exotic semantics of the tool: the target. This must be equal or larger than the size the target was compiled with. + - `AFL_CMPLOG_ONLY_NEW` will only perform the expensive cmplog feature for + newly found testcases and not for testcases that are loaded on startup + (`-i in`). This is an important feature to set when resuming a fuzzing + session. + - `AFL_TESTCACHE_SIZE` allows you to override the size of `#define TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if your fuzzing finds a huge amount of paths for large inputs. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 12db9e4d..e8a21cb5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -384,7 +384,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, afl_autoresume, afl_cal_fast, - afl_cycle_schedules, afl_expand_havoc, afl_statsd; + afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/common.h b/include/common.h index bdaa1735..bb8831f2 100644 --- a/include/common.h +++ b/include/common.h @@ -47,7 +47,7 @@ void argv_cpy_free(char **argv); char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv); char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv); char * get_afl_env(char *env); -u8 *get_libqasan_path(u8 *own_loc); +u8 * get_libqasan_path(u8 *own_loc); extern u8 be_quiet; extern u8 *doc_path; /* path to documentation dir */ diff --git a/include/envs.h b/include/envs.h index 926c9e27..210b34a6 100644 --- a/include/envs.h +++ b/include/envs.h @@ -28,6 +28,7 @@ static char *afl_environment_variables[] = { "AFL_CC", "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", + "AFL_CMPLOG_ONLY_NEW", "AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME", diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 28598ba0..20aef2da 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -1079,28 +1079,28 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file) { usage(argv[0]); } if (qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + ck_free(libqasan); - + } map_size = get_map_size(); diff --git a/src/afl-common.c b/src/afl-common.c index a69f2e97..235c4c05 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -364,11 +364,7 @@ u8 *get_libqasan_path(u8 *own_loc) { cp = alloc_printf("%s/libqasan.so", own_copy); ck_free(own_copy); - if (!access(cp, X_OK)) { - - return cp; - - } + if (!access(cp, X_OK)) { return cp; } } else { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 1808f0a1..2a7864f9 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -25,6 +25,7 @@ #include "afl-fuzz.h" #include +#include "cmplog.h" #ifdef HAVE_AFFINITY @@ -833,6 +834,8 @@ void perform_dry_run(afl_state_t *afl) { } + if (afl->afl_env.afl_cmplog_only_new) { q->colorized = CMPLOG_LVL_MAX; } + u8 *fn = strrchr(q->fname, '/') + 1; ACTF("Attempting dry run with '%s'...", fn); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ff766158..0cf889a8 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -26,6 +26,7 @@ #include "afl-fuzz.h" #include #include +#include "cmplog.h" /* MOpt */ @@ -553,7 +554,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(len < 4)) { - afl->queue_cur->colorized = 0xff; + afl->queue_cur->colorized = CMPLOG_LVL_MAX; } else { @@ -2981,7 +2982,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (unlikely(len < 4)) { - afl->queue_cur->colorized = 0xff; + afl->queue_cur->colorized = CMPLOG_LVL_MAX; } else { diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index fc620781..d7657c1d 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -1118,7 +1118,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, #ifdef ARITHMETIC_LESSER_GREATER if (lvl < LVL3 || attr == IS_TRANSFORM) { return 0; } - if (!(attr & (IS_GREATER | IS_LESSER)) || SHAPE_BYTES(h->shape) < 4) { return 0; } + if (!(attr & (IS_GREATER | IS_LESSER)) || SHAPE_BYTES(h->shape) < 4) { + + return 0; + + } // transform >= to < and <= to > if ((attr & IS_EQUAL) && (attr & (IS_GREATER | IS_LESSER))) { @@ -1138,110 +1142,110 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // lesser/greater FP comparison if (attr >= IS_FP && attr < IS_FP_MOD) { - u64 repl_new; - - if (attr & IS_GREATER) { + u64 repl_new; - if (SHAPE_BYTES(h->shape) == 4 && its_len >= 4) { + if (attr & IS_GREATER) { - float *f = (float *)&repl; - float g = *f; - g += 1.0; - u32 *r = (u32 *)&g; - repl_new = (u32)*r; + if (SHAPE_BYTES(h->shape) == 4 && its_len >= 4) { - } else if (SHAPE_BYTES(h->shape) == 8 && its_len >= 8) { + float *f = (float *)&repl; + float g = *f; + g += 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; - double *f = (double *)&repl; - double g = *f; - g += 1.0; + } else if (SHAPE_BYTES(h->shape) == 8 && its_len >= 8) { - u64 *r = (u64 *)&g; - repl_new = *r; + double *f = (double *)&repl; + double g = *f; + g += 1.0; - } else { + u64 *r = (u64 *)&g; + repl_new = *r; - return 0; + } else { - } + return 0; - changed_val = repl_new; + } - if (unlikely(cmp_extend_encoding( - afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, - taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + changed_val = repl_new; - return 1; + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { - } + return 1; - } else { + } - if (SHAPE_BYTES(h->shape) == 4) { + } else { - float *f = (float *)&repl; - float g = *f; - g -= 1.0; - u32 *r = (u32 *)&g; - repl_new = (u32)*r; + if (SHAPE_BYTES(h->shape) == 4) { - } else if (SHAPE_BYTES(h->shape) == 8) { + float *f = (float *)&repl; + float g = *f; + g -= 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; - double *f = (double *)&repl; - double g = *f; - g -= 1.0; - u64 *r = (u64 *)&g; - repl_new = *r; + } else if (SHAPE_BYTES(h->shape) == 8) { - } else { + double *f = (double *)&repl; + double g = *f; + g -= 1.0; + u64 *r = (u64 *)&g; + repl_new = *r; - return 0; + } else { - } + return 0; - changed_val = repl_new; + } - if (unlikely(cmp_extend_encoding( - afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, - taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + changed_val = repl_new; - return 1; + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { - } + return 1; } - // transform double to float, llvm likes to do that internally ... - if (SHAPE_BYTES(h->shape) == 8 && its_len >= 4) { + } - double *f = (double *)&repl; - float g = (float)*f; - repl_new = 0; + // transform double to float, llvm likes to do that internally ... + if (SHAPE_BYTES(h->shape) == 8 && its_len >= 4) { + + double *f = (double *)&repl; + float g = (float)*f; + repl_new = 0; #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - memcpy((char *)&repl_new, (char *)&g, 4); + memcpy((char *)&repl_new, (char *)&g, 4); #else - memcpy(((char *)&repl_new) + 4, (char *)&g, 4); + memcpy(((char *)&repl_new) + 4, (char *)&g, 4); #endif - changed_val = repl_new; - h->shape = 3; // modify shape - - // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new); + changed_val = repl_new; + h->shape = 3; // modify shape - if (unlikely(cmp_extend_encoding( - afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, - taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new); - h->shape = 7; // recover shape - return 1; - - } + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { h->shape = 7; // recover shape + return 1; } + h->shape = 7; // recover shape + } + } + else if (attr < IS_FP) { // lesser/greater integer comparison @@ -1707,6 +1711,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, try_to_add_to_dictN(afl, s128_v1, SHAPE_BYTES(h->shape)); } else + #endif { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 8423a3d1..5040e3ef 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -236,6 +236,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_custom_mutator_only = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CMPLOG_ONLY_NEW", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cmplog_only_new = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_NO_UI", afl_environment_variable_len)) { afl->afl_env.afl_no_ui = diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 312d9424..9d9b0434 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -181,6 +181,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_BENCH_JUST_ONE: run the target just once\n" "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" + "AFL_CMPLOG_ONLY_NEW: do not run cmplog on initial testcases (good for resumes!)\n" "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" @@ -326,8 +327,9 @@ int main(int argc, char **argv_orig, char **envp) { "compile time)"); } + #endif - + char **argv = argv_cpy_dup(argc, argv_orig); afl_state_t *afl = calloc(1, sizeof(afl_state_t)); @@ -356,8 +358,7 @@ int main(int argc, char **argv_orig, char **envp) { while ((opt = getopt( argc, argv, - "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > - 0) { + "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { switch (opt) { @@ -984,31 +985,31 @@ int main(int argc, char **argv_orig, char **envp) { usage(argv[0], show_help); } - + if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + afl->afl_env.afl_preload = (u8 *)getenv("AFL_PRELOAD"); ck_free(libqasan); - + } if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; @@ -1270,7 +1271,7 @@ int main(int argc, char **argv_orig, char **envp) { "instead of using AFL_PRELOAD?"); } - + if (afl->afl_env.afl_preload) { if (afl->fsrv.qemu_mode) { @@ -1322,7 +1323,7 @@ int main(int argc, char **argv_orig, char **envp) { FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); } - + save_cmdline(afl, argc, argv); fix_up_banner(afl, argv[optind]); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index f3cd5a90..62bf1021 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -942,30 +942,30 @@ int main(int argc, char **argv_orig, char **envp) { } if (optind == argc || !out_file) { usage(argv[0]); } - + if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + ck_free(libqasan); - + } if (in_dir) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 9e9e2d63..09b5211d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1074,30 +1074,30 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file || !output_file) { usage(argv[0]); } check_environment_vars(envp); - + if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + ck_free(libqasan); - + } /* initialize cmplog_mode */ -- cgit 1.4.1 From e5116c6d55185177413104cad1232ca64e04b844 Mon Sep 17 00:00:00 2001 From: aflpp Date: Sun, 31 Jan 2021 17:29:37 +0100 Subject: fix -Z, remove q->next --- include/afl-fuzz.h | 4 +- include/xxhash.h | 2 +- instrumentation/compare-transform-pass.so.cc | 2 +- src/afl-fuzz-init.c | 102 +++++++++++---------------- src/afl-fuzz-one.c | 3 +- src/afl-fuzz-queue.c | 39 +++++----- src/afl-fuzz-stats.c | 10 +-- src/afl-fuzz.c | 65 +++++------------ utils/afl_untracer/afl-untracer.c | 2 +- utils/libtokencap/libtokencap.so.c | 10 +-- utils/persistent_mode/persistent_demo_new.c | 2 +- utils/persistent_mode/test-instr.c | 2 +- 12 files changed, 100 insertions(+), 143 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e8a21cb5..9b27606c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -154,6 +154,7 @@ struct queue_entry { u8 *fname; /* File name for the test case */ u32 len; /* Input length */ + u32 id; /* entry number in queue_buf */ u8 colorized, /* Do not run redqueen stage again */ cal_failed; /* Calibration failed? */ @@ -191,8 +192,7 @@ struct queue_entry { u8 * cmplog_colorinput; /* the result buf of colorization */ struct tainted *taint; /* Taint information from CmpLog */ - struct queue_entry *mother, /* queue entry this based on */ - *next; /* Next element, if any */ + struct queue_entry *mother; /* queue entry this based on */ }; diff --git a/include/xxhash.h b/include/xxhash.h index 006d3f3d..3bd56d13 100644 --- a/include/xxhash.h +++ b/include/xxhash.h @@ -287,7 +287,7 @@ typedef uint32_t XXH32_hash_t; #else #include #if UINT_MAX == 0xFFFFFFFFUL -typedef unsigned int XXH32_hash_t; +typedef unsigned int XXH32_hash_t; #else #if ULONG_MAX == 0xFFFFFFFFUL typedef unsigned long XXH32_hash_t; diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index da5cf7e9..932540a7 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -68,7 +68,7 @@ class CompareTransform : public ModulePass { const char *getPassName() const override { #else - StringRef getPassName() const override { + StringRef getPassName() const override { #endif return "transforms compare functions"; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 2a7864f9..56dae48c 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -817,12 +817,15 @@ void read_testcases(afl_state_t *afl, u8 *directory) { void perform_dry_run(afl_state_t *afl) { - struct queue_entry *q = afl->queue; - u32 cal_failures = 0; + struct queue_entry *q; + u32 cal_failures = 0, idx; u8 * skip_crashes = afl->afl_env.afl_skip_crashes; u8 * use_mem; - while (q) { + for (idx = 0; idx < afl->queued_paths; idx++) { + + q = afl->queue_buf[idx]; + if (unlikely(q->disabled)) { continue; } u8 res; s32 fd; @@ -1052,20 +1055,22 @@ void perform_dry_run(afl_state_t *afl) { p->disabled = 1; p->perf_score = 0; - while (p && p->next != q) - p = p->next; - if (p) - p->next = q->next; - else - afl->queue = q->next; + u32 i = 0; + while (unlikely(afl->queue_buf[i]->disabled)) { + + ++i; + + } + + afl->queue = afl->queue_buf[i]; afl->max_depth = 0; - p = afl->queue; - while (p) { + for (i = 0; i < afl->queued_paths; i++) { - if (p->depth > afl->max_depth) afl->max_depth = p->depth; - p = p->next; + if (!afl->queue_buf[i]->disabled && + afl->queue_buf[i]->depth > afl->max_depth) + afl->max_depth = afl->queue_buf[i]->depth; } @@ -1098,8 +1103,6 @@ void perform_dry_run(afl_state_t *afl) { } - q = q->next; - } if (cal_failures) { @@ -1125,31 +1128,23 @@ void perform_dry_run(afl_state_t *afl) { /* Now we remove all entries from the queue that have a duplicate trace map */ - q = afl->queue; - struct queue_entry *p, *prev = NULL; - int duplicates = 0; - -restart_outer_cull_loop: + u32 duplicates = 0, i; - while (q) { + for (idx = 0; idx < afl->queued_paths; idx++) { - if (q->cal_failed || !q->exec_cksum) { goto next_entry; } + q = afl->queue_buf[idx]; + if (q->disabled || q->cal_failed || !q->exec_cksum) { continue; } - restart_inner_cull_loop: + u32 done = 0; + for (i = idx + 1; i < afl->queued_paths && !done; i++) { - p = q->next; + struct queue_entry *p = afl->queue_buf[i]; + if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; } - while (p) { - - if (!p->cal_failed && p->exec_cksum == q->exec_cksum) { + if (p->exec_cksum == q->exec_cksum) { duplicates = 1; - // We do not remove any of the memory allocated because for - // splicing the data might still be interesting. - // We only decouple them from the linked list. - // This will result in some leaks at exit, but who cares. - // we keep the shorter file if (p->len >= q->len) { @@ -1163,8 +1158,6 @@ restart_outer_cull_loop: p->disabled = 1; p->perf_score = 0; - q->next = p->next; - goto restart_inner_cull_loop; } else { @@ -1178,35 +1171,26 @@ restart_outer_cull_loop: q->disabled = 1; q->perf_score = 0; - if (prev) - prev->next = q = p; - else - afl->queue = q = p; - goto restart_outer_cull_loop; + + done = 1; } } - p = p->next; - } - next_entry: - - prev = q; - q = q->next; - } if (duplicates) { afl->max_depth = 0; - q = afl->queue; - while (q) { - if (q->depth > afl->max_depth) afl->max_depth = q->depth; - q = q->next; + for (idx = 0; idx < afl->queued_paths; idx++) { + + if (!afl->queue_buf[idx]->disabled && + afl->queue_buf[idx]->depth > afl->max_depth) + afl->max_depth = afl->queue_buf[idx]->depth; } @@ -1256,11 +1240,15 @@ static void link_or_copy(u8 *old_path, u8 *new_path) { void pivot_inputs(afl_state_t *afl) { struct queue_entry *q = afl->queue; - u32 id = 0; + u32 id = 0, i; ACTF("Creating hard links for all input files..."); - while (q) { + for (i = 0; i < afl->queued_paths; i++) { + + q = afl->queue_buf[i]; + + if (unlikely(q->disabled)) { continue; } u8 *nfn, *rsl = strrchr(q->fname, '/'); u32 orig_id; @@ -1288,19 +1276,14 @@ void pivot_inputs(afl_state_t *afl) { afl->resuming_fuzz = 1; nfn = alloc_printf("%s/queue/%s", afl->out_dir, rsl); - /* Since we're at it, let's also try to find parent and figure out the + /* Since we're at it, let's also get the parent and figure out the appropriate depth for this entry. */ src_str = strchr(rsl + 3, ':'); if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { - struct queue_entry *s = afl->queue; - while (src_id-- && s) { - - s = s->next; - - } + struct queue_entry *s = afl->queue_buf[src_id]; if (s) { q->depth = s->depth + 1; } @@ -1348,7 +1331,6 @@ void pivot_inputs(afl_state_t *afl) { if (q->passed_det) { mark_as_det_done(afl, q); } - q = q->next; ++id; } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 0cf889a8..18291fb7 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -544,7 +544,8 @@ u8 fuzz_one_original(afl_state_t *afl) { if (likely(!afl->old_seed_selection)) orig_perf = perf_score = afl->queue_cur->perf_score; else - orig_perf = perf_score = calculate_score(afl, afl->queue_cur); + afl->queue_cur->perf_score = orig_perf = perf_score = + calculate_score(afl, afl->queue_cur); if (unlikely(perf_score <= 0)) { goto abandon_entry; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 4442b400..ad3e3b8e 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -143,7 +143,7 @@ void create_alias_table(afl_state_t *afl) { struct queue_entry *q = afl->queue_buf[i]; - if (!q->disabled) { q->perf_score = calculate_score(afl, q); } + if (likely(!q->disabled)) { q->perf_score = calculate_score(afl, q); } sum += q->perf_score; @@ -444,7 +444,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { if (afl->queue_top) { - afl->queue_top->next = q; afl->queue_top = q; } else { @@ -465,6 +464,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { AFL_BUF_PARAM(queue), afl->queued_paths * sizeof(struct queue_entry *)); if (unlikely(!queue_buf)) { PFATAL("alloc"); } queue_buf[afl->queued_paths - 1] = q; + q->id = afl->queued_paths - 1; afl->last_path_time = get_cur_time(); @@ -641,10 +641,9 @@ void cull_queue(afl_state_t *afl) { if (likely(!afl->score_changed || afl->non_instrumented_mode)) { return; } - struct queue_entry *q; - u32 len = (afl->fsrv.map_size >> 3); - u32 i; - u8 * temp_v = afl->map_tmp_buf; + u32 len = (afl->fsrv.map_size >> 3); + u32 i; + u8 *temp_v = afl->map_tmp_buf; afl->score_changed = 0; @@ -653,12 +652,9 @@ void cull_queue(afl_state_t *afl) { afl->queued_favored = 0; afl->pending_favored = 0; - q = afl->queue; - - while (q) { + for (i = 0; i < afl->queued_paths; i++) { - q->favored = 0; - q = q->next; + afl->queue_buf[i]->favored = 0; } @@ -697,12 +693,13 @@ void cull_queue(afl_state_t *afl) { } - q = afl->queue; + for (i = 0; i < afl->queued_paths; i++) { + + if (likely(!afl->queue_buf[i]->disabled)) { - while (q) { + mark_as_redundant(afl, afl->queue_buf[i], !afl->queue_buf[i]->favored); - mark_as_redundant(afl, q, !q->favored); - q = q->next; + } } @@ -852,13 +849,15 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { // Don't modify perf_score for unfuzzed seeds if (q->fuzz_level == 0) break; - struct queue_entry *queue_it = afl->queue; - while (queue_it) { + u32 i; + for (i = 0; i < afl->queued_paths; i++) { - fuzz_mu += log2(afl->n_fuzz[q->n_fuzz_entry]); - n_paths++; + if (likely(!afl->queue_buf[i]->disabled)) { - queue_it = queue_it->next; + fuzz_mu += log2(afl->n_fuzz[afl->queue_buf[i]->n_fuzz_entry]); + n_paths++; + + } } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 82da8176..7e99bf8f 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1014,8 +1014,8 @@ void show_stats(afl_state_t *afl) { void show_init_stats(afl_state_t *afl) { - struct queue_entry *q = afl->queue; - u32 min_bits = 0, max_bits = 0, max_len = 0, count = 0; + struct queue_entry *q; + u32 min_bits = 0, max_bits = 0, max_len = 0, count = 0, i; u64 min_us = 0, max_us = 0; u64 avg_us = 0; @@ -1028,7 +1028,10 @@ void show_init_stats(afl_state_t *afl) { } - while (q) { + for (i = 0; i < afl->queued_paths; i++) { + + q = afl->queue_buf[i]; + if (unlikely(q->disabled)) { continue; } if (!min_us || q->exec_us < min_us) { min_us = q->exec_us; } if (q->exec_us > max_us) { max_us = q->exec_us; } @@ -1039,7 +1042,6 @@ void show_init_stats(afl_state_t *afl) { if (q->len > max_len) { max_len = q->len; } ++count; - q = q->next; } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9d9b0434..40d42c11 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1558,45 +1558,6 @@ int main(int argc, char **argv_orig, char **envp) { perform_dry_run(afl); - /* - if (!user_set_cache && afl->q_testcase_max_cache_size) { - - / * The user defined not a fixed number of entries for the cache. - Hence we autodetect a good value. After the dry run inputs are - trimmed and we know the average and max size of the input seeds. - We use this information to set a fitting size to max entries - based on the cache size. * / - - struct queue_entry *q = afl->queue; - u64 size = 0, count = 0, avg = 0, max = 0; - - while (q) { - - ++count; - size += q->len; - if (max < q->len) { max = q->len; } - q = q->next; - - } - - if (count) { - - avg = size / count; - avg = ((avg + max) / 2) + 1; - - } - - if (avg < 10240) { avg = 10240; } - - afl->q_testcase_max_cache_entries = afl->q_testcase_max_cache_size / avg; - - if (afl->q_testcase_max_cache_entries > 32768) - afl->q_testcase_max_cache_entries = 32768; - - } - - */ - if (afl->q_testcase_max_cache_entries) { afl->q_testcase_cache = @@ -1668,7 +1629,10 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) { afl->current_entry = 0; - afl->queue_cur = afl->queue; + while (unlikely(afl->queue_buf[afl->current_entry]->disabled)) { + ++afl->current_entry; + } + afl->queue_cur = afl->queue_buf[afl->current_entry]; if (unlikely(seek_to)) { @@ -1800,12 +1764,14 @@ int main(int argc, char **argv_orig, char **envp) { } - struct queue_entry *q = afl->queue; // we must recalculate the scores of all queue entries - while (q) { + for (i = 0; i < (s32)afl->queued_paths; i++) { + + if (likely(!afl->queue_buf[i]->disabled)) { - update_bitmap_score(afl, q); - q = q->next; + update_bitmap_score(afl, afl->queue_buf[i]); + + } } @@ -1847,8 +1813,15 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) { - afl->queue_cur = afl->queue_cur->next; - ++afl->current_entry; + while (++afl->current_entry < afl->queued_paths && + afl->queue_buf[afl->current_entry]->disabled) + ; + if (unlikely(afl->current_entry >= afl->queued_paths || + afl->queue_buf[afl->current_entry] == NULL || + afl->queue_buf[afl->current_entry]->disabled)) + afl->queue_cur = NULL; + else + afl->queue_cur = afl->queue_buf[afl->current_entry]; } diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c index f3894a06..d2bad0b9 100644 --- a/utils/afl_untracer/afl-untracer.c +++ b/utils/afl_untracer/afl-untracer.c @@ -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) { +void breakpoint(void) { if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); diff --git a/utils/libtokencap/libtokencap.so.c b/utils/libtokencap/libtokencap.so.c index 3629e804..26033b46 100644 --- a/utils/libtokencap/libtokencap.so.c +++ b/utils/libtokencap/libtokencap.so.c @@ -161,8 +161,8 @@ static void __tokencap_load_mappings(void) { #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ - #if defined __FreeBSD__ - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid}; + #if defined __FreeBSD__ + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid}; #elif defined __OpenBSD__ int mib[] = {CTL_KERN, KERN_PROC_VMMAP, __tokencap_pid}; #elif defined __NetBSD__ @@ -177,7 +177,7 @@ static void __tokencap_load_mappings(void) { #if defined __FreeBSD__ || defined __NetBSD__ len = len * 4 / 3; - #elif defined __OpenBSD__ + #elif defined __OpenBSD__ len -= len % sizeof(struct kinfo_vmentry); #endif @@ -202,8 +202,8 @@ static void __tokencap_load_mappings(void) { #if defined __FreeBSD__ || defined __NetBSD__ - #if defined __FreeBSD__ - size_t size = region->kve_structsize; + #if defined __FreeBSD__ + size_t size = region->kve_structsize; if (size == 0) break; #elif defined __NetBSD__ diff --git a/utils/persistent_mode/persistent_demo_new.c b/utils/persistent_mode/persistent_demo_new.c index 7e694696..ca616236 100644 --- a/utils/persistent_mode/persistent_demo_new.c +++ b/utils/persistent_mode/persistent_demo_new.c @@ -51,7 +51,7 @@ __AFL_FUZZ_INIT(); /* To ensure checks are not optimized out it is recommended to disable code optimization for the fuzzer harness main() */ #pragma clang optimize off -#pragma GCC optimize("O0") +#pragma GCC optimize("O0") int main(int argc, char **argv) { diff --git a/utils/persistent_mode/test-instr.c b/utils/persistent_mode/test-instr.c index 6da511de..2c6b6d77 100644 --- a/utils/persistent_mode/test-instr.c +++ b/utils/persistent_mode/test-instr.c @@ -24,7 +24,7 @@ __AFL_FUZZ_INIT(); /* To ensure checks are not optimized out it is recommended to disable code optimization for the fuzzer harness main() */ #pragma clang optimize off -#pragma GCC optimize("O0") +#pragma GCC optimize("O0") int main(int argc, char **argv) { -- cgit 1.4.1 From d808a8401e1acbcde3352d86e9e2da3f7bac97e8 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 1 Feb 2021 12:16:55 +0100 Subject: import cmplog opts --- include/afl-fuzz.h | 1 + src/afl-fuzz-one.c | 4 ++-- src/afl-fuzz-redqueen.c | 31 +++++++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 9b27606c..c3a8c2ee 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -647,6 +647,7 @@ typedef struct afl_state { u32 cmplog_prev_timed_out; u32 cmplog_max_filesize; u32 cmplog_lvl; + u32 colorize_success; struct afl_pass_stat *pass_stats; struct cmp_map * orig_cmp_map; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 18291fb7..c73e394a 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 15000) { + get_cur_time() - afl->last_path_time > 300000) { if (input_to_state_stage(afl, in_buf, out_buf, len)) { @@ -2990,7 +2990,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 15000) { + get_cur_time() - afl->last_path_time > 300000) { if (input_to_state_stage(afl, in_buf, out_buf, len)) { diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 74c9db38..997b7528 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -379,8 +379,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, } - *taints = taint; - /* temporary: clean ranges */ while (ranges) { @@ -423,6 +421,35 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, #endif + if (taint) { + + if (len / positions == 1 && positions > 16384 && + afl->active_paths / afl->colorize_success > 20) { + +#ifdef _DEBUG + fprintf(stderr, "Colorization unsatisfactory\n"); +#endif + + *taints = NULL; + + struct tainted *t; + while (taint) { + + t = taint->next; + ck_free(taint); + taint = t; + + } + + } else { + + *taints = taint; + ++afl->colorize_success; + + } + + } + afl->stage_finds[STAGE_COLORIZATION] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur; ck_free(backup); -- cgit 1.4.1 From 6f163bb0c50a103dc4565ec5f0b8b9b94b5c16f6 Mon Sep 17 00:00:00 2001 From: vj-27 Date: Fri, 5 Feb 2021 00:26:23 +0000 Subject: load existing stats file when in AFL_AUTORESUME or -i - --- include/afl-fuzz.h | 1 + src/afl-fuzz-stats.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/afl-fuzz.c | 1 + 3 files changed, 103 insertions(+) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c3a8c2ee..9e2913a2 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1067,6 +1067,7 @@ void destroy_extras(afl_state_t *); /* Stats */ +void load_stats_file(afl_state_t *); void write_setup_file(afl_state_t *, u32, char **); void write_stats_file(afl_state_t *, double, double, double); void maybe_update_plot_file(afl_state_t *, double, double); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 7e99bf8f..d75b8405 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -89,6 +89,107 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { } +/* load some of the existing stats file when resuming.*/ +void load_stats_file(afl_state_t *afl) { + + FILE *f; + u8 buf[MAX_LINE]; + u8 * lptr; + u8 fn[PATH_MAX]; + u32 lineno = 0; + + snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); + f = fopen(fn, "r"); + if (!f) { + + WARNF("Unable to load stats file '%s'", fn); + return; + + } + + while ((lptr = fgets(buf, MAX_LINE, f))) { + + lineno++; + u8 *lstartptr = lptr; + u8 *rptr = lptr + strlen(lptr) - 1; + u8 keystring[MAX_LINE]; + while (*lptr != ':' && lptr < rptr) { + + lptr++; + + } + + if (*lptr == '\n' || !*lptr) { + + WARNF("Unable to read line %d of stats file", lineno); + continue; + + } + + if (*lptr == ':') { + + *lptr = 0; + strcpy(keystring, lstartptr); + lptr++; + char *nptr; + switch (lineno) { + + case 5: + if (!strcmp(keystring, "cycles_done ")) + afl->queue_cycle = + strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0; + break; + case 7: + if (!strcmp(keystring, "execs_done ")) + afl->fsrv.total_execs = strtoull(lptr, &nptr, 10); + break; + case 10: + if (!strcmp(keystring, "paths_total ")) + afl->queued_paths = strtoul(lptr, &nptr, 10); + break; + case 11: + if (!strcmp(keystring, "paths_favored ")) + afl->queued_favored = strtoul(lptr, &nptr, 10); + break; + case 12: + if (!strcmp(keystring, "paths_found ")) + afl->queued_discovered = strtoul(lptr, &nptr, 10); + break; + case 13: + if (!strcmp(keystring, "paths_imported ")) + afl->queued_imported = strtoul(lptr, &nptr, 10); + break; + case 14: + if (!strcmp(keystring, "max_depth ")) + afl->max_depth = strtoul(lptr, &nptr, 10); + break; + case 16: + if (!strcmp(keystring, "pending_favs ")) + afl->pending_favored = strtoul(lptr, &nptr, 10); + break; + case 17: + if (!strcmp(keystring, "pending_total ")) + afl->pending_not_fuzzed = strtoul(lptr, &nptr, 10); + break; + case 21: + if (!strcmp(keystring, "unique_crashes ")) + afl->unique_crashes = strtoull(lptr, &nptr, 10); + break; + case 22: + if (!strcmp(keystring, "unique_hangs ")) + afl->unique_hangs = strtoull(lptr, &nptr, 10); + break; + default: + break; + + } + + } + + } + +} + /* Update stats file for unattended monitoring. */ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a579a8f5..6c617b18 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1682,6 +1682,7 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); + if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); -- cgit 1.4.1 From 1a8c242d280066b7bfb36897c91215d4f4b5eb01 Mon Sep 17 00:00:00 2001 From: vj-27 Date: Fri, 5 Feb 2021 19:46:24 +0000 Subject: load run time and donot load pending_* or *_favoured --- include/afl-fuzz.h | 2 +- src/afl-fuzz-stats.c | 29 ++++++++++++++--------------- src/afl-fuzz.c | 8 +++++++- 3 files changed, 22 insertions(+), 17 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 9e2913a2..1b2b9a8e 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1067,7 +1067,7 @@ void destroy_extras(afl_state_t *); /* Stats */ -void load_stats_file(afl_state_t *); +u32 load_stats_file(afl_state_t *); void write_setup_file(afl_state_t *, u32, char **); void write_stats_file(afl_state_t *, double, double, double); void maybe_update_plot_file(afl_state_t *, double, double); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d75b8405..3edb5bb6 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -90,20 +90,20 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { } /* load some of the existing stats file when resuming.*/ -void load_stats_file(afl_state_t *afl) { +u32 load_stats_file(afl_state_t *afl) { FILE *f; u8 buf[MAX_LINE]; u8 * lptr; u8 fn[PATH_MAX]; u32 lineno = 0; - + u32 prev_run_time = 0; snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); f = fopen(fn, "r"); if (!f) { WARNF("Unable to load stats file '%s'", fn); - return; + return prev_run_time; } @@ -134,6 +134,15 @@ void load_stats_file(afl_state_t *afl) { char *nptr; switch (lineno) { + case 3: + if (!strcmp(keystring, "run_time ")) { + + prev_run_time = 1000 * strtoull(lptr, &nptr, 10); + afl->start_time -= prev_run_time; + + } + + break; case 5: if (!strcmp(keystring, "cycles_done ")) afl->queue_cycle = @@ -147,10 +156,6 @@ void load_stats_file(afl_state_t *afl) { if (!strcmp(keystring, "paths_total ")) afl->queued_paths = strtoul(lptr, &nptr, 10); break; - case 11: - if (!strcmp(keystring, "paths_favored ")) - afl->queued_favored = strtoul(lptr, &nptr, 10); - break; case 12: if (!strcmp(keystring, "paths_found ")) afl->queued_discovered = strtoul(lptr, &nptr, 10); @@ -163,14 +168,6 @@ void load_stats_file(afl_state_t *afl) { if (!strcmp(keystring, "max_depth ")) afl->max_depth = strtoul(lptr, &nptr, 10); break; - case 16: - if (!strcmp(keystring, "pending_favs ")) - afl->pending_favored = strtoul(lptr, &nptr, 10); - break; - case 17: - if (!strcmp(keystring, "pending_total ")) - afl->pending_not_fuzzed = strtoul(lptr, &nptr, 10); - break; case 21: if (!strcmp(keystring, "unique_crashes ")) afl->unique_crashes = strtoull(lptr, &nptr, 10); @@ -188,6 +185,8 @@ void load_stats_file(afl_state_t *afl) { } + return prev_run_time; + } /* Update stats file for unattended monitoring. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 6c617b18..b7cd251a 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1682,7 +1682,11 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); - if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); + u32 prev_run_time = 0; // to not call load_stats_file again after line 1705 + afl->start_time = get_cur_time(); // without this, time taken for + // perform_dry_run gets added to run time. + if (afl->in_place_resume || afl->afl_env.afl_autoresume) + prev_run_time = load_stats_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); @@ -1701,6 +1705,8 @@ int main(int argc, char **argv_orig, char **envp) { // (void)nice(-20); // does not improve the speed // real start time, we reset, so this works correctly with -V afl->start_time = get_cur_time(); + if (afl->in_place_resume || afl->afl_env.afl_autoresume) + afl->start_time -= prev_run_time; u32 runs_in_current_cycle = (u32)-1; u32 prev_queued_paths = 0; -- cgit 1.4.1 From f54c4dbfdb17a06798b337a2182d7cf33ec178dd Mon Sep 17 00:00:00 2001 From: vj-27 Date: Sat, 6 Feb 2021 09:41:15 +0000 Subject: set prev_run_time inside afl state --- include/afl-fuzz.h | 3 ++- src/afl-fuzz-stats.c | 12 ++++++------ src/afl-fuzz.c | 6 ++---- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1b2b9a8e..4027a88f 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -569,6 +569,7 @@ typedef struct afl_state { blocks_eff_total, /* Blocks subject to effector maps */ blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ + prev_run_time, /* Runtime read from prev stats file*/ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ @@ -1067,7 +1068,7 @@ void destroy_extras(afl_state_t *); /* Stats */ -u32 load_stats_file(afl_state_t *); +void load_stats_file(afl_state_t *); void write_setup_file(afl_state_t *, u32, char **); void write_stats_file(afl_state_t *, double, double, double); void maybe_update_plot_file(afl_state_t *, double, double); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 3edb5bb6..880551d3 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -90,20 +90,20 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { } /* load some of the existing stats file when resuming.*/ -u32 load_stats_file(afl_state_t *afl) { +void load_stats_file(afl_state_t *afl) { FILE *f; u8 buf[MAX_LINE]; u8 * lptr; u8 fn[PATH_MAX]; u32 lineno = 0; - u32 prev_run_time = 0; + afl->prev_run_time = 0; snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); f = fopen(fn, "r"); if (!f) { WARNF("Unable to load stats file '%s'", fn); - return prev_run_time; + return; } @@ -137,8 +137,8 @@ u32 load_stats_file(afl_state_t *afl) { case 3: if (!strcmp(keystring, "run_time ")) { - prev_run_time = 1000 * strtoull(lptr, &nptr, 10); - afl->start_time -= prev_run_time; + afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10); + afl->start_time -= afl->prev_run_time; } @@ -185,7 +185,7 @@ u32 load_stats_file(afl_state_t *afl) { } - return prev_run_time; + return; } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b7cd251a..08724959 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1682,11 +1682,9 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); - u32 prev_run_time = 0; // to not call load_stats_file again after line 1705 afl->start_time = get_cur_time(); // without this, time taken for // perform_dry_run gets added to run time. - if (afl->in_place_resume || afl->afl_env.afl_autoresume) - prev_run_time = load_stats_file(afl); + if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); @@ -1706,7 +1704,7 @@ int main(int argc, char **argv_orig, char **envp) { // real start time, we reset, so this works correctly with -V afl->start_time = get_cur_time(); if (afl->in_place_resume || afl->afl_env.afl_autoresume) - afl->start_time -= prev_run_time; + afl->start_time -= afl->prev_run_time; u32 runs_in_current_cycle = (u32)-1; u32 prev_queued_paths = 0; -- cgit 1.4.1 From 96cdc97c98ee2e2af7df59252f4f0df1689afb7b Mon Sep 17 00:00:00 2001 From: vj-27 Date: Sun, 7 Feb 2021 03:33:47 +0530 Subject: prev_run_time loaded used only for ui and when writing the stats file --- include/afl-fuzz.h | 4 ++-- src/afl-fuzz-stats.c | 25 ++++++++++--------------- src/afl-fuzz.c | 5 +---- 3 files changed, 13 insertions(+), 21 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4027a88f..1d5ec1f0 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -425,7 +425,8 @@ typedef struct afl_state { really makes no sense to haul them around as function parameters. */ u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time, total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key, - most_time, most_execs_key, most_execs, old_hit_count, force_ui_update; + most_time, most_execs_key, most_execs, old_hit_count, force_ui_update, + prev_run_time; MOpt_globals_t mopt_globals_core, mopt_globals_pilot; @@ -569,7 +570,6 @@ typedef struct afl_state { blocks_eff_total, /* Blocks subject to effector maps */ blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ - prev_run_time, /* Runtime read from prev stats file*/ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 880551d3..66efeb20 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -97,7 +97,6 @@ void load_stats_file(afl_state_t *afl) { u8 * lptr; u8 fn[PATH_MAX]; u32 lineno = 0; - afl->prev_run_time = 0; snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); f = fopen(fn, "r"); if (!f) { @@ -135,13 +134,8 @@ void load_stats_file(afl_state_t *afl) { switch (lineno) { case 3: - if (!strcmp(keystring, "run_time ")) { - + if (!strcmp(keystring, "run_time ")) afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10); - afl->start_time -= afl->prev_run_time; - - } - break; case 5: if (!strcmp(keystring, "cycles_done ")) @@ -279,12 +273,13 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, "\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->start_time - afl->prev_run_time) / 1000, cur_time / 1000, + (afl->prev_run_time + 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), + ((double)(afl->prev_run_time + 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, @@ -479,8 +474,8 @@ void show_stats(afl_state_t *afl) { if (likely(cur_ms != afl->start_time)) { - afl->stats_avg_exec = - ((double)afl->fsrv.total_execs) * 1000 / (cur_ms - afl->start_time); + afl->stats_avg_exec = ((double)afl->fsrv.total_execs) * 1000 / + (afl->prev_run_time + cur_ms - afl->start_time); } @@ -692,7 +687,7 @@ void show_stats(afl_state_t *afl) { } - u_stringify_time_diff(time_tmp, cur_ms, afl->start_time); + u_stringify_time_diff(time_tmp, afl->prev_run_time + cur_ms, afl->start_time); SAYF(bV bSTOP " run time : " cRST "%-33s " bSTG bV bSTOP " cycles done : %s%-5s " bSTG bV "\n", time_tmp, tmp, u_stringify_int(IB(0), afl->queue_cycle - 1)); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 08724959..e4139857 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1682,8 +1682,7 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); - afl->start_time = get_cur_time(); // without this, time taken for - // perform_dry_run gets added to run time. + afl->start_time = get_cur_time(); if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); @@ -1703,8 +1702,6 @@ int main(int argc, char **argv_orig, char **envp) { // (void)nice(-20); // does not improve the speed // real start time, we reset, so this works correctly with -V afl->start_time = get_cur_time(); - if (afl->in_place_resume || afl->afl_env.afl_autoresume) - afl->start_time -= afl->prev_run_time; u32 runs_in_current_cycle = (u32)-1; u32 prev_queued_paths = 0; -- cgit 1.4.1 From 974aab6cf6aa4ae34ee73bdceed1bd44a212fc5e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 21 Feb 2021 17:53:09 +0100 Subject: cmplog config.h -> -l option --- include/afl-fuzz.h | 1 + include/config.h | 9 ++---- src/afl-common.c | 8 ++--- src/afl-fuzz-redqueen.c | 83 +++++++++++++++++++++++++------------------------ src/afl-fuzz.c | 46 ++++++++++++++++++++------- 5 files changed, 85 insertions(+), 62 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1d5ec1f0..10d94fed 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -649,6 +649,7 @@ typedef struct afl_state { u32 cmplog_max_filesize; u32 cmplog_lvl; u32 colorize_success; + u8 cmplog_enable_arith, cmplog_enable_transform; struct afl_pass_stat *pass_stats; struct cmp_map * orig_cmp_map; diff --git a/include/config.h b/include/config.h index 9f7db04d..535ce0d3 100644 --- a/include/config.h +++ b/include/config.h @@ -42,13 +42,8 @@ * */ -/* Enable arithmetic compare solving for both branches */ -#define CMPLOG_SOLVE_ARITHMETIC - -/* Enable transform following (XOR/ADD/SUB manipulations, hex en/decoding) */ -#define CMPLOG_SOLVE_TRANSFORM - -/* if TRANSFORM is enabled, this additionally enables base64 en/decoding */ +/* if TRANSFORM is enabled with '-l T', this additionally enables base64 + encoding/decoding */ // #define CMPLOG_SOLVE_TRANSFORM_BASE64 /* If a redqueen pass finds more than one solution, try to combine them? */ diff --git a/src/afl-common.c b/src/afl-common.c index 531753c2..ce63c262 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -561,13 +561,13 @@ void print_suggested_envs(char *mispelled_env) { memcpy(env_name, mispelled_env + 4, env_name_len); char *seen = ck_alloc(sizeof(afl_environment_variables) / sizeof(char *)); - int found = 0; + int found = 0; int j; for (j = 0; afl_environment_variables[j] != NULL; ++j) { char *afl_env = afl_environment_variables[j] + 4; - int distance = string_distance_levenshtein(afl_env, env_name); + int distance = string_distance_levenshtein(afl_env, env_name); if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) { SAYF("Did you mean %s?\n", afl_environment_variables[j]); @@ -575,14 +575,14 @@ void print_suggested_envs(char *mispelled_env) { found = 1; } - + } if (found) goto cleanup; for (j = 0; afl_environment_variables[j] != NULL; ++j) { - char *afl_env = afl_environment_variables[j] + 4; + char * afl_env = afl_environment_variables[j] + 4; size_t afl_env_len = strlen(afl_env); char * reduced = ck_alloc(afl_env_len + 1); diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index d77baf25..1ab5f996 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -30,7 +30,6 @@ //#define _DEBUG //#define CMPLOG_INTROSPECTION -#define CMPLOG_COMBINE // CMP attribute enum enum { @@ -523,7 +522,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { } -#ifdef CMPLOG_SOLVE_TRANSFORM +//#ifdef CMPLOG_SOLVE_TRANSFORM static int strntoll(const char *str, size_t sz, char **end, int base, long long *out) { @@ -608,7 +607,7 @@ static int is_hex(const char *str) { } - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 // tests 4 bytes at location static int is_base64(const char *str) { @@ -721,10 +720,10 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) { } - #endif - #endif +//#endif + static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 pattern, u64 repl, u64 o_pattern, u64 changed_val, u8 attr, u32 idx, u32 taint_len, @@ -748,9 +747,9 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // o_pattern, pattern, repl, changed_val, idx, taint_len, // h->shape + 1, attr); -#ifdef CMPLOG_SOLVE_TRANSFORM + //#ifdef CMPLOG_SOLVE_TRANSFORM // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 - if (lvl & LVL3) { + if (afl->cmplog_enable_transform && (lvl & LVL3)) { u8 * endptr; u8 use_num = 0, use_unum = 0; @@ -771,11 +770,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - #ifdef _DEBUG +#ifdef _DEBUG if (idx == 0) fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n", afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern); - #endif +#endif // num is likely not pattern as atoi("AAA") will be zero... if (use_num && ((u64)num == pattern || !num)) { @@ -1060,7 +1059,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } -#endif + //#endif // we only allow this for ascii2integer (above) so leave if this is the case if (unlikely(pattern == o_pattern)) { return 0; } @@ -1215,8 +1214,12 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // 16 = modified float, 32 = modified integer (modified = wont match // in original buffer) -#ifdef CMPLOG_SOLVE_ARITHMETIC - if (lvl < LVL3 || attr == IS_TRANSFORM) { return 0; } + //#ifdef CMPLOG_SOLVE_ARITHMETIC + if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) { + + return 0; + + } if (!(attr & (IS_GREATER | IS_LESSER)) || SHAPE_BYTES(h->shape) < 4) { @@ -1321,11 +1324,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, double *f = (double *)&repl; float g = (float)*f; repl_new = 0; - #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) memcpy((char *)&repl_new, (char *)&g, 4); - #else +#else memcpy(((char *)&repl_new) + 4, (char *)&g, 4); - #endif +#endif changed_val = repl_new; h->shape = 3; // modify shape @@ -1380,7 +1383,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } -#endif /* CMPLOG_SOLVE_ARITHMETIC */ + //#endif /* CMPLOG_SOLVE_ARITHMETIC return 0; @@ -1539,7 +1542,7 @@ static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) { for (k = 0; k < size; ++k) { #else - u32 off = 16 - size; + u32 off = 16 - size; for (k = 16 - size; k < 16; ++k) { #endif @@ -1857,9 +1860,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, #ifndef CMPLOG_COMBINE (void)(cbuf); #endif -#ifndef CMPLOG_SOLVE_TRANSFORM - (void)(changed_val); -#endif + //#ifndef CMPLOG_SOLVE_TRANSFORM + // (void)(changed_val); + //#endif u8 save[40]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; @@ -1939,16 +1942,16 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } -#ifdef CMPLOG_SOLVE_TRANSFORM + //#ifdef CMPLOG_SOLVE_TRANSFORM if (*status == 1) return 0; - if (lvl & LVL3) { + if (afl->cmplog_enable_transform && (lvl & LVL3)) { u32 toupper = 0, tolower = 0, xor = 0, arith = 0, tohex = 0, fromhex = 0; - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 u32 tob64 = 0, fromb64 = 0; - #endif +#endif u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0; u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0; u8 xor_val[32], arith_val[32], tmp[48]; @@ -2044,7 +2047,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 if (i % 3 == 2 && i < 24) { if (is_base64(repl + ((i / 3) << 2))) tob64 += 3; @@ -2057,7 +2060,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #endif +#endif if ((o_pattern[i] ^ orig_buf[idx + i]) == xor_val[i] && xor_val[i]) { @@ -2085,20 +2088,20 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #ifdef _DEBUG +#ifdef _DEBUG fprintf(stderr, "RTN idx=%u loop=%u xor=%u arith=%u tolower=%u toupper=%u " "tohex=%u fromhex=%u to_0=%u to_slash=%u to_x=%u " "from_0=%u from_slash=%u from_x=%u\n", idx, i, xor, arith, tolower, toupper, tohex, fromhex, to_0, to_slash, to_x, from_0, from_slash, from_x); - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 + #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 fprintf(stderr, "RTN idx=%u loop=%u tob64=%u from64=%u\n", tob64, fromb64); - #endif #endif +#endif - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 // input is base64 and converted to binary? convert repl to base64! if ((i % 4) == 3 && i < 24 && fromb64 > i) { @@ -2121,7 +2124,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #endif +#endif // input is converted to hex? convert repl to binary! if (i < 16 && tohex > i) { @@ -2250,16 +2253,16 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #ifdef CMPLOG_COMBINE +#ifdef CMPLOG_COMBINE if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i + 1); } - #endif +#endif if ((i >= 7 && (i >= xor&&i >= arith &&i >= tolower &&i >= toupper &&i > tohex &&i > (fromhex + from_0 + from_x + from_slash + 1) - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 && i > tob64 + 3 && i > fromb64 + 4 - #endif +#endif )) || repl[i] != changed_val[i] || *status == 1) { @@ -2273,7 +2276,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } -#endif + //#endif return 0; @@ -2606,9 +2609,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { } else if ((lvl & LVL1) -#ifdef CMPLOG_SOLVE_TRANSFORM - || (lvl & LVL3) -#endif + //#ifdef CMPLOG_SOLVE_TRANSFORM + || ((lvl & LVL3) && afl->cmplog_enable_transform) + //#endif ) { if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) { @@ -2689,7 +2692,7 @@ exit_its: #else u32 *v = (u32 *)afl->virgin_bits; u32 *s = (u32 *)virgin_save; - u32 i; + u32 i; for (i = 0; i < (afl->shm.map_size >> 2); i++) { v[i] &= s[i]; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e3e9007d..e2db029d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -103,7 +103,8 @@ static void usage(u8 *argv0, int more_help) { " quad -- see docs/power_schedules.md\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" - " -t msec - timeout for each run (auto-scaled, 50-... ms, default %u ms)\n" + " -t msec - timeout for each run (auto-scaled, 50-... ms, default " + "%u ms)\n" " add a '+' to skip over seeds running longer.\n" " -m megs - memory limit for child process (%u MB, 0 = no limit " "[default])\n" @@ -123,10 +124,10 @@ static void usage(u8 *argv0, int more_help) { " -c program - enable CmpLog by specifying a binary compiled for " "it.\n" " if using QEMU, just use -c 0.\n" - " -l cmplog_level - set the complexity/intensivity of CmpLog.\n" - " Values: 1 (basic), 2 (larger files) and 3 " - "(transform)\n\n" - + " -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n" + " 1=small files (default), 2=larger files, 3=all " + "files,\n" + " A=arithmetic solving, T=tranformational solving.\n\n" "Fuzzing behavior settings:\n" " -Z - sequential queue selection instead of weighted " "random\n" @@ -813,13 +814,36 @@ int main(int argc, char **argv_orig, char **envp) { case 'l': { - if (optarg) { afl->cmplog_lvl = atoi(optarg); } - if (afl->cmplog_lvl < 1 || afl->cmplog_lvl > CMPLOG_LVL_MAX) { + if (!optarg) { FATAL("missing parameter for 'l'"); } + char *c = optarg; + while (*c) { - FATAL( - "Bad complog level value, accepted values are 1 (default), 2 and " - "%u.", - CMPLOG_LVL_MAX); + switch (*c) { + + case '0': + case '1': + afl->cmplog_lvl = 1; + break; + case '2': + afl->cmplog_lvl = 2; + break; + case '3': + afl->cmplog_lvl = 3; + break; + case 'a': + case 'A': + afl->cmplog_enable_arith = 1; + break; + case 't': + case 'T': + afl->cmplog_enable_transform = 1; + break; + default: + FATAL("Unknown option value '%c' in -l %s", *c, optarg); + + } + + ++c; } -- cgit 1.4.1 From fb2a6b6941ffb6cf575d2a772c6e0d47b49835ee Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 22 Feb 2021 16:56:35 +0100 Subject: minimum sync time --- docs/Changelog.md | 1 + include/afl-fuzz.h | 1 + include/config.h | 5 +++++ src/afl-fuzz-run.c | 2 ++ src/afl-fuzz.c | 15 ++++++++++++--- 5 files changed, 21 insertions(+), 3 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index a006fccb..d8587334 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,7 @@ sending a mail to . - fixed a few crashes - switched to an even faster RNG - added hghwng's patch for faster trace map analysis + - added minimum SYNC_TIME to include/config.h (30 minutes default) - afl-cc - allow instrumenting LLVMFuzzerTestOneInput - fixed endless loop for allow/blocklist lines starting with a diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 10d94fed..e191543a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -570,6 +570,7 @@ typedef struct afl_state { blocks_eff_total, /* Blocks subject to effector maps */ blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ + last_sync_time, /* Time of last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ diff --git a/include/config.h b/include/config.h index 535ce0d3..083cad23 100644 --- a/include/config.h +++ b/include/config.h @@ -280,6 +280,11 @@ #define SYNC_INTERVAL 8 +/* Sync time (minimum time between syncing in ms, time is halfed for -M main + nodes): */ + +#define SYNC_TIME 18000000LLU /* 18000000 = 30 minutes */ + /* Output directory reuse grace period (minutes): */ #define OUTPUT_GRACE 25 diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 97cb7415..0b84a542 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -707,6 +707,8 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); + afl->last_sync_time = get_cur_time(); + } /* 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 9137dc23..f83aac9e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1986,15 +1986,24 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->is_main_node)) { - if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { + if (unlikely(get_cur_time() > + (SYNC_TIME >> 1) + afl->last_sync_time)) { - sync_fuzzers(afl); + if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { + + sync_fuzzers(afl); + + } } } else { - if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + if (unlikely(get_cur_time() > SYNC_TIME + afl->last_sync_time)) { + + if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + + } } -- cgit 1.4.1 From 4ab90e739ff4410f24c63d71dfffe333063c3b3a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 22 Feb 2021 22:24:59 +0100 Subject: code format --- include/afl-fuzz.h | 2 +- include/config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e191543a..d9dbad5a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -570,7 +570,7 @@ typedef struct afl_state { blocks_eff_total, /* Blocks subject to effector maps */ blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ - last_sync_time, /* Time of last sync */ + last_sync_time, /* Time of last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ diff --git a/include/config.h b/include/config.h index 083cad23..241b2e69 100644 --- a/include/config.h +++ b/include/config.h @@ -283,7 +283,7 @@ /* Sync time (minimum time between syncing in ms, time is halfed for -M main nodes): */ -#define SYNC_TIME 18000000LLU /* 18000000 = 30 minutes */ +#define SYNC_TIME 18000000LLU /* 18000000 = 30 minutes */ /* Output directory reuse grace period (minutes): */ -- cgit 1.4.1 From 047f3436e95b40d541bcc5b688be0052ef5e798e Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 24 Feb 2021 21:29:00 +0100 Subject: edges in plot file --- include/afl-fuzz.h | 4 ++-- src/afl-fuzz-init.c | 2 +- src/afl-fuzz-stats.c | 21 +++++++++++---------- src/afl-fuzz.c | 8 ++++---- 4 files changed, 18 insertions(+), 17 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index d9dbad5a..3531d672 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1072,8 +1072,8 @@ void destroy_extras(afl_state_t *); void load_stats_file(afl_state_t *); void write_setup_file(afl_state_t *, u32, char **); -void write_stats_file(afl_state_t *, double, double, double); -void maybe_update_plot_file(afl_state_t *, double, double); +void write_stats_file(afl_state_t *, u32, double, double, double); +void maybe_update_plot_file(afl_state_t *, u32, double, double); void show_stats(afl_state_t *); void show_init_stats(afl_state_t *); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index e372c803..ab743f4b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2026,7 +2026,7 @@ void setup_dirs_fds(afl_state_t *afl) { fprintf(afl->fsrv.plot_file, "# unix_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " - "unique_hangs, max_depth, execs_per_sec\n"); + "unique_hangs, max_depth, execs_per_sec, edges_found\n"); fflush(afl->fsrv.plot_file); /* ignore errors */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 66efeb20..192fdd62 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -185,15 +185,14 @@ void load_stats_file(afl_state_t *afl) { /* Update stats file for unattended monitoring. */ -void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, - double eps) { +void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, + double stability, double eps) { #ifndef __HAIKU__ struct rusage rus; #endif u64 cur_time = get_cur_time(); - u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); u8 fn[PATH_MAX]; FILE *f; @@ -353,7 +352,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, /* Update the plot file if there is a reason to. */ -void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { +void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, + double eps) { if (unlikely(afl->plot_prev_qp == afl->queued_paths && afl->plot_prev_pf == afl->pending_favored && @@ -384,16 +384,16 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { /* Fields in the file: unix_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, - favored_not_fuzzed, afl->unique_crashes, afl->unique_hangs, afl->max_depth, - execs_per_sec */ + favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, + execs_per_sec, edges_found */ fprintf( afl->fsrv.plot_file, - "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu\n", + "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, %u\n", get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry, afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, - afl->plot_prev_ed); /* ignore errors */ + afl->plot_prev_ed, t_bytes); /* ignore errors */ fflush(afl->fsrv.plot_file); @@ -532,7 +532,8 @@ void show_stats(afl_state_t *afl) { if (cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000) { afl->stats_last_stats_ms = cur_ms; - write_stats_file(afl, t_byte_ratio, stab_ratio, afl->stats_avg_exec); + write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio, + afl->stats_avg_exec); save_auto(afl); write_bitmap(afl); @@ -555,7 +556,7 @@ void show_stats(afl_state_t *afl) { if (cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000) { afl->stats_last_plot_ms = cur_ms; - maybe_update_plot_file(afl, t_byte_ratio, afl->stats_avg_exec); + maybe_update_plot_file(afl, t_bytes, t_byte_ratio, afl->stats_avg_exec); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f83aac9e..f029ef83 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1724,8 +1724,8 @@ int main(int argc, char **argv_orig, char **envp) { afl->start_time = get_cur_time(); if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); - write_stats_file(afl, 0, 0, 0); - maybe_update_plot_file(afl, 0, 0); + write_stats_file(afl, 0, 0, 0, 0); + maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); if (afl->stop_soon) { goto stop_fuzzing; } @@ -2018,12 +2018,12 @@ int main(int argc, char **argv_orig, char **envp) { } write_bitmap(afl); - maybe_update_plot_file(afl, 0, 0); + maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); stop_fuzzing: - write_stats_file(afl, 0, 0, 0); + write_stats_file(afl, 0, 0, 0, 0); afl->force_ui_update = 1; // ensure the screen is reprinted show_stats(afl); // print the screen one last time -- cgit 1.4.1 From 108e588e888df5c2679600ea49846a565bac23f9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 2 Mar 2021 17:46:43 +0100 Subject: add de-unicoded dictionary entries --- docs/Changelog.md | 2 + include/afl-fuzz.h | 1 + src/afl-fuzz-extras.c | 149 ++++++++++++++++++++++++++++++++++++++++++-------- src/afl-fuzz.c | 7 ++- 4 files changed, 134 insertions(+), 25 deletions(-) (limited to 'include/afl-fuzz.h') diff --git a/docs/Changelog.md b/docs/Changelog.md index 01240b2a..376f5f06 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,8 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.11a (dev) + - afl-fuzz + - add non-unicode variants from unicode-looking dictionary entries - afl-cc - fixed for a crash that can occur with ASAN + CMPLOG together plus better support for unicode (thanks to @stbergmann for reporting!) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 3531d672..5003b563 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1062,6 +1062,7 @@ u8 has_new_bits_unclassified(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); void dedup_extras(afl_state_t *); +void deunicode_extras(afl_state_t *); void add_extra(afl_state_t *afl, u8 *mem, u32 len); void maybe_add_auto(afl_state_t *, u8 *, u32); void save_auto(afl_state_t *); diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 7ecad233..52100fa1 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -387,6 +387,130 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } +/* add an extra/dict/token - no checks performed, no sorting */ + +static void add_extra_nocheck(afl_state_t *afl, u8 *mem, u32 len) { + + afl->extras = afl_realloc((void **)&afl->extras, + (afl->extras_cnt + 1) * sizeof(struct extra_data)); + + if (unlikely(!afl->extras)) { PFATAL("alloc"); } + + afl->extras[afl->extras_cnt].data = ck_alloc(len); + afl->extras[afl->extras_cnt].len = len; + memcpy(afl->extras[afl->extras_cnt].data, mem, len); + afl->extras_cnt++; + + /* We only want to print this once */ + + if (afl->extras_cnt == afl->max_det_extras + 1) { + + WARNF("More than %u tokens - will use them probabilistically.", + afl->max_det_extras); + + } + +} + +/* Sometimes strings in input is transformed to unicode internally, so for + fuzzing we should attempt to de-unicode if it looks like simple unicode */ + +void deunicode_extras(afl_state_t *afl) { + + if (!afl->extras_cnt) return; + + u32 i, j, orig_cnt = afl->extras_cnt; + u8 buf[64]; + + for (i = 0; i < orig_cnt; ++i) { + + if (afl->extras[i].len < 6 || afl->extras[i].len > 64 || + afl->extras[i].len % 2) { + + continue; + + } + + u32 k = 0, z1 = 0, z2 = 0, z3 = 0, z4 = 0, half = afl->extras[i].len >> 1; + u32 quarter = half >> 1; + + for (j = 0; j < afl->extras[i].len; ++j) { + + switch (j % 4) { + + case 2: + if (!afl->extras[i].data[j]) { ++z3; } + // fall through + case 0: + if (!afl->extras[i].data[j]) { ++z1; } + break; + case 3: + if (!afl->extras[i].data[j]) { ++z4; } + // fall through + case 1: + if (!afl->extras[i].data[j]) { ++z2; } + break; + + } + + } + + if ((z1 < half && z2 < half) || z1 + z2 == afl->extras[i].len) { continue; } + + // also maybe 32 bit unicode? + if (afl->extras[i].len % 4 == 0 && afl->extras[i].len >= 12 && + (z3 == quarter || z4 == quarter) && z1 + z2 == quarter * 3) { + + for (j = 0; j < afl->extras[i].len; ++j) { + + if (z4 < quarter) { + + if (j % 4 == 3) { buf[k++] = afl->extras[i].data[j]; } + + } else if (z3 < quarter) { + + if (j % 4 == 2) { buf[k++] = afl->extras[i].data[j]; } + + } else if (z2 < half) { + + if (j % 4 == 1) { buf[k++] = afl->extras[i].data[j]; } + + } else { + + if (j % 4 == 0) { buf[k++] = afl->extras[i].data[j]; } + + } + + } + + add_extra_nocheck(afl, buf, k); + k = 0; + + } + + for (j = 0; j < afl->extras[i].len; ++j) { + + if (z1 < half) { + + if (j % 2 == 0) { buf[k++] = afl->extras[i].data[j]; } + + } else { + + if (j % 2 == 1) { buf[k++] = afl->extras[i].data[j]; } + + } + + } + + add_extra_nocheck(afl, buf, k); + + } + + qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), + compare_extras_len); + +} + /* Removes duplicates from the loaded extras. This can happen if multiple files are loaded */ @@ -396,9 +520,9 @@ void dedup_extras(afl_state_t *afl) { u32 i, j, orig_cnt = afl->extras_cnt; - for (i = 0; i < afl->extras_cnt - 1; i++) { + for (i = 0; i < afl->extras_cnt - 1; ++i) { - for (j = i + 1; j < afl->extras_cnt; j++) { + for (j = i + 1; j < afl->extras_cnt; ++j) { restart_dedup: @@ -462,30 +586,11 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { } - afl->extras = afl_realloc((void **)&afl->extras, - (afl->extras_cnt + 1) * sizeof(struct extra_data)); - - if (unlikely(!afl->extras)) { PFATAL("alloc"); } - - afl->extras[afl->extras_cnt].data = ck_alloc(len); - afl->extras[afl->extras_cnt].len = len; - - memcpy(afl->extras[afl->extras_cnt].data, mem, len); - - afl->extras_cnt++; + add_extra_nocheck(afl, mem, len); qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), compare_extras_len); - /* We only want to print this once */ - - if (afl->extras_cnt == afl->max_det_extras + 1) { - - WARNF("More than %u tokens - will use them probabilistically.", - afl->max_det_extras); - - } - } /* Maybe add automatic extra. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a02eadb2..90f77919 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1449,9 +1449,6 @@ int main(int argc, char **argv_orig, char **envp) { } - dedup_extras(afl); - OKF("Loaded a total of %u extras.", afl->extras_cnt); - } if (!afl->timeout_given) { find_timeout(afl); } // only for resumes! @@ -1681,6 +1678,10 @@ int main(int argc, char **argv_orig, char **envp) { } + deunicode_extras(afl); + dedup_extras(afl); + if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); } + // after we have the correct bitmap size we can read the bitmap -B option // and set the virgin maps if (afl->in_bitmap) { -- cgit 1.4.1