diff options
-rw-r--r-- | include/afl-fuzz.h | 17 | ||||
-rw-r--r-- | src/afl-fuzz-mutators.c | 193 | ||||
-rw-r--r-- | src/afl-fuzz-one.c | 193 | ||||
-rw-r--r-- | src/afl-fuzz-python.c | 40 | ||||
-rw-r--r-- | src/afl-fuzz-queue.c | 17 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 49 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz.c | 4 | ||||
-rw-r--r-- | test/test-multiple-mutators.c | 24 | ||||
-rwxr-xr-x | test/test.sh | 32 |
10 files changed, 340 insertions, 231 deletions
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 2203cfdf..d6a19c5d 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -605,8 +605,11 @@ typedef struct afl_state { u8 * in_scratch_buf; size_t in_scratch_size; - u8 * ex_buf; - size_t ex_size; + u8 * ex_buf; + size_t ex_size; + u32 custom_mutators_count; + + list_t custom_mutator_list; /* this is a fixed buffer of size map_size that can be used by any function if * they do not call another function */ @@ -620,6 +623,8 @@ struct custom_mutator { void * dh; u8 * pre_save_buf; size_t pre_save_size; + u8 stacked_custom_prob, + stacked_custom; void *data; /* custom mutator data ptr */ @@ -808,14 +813,14 @@ void read_afl_environment(afl_state_t *, char **); /**** Prototypes ****/ /* Custom mutators */ -void setup_custom_mutator(afl_state_t *); -void destroy_custom_mutator(afl_state_t *); -u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf); +void setup_custom_mutators(afl_state_t *); +void destroy_custom_mutators(afl_state_t *); +u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf, struct custom_mutator * mutator); /* Python */ #ifdef USE_PYTHON -void load_custom_mutator_py(afl_state_t *, char *); +struct custom_mutator * load_custom_mutator_py(afl_state_t *, char *); void finalize_py_module(void *); size_t pre_save_py(void *, u8 *, size_t, u8 **); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index beb89092..23f15945 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -26,27 +26,47 @@ #include "afl-fuzz.h" -void load_custom_mutator(afl_state_t *, const char *); +struct custom_mutator *load_custom_mutator(afl_state_t *, const char *); +#ifdef USE_PYTHON +struct custom_mutator * load_custom_mutator_py(afl_state_t *, char *); +#endif -void setup_custom_mutator(afl_state_t *afl) { +void setup_custom_mutators(afl_state_t *afl) { /* Try mutator library first */ - u8 *fn = afl->afl_env.afl_custom_mutator_library; + struct custom_mutator * mutator; + u8 * fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + u32 prev_mutator_count = 0; if (fn) { - if (afl->limit_time_sig) { - + if (afl->limit_time_sig) FATAL( "MOpt and custom mutator are mutually exclusive. We accept pull " "requests that integrates MOpt with the optional mutators " "(custom/radamsa/redquenn/...)."); - } + u8 *fn_token = (u8 *)strsep((char **)&fn, ";"); + + if (likely(!fn_token)) { - load_custom_mutator(afl, fn); + mutator = load_custom_mutator(afl, fn); + list_append(&afl->custom_mutator_list, mutator); + afl->custom_mutators_count++; - return; + } else { + + while (fn_token) { + + prev_mutator_count = afl->custom_mutators_count; + mutator = load_custom_mutator(afl, fn_token); + list_append(&afl->custom_mutator_list, mutator); + afl->custom_mutators_count++; + if (prev_mutator_count > afl->custom_mutators_count) FATAL("Maximum Custom Mutator count reached."); + fn_token = (u8 *)strsep((char **)&fn, ";"); + + } + } } @@ -65,7 +85,9 @@ void setup_custom_mutator(afl_state_t *afl) { } - load_custom_mutator_py(afl, module_name); + struct custom_mutator * mutator = load_custom_mutator_py(afl, module_name); + afl->custom_mutators_count++; + list_append(&afl->custom_mutator_list, mutator); } @@ -80,114 +102,85 @@ void setup_custom_mutator(afl_state_t *afl) { } -void destroy_custom_mutator(afl_state_t *afl) { - - if (afl->mutator) { +void destroy_custom_mutators(afl_state_t *afl) { - afl->mutator->afl_custom_deinit(afl->mutator->data); + if (afl->custom_mutators_count) { - if (afl->mutator->dh) { dlclose(afl->mutator->dh); } + LIST_FOREACH_CLEAR(&afl->custom_mutator_list, struct custom_mutator, { - if (afl->mutator->pre_save_buf) { + if (!el->data) { FATAL("Deintializing NULL mutator"); } + el->afl_custom_deinit(el->data); + if (el->dh) dlclose(el->dh); - ck_free(afl->mutator->pre_save_buf); - afl->mutator->pre_save_buf = NULL; - afl->mutator->pre_save_size = 0; + if (el->pre_save_buf) { + ck_free(el->pre_save_buf); + el->pre_save_buf = NULL; + el->pre_save_size = 0; + } - } + ck_free(el); - ck_free(afl->mutator); - afl->mutator = NULL; + } ); } } -void load_custom_mutator(afl_state_t *afl, const char *fn) { +struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { - void *dh; - afl->mutator = ck_alloc(sizeof(struct custom_mutator)); - afl->mutator->pre_save_buf = NULL; - afl->mutator->pre_save_size = 0; + void * dh; + struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); - afl->mutator->name = fn; + mutator->name = fn; ACTF("Loading custom mutator library from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); - if (!dh) { FATAL("%s", dlerror()); } - afl->mutator->dh = dh; + if (!dh) FATAL("%s", dlerror()); + mutator->dh = dh; /* Mutator */ - /* "afl_custom_init", required */ - afl->mutator->afl_custom_init = dlsym(dh, "afl_custom_init"); - if (!afl->mutator->afl_custom_init) { - - FATAL("Symbol 'afl_custom_init' not found."); - - } - - /* "afl_custom_deinit", required */ - afl->mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit"); - if (!afl->mutator->afl_custom_deinit) { - - FATAL("Symbol 'afl_custom_deinit' not found."); - - } + /* "afl_custom_init", optional for backward compatibility */ + mutator->afl_custom_init = dlsym(dh, "afl_custom_init"); + if (!mutator->afl_custom_init) WARNF("Symbol 'afl_custom_init' not found."); /* "afl_custom_fuzz" or "afl_custom_mutator", required */ - afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz"); - if (!afl->mutator->afl_custom_fuzz) { + mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz"); + if (!mutator->afl_custom_fuzz) { /* Try "afl_custom_mutator" for backward compatibility */ WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'."); - afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator"); - if (!afl->mutator->afl_custom_fuzz) { - + mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator"); + if (!mutator->afl_custom_fuzz) FATAL("Symbol 'afl_custom_mutator' not found."); - } - } /* "afl_custom_pre_save", optional */ - afl->mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save"); - if (!afl->mutator->afl_custom_pre_save) { - + mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save"); + if (!mutator->afl_custom_pre_save) WARNF("Symbol 'afl_custom_pre_save' not found."); - } - u8 notrim = 0; /* "afl_custom_init_trim", optional */ - afl->mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); - if (!afl->mutator->afl_custom_init_trim) { - + mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); + if (!mutator->afl_custom_init_trim) WARNF("Symbol 'afl_custom_init_trim' not found."); - } - /* "afl_custom_trim", optional */ - afl->mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim"); - if (!afl->mutator->afl_custom_trim) { - - WARNF("Symbol 'afl_custom_trim' not found."); - - } + mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim"); + if (!mutator->afl_custom_trim) WARNF("Symbol 'afl_custom_trim' not found."); /* "afl_custom_post_trim", optional */ - afl->mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim"); - if (!afl->mutator->afl_custom_post_trim) { - + mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim"); + if (!mutator->afl_custom_post_trim) WARNF("Symbol 'afl_custom_post_trim' not found."); - } - if (notrim) { - afl->mutator->afl_custom_init_trim = NULL; - afl->mutator->afl_custom_trim = NULL; - afl->mutator->afl_custom_post_trim = NULL; + mutator->afl_custom_init_trim = NULL; + mutator->afl_custom_trim = NULL; + mutator->afl_custom_post_trim = NULL; WARNF( "Custom mutator does not implement all three trim APIs, standard " "trimming will be used."); @@ -195,53 +188,41 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { } /* "afl_custom_havoc_mutation", optional */ - afl->mutator->afl_custom_havoc_mutation = - dlsym(dh, "afl_custom_havoc_mutation"); - if (!afl->mutator->afl_custom_havoc_mutation) { - + mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation"); + if (!mutator->afl_custom_havoc_mutation) WARNF("Symbol 'afl_custom_havoc_mutation' not found."); - } - /* "afl_custom_havoc_mutation", optional */ - afl->mutator->afl_custom_havoc_mutation_probability = + mutator->afl_custom_havoc_mutation_probability = dlsym(dh, "afl_custom_havoc_mutation_probability"); - if (!afl->mutator->afl_custom_havoc_mutation_probability) { - + if (!mutator->afl_custom_havoc_mutation_probability) WARNF("Symbol 'afl_custom_havoc_mutation_probability' not found."); - } - /* "afl_custom_queue_get", optional */ - afl->mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get"); - if (!afl->mutator->afl_custom_queue_get) { - + mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get"); + if (!mutator->afl_custom_queue_get) WARNF("Symbol 'afl_custom_queue_get' not found."); - } - /* "afl_custom_queue_new_entry", optional */ - afl->mutator->afl_custom_queue_new_entry = - dlsym(dh, "afl_custom_queue_new_entry"); - if (!afl->mutator->afl_custom_queue_new_entry) { - + mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry"); + if (!mutator->afl_custom_queue_new_entry) WARNF("Symbol 'afl_custom_queue_new_entry' not found"); - } - OKF("Custom mutator '%s' installed successfully.", fn); /* Initialize the custom mutator */ - if (afl->mutator->afl_custom_init) { + if (mutator->afl_custom_init) + mutator->data = + mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); - afl->mutator->data = - afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); + mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation); + mutator->stacked_custom_prob = 6; // like one of the default mutations in havoc - } + return mutator; } -u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { +u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, struct custom_mutator *mutator) { u8 needs_write = 0, fault = 0; u32 trim_exec = 0; @@ -255,7 +236,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Initialize trimming in the custom mutator */ afl->stage_cur = 0; afl->stage_max = - afl->mutator->afl_custom_init_trim(afl->mutator->data, in_buf, q->len); + mutator->afl_custom_init_trim(mutator->data, in_buf, q->len); if (unlikely(afl->stage_max) < 0) { FATAL("custom_init_trim error ret: %d", afl->stage_max); @@ -278,7 +259,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { u32 cksum; - size_t retlen = afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf); + size_t retlen = mutator->afl_custom_trim(mutator->data, &retbuf); if (unlikely(!retbuf)) { @@ -319,7 +300,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Tell the custom mutator that the trimming was successful */ afl->stage_cur = - afl->mutator->afl_custom_post_trim(afl->mutator->data, 1); + mutator->afl_custom_post_trim(mutator->data, 1); if (afl->not_on_tty && afl->debug) { @@ -332,7 +313,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Tell the custom mutator that the trimming was unsuccessful */ afl->stage_cur = - afl->mutator->afl_custom_post_trim(afl->mutator->data, 0); + mutator->afl_custom_post_trim(mutator->data, 0); if (unlikely(afl->stage_cur < 0)) { FATAL("Error ret in custom_post_trim: %d", afl->stage_cur); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 6d399a03..dff1606a 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -384,17 +384,17 @@ u8 fuzz_one_original(afl_state_t *afl) { #else - if (unlikely(afl->mutator) && unlikely(afl->mutator->afl_custom_queue_get)) { + if (unlikely(afl->custom_mutators_count )) { /* The custom mutator will decide to skip this test case or not. */ - if (!afl->mutator->afl_custom_queue_get(afl->mutator->data, - afl->queue_cur->fname)) { + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - return 1; - - } + if (el->afl_custom_queue_get && !el->afl_custom_queue_get(el->data, afl->queue_cur->fname)) { + return 1; + } + } ); } if (likely(afl->pending_favored)) { @@ -1646,13 +1646,13 @@ custom_mutator_stage: * CUSTOM MUTATORS * *******************/ - if (likely(!afl->mutator)) { goto havoc_stage; } - if (likely(!afl->mutator->afl_custom_fuzz)) { goto havoc_stage; } + if (likely(!afl->custom_mutators_count)) { goto havoc_stage; } afl->stage_name = "custom mutator"; afl->stage_short = "custom"; afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100; afl->stage_val_type = STAGE_VAL_NONE; + bool has_custom_fuzz = false; if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; } @@ -1660,98 +1660,111 @@ custom_mutator_stage: orig_hit_cnt = afl->queued_paths + afl->unique_crashes; - for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { + LIST_FOREACH (&afl->custom_mutator_list, struct custom_mutator, { - struct queue_entry *target; - u32 tid; - u8 * new_buf; + if ( el->afl_custom_fuzz ) { - retry_external_pick: - /* Pick a random other queue entry for passing to external API */ - do { + has_custom_fuzz = true; - tid = rand_below(afl, afl->queued_paths); + for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - } while (tid == afl->current_entry && afl->queued_paths > 1); + struct queue_entry *target; + u32 tid; + u8 * new_buf; - target = afl->queue; + retry_external_pick: + /* Pick a random other queue entry for passing to external API */ + do { - while (tid >= 100) { + tid = rand_below(afl, afl->queued_paths); - target = target->next_100; - tid -= 100; + } while (tid == afl->current_entry && afl->queued_paths > 1); - } + target = afl->queue; - while (tid--) { + while (tid >= 100) { - target = target->next; + target = target->next_100; + tid -= 100; - } + } - /* Make sure that the target has a reasonable length. */ + while (tid--) { - while (target && (target->len < 2 || target == afl->queue_cur) && - afl->queued_paths > 1) { + target = target->next; - target = target->next; - ++afl->splicing_with; + } - } + /* Make sure that the target has a reasonable length. */ - if (!target) { goto retry_external_pick; } + while (target && (target->len < 2 || target == afl->queue_cur) && + afl->queued_paths > 1) { - /* 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); } + target = target->next; + ++afl->splicing_with; - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len); - ck_read(fd, new_buf, target->len, target->fname); - close(fd); + } - u8 *mutated_buf = NULL; + if (!target) { goto retry_external_pick; } - size_t mutated_size = afl->mutator->afl_custom_fuzz( - afl->mutator->data, out_buf, len, &mutated_buf, new_buf, target->len, - max_seed_size); + /* 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); } - if (unlikely(!mutated_buf)) { + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len); + ck_read(fd, new_buf, target->len, target->fname); + close(fd); - FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); + 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); - if (mutated_size > 0) { + if (unlikely(!mutated_buf)) { - if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { + FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); - goto abandon_entry; + } - } + if (mutated_size > 0) { + + if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { + + goto abandon_entry; + + } - /* If we're finding new stuff, let's run for a bit longer, limits - permitting. */ + /* If we're finding new stuff, let's run for a bit longer, limits + permitting. */ - if (afl->queued_paths != havoc_queued) { + if (afl->queued_paths != havoc_queued) { - if (perf_score <= afl->havoc_max_mult * 100) { + if (perf_score <= afl->havoc_max_mult * 100) { - afl->stage_max *= 2; - perf_score *= 2; + afl->stage_max *= 2; + perf_score *= 2; + + } + + havoc_queued = afl->queued_paths; + + } } - havoc_queued = afl->queued_paths; + /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */ + /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy. */ + memcpy(out_buf, in_buf, len); } } - /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */ - /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy. */ - memcpy(out_buf, in_buf, len); - } + } ); + + if (!has_custom_fuzz) goto havoc_stage; new_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -1803,20 +1816,25 @@ havoc_stage: havoc_queued = afl->queued_paths; - u8 stacked_custom = (afl->mutator && afl->mutator->afl_custom_havoc_mutation); - u8 stacked_custom_prob = 6; // like one of the default mutations in havoc + if (afl->custom_mutators_count) { - if (stacked_custom && afl->mutator->afl_custom_havoc_mutation_probability) { + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - stacked_custom_prob = - afl->mutator->afl_custom_havoc_mutation_probability(afl->mutator->data); - if (stacked_custom_prob > 100) { + if (el->stacked_custom && el->afl_custom_havoc_mutation_probability) { - FATAL( - "The probability returned by afl_custom_havoc_mutation_propability " - "has to be in the range 0-100."); + el->stacked_custom_prob = + el->afl_custom_havoc_mutation_probability(el->data); + if (el->stacked_custom_prob > 100) { - } + FATAL( + "The probability returned by afl_custom_havoc_mutation_propability " + "has to be in the range 0-100."); + + } + + } + + } ); } @@ -1831,29 +1849,36 @@ havoc_stage: for (i = 0; i < use_stacking; ++i) { - if (stacked_custom && rand_below(afl, 100) < stacked_custom_prob) { + if (afl->custom_mutators_count) { + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - u8 * custom_havoc_buf = NULL; - size_t new_len = afl->mutator->afl_custom_havoc_mutation( - afl->mutator->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE); - if (unlikely(!custom_havoc_buf)) { + if (el->stacked_custom && rand_below(afl, 100) < el->stacked_custom_prob) { - FATAL("Error in custom_havoc (return %zd)", new_len); + u8 * custom_havoc_buf = NULL; + size_t new_len = el->afl_custom_havoc_mutation( + el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE); + if (unlikely(!custom_havoc_buf)) { - } + FATAL("Error in custom_havoc (return %zd)", new_len); - if (likely(new_len > 0 && custom_havoc_buf)) { + } - temp_len = new_len; - if (out_buf != custom_havoc_buf) { + if (likely(new_len > 0 && custom_havoc_buf)) { - ck_maybe_grow(BUF_PARAMS(out), temp_len); - memcpy(out_buf, custom_havoc_buf, temp_len); + temp_len = new_len; + if (out_buf != custom_havoc_buf) { - } + ck_maybe_grow(BUF_PARAMS(out), temp_len); + memcpy(out_buf, custom_havoc_buf, temp_len); - } + } + + } + } + + } ); } switch (rand_below( diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 64cabcad..a65add55 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -295,88 +295,94 @@ void deinit_py(void *py_mutator) { } -void load_custom_mutator_py(afl_state_t *afl, char *module_name) { +struct custom_mutator * load_custom_mutator_py(afl_state_t *afl, char *module_name) { - afl->mutator = ck_alloc(sizeof(struct custom_mutator)); - afl->mutator->pre_save_buf = NULL; - afl->mutator->pre_save_size = 0; + struct custom_mutator * mutator; - afl->mutator->name = module_name; + mutator = ck_alloc(sizeof(struct custom_mutator)); + mutator->pre_save_buf = NULL; + mutator->pre_save_size = 0; + + mutator->name = module_name; ACTF("Loading Python mutator library from '%s'...", module_name); py_mutator_t *py_mutator; py_mutator = init_py_module(afl, module_name); - afl->mutator->data = py_mutator; + mutator->data = py_mutator; if (!py_mutator) { FATAL("Failed to load python mutator."); } PyObject **py_functions = py_mutator->py_functions; if (py_functions[PY_FUNC_INIT]) { - afl->mutator->afl_custom_init = unsupported; + mutator->afl_custom_init = unsupported; } if (py_functions[PY_FUNC_DEINIT]) { - afl->mutator->afl_custom_deinit = deinit_py; + mutator->afl_custom_deinit = deinit_py; } /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator is quite different from the custom mutator. */ - afl->mutator->afl_custom_fuzz = fuzz_py; + mutator->afl_custom_fuzz = fuzz_py; if (py_functions[PY_FUNC_PRE_SAVE]) { - afl->mutator->afl_custom_pre_save = pre_save_py; + mutator->afl_custom_pre_save = pre_save_py; } if (py_functions[PY_FUNC_INIT_TRIM]) { - afl->mutator->afl_custom_init_trim = init_trim_py; + mutator->afl_custom_init_trim = init_trim_py; } if (py_functions[PY_FUNC_POST_TRIM]) { - afl->mutator->afl_custom_post_trim = post_trim_py; + mutator->afl_custom_post_trim = post_trim_py; } - if (py_functions[PY_FUNC_TRIM]) { afl->mutator->afl_custom_trim = trim_py; } + if (py_functions[PY_FUNC_TRIM]) { mutator->afl_custom_trim = trim_py; } if (py_functions[PY_FUNC_HAVOC_MUTATION]) { - afl->mutator->afl_custom_havoc_mutation = havoc_mutation_py; + mutator->afl_custom_havoc_mutation = havoc_mutation_py; } if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY]) { - afl->mutator->afl_custom_havoc_mutation_probability = + mutator->afl_custom_havoc_mutation_probability = havoc_mutation_probability_py; } if (py_functions[PY_FUNC_QUEUE_GET]) { - afl->mutator->afl_custom_queue_get = queue_get_py; + mutator->afl_custom_queue_get = queue_get_py; } if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) { - afl->mutator->afl_custom_queue_new_entry = queue_new_entry_py; + mutator->afl_custom_queue_new_entry = queue_new_entry_py; } + + OKF("Python mutator '%s' installed successfully.", module_name); /* Initialize the custom mutator */ init_py(afl, py_mutator, rand_below(afl, 0xFFFFFFFF)); + return mutator; + } size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f998c06b..c33751d9 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -140,15 +140,20 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { afl->last_path_time = get_cur_time(); - if (afl->mutator && afl->mutator->afl_custom_queue_new_entry) { + if (afl->custom_mutators_count) { - u8 *fname_orig = NULL; + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - /* At the initialization stage, queue_cur is NULL */ - if (afl->queue_cur) { fname_orig = afl->queue_cur->fname; } + if ( el->afl_custom_queue_new_entry) { + u8 *fname_orig = NULL; - afl->mutator->afl_custom_queue_new_entry(afl->mutator->data, fname, - fname_orig); + /* At the initialization stage, queue_cur is NULL */ + if (afl->queue_cur) fname_orig = afl->queue_cur->fname; + + el->afl_custom_queue_new_entry(el->data, fname, fname_orig); + } + + } ); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index b7f7f29c..3876dec7 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -89,21 +89,41 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { #endif - if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) { + if (unlikely(afl->custom_mutators_count)) { u8 *new_buf = NULL; + ssize_t new_size = len; + void * new_mem = mem; - size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem, - len, &new_buf); + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - if (unlikely(!new_buf)) { + if (el->afl_custom_pre_save) { + new_size = el->afl_custom_pre_save( + el->data, new_mem, new_size, &new_buf + ); + + } + + new_mem = new_buf; + + } ); + + if (unlikely(!new_buf && (new_size <= 0))) { FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size); + } else if (likely(new_buf)) { + + /* everything as planned. use the new data. */ + afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); + + } else { + + /* custom mutators do not has a custom_pre_save function */ + afl_fsrv_write_to_testcase(&afl->fsrv, mem, len); + } - /* everything as planned. use the new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); } else { @@ -513,10 +533,23 @@ void sync_fuzzers(afl_state_t *afl) { u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Custom mutator trimmer */ - if (afl->mutator && afl->mutator->afl_custom_trim) { + if (afl->custom_mutators_count) { + + u8 trimmed_case = 0; + bool custom_trimmed = false; + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_trim) { + + trimmed_case = trim_case_custom(afl, q, in_buf, el); + custom_trimmed = true; + } - return trim_case_custom(afl, q, in_buf); + } ); + if (custom_trimmed) return trimmed_case; + } u8 needs_write = 0, fault = 0; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 3cbb2d8c..032cf01d 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -792,7 +792,7 @@ void show_stats(afl_state_t *afl) { } - if (afl->mutator) { + if (afl->custom_mutators_count) { sprintf(tmp, "%s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 64973260..14765981 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1077,7 +1077,7 @@ int main(int argc, char **argv_orig, char **envp) { setup_dirs_fds(afl); - setup_custom_mutator(afl); + setup_custom_mutators(afl); setup_cmdline_file(afl, argv + optind); @@ -1365,7 +1365,7 @@ stop_fuzzing: fclose(afl->fsrv.plot_file); destroy_queue(afl); destroy_extras(afl); - destroy_custom_mutator(afl); + destroy_custom_mutators(afl); afl_shm_deinit(&afl->shm); afl_fsrv_deinit(&afl->fsrv); if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } diff --git a/test/test-multiple-mutators.c b/test/test-multiple-mutators.c new file mode 100644 index 00000000..35e0407b --- /dev/null +++ b/test/test-multiple-mutators.c @@ -0,0 +1,24 @@ +/** + * Test-Case for multiple custom mutators in C + * Reference: + * https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char ** argv) +{ + int a=0; + char s[16]; + memset(s, 0, 16); + read(0, s, 0xa0); + + if ( s[17] != '\x00') { + abort(); + } + + return 0; +} diff --git a/test/test.sh b/test/test.sh index 90633a9f..1caa9985 100755 --- a/test/test.sh +++ b/test/test.sh @@ -949,7 +949,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { } test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && { unset AFL_CC - # Compile the vulnerable program + # Compile the vulnerable program for single mutator test -e ../afl-clang-fast && { ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 } || { @@ -959,6 +959,16 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { ../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 } } + # Compile the vulnerable program for multiple mutators + test -e ../afl-clang-fast && { + ../afl-clang-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1 + } || { + test -e ../afl-gcc-fast && { + ../afl-gcc-fast -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1 + } || { + ../afl-gcc -o test-multiple-mutators test-multiple-mutators.c > /dev/null 2>&1 + } + } # Compile the custom mutator make -C ../examples/custom_mutators libexamplemutator.so > /dev/null 2>&1 test -e test-custom-mutator -a -e ${CUSTOM_MUTATOR_PATH}/libexamplemutator.so && { @@ -986,6 +996,25 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { # Clean rm -rf out errors + #Run afl-fuzz w/ multiple C mutators + $ECHO "$GREY[*] running afl-fuzz with multiple custom C mutators, this will take approx 20 seconds" + { + AFL_CUSTOM_MUTATOR_LIBRARY="${CUSTOM_MUTATOR_PATH}/libexamplemutator.so;${CUSTOM_MUTATOR_PATH}/libexamplemutator.so" ../afl-fuzz -V20 -m ${MEM_LIMIT} -i in -o out -- ./test-multiple-mutators >>errors 2>&1 + } >>errors 2>&1 + + test -n "$( ls out/crashes/id:000000* 2>/dev/null )" && { # TODO: update here + $ECHO "$GREEN[+] afl-fuzz is working correctly with multiple C mutators" + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with multiple C mutators" + CODE=1 + } + + # Clean + rm -rf out errors + # Run afl-fuzz w/ the Python mutator $ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds" { @@ -1021,6 +1050,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { make -C ../examples/custom_mutators clean > /dev/null 2>&1 rm -f test-custom-mutator + rm -f test-custom-mutators } || { $ECHO "$YELLOW[-] no custom mutators in $CUSTOM_MUTATOR_PATH, cannot test" INCOMPLETE=1 |