Support multiple custom mutators (#282)

* Make a list of custom mutators using env variable

* Set up multiple custom mutators

* Add destroy custom mutator and changes to load_custom_mutator

* Use array instead of list, make changes to afl-fuzz-one for multiple mutators

* Make change to fuzz-one custom_queue_get to support multiple mutators

* Modify custom python mutator support

* Fix bug

* Fix missing afl->mutator->data

* Revert to list with max count

* Change custom_pre_save hook and code format

* Free custom_mutator struct in the list

* Add testcase for multiple custom mutators

* Resolve merge conflict
This commit is contained in:
Rishi Ranjan
2020-05-08 23:38:27 +05:30
committed by GitHub
parent 768053b6f2
commit 190f3024da
10 changed files with 363 additions and 254 deletions

View File

@ -607,6 +607,9 @@ typedef struct afl_state {
u8 * ex_buf; u8 * ex_buf;
size_t ex_size; 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 /* this is a fixed buffer of size map_size that can be used by any function if
* they do not call another function */ * they do not call another function */
@ -620,6 +623,8 @@ struct custom_mutator {
void * dh; void * dh;
u8 * pre_save_buf; u8 * pre_save_buf;
size_t pre_save_size; size_t pre_save_size;
u8 stacked_custom_prob,
stacked_custom;
void *data; /* custom mutator data ptr */ void *data; /* custom mutator data ptr */
@ -808,14 +813,14 @@ void read_afl_environment(afl_state_t *, char **);
/**** Prototypes ****/ /**** Prototypes ****/
/* Custom mutators */ /* Custom mutators */
void setup_custom_mutator(afl_state_t *); void setup_custom_mutators(afl_state_t *);
void destroy_custom_mutator(afl_state_t *); void destroy_custom_mutators(afl_state_t *);
u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf); u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf, struct custom_mutator * mutator);
/* Python */ /* Python */
#ifdef USE_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 *); void finalize_py_module(void *);
size_t pre_save_py(void *, u8 *, size_t, u8 **); size_t pre_save_py(void *, u8 *, size_t, u8 **);

View File

@ -26,27 +26,47 @@
#include "afl-fuzz.h" #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 */ /* 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 (fn) {
if (afl->limit_time_sig) { if (afl->limit_time_sig)
FATAL( FATAL(
"MOpt and custom mutator are mutually exclusive. We accept pull " "MOpt and custom mutator are mutually exclusive. We accept pull "
"requests that integrates MOpt with the optional mutators " "requests that integrates MOpt with the optional mutators "
"(custom/radamsa/redquenn/...)."); "(custom/radamsa/redquenn/...).");
u8 *fn_token = (u8 *)strsep((char **)&fn, ";");
if (likely(!fn_token)) {
mutator = load_custom_mutator(afl, fn);
list_append(&afl->custom_mutator_list, mutator);
afl->custom_mutators_count++;
} 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, ";");
}
} }
load_custom_mutator(afl, fn);
return;
} }
@ -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) { void destroy_custom_mutators(afl_state_t *afl) {
if (afl->mutator) { if (afl->custom_mutators_count) {
afl->mutator->afl_custom_deinit(afl->mutator->data); LIST_FOREACH_CLEAR(&afl->custom_mutator_list, struct custom_mutator, {
if (afl->mutator->dh) { dlclose(afl->mutator->dh); } if (!el->data) { FATAL("Deintializing NULL mutator"); }
el->afl_custom_deinit(el->data);
if (afl->mutator->pre_save_buf) { 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(afl->mutator); ck_free(el);
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; void * dh;
afl->mutator = ck_alloc(sizeof(struct custom_mutator)); struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
afl->mutator->pre_save_buf = NULL;
afl->mutator->pre_save_size = 0;
afl->mutator->name = fn; mutator->name = fn;
ACTF("Loading custom mutator library from '%s'...", fn); ACTF("Loading custom mutator library from '%s'...", fn);
dh = dlopen(fn, RTLD_NOW); dh = dlopen(fn, RTLD_NOW);
if (!dh) { FATAL("%s", dlerror()); } if (!dh) FATAL("%s", dlerror());
afl->mutator->dh = dh; mutator->dh = dh;
/* Mutator */ /* Mutator */
/* "afl_custom_init", required */ /* "afl_custom_init", optional for backward compatibility */
afl->mutator->afl_custom_init = dlsym(dh, "afl_custom_init"); mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
if (!afl->mutator->afl_custom_init) { if (!mutator->afl_custom_init) WARNF("Symbol 'afl_custom_init' not found.");
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_fuzz" or "afl_custom_mutator", required */ /* "afl_custom_fuzz" or "afl_custom_mutator", required */
afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz"); mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
if (!afl->mutator->afl_custom_fuzz) { if (!mutator->afl_custom_fuzz) {
/* Try "afl_custom_mutator" for backward compatibility */ /* Try "afl_custom_mutator" for backward compatibility */
WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'."); WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator"); mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
if (!afl->mutator->afl_custom_fuzz) { if (!mutator->afl_custom_fuzz)
FATAL("Symbol 'afl_custom_mutator' not found."); FATAL("Symbol 'afl_custom_mutator' not found.");
} }
}
/* "afl_custom_pre_save", optional */ /* "afl_custom_pre_save", optional */
afl->mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save"); mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save");
if (!afl->mutator->afl_custom_pre_save) { if (!mutator->afl_custom_pre_save)
WARNF("Symbol 'afl_custom_pre_save' not found."); WARNF("Symbol 'afl_custom_pre_save' not found.");
}
u8 notrim = 0; u8 notrim = 0;
/* "afl_custom_init_trim", optional */ /* "afl_custom_init_trim", optional */
afl->mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
if (!afl->mutator->afl_custom_init_trim) { if (!mutator->afl_custom_init_trim)
WARNF("Symbol 'afl_custom_init_trim' not found."); WARNF("Symbol 'afl_custom_init_trim' not found.");
}
/* "afl_custom_trim", optional */ /* "afl_custom_trim", optional */
afl->mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim"); mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
if (!afl->mutator->afl_custom_trim) { if (!mutator->afl_custom_trim) WARNF("Symbol 'afl_custom_trim' not found.");
WARNF("Symbol 'afl_custom_trim' not found.");
}
/* "afl_custom_post_trim", optional */ /* "afl_custom_post_trim", optional */
afl->mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim"); mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
if (!afl->mutator->afl_custom_post_trim) { if (!mutator->afl_custom_post_trim)
WARNF("Symbol 'afl_custom_post_trim' not found."); WARNF("Symbol 'afl_custom_post_trim' not found.");
}
if (notrim) { if (notrim) {
afl->mutator->afl_custom_init_trim = NULL; mutator->afl_custom_init_trim = NULL;
afl->mutator->afl_custom_trim = NULL; mutator->afl_custom_trim = NULL;
afl->mutator->afl_custom_post_trim = NULL; mutator->afl_custom_post_trim = NULL;
WARNF( WARNF(
"Custom mutator does not implement all three trim APIs, standard " "Custom mutator does not implement all three trim APIs, standard "
"trimming will be used."); "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_custom_havoc_mutation", optional */
afl->mutator->afl_custom_havoc_mutation = mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
dlsym(dh, "afl_custom_havoc_mutation"); if (!mutator->afl_custom_havoc_mutation)
if (!afl->mutator->afl_custom_havoc_mutation) {
WARNF("Symbol 'afl_custom_havoc_mutation' not found."); WARNF("Symbol 'afl_custom_havoc_mutation' not found.");
}
/* "afl_custom_havoc_mutation", optional */ /* "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"); 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."); WARNF("Symbol 'afl_custom_havoc_mutation_probability' not found.");
}
/* "afl_custom_queue_get", optional */ /* "afl_custom_queue_get", optional */
afl->mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get"); mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
if (!afl->mutator->afl_custom_queue_get) { if (!mutator->afl_custom_queue_get)
WARNF("Symbol 'afl_custom_queue_get' not found."); WARNF("Symbol 'afl_custom_queue_get' not found.");
}
/* "afl_custom_queue_new_entry", optional */ /* "afl_custom_queue_new_entry", optional */
afl->mutator->afl_custom_queue_new_entry = mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
dlsym(dh, "afl_custom_queue_new_entry"); if (!mutator->afl_custom_queue_new_entry)
if (!afl->mutator->afl_custom_queue_new_entry) {
WARNF("Symbol 'afl_custom_queue_new_entry' not found"); WARNF("Symbol 'afl_custom_queue_new_entry' not found");
}
OKF("Custom mutator '%s' installed successfully.", fn); OKF("Custom mutator '%s' installed successfully.", fn);
/* Initialize the custom mutator */ /* 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 = mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); 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; u8 needs_write = 0, fault = 0;
u32 trim_exec = 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 */ /* Initialize trimming in the custom mutator */
afl->stage_cur = 0; afl->stage_cur = 0;
afl->stage_max = 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) { if (unlikely(afl->stage_max) < 0) {
FATAL("custom_init_trim error ret: %d", afl->stage_max); 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; 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)) { 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 */ /* Tell the custom mutator that the trimming was successful */
afl->stage_cur = 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) { 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 */ /* Tell the custom mutator that the trimming was unsuccessful */
afl->stage_cur = 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)) { if (unlikely(afl->stage_cur < 0)) {
FATAL("Error ret in custom_post_trim: %d", afl->stage_cur); FATAL("Error ret in custom_post_trim: %d", afl->stage_cur);

View File

@ -384,17 +384,17 @@ u8 fuzz_one_original(afl_state_t *afl) {
#else #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. */ /* The custom mutator will decide to skip this test case or not. */
if (!afl->mutator->afl_custom_queue_get(afl->mutator->data, LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
afl->queue_cur->fname)) {
if (el->afl_custom_queue_get && !el->afl_custom_queue_get(el->data, afl->queue_cur->fname)) {
return 1; return 1;
} }
} );
} }
if (likely(afl->pending_favored)) { if (likely(afl->pending_favored)) {
@ -1646,13 +1646,13 @@ custom_mutator_stage:
* CUSTOM MUTATORS * * CUSTOM MUTATORS *
*******************/ *******************/
if (likely(!afl->mutator)) { goto havoc_stage; } if (likely(!afl->custom_mutators_count)) { goto havoc_stage; }
if (likely(!afl->mutator->afl_custom_fuzz)) { goto havoc_stage; }
afl->stage_name = "custom mutator"; afl->stage_name = "custom mutator";
afl->stage_short = "custom"; afl->stage_short = "custom";
afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100; afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100;
afl->stage_val_type = STAGE_VAL_NONE; afl->stage_val_type = STAGE_VAL_NONE;
bool has_custom_fuzz = false;
if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; } if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
@ -1660,6 +1660,12 @@ custom_mutator_stage:
orig_hit_cnt = afl->queued_paths + afl->unique_crashes; orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
LIST_FOREACH (&afl->custom_mutator_list, struct custom_mutator, {
if ( el->afl_custom_fuzz ) {
has_custom_fuzz = true;
for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
struct queue_entry *target; struct queue_entry *target;
@ -1711,8 +1717,8 @@ custom_mutator_stage:
u8 *mutated_buf = NULL; u8 *mutated_buf = NULL;
size_t mutated_size = afl->mutator->afl_custom_fuzz( size_t mutated_size = el->afl_custom_fuzz(
afl->mutator->data, out_buf, len, &mutated_buf, new_buf, target->len, el->data, out_buf, len, &mutated_buf, new_buf, target->len,
max_seed_size); max_seed_size);
if (unlikely(!mutated_buf)) { if (unlikely(!mutated_buf)) {
@ -1753,6 +1759,13 @@ custom_mutator_stage:
} }
}
} );
if (!has_custom_fuzz) goto havoc_stage;
new_hit_cnt = afl->queued_paths + afl->unique_crashes; new_hit_cnt = afl->queued_paths + afl->unique_crashes;
afl->stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt; afl->stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt;
@ -1803,14 +1816,15 @@ havoc_stage:
havoc_queued = afl->queued_paths; havoc_queued = afl->queued_paths;
u8 stacked_custom = (afl->mutator && afl->mutator->afl_custom_havoc_mutation); if (afl->custom_mutators_count) {
u8 stacked_custom_prob = 6; // like one of the default mutations in havoc
if (stacked_custom && afl->mutator->afl_custom_havoc_mutation_probability) { LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
stacked_custom_prob = if (el->stacked_custom && el->afl_custom_havoc_mutation_probability) {
afl->mutator->afl_custom_havoc_mutation_probability(afl->mutator->data);
if (stacked_custom_prob > 100) { el->stacked_custom_prob =
el->afl_custom_havoc_mutation_probability(el->data);
if (el->stacked_custom_prob > 100) {
FATAL( FATAL(
"The probability returned by afl_custom_havoc_mutation_propability " "The probability returned by afl_custom_havoc_mutation_propability "
@ -1820,6 +1834,10 @@ havoc_stage:
} }
} );
}
/* We essentially just do several thousand runs (depending on perf_score) /* We essentially just do several thousand runs (depending on perf_score)
where we take the input file and make random stacked tweaks. */ where we take the input file and make random stacked tweaks. */
@ -1831,11 +1849,15 @@ havoc_stage:
for (i = 0; i < use_stacking; ++i) { 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, {
if (el->stacked_custom && rand_below(afl, 100) < el->stacked_custom_prob) {
u8 * custom_havoc_buf = NULL; u8 * custom_havoc_buf = NULL;
size_t new_len = afl->mutator->afl_custom_havoc_mutation( size_t new_len = el->afl_custom_havoc_mutation(
afl->mutator->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE); el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE);
if (unlikely(!custom_havoc_buf)) { if (unlikely(!custom_havoc_buf)) {
FATAL("Error in custom_havoc (return %zd)", new_len); FATAL("Error in custom_havoc (return %zd)", new_len);
@ -1856,6 +1878,9 @@ havoc_stage:
} }
} );
}
switch (rand_below( switch (rand_below(
afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) {

View File

@ -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)); struct custom_mutator * mutator;
afl->mutator->pre_save_buf = NULL;
afl->mutator->pre_save_size = 0;
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); ACTF("Loading Python mutator library from '%s'...", module_name);
py_mutator_t *py_mutator; py_mutator_t *py_mutator;
py_mutator = init_py_module(afl, module_name); 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."); } if (!py_mutator) { FATAL("Failed to load python mutator."); }
PyObject **py_functions = py_mutator->py_functions; PyObject **py_functions = py_mutator->py_functions;
if (py_functions[PY_FUNC_INIT]) { if (py_functions[PY_FUNC_INIT]) {
afl->mutator->afl_custom_init = unsupported; mutator->afl_custom_init = unsupported;
} }
if (py_functions[PY_FUNC_DEINIT]) { 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 /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
is quite different from the custom 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]) { 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]) { 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]) { 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]) { 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]) { 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; havoc_mutation_probability_py;
} }
if (py_functions[PY_FUNC_QUEUE_GET]) { 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]) { 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); OKF("Python mutator '%s' installed successfully.", module_name);
/* Initialize the custom mutator */ /* Initialize the custom mutator */
init_py(afl, py_mutator, rand_below(afl, 0xFFFFFFFF)); 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) { size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) {

View File

@ -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(); afl->last_path_time = get_cur_time();
if (afl->mutator && afl->mutator->afl_custom_queue_new_entry) { if (afl->custom_mutators_count) {
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if ( el->afl_custom_queue_new_entry) {
u8 *fname_orig = NULL; u8 *fname_orig = NULL;
/* At the initialization stage, queue_cur is NULL */ /* At the initialization stage, queue_cur is NULL */
if (afl->queue_cur) { fname_orig = afl->queue_cur->fname; } if (afl->queue_cur) fname_orig = afl->queue_cur->fname;
afl->mutator->afl_custom_queue_new_entry(afl->mutator->data, fname, el->afl_custom_queue_new_entry(el->data, fname, fname_orig);
fname_orig); }
} );
} }

View File

@ -89,22 +89,42 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
#endif #endif
if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) { if (unlikely(afl->custom_mutators_count)) {
u8 *new_buf = NULL; 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, LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
len, &new_buf);
if (unlikely(!new_buf)) { if (el->afl_custom_pre_save) {
new_size = el->afl_custom_pre_save(
FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size); 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. */ /* everything as planned. use the new data. */
afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); 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);
}
} else { } else {
/* boring uncustom. */ /* boring uncustom. */
@ -513,9 +533,22 @@ void sync_fuzzers(afl_state_t *afl) {
u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
/* Custom mutator trimmer */ /* Custom mutator trimmer */
if (afl->mutator && afl->mutator->afl_custom_trim) { if (afl->custom_mutators_count) {
return trim_case_custom(afl, q, in_buf); 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;
}
} );
if (custom_trimmed) return trimmed_case;
} }

View File

@ -792,7 +792,7 @@ void show_stats(afl_state_t *afl) {
} }
if (afl->mutator) { if (afl->custom_mutators_count) {
sprintf(tmp, "%s/%s", sprintf(tmp, "%s/%s",
u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]),

View File

@ -1077,7 +1077,7 @@ int main(int argc, char **argv_orig, char **envp) {
setup_dirs_fds(afl); setup_dirs_fds(afl);
setup_custom_mutator(afl); setup_custom_mutators(afl);
setup_cmdline_file(afl, argv + optind); setup_cmdline_file(afl, argv + optind);
@ -1365,7 +1365,7 @@ stop_fuzzing:
fclose(afl->fsrv.plot_file); fclose(afl->fsrv.plot_file);
destroy_queue(afl); destroy_queue(afl);
destroy_extras(afl); destroy_extras(afl);
destroy_custom_mutator(afl); destroy_custom_mutators(afl);
afl_shm_deinit(&afl->shm); afl_shm_deinit(&afl->shm);
afl_fsrv_deinit(&afl->fsrv); afl_fsrv_deinit(&afl->fsrv);
if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }

View File

@ -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;
}

View File

@ -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 && { test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && {
unset AFL_CC unset AFL_CC
# Compile the vulnerable program # Compile the vulnerable program for single mutator
test -e ../afl-clang-fast && { test -e ../afl-clang-fast && {
../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 ../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 ../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 # Compile the custom mutator
make -C ../examples/custom_mutators libexamplemutator.so > /dev/null 2>&1 make -C ../examples/custom_mutators libexamplemutator.so > /dev/null 2>&1
test -e test-custom-mutator -a -e ${CUSTOM_MUTATOR_PATH}/libexamplemutator.so && { 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 # Clean
rm -rf out errors 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 # Run afl-fuzz w/ the Python mutator
$ECHO "$GREY[*] running afl-fuzz for the Python mutator, this will take approx 10 seconds" $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 make -C ../examples/custom_mutators clean > /dev/null 2>&1
rm -f test-custom-mutator rm -f test-custom-mutator
rm -f test-custom-mutators
} || { } || {
$ECHO "$YELLOW[-] no custom mutators in $CUSTOM_MUTATOR_PATH, cannot test" $ECHO "$YELLOW[-] no custom mutators in $CUSTOM_MUTATOR_PATH, cannot test"
INCOMPLETE=1 INCOMPLETE=1