From fedbd543250fae64a988c283ad67d2362db6b8c8 Mon Sep 17 00:00:00 2001 From: Khaled Yakdan Date: Wed, 15 May 2019 10:03:19 +0200 Subject: Define AFLCustomMutator hook that can be implemented by implemented by external libraries and provided to AFL --- afl-fuzz.c | 84 +++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 26 deletions(-) (limited to 'afl-fuzz.c') diff --git a/afl-fuzz.c b/afl-fuzz.c index 6db99acf..8af110a5 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -304,6 +304,9 @@ static u32 a_extras_cnt; /* Total number of tokens available */ static u8* (*post_handler)(u8* buf, u32* len); +/* A hook for the custom mutator function */ +extern size_t AFLCustomMutator(uint8_t *data, size_t size, size_t max_size, unsigned int seed) __attribute__((weak)); + /* Interesting values, as per config.h */ static s8 interesting_8[] = { INTERESTING_8 }; @@ -330,7 +333,8 @@ enum { /* 14 */ STAGE_EXTRAS_AO, /* 15 */ STAGE_HAVOC, /* 16 */ STAGE_SPLICE, - /* 17 */ STAGE_PYTHON + /* 17 */ STAGE_PYTHON, + /* 18 */ STAGE_CUSTOM_MUTATOR }; /* Stage value types */ @@ -1480,7 +1484,7 @@ static u64 next_p2(u64 val) { while (val > ret) ret <<= 1; return ret; -} +} /* When we bump into a new path, we call this to see if the path appears @@ -4127,7 +4131,7 @@ static void maybe_delete_out_dir(void) { fn = alloc_printf("%s/plot_data", out_dir); if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; ck_free(fn); - + fn = alloc_printf("%s/cmdline", out_dir); if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; ck_free(fn); @@ -4185,7 +4189,7 @@ static void show_stats(void) { /* Calculate smoothed exec speed stats. */ if (!last_execs) { - + avg_exec = ((double)total_execs) * 1000 / (cur_ms - start_time); } else { @@ -4217,7 +4221,7 @@ static void show_stats(void) { t_bytes = count_non_255_bytes(virgin_bits); t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; - if (t_bytes) + if (t_bytes) stab_ratio = 100 - ((double)var_byte_count) * 100 / t_bytes; else stab_ratio = 100; @@ -4239,7 +4243,7 @@ static void show_stats(void) { last_plot_ms = cur_ms; maybe_update_plot_file(t_byte_ratio, avg_exec); - + } /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */ @@ -4286,7 +4290,7 @@ static void show_stats(void) { memset(tmp, ' ', banner_pad); sprintf(tmp + banner_pad, "%s " cLCY VERSION cLGN - " (%s) " cPIN "[%s]", crash_mode ? cPIN "peruvian were-rabbit" : + " (%s) " cPIN "[%s]", crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop", use_banner, power_name); SAYF("\n%s\n", tmp); @@ -4348,7 +4352,7 @@ static void show_stats(void) { if (dumb_mode) - SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST + SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST " (non-instrumented mode) "); else @@ -4375,7 +4379,7 @@ static void show_stats(void) { sprintf(tmp, "%s%s", DI(unique_hangs), (unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); - SAYF(bV bSTOP " last uniq hang : " cRST "%-33s " bSTG bV bSTOP + SAYF(bV bSTOP " last uniq hang : " cRST "%-33s " bSTG bV bSTOP " uniq hangs : " cRST "%-6s" bSTG bV "\n", DTD(cur_ms, last_hang_time), tmp); @@ -4392,10 +4396,10 @@ static void show_stats(void) { SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp); - sprintf(tmp, "%0.02f%% / %0.02f%%", ((double)queue_cur->bitmap_size) * + sprintf(tmp, "%0.02f%% / %0.02f%%", ((double)queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio); - SAYF(" map density : %s%-21s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD : + SAYF(" map density : %s%-21s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD : ((t_bytes < 200 && !dumb_mode) ? cPIN : cRST), tmp); sprintf(tmp, "%s (%0.02f%%)", DI(cur_skipped_paths), @@ -4416,7 +4420,7 @@ static void show_stats(void) { /* Yeah... it's still going on... halp? */ - SAYF(bV bSTOP " now trying : " cRST "%-20s " bSTG bV bSTOP + SAYF(bV bSTOP " now trying : " cRST "%-20s " bSTG bV bSTOP " favored paths : " cRST "%-22s" bSTG bV "\n", stage_name, tmp); if (!stage_max) { @@ -4543,7 +4547,7 @@ static void show_stats(void) { if (t_bytes) sprintf(tmp, "%0.02f%%", stab_ratio); else strcpy(tmp, "n/a"); - SAYF(" stability : %s%-10s" bSTG bV "\n", (stab_ratio < 85 && var_byte_count > 40) + SAYF(" stability : %s%-10s" bSTG bV "\n", (stab_ratio < 85 && var_byte_count > 40) ? cLRD : ((queued_variable && (!persistent_mode || var_byte_count > 20)) ? cMGN : cRST), tmp); @@ -4577,9 +4581,14 @@ static void show_stats(void) { strcat(tmp, tmp2); } - - SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n" + if (AFLCustomMutator) { + sprintf(tmp, "%s/%s", DI(stage_finds[STAGE_CUSTOM_MUTATOR]), DI(stage_cycles[STAGE_CUSTOM_MUTATOR])); + SAYF(bV bSTOP " custom mut. : " cRST "%-37s " bSTG bVR bH20 bH2 bH2 bRB "\n" + bLB bH30 bH20 bH2 bH bRB bSTOP cRST RESET_G1, tmp); + } else { + SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n" bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1, tmp); + } /* Provide some CPU utilization stats. */ @@ -5140,7 +5149,7 @@ static u32 calculate_score(struct queue_entry* q) { switch (schedule) { - case EXPLORE: + case EXPLORE: break; case EXPLOIT: @@ -5151,7 +5160,7 @@ static u32 calculate_score(struct queue_entry* q) { fuzz_total = 0; n_paths = 0; - struct queue_entry *queue_it = queue; + struct queue_entry *queue_it = queue; while (queue_it) { fuzz_total += queue_it->n_fuzz; n_paths ++; @@ -5162,22 +5171,22 @@ static u32 calculate_score(struct queue_entry* q) { if (fuzz <= fuzz_mu) { if (q->fuzz_level < 16) factor = ((u32) (1 << q->fuzz_level)); - else + else factor = MAX_FACTOR; } else { factor = 0; } break; - + case FAST: if (q->fuzz_level < 16) { - factor = ((u32) (1 << q->fuzz_level)) / (fuzz == 0 ? 1 : fuzz); + factor = ((u32) (1 << q->fuzz_level)) / (fuzz == 0 ? 1 : fuzz); } else factor = MAX_FACTOR / (fuzz == 0 ? 1 : next_p2 (fuzz)); break; case LIN: - factor = q->fuzz_level / (fuzz == 0 ? 1 : fuzz); + factor = q->fuzz_level / (fuzz == 0 ? 1 : fuzz); break; case QUAD: @@ -5187,7 +5196,7 @@ static u32 calculate_score(struct queue_entry* q) { default: PFATAL ("Unknown Power Schedule"); } - if (factor > MAX_FACTOR) + if (factor > MAX_FACTOR) factor = MAX_FACTOR; perf_score *= factor / POWER_BETA; @@ -5500,7 +5509,7 @@ static u8 fuzz_one(char** argv) { * TRIMMING * ************/ - if (!dumb_mode && !queue_cur->trim_done) { + if (!dumb_mode && !queue_cur->trim_done && !AFLCustomMutator) { u8 res = trim_case(argv, queue_cur, in_buf); @@ -5530,16 +5539,39 @@ static u8 fuzz_one(char** argv) { if (perf_score == 0) goto abandon_entry; + if (AFLCustomMutator) { + stage_short = "custom"; + stage_name = "custom mutator"; + stage_max = 1 << 16; + stage_val_type = STAGE_VAL_NONE; + + orig_hit_cnt = queued_paths + unique_crashes; + + for (stage_cur = 0 ; stage_cur < stage_max ; stage_cur++) { + size_t orig_size = (size_t) len; + size_t mutated_size = AFLCustomMutator(out_buf, orig_size, orig_size + 10000, UR(UINT32_MAX)); + if (common_fuzz_stuff(argv, out_buf, (u32)mutated_size)) { + goto abandon_entry; + } + } + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_CUSTOM_MUTATOR] += stage_max; + goto abandon_entry; + } + + /* Skip right away if -d is given, if it has not been chosen sufficiently often to warrant the expensive deterministic stage (fuzz_level), or if it has gone through deterministic testing in earlier, resumed runs (passed_det). */ - if (skip_deterministic - || ((!queue_cur->passed_det) + if (skip_deterministic + || ((!queue_cur->passed_det) && perf_score < ( queue_cur->depth * 30 <= HAVOC_MAX_MULT * 100 - ? queue_cur->depth * 30 + ? queue_cur->depth * 30 : HAVOC_MAX_MULT * 100)) || queue_cur->passed_det) #ifdef USE_PYTHON -- cgit 1.4.1 From 14aa5fe521adb12bea7f36194cd0db17215d3b8c Mon Sep 17 00:00:00 2001 From: Khaled Yakdan Date: Thu, 4 Jul 2019 14:25:19 +0200 Subject: Added two hooks that are necessary for the grammar fuzzer --- Makefile | 4 ++-- afl-fuzz.c | 43 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 9 deletions(-) (limited to 'afl-fuzz.c') diff --git a/Makefile b/Makefile index f65650b7..17e35a27 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ afl-fuzz: afl-fuzz.c $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) $(PYFLAGS) smart-rabbit: afl-fuzz.c $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) afl-fuzz.c -o $@ $(LDFLAGS) -lstdc++ -lpthread -lm \ + $(CC) $(CFLAGS) afl-fuzz.c -o $@ $(LDFLAGS) -lstdc++ -lpthread -lm -lrt \ -Wl,--whole-archive -Wl,$(CLANG_COMPILER_RT)/libclang_rt.ubsan_standalone-x86_64.a -Wl,--no-whole-archive \ -Wl,--dynamic-list=$(CLANG_COMPILER_RT)/libclang_rt.ubsan_standalone-x86_64.a.syms \ -Wl,--whole-archive -Wl,$(CLANG_COMPILER_RT)/libclang_rt.ubsan_standalone_cxx-x86_64.a -Wl,--no-whole-archive \ @@ -145,7 +145,7 @@ all_done: test_build .NOTPARALLEL: clean clean: - rm -f $(PROGS) afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.10.0.tar.bz2 afl-qemu-trace + rm -f $(PROGS) smart-rabbit afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.10.0.tar.bz2 afl-qemu-trace rm -rf out_dir qemu_mode/qemu-2.10.0 $(MAKE) -C llvm_mode clean $(MAKE) -C libdislocator clean diff --git a/afl-fuzz.c b/afl-fuzz.c index 8af110a5..b7ebdb0b 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -304,8 +304,10 @@ static u32 a_extras_cnt; /* Total number of tokens available */ static u8* (*post_handler)(u8* buf, u32* len); -/* A hook for the custom mutator function */ -extern size_t AFLCustomMutator(uint8_t *data, size_t size, size_t max_size, unsigned int seed) __attribute__((weak)); +/* hooks for the custom mutator function */ +static size_t (*custom_mutator)(u8 *data, size_t size, size_t max_size, unsigned int seed); +static size_t (*pre_save_handler)(u8 *data, size_t size, u8 **new_data); + /* Interesting values, as per config.h */ @@ -1671,6 +1673,26 @@ static void setup_post(void) { } +static void setup_custom_mutator(void) { + void* dh; + u8* fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + + if (!fn) return; + + ACTF("Loading custom mutator library from '%s'...", fn); + + dh = dlopen(fn, RTLD_NOW); + if (!dh) FATAL("%s", dlerror()); + + custom_mutator = dlsym(dh, "afl_custom_mutator"); + if (!custom_mutator) FATAL("Symbol 'afl_custom_mutator' not found."); + + pre_save_handler = dlsym(dh, "afl_pre_save_handler"); +// if (!pre_save_handler) WARNF("Symbol 'afl_pre_save_handler' not found."); + + OKF("Custom mutator installed successfully."); +} + /* Read all testcases from the input directory, then queue them for testing. Called at startup. */ @@ -2754,7 +2776,13 @@ static void write_to_testcase(void* mem, u32 len) { } else lseek(fd, 0, SEEK_SET); - ck_write(fd, mem, len, out_file); + if (pre_save_handler) { + u8* new_data; + size_t new_size = pre_save_handler(mem, len, &new_data); + ck_write(fd, new_data, new_size, out_file); + } else { + ck_write(fd, mem, len, out_file); + } if (!out_file) { @@ -4581,7 +4609,7 @@ static void show_stats(void) { strcat(tmp, tmp2); } - if (AFLCustomMutator) { + if (custom_mutator) { sprintf(tmp, "%s/%s", DI(stage_finds[STAGE_CUSTOM_MUTATOR]), DI(stage_cycles[STAGE_CUSTOM_MUTATOR])); SAYF(bV bSTOP " custom mut. : " cRST "%-37s " bSTG bVR bH20 bH2 bH2 bRB "\n" bLB bH30 bH20 bH2 bH bRB bSTOP cRST RESET_G1, tmp); @@ -5509,7 +5537,7 @@ static u8 fuzz_one(char** argv) { * TRIMMING * ************/ - if (!dumb_mode && !queue_cur->trim_done && !AFLCustomMutator) { + if (!dumb_mode && !queue_cur->trim_done && !custom_mutator) { u8 res = trim_case(argv, queue_cur, in_buf); @@ -5539,7 +5567,7 @@ static u8 fuzz_one(char** argv) { if (perf_score == 0) goto abandon_entry; - if (AFLCustomMutator) { + if (custom_mutator) { stage_short = "custom"; stage_name = "custom mutator"; stage_max = 1 << 16; @@ -5549,7 +5577,7 @@ static u8 fuzz_one(char** argv) { for (stage_cur = 0 ; stage_cur < stage_max ; stage_cur++) { size_t orig_size = (size_t) len; - size_t mutated_size = AFLCustomMutator(out_buf, orig_size, orig_size + 10000, UR(UINT32_MAX)); + size_t mutated_size = custom_mutator(out_buf, orig_size, orig_size, UR(UINT32_MAX)); if (common_fuzz_stuff(argv, out_buf, (u32)mutated_size)) { goto abandon_entry; } @@ -8671,6 +8699,7 @@ int main(int argc, char** argv) { check_cpu_governor(); setup_post(); + setup_custom_mutator(); setup_shm(); init_count_class16(); -- cgit 1.4.1 From b2f0b6f2b49a260cbeba01e54998b7bf62dae1d6 Mon Sep 17 00:00:00 2001 From: Khaled Yakdan Date: Sat, 6 Jul 2019 11:03:00 +0200 Subject: Update the interface of the custom_mutator to handle cases where the mutation returns a larger buffer than the original buffer --- afl-fuzz.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'afl-fuzz.c') diff --git a/afl-fuzz.c b/afl-fuzz.c index b7ebdb0b..35f1af7f 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -305,7 +305,7 @@ static u32 a_extras_cnt; /* Total number of tokens available */ static u8* (*post_handler)(u8* buf, u32* len); /* hooks for the custom mutator function */ -static size_t (*custom_mutator)(u8 *data, size_t size, size_t max_size, unsigned int seed); +static size_t (*custom_mutator)(u8 *data, size_t size, u8* mutated_out, size_t max_size, unsigned int seed); static size_t (*pre_save_handler)(u8 *data, size_t size, u8 **new_data); @@ -4611,7 +4611,7 @@ static void show_stats(void) { } if (custom_mutator) { sprintf(tmp, "%s/%s", DI(stage_finds[STAGE_CUSTOM_MUTATOR]), DI(stage_cycles[STAGE_CUSTOM_MUTATOR])); - SAYF(bV bSTOP " custom mut. : " cRST "%-37s " bSTG bVR bH20 bH2 bH2 bRB "\n" + SAYF(bV bSTOP " custom mut. : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n" bLB bH30 bH20 bH2 bH bRB bSTOP cRST RESET_G1, tmp); } else { SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n" @@ -5570,18 +5570,25 @@ static u8 fuzz_one(char** argv) { if (custom_mutator) { stage_short = "custom"; stage_name = "custom mutator"; - stage_max = 1 << 16; + stage_max = len << 3; stage_val_type = STAGE_VAL_NONE; + const u32 max_seed_size = 4096*4096; + u8* mutated_buf = ck_alloc(max_seed_size); + orig_hit_cnt = queued_paths + unique_crashes; for (stage_cur = 0 ; stage_cur < stage_max ; stage_cur++) { size_t orig_size = (size_t) len; - size_t mutated_size = custom_mutator(out_buf, orig_size, orig_size, UR(UINT32_MAX)); + size_t mutated_size = custom_mutator(out_buf, orig_size, mutated_buf, max_seed_size, UR(UINT32_MAX)); + out_buf = ck_realloc(out_buf, mutated_size); + memcpy(out_buf, mutated_buf, mutated_size); if (common_fuzz_stuff(argv, out_buf, (u32)mutated_size)) { goto abandon_entry; } } + + ck_free(mutated_buf); new_hit_cnt = queued_paths + unique_crashes; stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt; -- cgit 1.4.1 From a949b40d11956f34c51f4546412a73e0400d1ffc Mon Sep 17 00:00:00 2001 From: Khaled Yakdan Date: Sat, 27 Jul 2019 01:18:30 +0200 Subject: Only execute the mutated input when it is not empty --- afl-fuzz.c | 10 ++++++---- libclang_rt.fuzzer_no_main-x86_64.a.syms | 3 --- 2 files changed, 6 insertions(+), 7 deletions(-) delete mode 100644 libclang_rt.fuzzer_no_main-x86_64.a.syms (limited to 'afl-fuzz.c') diff --git a/afl-fuzz.c b/afl-fuzz.c index 35f1af7f..42970e39 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -5581,10 +5581,12 @@ static u8 fuzz_one(char** argv) { for (stage_cur = 0 ; stage_cur < stage_max ; stage_cur++) { size_t orig_size = (size_t) len; size_t mutated_size = custom_mutator(out_buf, orig_size, mutated_buf, max_seed_size, UR(UINT32_MAX)); - out_buf = ck_realloc(out_buf, mutated_size); - memcpy(out_buf, mutated_buf, mutated_size); - if (common_fuzz_stuff(argv, out_buf, (u32)mutated_size)) { - goto abandon_entry; + if (mutated_size > 0) { + out_buf = ck_realloc(out_buf, mutated_size); + memcpy(out_buf, mutated_buf, mutated_size); + if (common_fuzz_stuff(argv, out_buf, (u32) mutated_size)) { + goto abandon_entry; + } } } diff --git a/libclang_rt.fuzzer_no_main-x86_64.a.syms b/libclang_rt.fuzzer_no_main-x86_64.a.syms deleted file mode 100644 index 289454c8..00000000 --- a/libclang_rt.fuzzer_no_main-x86_64.a.syms +++ /dev/null @@ -1,3 +0,0 @@ -{ - LLVMFuzzerMutate; -}; \ No newline at end of file -- cgit 1.4.1