From 6d3dc83c5dde31ccb74e04815a04b85b05761b30 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 25 Mar 2020 11:31:01 +0100 Subject: code format --- examples/custom_mutators/example.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 560a5919..2df17dec 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -23,7 +23,6 @@ static const char *commands[] = { }; - typedef struct my_mutator { afl_t *afl; @@ -34,21 +33,26 @@ typedef struct my_mutator { /** * Initialize this custom mutator * - * @param[in] afl a pointer to the internal state object. Can be ignored for now. - * @param[in] seed A seed for this mutator - the same seed should always mutate in the same way. + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * 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. */ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - srand(seed); // needed also by surgical_havoc_mutate() + srand(seed); // needed also by surgical_havoc_mutate() my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); if (!data) { + perror("afl_custom_init alloc"); return NULL; + } + data->afl = afl; return data; @@ -71,8 +75,8 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { */ 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 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 @@ -113,7 +117,8 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t **buf, size_t buf_size, * will release the memory after saving the test case. * @return Size of the output buffer after processing */ -size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { +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; @@ -183,7 +188,8 @@ int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) { * the memory after saving the test case. * @param[out] out_buf_size 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) { +void afl_custom_trim(my_mutator_t *data, uint8_t **out_buf, + size_t *out_buf_size) { *out_buf_size = trim_buf_size - 1; @@ -233,8 +239,8 @@ int afl_custom_post_trim(my_mutator_t *data, int success) { * 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, uint8_t **buf, + size_t buf_size, size_t max_size) { if (buf_size == 0) { @@ -292,7 +298,8 @@ uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { * @param filename_new_queue File name of the new queue entry * @param filename_orig_queue File name of the original queue entry */ -void afl_custom_queue_new_entry(my_mutator_t *data, const uint8_t *filename_new_queue, +void afl_custom_queue_new_entry(my_mutator_t * data, + const uint8_t *filename_new_queue, const uint8_t *filename_orig_queue) { /* Additional analysis on the original or new test case */ -- 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 'examples/custom_mutators/example.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 'examples/custom_mutators/example.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 604f122819bbcba6a041b4b471805a3b586916cc Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 26 Mar 2020 19:47:16 +0100 Subject: docu --- examples/custom_mutators/example.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 04b72c77..220d0ca1 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -126,17 +126,14 @@ 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[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. - * 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. + * @param[out] out_buf Pointer to the buffer containing the test case after + * 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. - * return 0 to indicate the original buf should be used. + * A return smaller 1 indicates an error. */ 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) { + uint8_t **out_buf) { if (data->pre_save_size < buf_size + 5) { -- cgit 1.4.1 From 932eae7343c59aee7ade950e5e233ac71acaf745 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 26 Mar 2020 19:48:26 +0100 Subject: example fixed --- examples/custom_mutators/example.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 220d0ca1..8a45d87f 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -149,14 +149,15 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, data->pre_save_size = buf_size + 5; } - - 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'; - out_buf[3] = '+'; - out_buf[4] = '+'; + *out_buf = data->pre_save_buf; + + memcpy(*out_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] = '+'; return out_buf_size; -- cgit 1.4.1 From e71c2937de8a19cf9b3627b86894cafabcd45513 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 27 Mar 2020 23:30:15 +0100 Subject: code format --- examples/custom_mutators/example.c | 1 + include/afl-fuzz.h | 17 ++++++++--------- include/alloc-inl.h | 13 ++++++++++--- llvm_mode/afl-clang-fast.c | 10 +++++----- llvm_mode/afl-llvm-pass.so.cc | 7 ++++++- src/afl-fuzz-bitmap.c | 22 +++++++++++++--------- src/afl-fuzz-init.c | 11 ++++------- src/afl-fuzz-one.c | 30 +++++++++++++----------------- src/afl-fuzz-queue.c | 8 +++++--- src/afl-fuzz-stats.c | 2 +- 10 files changed, 66 insertions(+), 55 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 8a45d87f..4b0a461b 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -149,6 +149,7 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, data->pre_save_size = buf_size + 5; } + *out_buf = data->pre_save_buf; memcpy(*out_buf + 5, buf, buf_size); diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 2154d860..32eaf4af 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -583,27 +583,26 @@ typedef struct afl_state { u8 clean_trace_custom[MAP_SIZE]; u8 first_trace[MAP_SIZE]; -/*needed for afl_fuzz_one */ -// TODO: see which we can reuse - u8 *out_buf; + /*needed for afl_fuzz_one */ + // TODO: see which we can reuse + u8 * out_buf; size_t out_size; - u8 *out_scratch_buf; + u8 * out_scratch_buf; size_t out_scratch_size; - u8 *eff_buf; + u8 * eff_buf; size_t eff_size; - u8 *in_buf; + u8 * in_buf; size_t in_size; - u8 *in_scratch_buf; + u8 * in_scratch_buf; size_t in_scratch_size; - u8 *ex_buf; + u8 * ex_buf; size_t ex_size; - } afl_state_t; /* A global pointer to all instances is needed (for now) for signals to arrive diff --git a/include/alloc-inl.h b/include/alloc-inl.h index 75b038c1..92d29c1e 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -774,7 +774,8 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, Will FATAL if size_needed is <1 or *size is negative. @return For convenience, this function returns *buf. */ -static inline void *ck_maybe_grow(void **buf, size_t *size, size_t size_needed) { +static inline void *ck_maybe_grow(void **buf, size_t *size, + size_t size_needed) { /* Oops. found a bug? */ if (unlikely(size_needed < 1)) FATAL("cannot grow to non-positive size"); @@ -785,21 +786,27 @@ static inline void *ck_maybe_grow(void **buf, size_t *size, size_t size_needed) /* No inital size was set */ if (*size == 0) *size = INITIAL_GROWTH_SIZE; while (*size < size_needed) { + *size *= 2; + } + *buf = ck_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; +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 diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index c45c8799..99bc8d03 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -397,15 +397,15 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (getenv("AFL_USE_CFISAN")) { - if (!lto_mode) { - + if (!lto_mode) { + uint32_t i = 0, found = 0; while (envp[i] != NULL && !found) - if (strncmp("-flto", envp[i++], 5) == 0) - found = 1; + if (strncmp("-flto", envp[i++], 5) == 0) found = 1; if (!found) cc_params[cc_par_cnt++] = "-flto"; - + } + cc_params[cc_par_cnt++] = "-fsanitize=cfi"; cc_params[cc_par_cnt++] = "-fvisibility=hidden"; diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 1c0a3c93..f6ead9ec 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -132,8 +132,11 @@ class AFLCoverage : public ModulePass { char AFLCoverage::ID = 0; /* needed up to 3.9.0 */ -#if LLVM_VERSION_MAJOR == 3 && (LLVM_VERSION_MINOR < 9 || (LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1)) +#if LLVM_VERSION_MAJOR == 3 && \ + (LLVM_VERSION_MINOR < 9 || \ + (LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1)) uint64_t PowerOf2Ceil(unsigned in) { + uint64_t in64 = in - 1; in64 |= (in64 >> 1); in64 |= (in64 >> 2); @@ -142,7 +145,9 @@ uint64_t PowerOf2Ceil(unsigned in) { in64 |= (in64 >> 16); in64 |= (in64 >> 32); return in64 + 1; + } + #endif bool AFLCoverage::runOnModule(Module &M) { diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index bb01ad21..8ca286b2 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -31,7 +31,7 @@ void write_bitmap(afl_state_t *afl) { - u8 fname[PATH_MAX]; + u8 fname[PATH_MAX]; s32 fd; if (!afl->bitmap_changed) return; @@ -461,7 +461,7 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) { static void write_crash_readme(afl_state_t *afl) { - u8 fn[PATH_MAX]; + u8 fn[PATH_MAX]; s32 fd; FILE *f; @@ -558,12 +558,13 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, afl->queued_paths, - describe_op(afl, hnb)); + queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, + afl->queued_paths, describe_op(afl, hnb)); #else - queue_fn = alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths); + queue_fn = + alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths); #endif /* ^!SIMPLE_FILES */ @@ -645,11 +646,12 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir, - afl->unique_hangs, describe_op(afl, 0)); + afl->unique_hangs, describe_op(afl, 0)); #else - snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir, afl->unique_hangs); + snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir, + afl->unique_hangs); #endif /* ^!SIMPLE_FILES */ @@ -687,11 +689,13 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, afl->unique_crashes, afl->kill_signal, describe_op(afl, 0)); + snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, + afl->unique_crashes, afl->kill_signal, describe_op(afl, 0)); #else - snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir, afl->unique_crashes, afl->kill_signal); + snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir, + afl->unique_crashes, afl->kill_signal); #endif /* ^!SIMPLE_FILES */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 1033c587..19092204 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -76,7 +76,7 @@ void bind_to_free_cpu(afl_state_t *afl) { while ((de = readdir(d))) { - u8 fn[PATH_MAX]; + u8 fn[PATH_MAX]; FILE *f; u8 tmp[MAX_LINE]; u8 has_vmsize = 0; @@ -85,11 +85,7 @@ void bind_to_free_cpu(afl_state_t *afl) { snprintf(fn, PATH_MAX, "/proc/%s/status", de->d_name); - if (!(f = fopen(fn, "r"))) { - - continue; - - } + if (!(f = fopen(fn, "r"))) { continue; } while (fgets(tmp, MAX_LINE, f)) { @@ -368,7 +364,8 @@ void read_testcases(afl_state_t *afl) { struct stat st; u8 dfn[PATH_MAX]; - snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, nl[i]->d_name); + snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, + nl[i]->d_name); u8 *fn2 = alloc_printf("%s/%s", afl->in_dir, nl[i]->d_name); u8 passed_det = 0; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 6c1d69ad..c731ebc6 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1957,7 +1957,9 @@ havoc_stage: clone_to = rand_below(afl, temp_len); - new_buf = ck_maybe_grow((void **)&afl->out_scratch_buf, &afl->out_scratch_size, temp_len + clone_len); + new_buf = + ck_maybe_grow((void **)&afl->out_scratch_buf, + &afl->out_scratch_size, temp_len + clone_len); /* Head */ @@ -1977,8 +1979,8 @@ havoc_stage: memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); - - swap_bufs((void **)&afl->out_buf, &afl->out_size, (void **)&afl->out_scratch_buf, &afl->out_scratch_size); + swap_bufs((void **)&afl->out_buf, &afl->out_size, + (void **)&afl->out_scratch_buf, &afl->out_scratch_size); out_buf = new_buf; temp_len += clone_len; @@ -2072,7 +2074,8 @@ havoc_stage: if (temp_len + extra_len >= MAX_FILE) break; - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + extra_len); + new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + extra_len); /* Head */ memcpy(new_buf, out_buf, insert_at); @@ -2088,7 +2091,8 @@ havoc_stage: if (temp_len + extra_len >= MAX_FILE) break; - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + extra_len); + new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + extra_len); /* Head */ memcpy(new_buf, out_buf, insert_at); @@ -2236,11 +2240,7 @@ retry_splicing: locate_diffs(in_buf, new_buf, MIN(len, target->len), &f_diff, &l_diff); - if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { - - goto retry_splicing; - - } + if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; } /* Split somewhere between the first and last differing byte. */ @@ -2308,11 +2308,7 @@ radamsa_stage: } - if (common_fuzz_stuff(afl, tmp_buf, temp_len)) { - - goto abandon_entry; - - } + if (common_fuzz_stuff(afl, tmp_buf, temp_len)) { goto abandon_entry; } } @@ -3885,7 +3881,8 @@ pacemaker_fuzzing: clone_to = rand_below(afl, temp_len); - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), + temp_len + clone_len); /* Head */ @@ -4399,7 +4396,6 @@ u8 fuzz_one(afl_state_t *afl) { return key_val_lv; - #undef BUF_PARAMS } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index b5ae1255..4f1bd041 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -30,10 +30,11 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { - u8 fn[PATH_MAX]; + u8 fn[PATH_MAX]; s32 fd; - snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir, strrchr(q->fname, '/') + 1); + snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir, + strrchr(q->fname, '/') + 1); fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) PFATAL("Unable to create '%s'", fn); @@ -79,7 +80,8 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { q->fs_redundant = state; - sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir, strrchr(q->fname, '/') + 1); + sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir, + strrchr(q->fname, '/') + 1); if (state) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d6403830..7fde2fdc 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -33,7 +33,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, struct rusage rus; unsigned long long int cur_time = get_cur_time(); - u8 fn[PATH_MAX]; + u8 fn[PATH_MAX]; s32 fd; FILE * f; -- 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 'examples/custom_mutators/example.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 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 'examples/custom_mutators/example.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 'examples/custom_mutators/example.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 98545f30aa52c1b82b88e54088848b90e178a929 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 28 Mar 2020 12:59:41 +0100 Subject: code format --- examples/custom_mutators/custom_mutator_helpers.h | 13 ++++++------- examples/custom_mutators/example.c | 6 +++++- include/alloc-inl.h | 9 +++++---- src/afl-fuzz-mutators.c | 6 ++++-- 4 files changed, 20 insertions(+), 14 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h index e5ce3569..0848321f 100644 --- a/examples/custom_mutators/custom_mutator_helpers.h +++ b/examples/custom_mutators/custom_mutator_helpers.h @@ -277,12 +277,13 @@ 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 */ + + 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; @@ -290,6 +291,7 @@ static inline size_t next_pow2(size_t in) { out |= out >> 8; out |= out >> 16; return out + 1; + } /* This function makes sure *size is > size_needed after call. @@ -299,8 +301,7 @@ static inline size_t next_pow2(size_t in) { 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) { +static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { /* No need to realloc */ if (likely(size_needed && *size >= size_needed)) return *buf; @@ -312,9 +313,7 @@ static inline void *maybe_grow(void **buf, size_t *size, size_t next_size = next_pow2(size_needed); /* handle overflow */ - if (!next_size) { - next_size = size_needed; - } + if (!next_size) { next_size = size_needed; } /* alloc */ *buf = realloc(*buf, next_size); diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 488ece81..a9764f5b 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -193,7 +193,8 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, * @return The amount of possible iteration steps to trim the input. * negative on error. */ -int32_t 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; @@ -201,9 +202,12 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) data->cur_step = 0; 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; diff --git a/include/alloc-inl.h b/include/alloc-inl.h index 91564932..4211e398 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -771,7 +771,9 @@ static inline void TRK_ck_free(void *ptr, const char *file, const char *func, @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 */ + + 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; @@ -779,6 +781,7 @@ static inline size_t next_pow2(size_t in) { out |= out >> 8; out |= out >> 16; return out + 1; + } /* This function makes sure *size is > size_needed after call. @@ -804,9 +807,7 @@ static inline void *ck_maybe_grow(void **buf, size_t *size, size_t next_size = next_pow2(size_needed); /* handle overflow */ - if (!next_size) { - next_size = size_needed; - } + if (!next_size) { next_size = size_needed; } /* alloc */ *buf = ck_realloc(*buf, next_size); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 90d7de40..754b2190 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -213,7 +213,8 @@ 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 (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,7 +274,8 @@ 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 (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); -- 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 'examples/custom_mutators/example.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 61ea39861271fd54a193a14d3adbb72c072df75f Mon Sep 17 00:00:00 2001 From: h1994st Date: Mon, 30 Mar 2020 05:21:01 -0400 Subject: Fix heap allocation bug - Reason: `afl->out_size` is not consistent with the actual allocation of `afl->out_buf`. The deleted line in `src/afl-fuzz-one.c` may change `afl->out_size`, but `afl->out_buf` is not changed --- examples/custom_mutators/example.c | 12 ++++++------ src/afl-fuzz-one.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index 7d827029..ec47104d 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -159,13 +159,13 @@ size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t *pre_save_buf = data->pre_save_buf; - memcpy(pre_save_buf + 5, buf, buf_size); + memcpy(pre_save_buf, buf, buf_size); size_t out_buf_size = buf_size + 5; - pre_save_buf[0] = 'A'; - pre_save_buf[1] = 'F'; - pre_save_buf[2] = 'L'; - pre_save_buf[3] = '+'; - pre_save_buf[4] = '+'; + pre_save_buf[buf_size + 0] = 'A'; + pre_save_buf[buf_size + 1] = 'F'; + pre_save_buf[buf_size + 2] = 'L'; + pre_save_buf[buf_size + 3] = '+'; + pre_save_buf[buf_size + 4] = '+'; *out_buf = pre_save_buf; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index b1bbad0a..29dd73ad 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1621,8 +1621,6 @@ custom_mutator_stage: if (unlikely(!mutated_buf)) FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); - if (mutated_size > len) afl->out_size = mutated_size; - if (mutated_size > 0) { if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { @@ -1650,6 +1648,8 @@ custom_mutator_stage: } out_buf = ck_maybe_grow(BUF_PARAMS(out), len); + // ??? (h1994st): this line may be not necessary, as we do not modify the + // content of "out_buf". memcpy(out_buf, in_buf, len); } -- cgit 1.4.1 From c36c34cf9e3c7f34466efbb191100b6ae699091c Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 30 Mar 2020 16:38:51 +0200 Subject: fixed example --- examples/custom_mutators/example.c | 33 ++++++++++++--------------------- src/afl-fuzz-one.c | 6 ++---- 2 files changed, 14 insertions(+), 25 deletions(-) (limited to 'examples/custom_mutators/example.c') diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c index ec47104d..c8200b26 100644 --- a/examples/custom_mutators/example.c +++ b/examples/custom_mutators/example.c @@ -142,34 +142,25 @@ 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) { - if (data->pre_save_size < buf_size + 5) { + uint8_t *pre_save_buf = maybe_grow(BUF_PARAMS(data, pre_save), buf_size + 5); + if (!pre_save_buf) { - data->pre_save_buf = maybe_grow(BUF_PARAMS(data, pre_save), buf_size + 5); - if (!data->pre_save_buf) { - - perror("custom mutator realloc failed."); - *out_buf = NULL; - return 0; - - } - - data->pre_save_size = buf_size + 5; + perror("custom mutator realloc failed."); + *out_buf = NULL; + return 0; } - uint8_t *pre_save_buf = data->pre_save_buf; - - memcpy(pre_save_buf, buf, buf_size); - size_t out_buf_size = buf_size + 5; - pre_save_buf[buf_size + 0] = 'A'; - pre_save_buf[buf_size + 1] = 'F'; - pre_save_buf[buf_size + 2] = 'L'; - pre_save_buf[buf_size + 3] = '+'; - pre_save_buf[buf_size + 4] = '+'; + memcpy(pre_save_buf + 5, buf, buf_size); + 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; + return buf_size + 5; } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c61c9084..2e49e19b 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1647,10 +1647,8 @@ custom_mutator_stage: } - /* `afl->out_buf` is actually not changed in the loop. Since `ck_maybe_grow` - is cheap, we still keep the following line but remove `memcpy`. */ - out_buf = ck_maybe_grow(BUF_PARAMS(out), len); - // memcpy(out_buf, in_buf, len); + /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */ + memcpy(out_buf, in_buf, len); } -- cgit 1.4.1