From 6d3dc83c5dde31ccb74e04815a04b85b05761b30 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 25 Mar 2020 11:31:01 +0100 Subject: code format --- src/afl-fuzz-python.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index d3027d2b..418497d0 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -29,8 +29,10 @@ #ifdef USE_PYTHON static void *unsupported(afl_state_t *afl, unsigned int seed) { + FATAL("Python Mutator cannot be called twice yet"); return NULL; + } size_t fuzz_py(void *py_mutator, u8 **buf, size_t buf_size, u8 *add_buf, @@ -77,7 +79,8 @@ size_t fuzz_py(void *py_mutator, u8 **buf, size_t buf_size, u8 *add_buf, PyTuple_SetItem(py_args, 2, py_value); - py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ], py_args); Py_DECREF(py_args); @@ -99,7 +102,6 @@ size_t fuzz_py(void *py_mutator, u8 **buf, size_t buf_size, u8 *add_buf, } - static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { if (!module_name) return NULL; @@ -223,7 +225,8 @@ void finalize_py_module(void *py_mutator) { } -static void init_py(afl_state_t *afl, py_mutator_t *py_mutator, unsigned int seed) { +static void init_py(afl_state_t *afl, py_mutator_t *py_mutator, + unsigned int seed) { PyObject *py_args, *py_value; @@ -244,7 +247,8 @@ static void init_py(afl_state_t *afl, py_mutator_t *py_mutator, unsigned int see PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(py_mutator->py_functions[PY_FUNC_INIT], py_args); + py_value = + PyObject_CallObject(py_mutator->py_functions[PY_FUNC_INIT], py_args); Py_DECREF(py_args); @@ -289,9 +293,7 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { py_mutator_t *py_mutator; py_mutator = init_py_module(afl, module_name); - 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; @@ -334,7 +336,6 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { } - size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { size_t out_buf_size; @@ -350,7 +351,8 @@ size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_PRE_SAVE], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_PRE_SAVE], py_args); Py_DECREF(py_args); @@ -386,7 +388,8 @@ u32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) { PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INIT_TRIM], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INIT_TRIM], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -424,7 +427,8 @@ u32 post_trim_py(void *py_mutator, u8 success) { PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_TRIM], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_TRIM], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -451,7 +455,8 @@ void trim_py(void *py_mutator, u8 **out_buf, size_t *out_buf_size) { PyObject *py_args, *py_value; py_args = PyTuple_New(0); - py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_TRIM], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_TRIM], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -503,8 +508,9 @@ size_t havoc_mutation_py(void *py_mutator, u8 **buf, size_t buf_size, PyTuple_SetItem(py_args, 1, py_value); - py_value = - PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION], + py_args); Py_DECREF(py_args); @@ -533,7 +539,9 @@ u8 havoc_mutation_probability_py(void *py_mutator) { py_args = PyTuple_New(0); py_value = PyObject_CallObject( - ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY], py_args); + ((py_mutator_t *)py_mutator) + ->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY], + py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -573,7 +581,8 @@ u8 queue_get_py(void *py_mutator, const u8 *filename) { PyTuple_SetItem(py_args, 0, py_value); // Call Python function - py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_GET], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_GET], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -642,8 +651,9 @@ void queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue, PyTuple_SetItem(py_args, 1, py_value); // Call - py_value = - PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_NEW_ENTRY], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_NEW_ENTRY], + py_args); Py_DECREF(py_args); if (py_value == NULL) { -- cgit 1.4.1 From e9c7610cb7d309f4c7fd1fd6435c29e736869772 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 25 Mar 2020 21:54:52 +0100 Subject: edited custom mutator pre_save api --- docs/custom_mutators.md | 2 +- examples/custom_mutators/example.c | 25 +++++++++++------ include/afl-fuzz.h | 12 +++++++-- src/afl-fuzz-mutators.c | 21 ++++++++++++++- src/afl-fuzz-python.c | 55 +++++++++++++++++++++++++++++++++----- src/afl-fuzz-run.c | 52 +++++++++++++++++++++++++++++------ 6 files changed, 140 insertions(+), 27 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 14d8f518..ecbd50ba 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -30,7 +30,7 @@ C/C++: void afl_custom_init(unsigned int seed); size_t afl_custom_fuzz(uint8_t** buf, size_t buf_size, uint8_t* add_buf, size_t add_buf_size, size_t max_size); -size_t afl_custom_pre_save(uint8_t* buf, size_t buf_size, uint8_t** out_buf); +size_t afl_custom_write_to_testcase(uint8_t* buf, size_t buf_size, uint8_t** out_buf); uint32_t afl_custom_init_trim(uint8_t* buf, size_t buf_size); void afl_custom_trim(uint8_t** out_buf, size_t* out_buf_size); uint32_t afl_custom_post_trim(uint8_t success); diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 2df17dec..3e708db8 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -12,6 +12,7 @@ #include #include #include +#include #define DATA_SIZE (100) @@ -112,21 +113,29 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t **buf, size_t buf_size, * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Buffer containing the test case to be executed * @param[in] buf_size Size of the test case - * @param[out] out_buf Pointer to the buffer containing the test case after + * @param[in] out_buf Pointer to the buffer containing the test case after * processing. External library should allocate memory for out_buf. AFL++ * will release the memory after saving the test case. - * @return Size of the output buffer after processing + * out_buf will always be at least as large as buf. + * @param[in] out_buf_size The maximum size we may use. + * In case we need to have this bigger, simply return that. + * @return Size of the output buffer after processing or the needed amount. + * return 0 to indicate the original buf should be used. */ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, - uint8_t **out_buf) { + uint8_t *out_buf, size_t out_buf_size) { - size_t out_buf_size; + // In case we need more than out_buf_size, we return that amount and get + // called again. + if (out_buf_size < 32000) return 32000; + memcpy(out_buf, buf, buf_size); out_buf_size = buf_size; - - // External mutator should allocate memory for `out_buf` - *out_buf = malloc(out_buf_size); - memcpy(*out_buf, buf, out_buf_size); + out_buf[0] = 'A'; + out_buf[1] = 'F'; + out_buf[2] = 'L'; + out_buf[3] = '+'; + out_buf[4] = '+'; return out_buf_size; diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index d610ac29..8bf66403 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -30,6 +30,9 @@ #define AFL_MAIN #define MESSAGES_TO_STDOUT +/* We preallocate a buffer of this size for afl_custom_pre_save */ +#define PRE_SAVE_BUF_INIT_SIZE (16384) + #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif @@ -293,6 +296,9 @@ typedef struct py_mutator { void * afl_state; void * py_data; + PyObject *scratch_buf; + size_t scratch_size; + } py_mutator_t; #endif @@ -591,6 +597,8 @@ struct custom_mutator { const char *name; void * dh; + u8 * pre_save_buf; + size_t pre_save_size; void *data; /* custom mutator data ptr */ @@ -639,7 +647,7 @@ struct custom_mutator { * @return Size of the output buffer after processing */ size_t (*afl_custom_pre_save)(void *data, u8 *buf, size_t buf_size, - u8 **out_buf); + u8 *out_buf, size_t out_buf_size); /** * This method is called at the start of each trimming operation and receives @@ -775,7 +783,7 @@ u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf); 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 *, size_t); u32 init_trim_py(void *, u8 *, size_t); u32 post_trim_py(void *, u8); void trim_py(void *, u8 **, size_t *); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 0b0c3394..fac97f8e 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -80,6 +80,14 @@ void destroy_custom_mutator(afl_state_t *afl) { if (afl->mutator->dh) dlclose(afl->mutator->dh); + if (afl->mutator->pre_save_buf) { + + ck_free(afl->mutator->pre_save_buf); + afl->mutator->pre_save_buf = NULL; + afl->mutator->pre_save_size = 0; + + } + ck_free(afl->mutator); afl->mutator = NULL; @@ -91,6 +99,8 @@ void 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; afl->mutator->name = fn; ACTF("Loading custom mutator library from '%s'...", fn); @@ -125,9 +135,18 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { /* "afl_custom_pre_save", optional */ afl->mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save"); - if (!afl->mutator->afl_custom_pre_save) + if (!afl->mutator->afl_custom_pre_save) { + WARNF("Symbol 'afl_custom_pre_save' not found."); + } else { + + /* if we have a pre_save hook, prealloc some memory. */ + afl->mutator->pre_save_buf = ck_alloc(PRE_SAVE_BUF_INIT_SIZE * sizeof(u8)); + afl->mutator->pre_save_size = PRE_SAVE_BUF_INIT_SIZE; + + } + u8 notrim = 0; /* "afl_custom_init_trim", optional */ afl->mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 418497d0..b053e8d5 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -287,6 +287,8 @@ void deinit_py(void *py_mutator) { void 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; afl->mutator->name = module_name; ACTF("Loading Python mutator library from '%s'...", module_name); @@ -305,8 +307,14 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { is quite different from the custom mutator. */ afl->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; + /* if we have a pre_save hook, prealloc some memory. */ + afl->mutator->pre_save_buf = ck_alloc(PRE_SAVE_BUF_INIT_SIZE * sizeof(u8)); + afl->mutator->pre_save_size = PRE_SAVE_BUF_INIT_SIZE; + + } if (py_functions[PY_FUNC_INIT_TRIM]) afl->mutator->afl_custom_init_trim = init_trim_py; @@ -336,10 +344,33 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { } -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, + size_t out_buf_size) { - size_t out_buf_size; + size_t py_out_buf_size; PyObject *py_args, *py_value; + + if (((py_mutator_t *)py_mutator)->scratch_buf) { + + /* We are being recalled from an earlier run + where we didn't have enough mem. */ + if (((py_mutator_t *)py_mutator)->scratch_size < out_buf_size) { + + FATAL("out_buf is still too small after resizing in custom mutator."); + + } + + py_value = ((py_mutator_t *)py_mutator)->scratch_buf; + py_out_buf_size = ((py_mutator_t *)py_mutator)->scratch_size; + ((py_mutator_t *)py_mutator)->scratch_buf = NULL; + py_out_buf_size = 0; + + memcpy(out_buf, PyByteArray_AsString(py_value), py_out_buf_size); + Py_DECREF(py_value); + return py_out_buf_size; + + } + py_args = PyTuple_New(1); py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { @@ -358,11 +389,21 @@ size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { if (py_value != NULL) { - out_buf_size = PyByteArray_Size(py_value); - *out_buf = malloc(out_buf_size); - memcpy(*out_buf, PyByteArray_AsString(py_value), out_buf_size); + py_out_buf_size = PyByteArray_Size(py_value); + if (py_out_buf_size > out_buf_size) { + + /* Not enough space! + We will get called again right after resizing the buf. + Keep the references to our data for now. */ + ((py_mutator_t *)py_mutator)->scratch_buf = py_value; + ((py_mutator_t *)py_mutator)->scratch_size = py_out_buf_size; + return py_out_buf_size; + + } + + memcpy(out_buf, PyByteArray_AsString(py_value), py_out_buf_size); Py_DECREF(py_value); - return out_buf_size; + return py_out_buf_size; } else { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index e8ef3049..a539b469 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -216,14 +216,49 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { if (afl->mutator && afl->mutator->afl_custom_pre_save) { - u8 * new_data; - size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem, - len, &new_data); - ck_write(fd, new_data, new_size, afl->fsrv.out_file); - free(new_data); + if (unlikely(afl->mutator->pre_save_size < len)) { + + afl->mutator->pre_save_buf = + ck_realloc(afl->mutator->pre_save_buf, len * sizeof(u8)); + afl->mutator->pre_save_size = len; + + } + + u8 buf_written = 0; + while (!buf_written) { + + buf_written = 1; + size_t new_size = afl->mutator->afl_custom_pre_save( + afl->mutator->data, mem, len, afl->mutator->pre_save_buf, + afl->mutator->pre_save_size); + + if (unlikely(new_size) == 0) { + + /* custom_pre_save wants us to use the old buf */ + ck_write(fd, mem, len, afl->fsrv.out_file); + + } else if (unlikely(new_size) > afl->mutator->pre_save_size) { + + /* The custom func needs more space. + Realloc and call again. */ + afl->mutator->pre_save_buf = + ck_realloc(afl->mutator->pre_save_buf, new_size * sizeof(u8)); + afl->mutator->pre_save_size = new_size; + buf_written = 0; + continue; + + } else { + + /* everything as planned. use the new data. */ + ck_write(fd, afl->mutator->pre_save_buf, new_size, afl->fsrv.out_file); + + } + + } } else { + /* boring uncustom. */ ck_write(fd, mem, len, afl->fsrv.out_file); } @@ -505,8 +540,8 @@ void sync_fuzzers(afl_state_t *afl) { afl->stage_cur = 0; afl->stage_max = 0; - /* For every file queued by this fuzzer, parse ID and see if we have looked - at it before; exec a test case if not. */ + /* For every file queued by this fuzzer, parse ID and see if we have + looked at it before; exec a test case if not. */ while ((qd_ent = readdir(qd))) { @@ -645,7 +680,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (afl->stop_soon || fault == FAULT_ERROR) goto abort_trimming; - /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ + /* Note that we don't keep track of crashes or hangs here; maybe TODO? + */ cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); -- cgit 1.4.1 From d6a7630fe2938621db05e616fe6b1b21dfaf21b3 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 26 Mar 2020 19:44:44 +0100 Subject: more api --- docs/custom_mutators.md | 3 +- examples/custom_mutators/example.c | 35 ++++++++++++++++++++---- include/afl-fuzz.h | 19 ++++++------- src/afl-fuzz-mutators.c | 11 +------- src/afl-fuzz-python.c | 56 ++++++++++---------------------------- src/afl-fuzz-run.c | 45 ++++++------------------------ src/afl-fuzz-stats.c | 14 +++++----- 7 files changed, 71 insertions(+), 112 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index ecbd50ba..2163b2d5 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -27,7 +27,7 @@ performed with the custom mutator. C/C++: ```c -void afl_custom_init(unsigned int seed); +void afl_custom_init(void *afl, unsigned int seed); size_t afl_custom_fuzz(uint8_t** buf, size_t buf_size, uint8_t* add_buf, size_t add_buf_size, size_t max_size); size_t afl_custom_write_to_testcase(uint8_t* buf, size_t buf_size, uint8_t** out_buf); @@ -39,6 +39,7 @@ uint8_t afl_custom_havoc_mutation_probability(void); uint8_t afl_custom_queue_get(const uint8_t* filename); void afl_custom_queue_new_entry(const uint8_t* filename_new_queue, const uint8_t* filename_orig_queue); +void afl_custom_deinit(void *data); ``` Python: diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 3e708db8..04b72c77 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -15,6 +15,7 @@ #include #define DATA_SIZE (100) +#define INITIAL_BUF_SIZE (16384) static const char *commands[] = { @@ -28,6 +29,8 @@ typedef struct my_mutator { afl_t *afl; // any additional data here! + size_t pre_save_size; + u8 * pre_save_buf; } my_mutator_t; @@ -56,6 +59,16 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { data->afl = afl; + data->pre_save_buf = malloc(INITIAL_BUF_SIZE); + if (!data->pre_save_buf) { + + free(data); + return NULL; + + } + + data->pre_save_size = INITIAL_BUF_SIZE; + return data; } @@ -125,12 +138,23 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t **buf, size_t buf_size, size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t *out_buf, size_t out_buf_size) { - // In case we need more than out_buf_size, we return that amount and get - // called again. - if (out_buf_size < 32000) return 32000; + if (data->pre_save_size < buf_size + 5) { + + data->pre_save_buf = realloc(data->pre_save_buf, buf_size + 5); + if (!data->pre_save_buf) { + + perror("custom mutator realloc"); + free(data); + return -1; + + } + + data->pre_save_size = buf_size + 5; + + } - memcpy(out_buf, buf, buf_size); - out_buf_size = buf_size; + memcpy(out_buf + 5, buf, buf_size); + out_buf_size = buf_size + 5; out_buf[0] = 'A'; out_buf[1] = 'F'; out_buf[2] = 'L'; @@ -322,6 +346,7 @@ void afl_custom_queue_new_entry(my_mutator_t * data, */ void afl_custom_deinit(my_mutator_t *data) { + free(data->pre_save_buf); free(data); } diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8bf66403..530a4b6a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -30,9 +30,6 @@ #define AFL_MAIN #define MESSAGES_TO_STDOUT -/* We preallocate a buffer of this size for afl_custom_pre_save */ -#define PRE_SAVE_BUF_INIT_SIZE (16384) - #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif @@ -296,8 +293,8 @@ typedef struct py_mutator { void * afl_state; void * py_data; - PyObject *scratch_buf; - size_t scratch_size; + u8 * pre_save_buf; + size_t pre_save_size; } py_mutator_t; @@ -641,13 +638,13 @@ struct custom_mutator { * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Buffer containing the test case to be executed * @param[in] buf_size Size of the test case - * @param[out] out_buf Pointer to the buffer of storing the test case after - * processing. External library should allocate memory for out_buf. AFL++ - * will release the memory after saving the test case. - * @return Size of the output buffer after processing + * @param[out] out_buf Pointer to the buffer storing the test case after + * processing. External library should allocate memory for out_buf. + * It can chose to alter buf in-place, if the space is large enough. + * @return Size of the output buffer. */ size_t (*afl_custom_pre_save)(void *data, u8 *buf, size_t buf_size, - u8 *out_buf, size_t out_buf_size); + u8 **out_buf); /** * This method is called at the start of each trimming operation and receives @@ -783,7 +780,7 @@ u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf); void finalize_py_module(void *); -size_t pre_save_py(void *, u8 *, size_t, u8 *, size_t); +size_t pre_save_py(void *, u8 *, size_t, u8 **); u32 init_trim_py(void *, u8 *, size_t); u32 post_trim_py(void *, u8); void trim_py(void *, u8 **, size_t *); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index fac97f8e..9d8610c0 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -135,18 +135,9 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { /* "afl_custom_pre_save", optional */ afl->mutator->afl_custom_pre_save = dlsym(dh, "afl_custom_pre_save"); - if (!afl->mutator->afl_custom_pre_save) { - + if (!afl->mutator->afl_custom_pre_save) WARNF("Symbol 'afl_custom_pre_save' not found."); - } else { - - /* if we have a pre_save hook, prealloc some memory. */ - afl->mutator->pre_save_buf = ck_alloc(PRE_SAVE_BUF_INIT_SIZE * sizeof(u8)); - afl->mutator->pre_save_size = PRE_SAVE_BUF_INIT_SIZE; - - } - u8 notrim = 0; /* "afl_custom_init_trim", optional */ afl->mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim"); diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index b053e8d5..6fbdb678 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -307,14 +307,8 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { is quite different from the custom mutator. */ afl->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; - /* if we have a pre_save hook, prealloc some memory. */ - afl->mutator->pre_save_buf = ck_alloc(PRE_SAVE_BUF_INIT_SIZE * sizeof(u8)); - afl->mutator->pre_save_size = PRE_SAVE_BUF_INIT_SIZE; - - } if (py_functions[PY_FUNC_INIT_TRIM]) afl->mutator->afl_custom_init_trim = init_trim_py; @@ -344,39 +338,18 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { } -size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 *out_buf, - size_t out_buf_size) { - - size_t py_out_buf_size; - PyObject *py_args, *py_value; - - if (((py_mutator_t *)py_mutator)->scratch_buf) { - - /* We are being recalled from an earlier run - where we didn't have enough mem. */ - if (((py_mutator_t *)py_mutator)->scratch_size < out_buf_size) { - - FATAL("out_buf is still too small after resizing in custom mutator."); - - } - - py_value = ((py_mutator_t *)py_mutator)->scratch_buf; - py_out_buf_size = ((py_mutator_t *)py_mutator)->scratch_size; - ((py_mutator_t *)py_mutator)->scratch_buf = NULL; - py_out_buf_size = 0; +size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { - memcpy(out_buf, PyByteArray_AsString(py_value), py_out_buf_size); - Py_DECREF(py_value); - return py_out_buf_size; - - } + size_t py_out_buf_size; + PyObject * py_args, *py_value; + py_mutator_t *py = (py_mutator_t *)py_mutator; py_args = PyTuple_New(1); py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { Py_DECREF(py_args); - FATAL("Failed to convert arguments"); + FATAL("Failed to convert arguments in custom pre_save"); } @@ -390,25 +363,26 @@ size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 *out_buf, if (py_value != NULL) { py_out_buf_size = PyByteArray_Size(py_value); - if (py_out_buf_size > out_buf_size) { + + if (py_out_buf_size > py->pre_save_size) { /* Not enough space! - We will get called again right after resizing the buf. - Keep the references to our data for now. */ - ((py_mutator_t *)py_mutator)->scratch_buf = py_value; - ((py_mutator_t *)py_mutator)->scratch_size = py_out_buf_size; - return py_out_buf_size; + Let's resize our buf */ + py->pre_save_buf = ck_realloc(py->pre_save_buf, py_out_buf_size); + py->pre_save_size = py_out_buf_size; } - memcpy(out_buf, PyByteArray_AsString(py_value), py_out_buf_size); + memcpy(py->pre_save_buf, PyByteArray_AsString(py_value), py_out_buf_size); Py_DECREF(py_value); + + *out_buf = py->pre_save_buf; return py_out_buf_size; } else { PyErr_Print(); - FATAL("Call failed"); + FATAL("Python custom mutator: pre_save call failed."); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a539b469..a43bfad2 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -214,47 +214,18 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { lseek(fd, 0, SEEK_SET); - if (afl->mutator && afl->mutator->afl_custom_pre_save) { + if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) { - if (unlikely(afl->mutator->pre_save_size < len)) { + u8 *new_buf = NULL; - afl->mutator->pre_save_buf = - ck_realloc(afl->mutator->pre_save_buf, len * sizeof(u8)); - afl->mutator->pre_save_size = len; + size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem, + len, &new_buf); - } - - u8 buf_written = 0; - while (!buf_written) { - - buf_written = 1; - size_t new_size = afl->mutator->afl_custom_pre_save( - afl->mutator->data, mem, len, afl->mutator->pre_save_buf, - afl->mutator->pre_save_size); - - if (unlikely(new_size) == 0) { - - /* custom_pre_save wants us to use the old buf */ - ck_write(fd, mem, len, afl->fsrv.out_file); - - } else if (unlikely(new_size) > afl->mutator->pre_save_size) { - - /* The custom func needs more space. - Realloc and call again. */ - afl->mutator->pre_save_buf = - ck_realloc(afl->mutator->pre_save_buf, new_size * sizeof(u8)); - afl->mutator->pre_save_size = new_size; - buf_written = 0; - continue; - - } else { - - /* everything as planned. use the new data. */ - ck_write(fd, afl->mutator->pre_save_buf, new_size, afl->fsrv.out_file); + if (unlikely(new_size <= 0 || !new_buf)) + FATAL("Custom_pre_save failed (ret: %ld)", new_size); - } - - } + /* everything as planned. use the new data. */ + ck_write(fd, new_buf, new_size, afl->fsrv.out_file); } else { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 53c162a2..5536c201 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -361,9 +361,9 @@ void show_stats(afl_state_t *afl) { /* Lord, forgive me this. */ - SAYF(SET_G1 bSTG bLT bH bSTOP cCYA + SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA - " overall results " bSTG bH2 bH2 bRT "\n"); + " overall results " bSTG bH2 bH2 bRT "\n"); if (afl->dumb_mode) { @@ -445,9 +445,9 @@ void show_stats(afl_state_t *afl) { " uniq hangs : " cRST "%-6s" bSTG bV "\n", time_tmp, tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA - " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); + " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); /* This gets funny because we want to print several variable-length variables together, but then cram them into a fixed-width field - so we need to @@ -476,9 +476,9 @@ void show_stats(afl_state_t *afl) { SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA - " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); + " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored), ((double)afl->queued_favored) * 100 / afl->queued_paths); @@ -552,7 +552,7 @@ void show_stats(afl_state_t *afl) { /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); -- cgit 1.4.1 From 9785b15ed264951b006093f9ee4564820c153593 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 28 Mar 2020 04:57:44 +0100 Subject: more custom mutator remodelling --- examples/custom_mutators/custom_mutator_helpers.h | 61 ++++++++++++ examples/custom_mutators/example.c | 113 ++++++++++++---------- examples/post_library/post_library.so.c | 84 +++++++++++----- examples/post_library/post_library_png.so.c | 71 +++++++++++--- include/afl-fuzz.h | 41 +++++--- src/afl-fuzz-cmplog.c | 9 +- src/afl-fuzz-globals.c | 2 + src/afl-fuzz-init.c | 14 ++- src/afl-fuzz-mutators.c | 24 ++--- src/afl-fuzz-one.c | 29 +++++- src/afl-fuzz-python.c | 64 +++++++----- src/afl-fuzz-run.c | 9 +- 12 files changed, 370 insertions(+), 151 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h index cd3a15f0..0dc00d96 100644 --- a/examples/custom_mutators/custom_mutator_helpers.h +++ b/examples/custom_mutators/custom_mutator_helpers.h @@ -5,8 +5,18 @@ #include "types.h" #include +#define INITIAL_GROWTH_SIZE (64) + #define RAND_BELOW(limit) (rand() % (limit)) +/* Use in a struct: creates a name_buf and a name_size variable. */ +#define BUF_VAR(type, name) \ + type * name##_buf; \ + size_t name##_size; +/* this filles in `&structptr->something_buf, &structptr->something_size`. */ +#define BUF_PARAMS(struct, name) \ + (void **)&struct->name##_buf, &struct->name##_size + typedef struct { } afl_t; @@ -267,5 +277,56 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { } +/* This function makes sure *size is > size_needed after call. + It changes buf and size in-place, if needed. + It will realloc *buf otherwise. + *size will grow exponentially as per: + https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ + Will return NULL if size_needed is <1 or *size is negative or malloc Failed. + @return For convenience, this function returns *buf. NULL on error. + */ +static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { + + /* Oops. found a bug? */ + if (unlikely(size_needed < 1)) return NULL; + + /* No need to realloc */ + if (likely(*size >= size_needed)) return *buf; + if (unlikely(*size < 0)) return NULL; + /* No inital size was set */ + if (*size == 0) *size = INITIAL_GROWTH_SIZE; + while (*size < size_needed) { + + *size *= 2; + if ((*size) < 0) { + + /* An overflow occurred. Fall back to size_needed */ + *size = size_needed; + + } + + } + + *buf = realloc(*buf, *size); + + return *buf; + +} + +/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ +static inline void swap_bufs(void **buf1, size_t *size1, void **buf2, + size_t *size2) { + + void * scratch_buf = *buf1; + size_t scratch_size = *size1; + *buf1 = *buf2; + *size1 = *size2; + *buf2 = scratch_buf; + *size2 = scratch_size; + +} + +#undef INITIAL_GROWTH_SIZE + #endif diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 4b0a461b..54fc9d47 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -15,7 +15,6 @@ #include #define DATA_SIZE (100) -#define INITIAL_BUF_SIZE (16384) static const char *commands[] = { @@ -28,9 +27,19 @@ static const char *commands[] = { typedef struct my_mutator { afl_t *afl; + // any additional data here! - size_t pre_save_size; - u8 * pre_save_buf; + uint8_t *trim_buf; + size_t trim_buf_size; + int trimmming_steps; + int cur_step; + + // Reused buffers: + BUF_VAR(u8, fuzz); + BUF_VAR(u8, data); + BUF_VAR(u8, havoc); + BUF_VAR(u8, trim_out); + BUF_VAR(u8, pre_save); } my_mutator_t; @@ -59,16 +68,6 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { data->afl = afl; - data->pre_save_buf = malloc(INITIAL_BUF_SIZE); - if (!data->pre_save_buf) { - - free(data); - return NULL; - - } - - data->pre_save_size = INITIAL_BUF_SIZE; - return data; } @@ -85,20 +84,25 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { * @param[in] add_buf_size Size of the additional test case * @param[in] max_size Maximum size of the mutated output. The mutation must not * produce data larger than max_size. - * @return Size of the mutated output. + * @return Size of the mutated output. Negative return will abort fuzzing. */ -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t **buf, size_t buf_size, - uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { // Make sure that the packet size does not exceed the maximum size expected by // the fuzzer size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; - if (mutated_size > buf_size) *buf = realloc(*buf, mutated_size); + // maybe_grow is optimized to be quick for reused buffers. + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); + if (!mutated_out) { + + perror("custom mutator allocation (maybe_grow)"); + return -1; /* afl-fuzz will very likely error out after this. */ - uint8_t *mutated_out = *buf; + } // Randomly select a command string to add as a header to the packet memcpy(mutated_out, commands[rand() % 3], 3); @@ -112,6 +116,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t **buf, size_t buf_size, } + *out_buf = mutated_out; return mutated_size; } @@ -137,11 +142,10 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, if (data->pre_save_size < buf_size + 5) { - data->pre_save_buf = realloc(data->pre_save_buf, buf_size + 5); + data->pre_save_buf = maybe_grow(BUF_PARAMS(data, pre_save), buf_size + 5); if (!data->pre_save_buf) { - perror("custom mutator realloc"); - free(data); + perror("custom mutator realloc failed."); return -1; } @@ -164,11 +168,6 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, } -static uint8_t *trim_buf; -static size_t trim_buf_size; -static int trimmming_steps; -static int cur_step; - /** * This method is called at the start of each trimming operation and receives * the initial buffer. It should return the amount of iteration steps possible @@ -193,20 +192,20 @@ static int cur_step; int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { // We simply trim once - trimmming_steps = 1; + data->trimmming_steps = 1; - cur_step = 0; - trim_buf = buf; - trim_buf_size = buf_size; + data->cur_step = 0; + data->trim_buf = buf; + data->trim_buf_size = buf_size; - return trimmming_steps; + return data->trimmming_steps; } /** * This method is called for each trimming operation. It doesn't have any * arguments because we already have the initial buffer from init_trim and we - * can memorize the current state in global variables. This can also save + * can memorize the current state in *data. This can also save * reparsing steps for each iteration. It should return the trimmed input * buffer, where the returned data must not exceed the initial input data in * length. Returning anything that is larger than the original data (passed @@ -216,19 +215,18 @@ int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { * * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[out] out_buf Pointer to the buffer containing the trimmed test case. - * External library should allocate memory for out_buf. AFL++ will release - * the memory after saving the test case. - * @param[out] out_buf_size Pointer to the size of the trimmed test case + * External library should allocate memory for out_buf. + * AFL++ will not release the memory after saving the test case. + * Keep a ref in *data. + * @return Pointer to the size of the trimmed test case */ -void afl_custom_trim(my_mutator_t *data, uint8_t **out_buf, - size_t *out_buf_size) { +size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { - *out_buf_size = trim_buf_size - 1; + size_t ret = data->trim_buf_size - 1; - // External mutator should allocate memory for `out_buf` - *out_buf = malloc(*out_buf_size); + *out_buf = maybe_grow(BUF_PARAMS(data, trim_out), ret); // Remove the last byte of the trimming input - memcpy(*out_buf, trim_buf, *out_buf_size); + memcpy(*out_buf, data->trim_buf, ret); } @@ -248,12 +246,12 @@ int afl_custom_post_trim(my_mutator_t *data, int success) { if (success) { - ++cur_step; - return cur_step; + ++data->cur_step; + return data->cur_step; } - return trimmming_steps; + return data->trimmming_steps; } @@ -264,26 +262,33 @@ int afl_custom_post_trim(my_mutator_t *data, int success) { * (Optional) * * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[inout] buf Pointer to the input data to be mutated and the mutated + * @param[in] buf Pointer to the input data to be mutated and the mutated * output * @param[in] buf_size Size of input data + * @param[out] out_buf The output buffer. buf can be reused, if the content + * fits. * @param[in] max_size Maximum size of the mutated output. The mutation must * not produce data larger than max_size. * @return Size of the mutated output. */ -size_t afl_custom_havoc_mutation(my_mutator_t *data, uint8_t **buf, - size_t buf_size, size_t max_size) { +size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size) { if (buf_size == 0) { - *buf = realloc(*buf, 1); - **buf = rand() % 256; + *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); + **out_buf = rand() % 256; buf_size = 1; + } else { + + // We reuse buf here. It's legal and faster. + *out_buf = buf; + } size_t victim = rand() % buf_size; - (*buf)[victim] += rand() % 10; + (*out_buf)[victim] += rand() % 10; return buf_size; @@ -346,6 +351,10 @@ void afl_custom_queue_new_entry(my_mutator_t * data, void afl_custom_deinit(my_mutator_t *data) { free(data->pre_save_buf); + free(data->havoc_buf); + free(data->data_buf); + free(data->fuzz_buf); + free(data->trim_out_buf); free(data); } diff --git a/examples/post_library/post_library.so.c b/examples/post_library/post_library.so.c index 5d2685cd..735aae9b 100644 --- a/examples/post_library/post_library.so.c +++ b/examples/post_library/post_library.so.c @@ -3,6 +3,7 @@ -------------------------------------------------- Originally written by Michal Zalewski + Edited by Dominik Maier, 2020 Copyright 2015 Google Inc. All rights reserved. @@ -41,22 +42,23 @@ AFL will call the afl_postprocess() function for every mutated output buffer. From there, you have three choices: - 1) If you don't want to modify the test case, simply return the original - buffer pointer ('in_buf'). + 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` + and return the original `len`. 2) If you want to skip this test case altogether and have AFL generate a - new one, return NULL. Use this sparingly - it's faster than running - the target program with patently useless inputs, but still wastes CPU - time. + new one, return 0 or set `*out_buf = NULL`. + Use this sparingly - it's faster than running the target program + with patently useless inputs, but still wastes CPU time. 3) If you want to modify the test case, allocate an appropriately-sized buffer, move the data into that buffer, make the necessary changes, and - then return the new pointer. You can update *len if necessary, too. + then return the new pointer as out_buf. Return an appropriate len + afterwards. Note that the buffer will *not* be freed for you. To avoid memory leaks, you need to free it or reuse it on subsequent calls (as shown below). - *** DO NOT MODIFY THE ORIGINAL 'in_buf' BUFFER. *** + *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** Aight. The example below shows a simple postprocessor that tries to make sure that all input files start with "GIF89a". @@ -74,47 +76,83 @@ #define HEADER "GIF89a" -/* The actual postprocessor routine called by afl-fuzz: */ +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_postprocess_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { -const unsigned char *afl_postprocess(const unsigned char *in_buf, - unsigned int * len) { + perror("malloc"); + return NULL; - static unsigned char *saved_buf; - unsigned char * new_buf; + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { return NULL; } + + return state; + +} + +/* The actual postprocessor routine called by afl-fuzz: */ + +size_t afl_postprocess(post_state_t *data, unsigned char *in_buf, + unsigned int len, unsigned char **out_buf) { /* Skip execution altogether for buffers shorter than 6 bytes (just to - show how it's done). We can trust *len to be sane. */ + show how it's done). We can trust len to be sane. */ - if (*len < strlen(HEADER)) return NULL; + if (len < strlen(HEADER)) return 0; /* Do nothing for buffers that already start with the expected header. */ - if (!memcmp(in_buf, HEADER, strlen(HEADER))) return in_buf; + if (!memcmp(in_buf, HEADER, strlen(HEADER))) { + + *out_buf = in_buf; + return len; + + } /* Allocate memory for new buffer, reusing previous allocation if possible. */ - new_buf = realloc(saved_buf, *len); + *out_buf = realloc(data->buf, len); /* If we're out of memory, the most graceful thing to do is to return the original buffer and give up on modifying it. Let AFL handle OOM on its own later on. */ - if (!new_buf) return in_buf; - saved_buf = new_buf; + if (!*out_buf) { + + *out_buf = in_buf; + return len; + + } /* Copy the original data to the new location. */ - memcpy(new_buf, in_buf, *len); + memcpy(*out_buf, in_buf, len); /* Insert the new header. */ - memcpy(new_buf, HEADER, strlen(HEADER)); + memcpy(*out_buf, HEADER, strlen(HEADER)); - /* Return modified buffer. No need to update *len in this particular case, - as we're not changing it. */ + /* Return the new len. It hasn't changed, so it's just len. */ - return new_buf; + return len; } +/* Gets called afterwards */ +void afl_postprocess_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} diff --git a/examples/post_library/post_library_png.so.c b/examples/post_library/post_library_png.so.c index 60ab318f..8597c88c 100644 --- a/examples/post_library/post_library_png.so.c +++ b/examples/post_library/post_library_png.so.c @@ -5,6 +5,7 @@ Originally written by Michal Zalewski Copyright 2015 Google Inc. All rights reserved. + Adapted to the new API, 2020 by Dominik Maier Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,11 +36,32 @@ #define UP4K(_i) ((((_i) >> 12) + 1) << 12) -const unsigned char *afl_postprocess(const unsigned char *in_buf, - unsigned int * len) { +typedef struct post_state { - static unsigned char *saved_buf; - static unsigned int saved_len; + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_postprocess_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { return NULL; } + + return state; + +} + +size_t afl_postprocess(post_state_t *data, const unsigned char *in_buf, + unsigned int len, const unsigned char **out_buf) { unsigned char *new_buf = (unsigned char *)in_buf; unsigned int pos = 8; @@ -47,12 +69,17 @@ const unsigned char *afl_postprocess(const unsigned char *in_buf, /* Don't do anything if there's not enough room for the PNG header (8 bytes). */ - if (*len < 8) return in_buf; + if (len < 8) { + + *out_buf = in_buf; + return len; + + } /* Minimum size of a zero-length PNG chunk is 12 bytes; if we don't have that, we can bail out. */ - while (pos + 12 <= *len) { + while (pos + 12 <= len) { unsigned int chunk_len, real_cksum, file_cksum; @@ -62,7 +89,7 @@ const unsigned char *afl_postprocess(const unsigned char *in_buf, /* Bail out if chunk size is too big or goes past EOF. */ - if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > *len) break; + if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; /* Chunk checksum is calculated for chunk ID (dword) and the actual payload. */ @@ -82,17 +109,23 @@ const unsigned char *afl_postprocess(const unsigned char *in_buf, if (new_buf == in_buf) { - if (*len <= saved_len) { + if (len <= data->size) { - new_buf = saved_buf; + new_buf = data->buf; } else { - new_buf = realloc(saved_buf, UP4K(*len)); - if (!new_buf) return in_buf; - saved_buf = new_buf; - saved_len = UP4K(*len); - memcpy(new_buf, in_buf, *len); + new_buf = realloc(data->buf, UP4K(len)); + if (!new_buf) { + + *out_buf = in_buf; + return len; + + } + + data->buf = new_buf; + data->size = UP4K(len); + memcpy(new_buf, in_buf, len); } @@ -108,7 +141,15 @@ const unsigned char *afl_postprocess(const unsigned char *in_buf, } - return new_buf; + *out_buf = new_buf; + return len; } +/* Gets called afterwards */ +void afl_postprocess_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 32eaf4af..5f9891bc 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -293,9 +293,18 @@ typedef struct py_mutator { void * afl_state; void * py_data; + u8 * fuzz_buf; + size_t fuzz_size; + u8 * pre_save_buf; size_t pre_save_size; + u8 * trim_buf; + size_t trim_size; + + u8 * havoc_buf; + size_t havoc_size; + } py_mutator_t; #endif @@ -544,7 +553,11 @@ typedef struct afl_state { struct extra_data *a_extras; /* Automatically selected extras */ u32 a_extras_cnt; /* Total number of tokens available */ - u8 *(*post_handler)(u8 *buf, u32 *len); + /* afl_postprocess API */ + void *(*post_init)(struct afl_state *afl); + size_t (*post_handler)(void *data, u8 *buf, u32 len, u8 **out_buf); + void *(*post_deinit)(void *data); + void *post_data; /* CmpLog */ @@ -643,10 +656,10 @@ struct custom_mutator { * @param[in] add_buf_size Size of the additional test case * @param[in] max_size Maximum size of the mutated output. The mutation must * not produce data larger than max_size. - * @return Size of the mutated output. + * @return Size of the mutated output. Negative on error will abort exeuction. */ - size_t (*afl_custom_fuzz)(void *data, u8 **buf, size_t buf_size, u8 *add_buf, - size_t add_buf_size, size_t max_size); + size_t (*afl_custom_fuzz)(void *data, u8 *buf, size_t buf_size, u8 **out_buf, + u8 *add_buf, size_t add_buf_size, size_t max_size); /** * A post-processing function to use right before AFL writes the test case to @@ -704,9 +717,9 @@ struct custom_mutator { * @param[out] out_buf Pointer to the buffer containing the trimmed test case. * External library should allocate memory for out_buf. AFL++ will release * the memory after saving the test case. - * @param[out] out_buf_size Pointer to the size of the trimmed test case + * @return the size of the trimmed test case */ - void (*afl_custom_trim)(void *data, u8 **out_buf, size_t *out_buf_size); + size_t (*afl_custom_trim)(void *data, u8 **out_buf); /** * This method is called after each trim operation to inform you if your @@ -728,16 +741,18 @@ struct custom_mutator { * * (Optional) * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param[inout] buf Pointer to the input data to be mutated and the mutated + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to the input data to be mutated and the mutated * output * @param[in] buf_size Size of input data + * @param[out] out_buf The new buffer. It's legal to reuse *buf if it's < + * buf_size. * @param[in] max_size Maximum size of the mutated output. The mutation must * not produce data larger than max_size. - * @return Size of the mutated output. + * @return Size of the mutated output (out_size). */ - size_t (*afl_custom_havoc_mutation)(void *data, u8 **buf, size_t buf_size, - size_t max_size); + size_t (*afl_custom_havoc_mutation)(void *data, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size); /** * Return the probability (in percentage) that afl_custom_havoc_mutation @@ -803,8 +818,8 @@ void finalize_py_module(void *); size_t pre_save_py(void *, u8 *, size_t, u8 **); u32 init_trim_py(void *, u8 *, size_t); u32 post_trim_py(void *, u8); -void trim_py(void *, u8 **, size_t *); -size_t havoc_mutation_py(void *, u8 **, size_t, size_t); +size_t trim_py(void *, u8 **); +size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t); u8 havoc_mutation_probability_py(void *); u8 queue_get_py(void *, const u8 *); void queue_new_entry_py(void *, const u8 *, const u8 *); diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 6c6f05ac..7c398507 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -527,8 +527,13 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (afl->post_handler) { - out_buf = afl->post_handler(out_buf, &len); - if (!out_buf || !len) return 0; + u8 *post_buf = NULL; + + size_t post_len = + afl->post_handler(afl->post_data, out_buf, len, &post_buf); + if (!post_buf || !post_len) return 0; + out_buf = post_buf; + len = post_len; } diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-globals.c index 3e573dd2..1d99e1fa 100644 --- a/src/afl-fuzz-globals.c +++ b/src/afl-fuzz-globals.c @@ -349,6 +349,8 @@ void read_afl_environment(afl_state_t *afl, char **envp) { void afl_state_deinit(afl_state_t *afl) { + if (afl->post_deinit) afl->post_deinit(afl->post_data); + free(afl->out_buf); free(afl->out_scratch_buf); free(afl->eff_buf); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index a69c3b61..fe2be4d2 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -270,7 +270,9 @@ void setup_post(afl_state_t *afl) { void *dh; u8 * fn = afl->afl_env.afl_post_library; + u8 tbuf[6]; u32 tlen = 6; + strncpy(tbuf, "hello", tlen); if (!fn) return; @@ -281,10 +283,20 @@ void setup_post(afl_state_t *afl) { afl->post_handler = dlsym(dh, "afl_postprocess"); if (!afl->post_handler) FATAL("Symbol 'afl_postprocess' not found."); + afl->post_init = dlsym(dh, "afl_postprocess_init"); + if (!afl->post_init) FATAL("Symbol 'afl_postprocess_init' not found."); + afl->post_deinit = dlsym(dh, "afl_postprocess_deinit"); + if (!afl->post_deinit) FATAL("Symbol 'afl_postprocess_deinit' not found."); /* Do a quick test. It's better to segfault now than later =) */ - afl->post_handler("hello", &tlen); + u8 *post_buf = NULL; + afl->post_data = afl->post_init(afl); + if (!afl->post_data) FATAL("Could not initialize post handler."); + + size_t post_len = afl->post_handler(afl->post_data, tbuf, tlen, &post_buf); + if (!post_len || !post_buf) + SAYF("Empty return in test post handler for buf=\"hello\\0\"."); OKF("Postprocessor installed successfully."); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 41bc69c8..0692ebb0 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -7,6 +7,7 @@ Now maintained by Marc Heuse , Heiko Eißfeldt and Andrea Fioraldi + Dominik Maier Copyright 2016, 2017 Google Inc. All rights reserved. Copyright 2019-2020 AFLplusplus Project. All rights reserved. @@ -192,7 +193,8 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { /* Initialize the custom mutator */ if (afl->mutator->afl_custom_init) - afl->mutator->data = afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); + afl->mutator->data = + afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); } @@ -218,17 +220,18 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { while (afl->stage_cur < afl->stage_max) { + u8 *retbuf = NULL; + sprintf(afl->stage_name_buf, "ptrim %s", u_stringify_int(val_buf, trim_exec)); u32 cksum; - u8 * retbuf = NULL; - size_t retlen = 0; - - afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf, &retlen); + size_t retlen = afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf); - if (retlen > orig_len) + if (unlikely(retlen < 0 || !retbuf)) + FATAL("custom_trim failed (ret %zd)", retlen); + else if (unlikely(retlen > orig_len)) FATAL( "Trimmed data returned by custom mutator is larger than original " "data"); @@ -238,12 +241,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fault = run_target(afl, afl->fsrv.exec_tmout); ++afl->trim_execs; - if (afl->stop_soon || fault == FAULT_ERROR) { - - ck_free(retbuf); - goto abort_trimming; - - } + if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; } cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); @@ -281,8 +279,6 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } - ck_free(retbuf); - /* Since this can be slow, update the screen every now and then. */ if (!(trim_exec++ % afl->stats_update_freq)) show_stats(afl); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 024b4665..8dfafb7b 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1612,15 +1612,20 @@ custom_mutator_stage: ck_read(fd, new_buf, target->len, target->fname); close(fd); - // TODO: clean up this mess. + u8 *mutated_buf = NULL; + size_t mutated_size = afl->mutator->afl_custom_fuzz( - afl->mutator->data, &out_buf, len, new_buf, target->len, max_seed_size); + afl->mutator->data, out_buf, len, &mutated_buf, new_buf, target->len, + max_seed_size); + + if (unlikely(mutated_size < 0)) + FATAL("custom_fuzz returned %zd", mutated_size); if (mutated_size > len) afl->out_size = mutated_size; if (mutated_size > 0) { - if (common_fuzz_stuff(afl, out_buf, (u32)mutated_size)) { + if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { goto abandon_entry; @@ -1726,8 +1731,22 @@ havoc_stage: if (stacked_custom && rand_below(afl, 100) < stacked_custom_prob) { - temp_len = afl->mutator->afl_custom_havoc_mutation( - afl->mutator->data, &out_buf, temp_len, MAX_FILE); + 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(new_len < 0)) + 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) { + + ck_maybe_grow(BUF_PARAMS(out), temp_len); + memcpy(out_buf, custom_havoc_buf, temp_len); + + } + + } } diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 6fbdb678..f9f71929 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -35,15 +35,22 @@ static void *unsupported(afl_state_t *afl, unsigned int seed) { } -size_t fuzz_py(void *py_mutator, u8 **buf, size_t buf_size, u8 *add_buf, - size_t add_buf_size, size_t max_size) { +/* sorry for this makro... +it just filles in `&py_mutator->something_buf, &py_mutator->something_size`. */ +#define BUF_PARAMS(name) \ + (void **)&((py_mutator_t *)py_mutator)->name##_buf, \ + &((py_mutator_t *)py_mutator)->name##_size + +size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, + u8 *add_buf, size_t add_buf_size, size_t max_size) { size_t mutated_size; PyObject *py_args, *py_value; py_args = PyTuple_New(3); + py_mutator_t *py = (py_mutator_t *)py_mutator; /* buf */ - py_value = PyByteArray_FromStringAndSize(*buf, buf_size); + py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { Py_DECREF(py_args); @@ -79,17 +86,17 @@ size_t fuzz_py(void *py_mutator, u8 **buf, size_t buf_size, u8 *add_buf, PyTuple_SetItem(py_args, 2, py_value); - py_value = PyObject_CallObject( - ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ], py_args); + py_value = PyObject_CallObject(py->py_functions[PY_FUNC_FUZZ], py_args); Py_DECREF(py_args); if (py_value != NULL) { mutated_size = PyByteArray_Size(py_value); - if (buf_size < mutated_size) *buf = ck_realloc(*buf, mutated_size); - memcpy(*buf, PyByteArray_AsString(py_value), mutated_size); + *out_buf = ck_maybe_grow(BUF_PARAMS(fuzz), mutated_size); + + memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size); Py_DECREF(py_value); return mutated_size; @@ -364,14 +371,8 @@ size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { py_out_buf_size = PyByteArray_Size(py_value); - if (py_out_buf_size > py->pre_save_size) { - - /* Not enough space! - Let's resize our buf */ - py->pre_save_buf = ck_realloc(py->pre_save_buf, py_out_buf_size); - py->pre_save_size = py_out_buf_size; - - } + ck_maybe_grow((void **)&py->pre_save_buf, &py->pre_save_size, + py_out_buf_size); memcpy(py->pre_save_buf, PyByteArray_AsString(py_value), py_out_buf_size); Py_DECREF(py_value); @@ -465,9 +466,10 @@ u32 post_trim_py(void *py_mutator, u8 success) { } -void trim_py(void *py_mutator, u8 **out_buf, size_t *out_buf_size) { +size_t trim_py(void *py_mutator, u8 **out_buf) { PyObject *py_args, *py_value; + size_t ret; py_args = PyTuple_New(0); py_value = PyObject_CallObject( @@ -476,9 +478,9 @@ void trim_py(void *py_mutator, u8 **out_buf, size_t *out_buf_size) { if (py_value != NULL) { - *out_buf_size = PyByteArray_Size(py_value); - *out_buf = malloc(*out_buf_size); - memcpy(*out_buf, PyByteArray_AsString(py_value), *out_buf_size); + ret = PyByteArray_Size(py_value); + *out_buf = ck_maybe_grow(BUF_PARAMS(trim), ret); + memcpy(*out_buf, PyByteArray_AsString(py_value), ret); Py_DECREF(py_value); } else { @@ -488,17 +490,19 @@ void trim_py(void *py_mutator, u8 **out_buf, size_t *out_buf_size) { } + return ret; + } -size_t havoc_mutation_py(void *py_mutator, u8 **buf, size_t buf_size, - size_t max_size) { +size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size) { size_t mutated_size; PyObject *py_args, *py_value; py_args = PyTuple_New(2); /* buf */ - py_value = PyByteArray_FromStringAndSize(*buf, buf_size); + py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { Py_DECREF(py_args); @@ -532,9 +536,19 @@ size_t havoc_mutation_py(void *py_mutator, u8 **buf, size_t buf_size, if (py_value != NULL) { mutated_size = PyByteArray_Size(py_value); - if (buf_size < mutated_size) *buf = ck_realloc(*buf, mutated_size); + if (mutated_size <= buf_size) { + + /* We reuse the input buf here. */ + *out_buf = buf; + + } else { - memcpy(*buf, PyByteArray_AsString(py_value), mutated_size); + /* A new buf is needed... */ + *out_buf = ck_maybe_grow(BUF_PARAMS(havoc), mutated_size); + + } + + memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size); Py_DECREF(py_value); return mutated_size; @@ -680,5 +694,7 @@ void queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue, } +#undef BUF_PARAMS + #endif /* USE_PYTHON */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a43bfad2..9ba2c5f7 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -741,8 +741,13 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (afl->post_handler) { - out_buf = afl->post_handler(out_buf, &len); - if (!out_buf || !len) return 0; + u8 *post_buf = NULL; + + size_t post_len = + afl->post_handler(afl->post_data, out_buf, len, &post_buf); + if (!post_buf || !post_len) return 0; + out_buf = post_buf; + len = post_len; } -- cgit 1.4.1 From 1119a2e185498c83cdc672c4a4753494197314f2 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sat, 28 Mar 2020 11:01:29 +0100 Subject: alloc-inl.h/ck_maybe_grow() back to size_t, reimplement overflow check --- include/alloc-inl.h | 12 ++++++------ src/afl-fuzz-python.c | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/include/alloc-inl.h b/include/alloc-inl.h index ae908162..11c1143a 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -771,10 +771,10 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, It will realloc *buf otherwise. *size will grow exponentially as per: https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will FATAL if size_needed is <1 or *size is negative. + Will FATAL if size_needed is <1. @return For convenience, this function returns *buf. */ -static inline void *ck_maybe_grow(void **buf, ssize_t *size, +static inline void *ck_maybe_grow(void **buf, size_t *size, size_t size_needed) { /* Oops. found a bug? */ @@ -782,14 +782,14 @@ static inline void *ck_maybe_grow(void **buf, ssize_t *size, /* No need to realloc */ if (likely(*size >= size_needed)) return *buf; - if (unlikely(*size < 0)) FATAL("Negative size detected!"); - /* No inital size was set */ + + /* No initial size was set */ if (*size == 0) *size = INITIAL_GROWTH_SIZE; while (*size < size_needed) { - *size *= 2; /* in case of overflow we'll realloc to size_needed */ - if ((*size) < 0) *size = size_needed; + if (2*(*size) < size_needed) *size = size_needed; + else *size *= 2; } diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index f9f71929..6f8982c0 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -36,7 +36,7 @@ static void *unsupported(afl_state_t *afl, unsigned int seed) { } /* sorry for this makro... -it just filles in `&py_mutator->something_buf, &py_mutator->something_size`. */ +it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */ #define BUF_PARAMS(name) \ (void **)&((py_mutator_t *)py_mutator)->name##_buf, \ &((py_mutator_t *)py_mutator)->name##_size @@ -371,8 +371,7 @@ size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { py_out_buf_size = PyByteArray_Size(py_value); - ck_maybe_grow((void **)&py->pre_save_buf, &py->pre_save_size, - py_out_buf_size); + ck_maybe_grow(BUF_PARAMS(pre_save), py_out_buf_size); memcpy(py->pre_save_buf, PyByteArray_AsString(py_value), py_out_buf_size); Py_DECREF(py_value); -- cgit 1.4.1 From ab5e0703dab404a77cd4726f720db99bed1a0c71 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 28 Mar 2020 11:55:10 +0100 Subject: tiny changes in custom mut api --- examples/custom_mutators/example.c | 46 ++++++++++++++++++++++++-------------- include/afl-fuzz.h | 6 +++-- src/afl-fuzz-mutators.c | 2 +- src/afl-fuzz-one.c | 6 ++--- src/afl-fuzz-python.c | 2 +- src/afl-fuzz-run.c | 2 +- 6 files changed, 39 insertions(+), 25 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 54fc9d47..9a62d1a7 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -29,16 +29,15 @@ typedef struct my_mutator { afl_t *afl; // any additional data here! - uint8_t *trim_buf; - size_t trim_buf_size; - int trimmming_steps; - int cur_step; + size_t trim_size_current; + int trimmming_steps; + int cur_step; // Reused buffers: BUF_VAR(u8, fuzz); BUF_VAR(u8, data); BUF_VAR(u8, havoc); - BUF_VAR(u8, trim_out); + BUF_VAR(u8, trim); BUF_VAR(u8, pre_save); } my_mutator_t; @@ -52,7 +51,7 @@ typedef struct my_mutator { * in the same way. * @return Pointer to the data object this custom mutator instance should use. * There may be multiple instances of this mutator in one afl-fuzz run! - * Returns NULL on error. + * Return NULL on error. */ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { @@ -80,11 +79,13 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param[in] buf Pointer to input data to be mutated * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. * @param[in] add_buf Buffer containing the additional test case * @param[in] add_buf_size Size of the additional test case * @param[in] max_size Maximum size of the mutated output. The mutation must not * produce data larger than max_size. - * @return Size of the mutated output. Negative return will abort fuzzing. + * @return Size of the mutated output. */ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, @@ -100,7 +101,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, if (!mutated_out) { perror("custom mutator allocation (maybe_grow)"); - return -1; /* afl-fuzz will very likely error out after this. */ + return 0; /* afl-fuzz will very likely error out after this. */ } @@ -135,7 +136,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, * processing. External library should allocate memory for out_buf. * The buf pointer may be reused (up to the given buf_size); * @return Size of the output buffer after processing or the needed amount. - * A return smaller 1 indicates an error. + * A return of 0 indicates an error. */ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { @@ -146,7 +147,8 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, if (!data->pre_save_buf) { perror("custom mutator realloc failed."); - return -1; + *out_buf = NULL; + return 0; } @@ -195,8 +197,11 @@ int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { data->trimmming_steps = 1; data->cur_step = 0; - data->trim_buf = buf; - data->trim_buf_size = buf_size; + + maybe_grow(BUF_PARAMS(data, trim), buf_size); + memcpy(data->trim_buf, buf, buf_size); + + data->trim_size_current = buf_size; return data->trimmming_steps; @@ -218,15 +223,15 @@ int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { * External library should allocate memory for out_buf. * AFL++ will not release the memory after saving the test case. * Keep a ref in *data. + * *out_buf = NULL is treated as error. * @return Pointer to the size of the trimmed test case */ size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { - size_t ret = data->trim_buf_size - 1; + *out_buf = data->trim_buf; - *out_buf = maybe_grow(BUF_PARAMS(data, trim_out), ret); // Remove the last byte of the trimming input - memcpy(*out_buf, data->trim_buf, ret); + return data->trim_size_current - 1; } @@ -266,7 +271,7 @@ int afl_custom_post_trim(my_mutator_t *data, int success) { * output * @param[in] buf_size Size of input data * @param[out] out_buf The output buffer. buf can be reused, if the content - * fits. + * fits. *out_buf = NULL is treated as error. * @param[in] max_size Maximum size of the mutated output. The mutation must * not produce data larger than max_size. * @return Size of the mutated output. @@ -277,6 +282,13 @@ size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, if (buf_size == 0) { *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); + if (!*out_buf) { + + perror("custom havoc: maybe_grow"); + return 0; + + } + **out_buf = rand() % 256; buf_size = 1; @@ -354,7 +366,7 @@ void afl_custom_deinit(my_mutator_t *data) { free(data->havoc_buf); free(data->data_buf); free(data->fuzz_buf); - free(data->trim_out_buf); + free(data->trim_buf); free(data); } diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5f9891bc..79878cb6 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -649,14 +649,16 @@ struct custom_mutator { * (Optional for now. Required in the future) * * @param data pointer returned in afl_custom_init for this fuzz case - * @param[inout] buf Pointer to the input data to be mutated and the mutated + * @param[in] buf Pointer to the input data to be mutated and the mutated * output * @param[in] buf_size Size of the input/output data + * @param[out] out_buf the new buffer. We may reuse *buf if large enough. + * *out_buf = NULL is treated as FATAL. * @param[in] add_buf Buffer containing the additional test case * @param[in] add_buf_size Size of the additional test case * @param[in] max_size Maximum size of the mutated output. The mutation must * not produce data larger than max_size. - * @return Size of the mutated output. Negative on error will abort exeuction. + * @return Size of the mutated output. */ size_t (*afl_custom_fuzz)(void *data, u8 *buf, size_t buf_size, u8 **out_buf, u8 *add_buf, size_t add_buf_size, size_t max_size); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 0692ebb0..f14a57bb 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -229,7 +229,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { size_t retlen = afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf); - if (unlikely(retlen < 0 || !retbuf)) + if (unlikely(!retbuf)) FATAL("custom_trim failed (ret %zd)", retlen); else if (unlikely(retlen > orig_len)) FATAL( diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 8dfafb7b..b1bbad0a 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1618,8 +1618,8 @@ custom_mutator_stage: afl->mutator->data, out_buf, len, &mutated_buf, new_buf, target->len, max_seed_size); - if (unlikely(mutated_size < 0)) - FATAL("custom_fuzz returned %zd", mutated_size); + if (unlikely(!mutated_buf)) + FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); if (mutated_size > len) afl->out_size = mutated_size; @@ -1734,7 +1734,7 @@ havoc_stage: 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(new_len < 0)) + if (unlikely(!custom_havoc_buf)) FATAL("Error in custom_havoc (return %zd)", new_len); if (likely(new_len > 0 && custom_havoc_buf)) { diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 6f8982c0..76b5ca80 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -103,7 +103,7 @@ size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, } else { PyErr_Print(); - FATAL("Call failed"); + FATAL("python custom fuzz: call failed"); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 315539d1..90cb2ed5 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -221,7 +221,7 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem, len, &new_buf); - if (unlikely(new_size <= 0 || !new_buf)) + if (unlikely(!new_buf)) FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size); /* everything as planned. use the new data. */ -- cgit 1.4.1 From 81873d97f8a24a874a52f56aae5ca87745f1aaec Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 28 Mar 2020 12:58:56 +0100 Subject: error handling for custom mutators --- examples/custom_mutators/custom_mutator_helpers.h | 49 ++++++++++++++--------- examples/custom_mutators/example.c | 15 ++++--- include/afl-fuzz.h | 13 +++--- include/alloc-inl.h | 6 +-- src/afl-fuzz-mutators.c | 3 +- src/afl-fuzz-python.c | 4 +- 6 files changed, 54 insertions(+), 36 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h index 0dc00d96..e5ce3569 100644 --- a/examples/custom_mutators/custom_mutator_helpers.h +++ b/examples/custom_mutators/custom_mutator_helpers.h @@ -277,37 +277,48 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { } + +/* This function calculates the next power of 2 greater or equal its argument. + @return The rounded up power of 2 (if no overflow) or 0 on overflow. +*/ +static inline size_t next_pow2(size_t in) { + if (in == 0 || in > (size_t)-1) return 0; /* avoid undefined behaviour under-/overflow */ + size_t out = in - 1; + out |= out >> 1; + out |= out >> 2; + out |= out >> 4; + out |= out >> 8; + out |= out >> 16; + return out + 1; +} + /* This function makes sure *size is > size_needed after call. - It changes buf and size in-place, if needed. It will realloc *buf otherwise. *size will grow exponentially as per: https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL if size_needed is <1 or *size is negative or malloc Failed. - @return For convenience, this function returns *buf. NULL on error. + Will return NULL and free *buf if size_needed is <1 or realloc failed. + @return For convenience, this function returns *buf. */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { - - /* Oops. found a bug? */ - if (unlikely(size_needed < 1)) return NULL; +static inline void *maybe_grow(void **buf, size_t *size, + size_t size_needed) { /* No need to realloc */ - if (likely(*size >= size_needed)) return *buf; - if (unlikely(*size < 0)) return NULL; - /* No inital size was set */ - if (*size == 0) *size = INITIAL_GROWTH_SIZE; - while (*size < size_needed) { - - *size *= 2; - if ((*size) < 0) { + if (likely(size_needed && *size >= size_needed)) return *buf; - /* An overflow occurred. Fall back to size_needed */ - *size = size_needed; + /* No initial size was set */ + if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; - } + /* grow exponentially */ + size_t next_size = next_pow2(size_needed); + /* handle overflow */ + if (!next_size) { + next_size = size_needed; } - *buf = realloc(*buf, *size); + /* alloc */ + *buf = realloc(*buf, next_size); + *size = *buf ? next_size : 0; return *buf; diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 9a62d1a7..488ece81 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -100,6 +100,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); if (!mutated_out) { + *out_buf = NULL; perror("custom mutator allocation (maybe_grow)"); return 0; /* afl-fuzz will very likely error out after this. */ @@ -189,16 +190,20 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, * @param data pointer returned in afl_custom_init for this fuzz case * @param buf Buffer containing the test case * @param buf_size Size of the test case - * @return The amount of possible iteration steps to trim the input + * @return The amount of possible iteration steps to trim the input. + * negative on error. */ -int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { +int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { // We simply trim once data->trimmming_steps = 1; data->cur_step = 0; - maybe_grow(BUF_PARAMS(data, trim), buf_size); + if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { + perror("init_trim grow"); + return -1; + } memcpy(data->trim_buf, buf, buf_size); data->trim_size_current = buf_size; @@ -245,9 +250,9 @@ size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { * @param[in] data pointer returned in afl_custom_init for this fuzz case * @param success Indicates if the last trim operation was successful. * @return The next trim iteration index (from 0 to the maximum amount of - * steps returned in init_trim) + * steps returned in init_trim). negative ret on failure. */ -int afl_custom_post_trim(my_mutator_t *data, int success) { +int32_t afl_custom_post_trim(my_mutator_t *data, int success) { if (success) { diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 79878cb6..a265c1a3 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -700,9 +700,10 @@ struct custom_mutator { * @param data pointer returned in afl_custom_init for this fuzz case * @param buf Buffer containing the test case * @param buf_size Size of the test case - * @return The amount of possible iteration steps to trim the input + * @return The amount of possible iteration steps to trim the input. + * Negative on error. */ - u32 (*afl_custom_init_trim)(void *data, u8 *buf, size_t buf_size); + s32 (*afl_custom_init_trim)(void *data, u8 *buf, size_t buf_size); /** * This method is called for each trimming operation. It doesn't have any @@ -733,9 +734,9 @@ struct custom_mutator { * @param data pointer returned in afl_custom_init for this fuzz case * @param success Indicates if the last trim operation was successful. * @return The next trim iteration index (from 0 to the maximum amount of - * steps returned in init_trim) + * steps returned in init_trim). Negative on error. */ - u32 (*afl_custom_post_trim)(void *data, u8 success); + s32 (*afl_custom_post_trim)(void *data, u8 success); /** * Perform a single custom mutation on a given input. @@ -818,8 +819,8 @@ u8 trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf); void finalize_py_module(void *); size_t pre_save_py(void *, u8 *, size_t, u8 **); -u32 init_trim_py(void *, u8 *, size_t); -u32 post_trim_py(void *, u8); +s32 init_trim_py(void *, u8 *, size_t); +s32 post_trim_py(void *, u8); size_t trim_py(void *, u8 **); size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t); u8 havoc_mutation_probability_py(void *); diff --git a/include/alloc-inl.h b/include/alloc-inl.h index b8c83db4..91564932 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -767,10 +767,10 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, #endif /* _WANT_ORIGINAL_AFL_ALLOC */ -/* This function calculates the lowest power of 2 greater or equal its argument. +/* This function calculates the next power of 2 greater or equal its argument. @return The rounded up power of 2 (if no overflow) or 0 on overflow. */ -static inline size_t powerOf2Ceil(size_t in) { +static inline size_t next_pow2(size_t in) { if (in == 0 || in > (size_t)-1) return 0; /* avoid undefined behaviour under-/overflow */ size_t out = in - 1; out |= out >> 1; @@ -801,7 +801,7 @@ static inline void *ck_maybe_grow(void **buf, size_t *size, if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; /* grow exponentially */ - size_t next_size = powerOf2Ceil(size_needed); + size_t next_size = next_pow2(size_needed); /* handle overflow */ if (!next_size) { diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index f14a57bb..90d7de40 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -213,7 +213,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { afl->stage_cur = 0; afl->stage_max = afl->mutator->afl_custom_init_trim(afl->mutator->data, in_buf, q->len); - + if (unlikely(afl->stage_max) < 0) FATAL("custom_init_trim error ret: %d", afl->stage_max); if (afl->not_on_tty && afl->debug) SAYF("[Custom Trimming] START: Max %d iterations, %u bytes", afl->stage_max, q->len); @@ -273,6 +273,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); + if (unlikely(afl->stage_cur < 0)) FATAL("Error ret in custom_post_trim: %d", afl->stage_cur); if (afl->not_on_tty && afl->debug) SAYF("[Custom Trimming] FAILURE: %d/%d iterations", afl->stage_cur, afl->stage_max); diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 76b5ca80..91e5b084 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -388,7 +388,7 @@ size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { } -u32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) { +s32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) { PyObject *py_args, *py_value; @@ -426,7 +426,7 @@ u32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) { } -u32 post_trim_py(void *py_mutator, u8 success) { +s32 post_trim_py(void *py_mutator, u8 success) { PyObject *py_args, *py_value; -- cgit 1.4.1 From 0dd8ed9171cdbee3360f4b7f6a9fd91e7478a508 Mon Sep 17 00:00:00 2001 From: h1994st Date: Sat, 28 Mar 2020 00:52:29 -0400 Subject: Fix invalid memory access bug in `afl_custom_pre_save` of example.c --- examples/custom_mutators/example.c | 16 +++++++++------- src/afl-fuzz-python.c | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index a9764f5b..7d827029 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -157,15 +157,17 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, } - *out_buf = data->pre_save_buf; + uint8_t *pre_save_buf = data->pre_save_buf; - memcpy(*out_buf + 5, buf, buf_size); + memcpy(pre_save_buf + 5, buf, buf_size); size_t out_buf_size = buf_size + 5; - *out_buf[0] = 'A'; - *out_buf[1] = 'F'; - *out_buf[2] = 'L'; - *out_buf[3] = '+'; - *out_buf[4] = '+'; + pre_save_buf[0] = 'A'; + pre_save_buf[1] = 'F'; + pre_save_buf[2] = 'L'; + pre_save_buf[3] = '+'; + pre_save_buf[4] = '+'; + + *out_buf = pre_save_buf; return out_buf_size; diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 91e5b084..01503d2c 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -133,8 +133,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { if (py_module != NULL) { u8 py_notrim = 0, py_idx; + /* init, required */ py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init"); - py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); py_functions[PY_FUNC_PRE_SAVE] = PyObject_GetAttrString(py_module, "pre_save"); @@ -151,6 +151,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "queue_get"); py_functions[PY_FUNC_QUEUE_NEW_ENTRY] = PyObject_GetAttrString(py_module, "queue_new_entry"); + py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { -- cgit 1.4.1 From 50fc7327f2556db588c65fe7941198b622ab50af Mon Sep 17 00:00:00 2001 From: h1994st Date: Sun, 29 Mar 2020 01:07:29 -0400 Subject: python mutator: fix nullptr for python mutator data --- include/afl-fuzz.h | 3 --- src/afl-fuzz-python.c | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src/afl-fuzz-python.c') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index a265c1a3..fcbc09e5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -566,9 +566,6 @@ typedef struct afl_state { /* Custom mutators */ struct custom_mutator *mutator; -#ifdef USE_PYTHON - struct custom_mutator *py_mutator; -#endif /* cmplog forkserver ids */ s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd; diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 01503d2c..12c3a09d 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -303,6 +303,7 @@ void load_custom_mutator_py(afl_state_t *afl, char *module_name) { py_mutator_t *py_mutator; py_mutator = init_py_module(afl, module_name); + afl->mutator->data = py_mutator; if (!py_mutator) { FATAL("Failed to load python mutator."); } PyObject **py_functions = py_mutator->py_functions; -- cgit 1.4.1