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 --- src/afl-fuzz-one.c | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) (limited to 'src/afl-fuzz-one.c') 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. */ -- 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 'src/afl-fuzz-one.c') 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 a75e7594f78454a11e3d93b3cb4878a21e4e943f Mon Sep 17 00:00:00 2001 From: Vitalii Akolzin Date: Thu, 24 Sep 2020 18:50:59 +0300 Subject: Add comments Co-authored-by: Ivan Gulakov --- src/afl-fuzz-one.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index edae2a88..8c1aa179 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1699,6 +1699,9 @@ 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)) { @@ -2769,7 +2772,7 @@ 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 */ + /* maybe current entry is not ready for splicing anymore */ if (old_len > 1 && afl->queue_cur->len == 1) afl->ready_for_splicing_count--; -- 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 'src/afl-fuzz-one.c') 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 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 'src/afl-fuzz-one.c') 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 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 'src/afl-fuzz-one.c') 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 'src/afl-fuzz-one.c') 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 2d5fadc1e6a684b5e3e527a64b614f6b1ba8415f Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 6 Oct 2020 16:45:25 +0200 Subject: hunting ref underflow --- src/afl-fuzz-one.c | 3 --- src/afl-fuzz-queue.c | 11 +++++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index a5f77f11..f25ab4ee 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -4695,9 +4695,6 @@ 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 58e026f5..0b491202 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -837,10 +837,17 @@ u8 *queue_testcase_take(afl_state_t *afl, struct queue_entry *q) { } q->testcase_refs++; - if (!q->testcase_buf) { + if (unlikely(!q->testcase_buf || !q->testcase_refs)) { + if (!q->testcase_buf) { + + FATAL("Testcase buf is NULL, this should never happen"); - 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; -- 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 'src/afl-fuzz-one.c') 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 'src/afl-fuzz-one.c') 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 d6da5605c80d65091375c08ae5389d14d671500a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 12 Oct 2020 04:03:42 +0200 Subject: fix splicing selection --- src/afl-fuzz-one.c | 47 ++++++++--------------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 6ef728e0..fc092f8d 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1712,9 +1712,9 @@ custom_mutator_stage: tid = rand_below(afl, afl->queued_paths); - } while (unlikely(tid == afl->current_entry && + } while (unlikely(tid == afl->current_entry || - afl->queue_buf[tid]->len >= 4)); + afl->queue_buf[tid]->len < 4)); target = afl->queue_buf[tid]; afl->splicing_with = tid; @@ -1872,7 +1872,7 @@ havoc_stage: u32 r_max, r; - if (unlikely(afl->expand_havoc)) { + 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 */ @@ -2323,24 +2323,15 @@ havoc_stage: /* Overwrite bytes with a randomly selected chunk from another testcase or insert that chunk. */ - if (afl->queued_paths < 4) break; - /* Pick a random queue entry and seek to it. */ u32 tid; do tid = rand_below(afl, afl->queued_paths); - while (tid == afl->current_entry); + while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); struct queue_entry *target = afl->queue_buf[tid]; - /* Make sure that the target has a reasonable length. */ - - while (target && (target->len < 2 || target == afl->queue_cur)) - target = target->next; - - if (!target) break; - /* Read the testcase into a new buffer. */ fd = open(target->fname, O_RDONLY); @@ -2480,7 +2471,7 @@ havoc_stage: retry_splicing: if (afl->use_splicing && splice_cycle++ < SPLICE_CYCLES && - afl->queued_paths > 1 && afl->queue_cur->len > 1) { + afl->ready_for_splicing_count > 1 && afl->queue_cur->len >= 4) { struct queue_entry *target; u32 tid, split_at; @@ -2503,22 +2494,11 @@ retry_splicing: tid = rand_below(afl, afl->queued_paths); - } while (tid == afl->current_entry); + } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); 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)) { - - target = target->next; - ++afl->splicing_with; - - } - - if (!target) { goto retry_splicing; } - /* Read the testcase into a new buffer. */ fd = open(target->fname, O_RDONLY); @@ -4487,7 +4467,7 @@ pacemaker_fuzzing: if (afl->use_splicing && splice_cycle++ < (u32)afl->SPLICE_CYCLES_puppet && - afl->queued_paths > 1 && afl->queue_cur->len > 1) { + afl->ready_for_splicing_count > 1 && afl->queue_cur->len >= 4) { struct queue_entry *target; u32 tid, split_at; @@ -4511,22 +4491,11 @@ pacemaker_fuzzing: tid = rand_below(afl, afl->queued_paths); - } while (tid == afl->current_entry); + } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); 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)) { - - target = target->next; - ++afl->splicing_with; - - } - - if (!target) { goto retry_splicing_puppet; } - /* Read the testcase into a new buffer. */ fd = open(target->fname, O_RDONLY); -- 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 'src/afl-fuzz-one.c') 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 24e0c9cf65428efce181eaecc8c69ee030b8dfcc Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 15 Oct 2020 10:22:40 +0200 Subject: add missing swap bufs --- src/afl-fuzz-one.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 154e4b45..9c5e2e3c 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2465,6 +2465,7 @@ retry_splicing: 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); + afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = afl->in_scratch_buf; out_buf = afl_realloc(AFL_BUF_PARAM(out), len); -- cgit 1.4.1 From 0139b8cdcb81ec1ed873f182946b686a04f46ac6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 15 Oct 2020 10:28:11 +0200 Subject: add missing swap bufs --- src/afl-fuzz-one.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 9c5e2e3c..cbfbbc58 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -4434,6 +4434,7 @@ pacemaker_fuzzing: 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); + afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = afl->in_scratch_buf; out_buf = afl_realloc(AFL_BUF_PARAM(out), len); -- cgit 1.4.1 From d1e18f9edf43dc71ab81619eeed7a0f5fa0bb15f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 15 Oct 2020 12:20:33 +0200 Subject: fix afl_swap_bufs usage? --- src/afl-fuzz-one.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index cbfbbc58..1899193e 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2149,7 +2149,6 @@ havoc_stage: temp_len - clone_to); afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - out_buf = new_buf; temp_len += clone_len; } @@ -2346,7 +2345,6 @@ havoc_stage: temp_len - clone_to); afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - out_buf = temp_buf; temp_len += clone_len; } @@ -2465,8 +2463,8 @@ retry_splicing: 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); - afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = afl->in_scratch_buf; + afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } @@ -4142,7 +4140,6 @@ pacemaker_fuzzing: temp_len - clone_to); 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; @@ -4434,8 +4431,8 @@ pacemaker_fuzzing: 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); - afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); in_buf = afl->in_scratch_buf; + afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } -- cgit 1.4.1 From ea0851c654285cc33ac25637d2054044ee6ee2ee Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 15 Oct 2020 12:54:18 +0200 Subject: fix previous commit --- src/afl-fuzz-one.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 1899193e..02550d36 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2148,6 +2148,7 @@ havoc_stage: memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); + out_buf = new_buf; afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); temp_len += clone_len; @@ -2344,6 +2345,7 @@ havoc_stage: 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; @@ -4139,6 +4141,7 @@ pacemaker_fuzzing: memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); + 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; -- cgit 1.4.1 From ac1c3b87015dd2c9b1bae0198f7925816aa63aec Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 19 Oct 2020 11:34:57 +0200 Subject: mini improvements --- TODO.md | 1 + src/afl-fuzz-one.c | 2 +- src/afl-fuzz-queue.c | 8 ++++---- src/afl-fuzz.c | 56 +++++++++++++++++++++++++++------------------------- src/afl-showmap.c | 10 ++++++---- 5 files changed, 41 insertions(+), 36 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/TODO.md b/TODO.md index 6b43d6be..7e203d26 100644 --- a/TODO.md +++ b/TODO.md @@ -7,6 +7,7 @@ - afl-plot to support multiple plot_data - afl_custom_fuzz_splice_optin() - intel-pt tracer + - own sancov for llvm 12 ## Further down the road diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 02550d36..1e63abc7 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2540,7 +2540,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { #else - if (afl->pending_favored) { + if (likely(afl->pending_favored)) { /* If we have any favored, non-fuzzed new arrivals in the queue, possibly skip to them at the expense of already-fuzzed or non-favored diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index e0df7206..7f157121 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -179,9 +179,9 @@ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { - u8 fn[PATH_MAX]; + if (likely(state == q->fs_redundant)) { return; } - if (state == q->fs_redundant) { return; } + u8 fn[PATH_MAX]; q->fs_redundant = state; @@ -521,13 +521,13 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { 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; - if (afl->non_instrumented_mode || !afl->score_changed) { return; } - afl->score_changed = 0; memset(temp_v, 255, len); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9a82edeb..7215ecec 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1378,10 +1378,9 @@ int main(int argc, char **argv_orig, char **envp) { u32 runs_in_current_cycle = (u32)-1; u32 prev_queued_paths = 0; + u8 skipped_fuzz; - while (1) { - - u8 skipped_fuzz; + while (likely(!afl->stop_soon)) { cull_queue(afl); @@ -1418,8 +1417,8 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (afl->queued_paths == prev_queued && - (get_cur_time() - afl->start_time) >= 3600) { + if (unlikely(afl->queued_paths == prev_queued && + (get_cur_time() - afl->start_time) >= 3600)) { if (afl->use_splicing) { @@ -1534,46 +1533,49 @@ int main(int argc, char **argv_orig, char **envp) { } - if (likely(!afl->old_seed_selection)) { + ++runs_in_current_cycle; - ++runs_in_current_cycle; - if (unlikely(prev_queued_paths < afl->queued_paths)) { + do { - // we have new queue entries since the last run, recreate alias table - prev_queued_paths = afl->queued_paths; - create_alias_table(afl); + if (likely(!afl->old_seed_selection)) { - } + if (unlikely(prev_queued_paths < afl->queued_paths)) { - afl->current_entry = select_next_queue_entry(afl); - afl->queue_cur = afl->queue_buf[afl->current_entry]; + // we have new queue entries since the last run, recreate alias table + prev_queued_paths = afl->queued_paths; + create_alias_table(afl); - } + } - skipped_fuzz = fuzz_one(afl); + afl->current_entry = select_next_queue_entry(afl); + afl->queue_cur = afl->queue_buf[afl->current_entry]; - if (!skipped_fuzz && !afl->stop_soon && afl->sync_id) { + } - if (unlikely(afl->is_main_node)) { + skipped_fuzz = fuzz_one(afl); - if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { sync_fuzzers(afl); } + if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; } - } else { + if (unlikely(afl->old_seed_selection)) { - if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + afl->queue_cur = afl->queue_cur->next; + ++afl->current_entry; } - } + } while (skipped_fuzz && afl->queue_cur && !afl->stop_soon); - if (!afl->stop_soon && exit_1) { afl->stop_soon = 2; } + if (!afl->stop_soon && afl->sync_id) { - if (afl->stop_soon) { break; } + if (unlikely(afl->is_main_node)) { - if (unlikely(afl->old_seed_selection)) { + if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { sync_fuzzers(afl); } - afl->queue_cur = afl->queue_cur->next; - ++afl->current_entry; + } else { + + if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + + } } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index bd0d1a29..4b357254 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -209,10 +209,10 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (!outfile) { FATAL("Output filename not set (Bug in AFL++?)"); } - if (cmin_mode && (fsrv->last_run_timed_out - || (!caa && child_crashed != cco))) { + if (cmin_mode && + (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { - return ret; + return ret; } @@ -298,7 +298,8 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); } - if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(fsrv->child_status)) { + if (!fsrv->last_run_timed_out && !stop_soon && + WIFSIGNALED(fsrv->child_status)) { child_crashed = 1; @@ -1202,6 +1203,7 @@ int main(int argc, char **argv_orig, char **envp) { ret = child_crashed * 2 + fsrv->last_run_timed_out; } + if (fsrv->target_path) { ck_free(fsrv->target_path); } afl_fsrv_deinit(fsrv); -- cgit 1.4.1 From fe705bb9567341427ce1ea39d5fc6b19fdee1646 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 28 Oct 2020 14:32:53 +0100 Subject: expand havoc if not new findings in the last 5 seconds --- src/afl-fuzz-one.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index bf568c38..2e186b90 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1884,16 +1884,22 @@ havoc_stage: u32 r_max, r; + r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + if (unlikely(afl->expand_havoc)) { /* add expensive havoc cases here, they are activated after a full cycle without finds happened */ - r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + r_max += 1; - } else { + } + + if (unlikely(get_cur_time() - afl->last_path_time > 5000)) { + + /* add expensive havoc cases here if there is no findings in the last 5s */ - r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + r_max += 1; } -- cgit 1.4.1 From b5686eb63e1fcd6dac49cc458c50e52b51709f8c Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 29 Oct 2020 00:05:28 +0100 Subject: fixes two huge bugs --- src/afl-fuzz-one.c | 5 +++-- src/afl-fuzz-run.c | 3 ++- src/afl-fuzz-stats.c | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 35ff5466..0f3393d2 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1850,8 +1850,9 @@ havoc_stage: r_max += 1; } - - if (unlikely(get_cur_time() - afl->last_path_time > 5000)) { + + if (unlikely(get_cur_time() - afl->last_path_time > 5000 && + afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here if there is no findings in the last 5s */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index dfd3abfb..fb259b5d 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -587,9 +587,10 @@ void sync_fuzzers(afl_state_t *afl) { u8 entry[12]; sprintf(entry, "id:%06u", next_min_accept); + while (m < n) { - if (memcmp(namelist[m]->d_name, entry, 9)) { + if (strcmp(namelist[m]->d_name, entry)) { m++; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 6841eb88..321bbb35 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1154,7 +1154,8 @@ void show_init_stats(afl_state_t *afl) { } else { - OKF("-t option specified. We'll use an exec timeout of %s ms.", afl->fsrv.exec_tmout); + ACTF("-t option specified. We'll use an exec timeout of %d ms.", + afl->fsrv.exec_tmout); } -- 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 'src/afl-fuzz-one.c') 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 'src/afl-fuzz-one.c') 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