From b9edfa8e3a767df76cb4ffd576bc1eb91d3fe9bd Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 25 Sep 2020 17:02:12 +0200 Subject: [PATCH] next step for seed initialization --- examples/forking-fuzzer.c | 10 +-- examples/libaflfuzzer.c | 126 +++++++++++++++++++++++++++----------- include/aflpp.h | 6 +- include/input.h | 3 +- include/llmp.h | 2 + include/queue.h | 20 ++++-- src/engine.c | 17 +---- src/llmp.c | 20 ++++++ src/queue.c | 30 ++++++--- src/stage.c | 9 ++- 10 files changed, 170 insertions(+), 73 deletions(-) diff --git a/examples/forking-fuzzer.c b/examples/forking-fuzzer.c index 213123f..ee9b43a 100644 --- a/examples/forking-fuzzer.c +++ b/examples/forking-fuzzer.c @@ -186,18 +186,18 @@ static float timeout_fbck_is_interesting(afl_feedback_t *feedback, afl_executor_ obs_channel_time_t *observer_time = time_fbck->timeout_observer; u32 last_run_time = *observer_time->last_run_time_p; - if (last_run_time == exec_timeout) { + if (last_run_time >= exec_timeout) { afl_input_t *input = fsrv->base.current_input->funcs.copy(fsrv->base.current_input); if (!input) { FATAL("Error creating a copy of input"); } - afl_entry_t *new_entry = afl_entry_new(input); + afl_entry_t *new_entry = afl_entry_new(input, NULL); + new_entry->info->skip_entry = 1; + feedback->queue->base.funcs.insert(&feedback->queue->base, new_entry); return 0.0; - } - - else { + } else { return 0.0; diff --git a/examples/libaflfuzzer.c b/examples/libaflfuzzer.c index 7db673c..02b546e 100644 --- a/examples/libaflfuzzer.c +++ b/examples/libaflfuzzer.c @@ -30,11 +30,12 @@ static u8 *virgin_bits; /* The current client this process works on. We need this for our segfault handler */ static llmp_client_t *current_client = NULL; /* Ptr to the message we're trying to fuzz right now - in case we crash... */ -static llmp_message_t *current_fuzz_input_msg = NULL; -static afl_input_t * current_input = NULL; -static int debug = 0; -static char * queue_dirpath; -static ssize_t calibration_idx = -1; +static llmp_message_t * current_fuzz_input_msg = NULL; +static afl_queue_global_t *global_queue; +static afl_input_t * current_input = NULL; +static int debug = 0; +static char * queue_dirpath; +static ssize_t calibration_idx = -1; typedef struct cur_state { @@ -113,26 +114,31 @@ static afl_ret_t in_memory_fuzzer_initialize(afl_executor_t *executor) { if (LLVMFuzzerInitialize) { LLVMFuzzerInitialize(&in_memory_fuzzer->argc, &in_memory_fuzzer->argv); } - /* TODO - while(calibration_idx > 0) { + global_queue = in_memory_fuzzer->global_queue; - --calibration_idx; - afl_entry_t *queue_entry = global_queue->base.funcs.get_queue_entry((afl_queue_t *)global_queue, calibration_idx); - if (queue_entry && queue_entry->skip_entry == false) { + fprintf(stderr, "Calibration todo %d\n", calibration_idx); + sleep(1); + while (calibration_idx > 0) { - if (afl_stage_run(stage, queue_entry->input) != AFL_RET_SUCCESS) { + --calibration_idx; + fprintf(stderr, "Seed %u\n", calibration_idx); + afl_entry_t *queue_entry = in_memory_fuzzer->global_queue->base.funcs.get_queue_entry( + (afl_queue_t *)in_memory_fuzzer->global_queue, calibration_idx); + if (queue_entry && !queue_entry->info->skip_entry) { - WARNF("Queue entry %d misbehaved, disabling...", calibration_idx); - queue_entry->skip_entry = true; + fprintf(stderr, "Seed %u testing ...\n", calibration_idx); + if (afl_stage_run(in_memory_fuzzer->stage, queue_entry->input, false) != AFL_RET_SUCCESS) { - } + WARNF("Queue entry %d misbehaved, disabling...", calibration_idx); + queue_entry->info->skip_entry = 1; } } - calibration_idx = -1; // we are done - */ + } + + calibration_idx = -1; // we are done return AFL_RET_SUCCESS; @@ -177,6 +183,19 @@ static void handle_timeout(int sig, siginfo_t *info, void *ucontext) { } + if (calibration_idx && global_queue) { + + afl_entry_t *queue_entry = global_queue->base.funcs.get_queue_entry((afl_queue_t *)global_queue, calibration_idx); + + if (queue_entry && !queue_entry->info->skip_entry) { + + WARNF("Seed entry %d timed out, disabling...", calibration_idx); + queue_entry->info->skip_entry = 1; + + } + + } + write_cur_state(current_fuzz_input_msg); current_fuzz_input_msg->tag = LLMP_TAG_TIMEOUT_V1; if (!llmp_client_send(current_client, current_fuzz_input_msg)) { FATAL("Error sending timeout info!"); } @@ -212,6 +231,19 @@ static void handle_crash(int sig, siginfo_t *info, void *ucontext) { } + if (calibration_idx && global_queue) { + + afl_entry_t *queue_entry = global_queue->base.funcs.get_queue_entry((afl_queue_t *)global_queue, calibration_idx); + + if (queue_entry && !queue_entry->info->skip_entry) { + + WARNF("Seed entry %d crashed, disabling...", calibration_idx); + queue_entry->info->skip_entry = 1; + + } + + } + llmp_page_t *current_out_map = shmem2page(¤t_client->out_maps[current_client->out_map_count - 1]); /* TODO: Broker should probably check for sender_dead and restart us? */ current_out_map->sender_dead = true; @@ -355,12 +387,14 @@ u8 execute(afl_engine_t *engine, afl_input_t *input) { } /* This initializes the fuzzer */ -afl_engine_t *initialize_fuzzer(char *in_dir, char *queue_dir, int argc, char *argv[]) { +afl_engine_t *initialize_fuzzer(char *in_dir, char *queue_dir, int argc, char *argv[], u32 instance) { + + (void)(instance); /* Let's create an in-memory executor */ in_memory_executor_t *in_memory_executor = calloc(1, sizeof(in_memory_executor_t)); if (!in_memory_executor) { PFATAL("Unable to allocate mem."); } - if (debug) { + if (debug == 1234) { // TODO FIXME in_memory_executor_init(in_memory_executor, debug_harness_func); @@ -393,21 +427,21 @@ afl_engine_t *initialize_fuzzer(char *in_dir, char *queue_dir, int argc, char *a coverage_feedback_queue->base.funcs.set_dirpath(&coverage_feedback_queue->base, queue_dir); /* Global queue creation */ - afl_queue_global_t *global_queue = afl_queue_global_new(); - if (!global_queue) { FATAL("Error initializing global queue"); } - global_queue->funcs.add_feedback_queue(global_queue, coverage_feedback_queue); - global_queue->base.funcs.set_dirpath(&global_queue->base, queue_dir); + afl_queue_global_t *new_global_queue = afl_queue_global_new(); + if (!new_global_queue) { FATAL("Error initializing global queue"); } + new_global_queue->funcs.add_feedback_queue(new_global_queue, coverage_feedback_queue); + new_global_queue->base.funcs.set_dirpath(&new_global_queue->base, queue_dir); /* Coverage Feedback initialization */ afl_feedback_cov_t *coverage_feedback = afl_feedback_cov_new(coverage_feedback_queue, observer_covmap); if (!coverage_feedback) { FATAL("Error initializing feedback"); } /* Let's build an engine now */ - afl_engine_t *engine = afl_engine_new(&in_memory_executor->base, NULL, global_queue); + afl_engine_t *engine = afl_engine_new(&in_memory_executor->base, NULL, new_global_queue); if (!engine) { FATAL("Error initializing Engine"); } engine->verbose = 1; engine->funcs.add_feedback(engine, &coverage_feedback->base); - engine->funcs.set_global_queue(engine, global_queue); + engine->funcs.set_global_queue(engine, new_global_queue); engine->in_dir = in_dir; engine->funcs.execute = execute; @@ -427,6 +461,8 @@ afl_engine_t *initialize_fuzzer(char *in_dir, char *queue_dir, int argc, char *a if (!stage) { FATAL("Error creating fuzzing stage"); } AFL_TRY(stage->funcs.add_mutator_to_stage(stage, &mutators_havoc->base), { FATAL("Error adding mutator: %s", afl_ret_stringify(err)); }); + in_memory_executor->stage = stage; + in_memory_executor->global_queue = new_global_queue; /* Now add the testcases */ /* first we want to support restarts and read the queue */ @@ -456,7 +492,7 @@ afl_engine_t *initialize_fuzzer(char *in_dir, char *queue_dir, int argc, char *a input->bytes[input_len] = 0; - afl_entry_t *new_entry = afl_entry_new(input); + afl_entry_t *new_entry = afl_entry_new(input, NULL); if (!new_entry) { FATAL("Could not create new entry"); } engine->global_queue->base.funcs.insert(&engine->global_queue->base, new_entry); @@ -633,22 +669,22 @@ bool broker_message_hook(llmp_broker_t *broker, llmp_broker_clientdata_t *client DBG("We found a timeout..."); /* write timeout output */ state = LLMP_MSG_BUF_AS(msg, cur_state_t); - if (state->calibration_idx < calibration_idx) calibration_idx = state->calibration_idx; - /* - if (state->calibration_idx >= 0) { - afl_entry_t *queue_entry = global_queue->base.funcs.get_queue_entry((afl_queue_t *)global_queue, - calibration_idx); if (queue_entry && queue_entry->skip_entry == false) { if (afl_stage_run(stage, - queue_entry->input) != AFL_RET_SUCCESS) { WARNF("Queue entry %d misbehaved, disabling...", calibration_idx); - queue_entry->skip_entry = true; + if (state->calibration_idx < calibration_idx) { calibration_idx = state->calibration_idx; } + if (state->calibration_idx >= 0) { - } + afl_entry_t *queue_entry = + global_queue->base.funcs.get_queue_entry((afl_queue_t *)global_queue, state->calibration_idx); - } + if (queue_entry && !queue_entry->info->skip_entry) { - } + WARNF("Seed entry %d timed out, disabling...", state->calibration_idx); + queue_entry->info->skip_entry = 1; + + } + + } - */ afl_input_t timeout_input = {0}; AFL_TRY(afl_input_init(&timeout_input), { FATAL("Error initializing input for crash: %s", afl_ret_stringify(err)); }); @@ -679,7 +715,22 @@ bool broker_message_hook(llmp_broker_t *broker, llmp_broker_clientdata_t *client DBG("We found a crash!"); /* write crash output */ state = LLMP_MSG_BUF_AS(msg, cur_state_t); + if (state->calibration_idx < calibration_idx) calibration_idx = state->calibration_idx; + if (state->calibration_idx >= 0) { + + afl_entry_t *queue_entry = + global_queue->base.funcs.get_queue_entry((afl_queue_t *)global_queue, state->calibration_idx); + + if (queue_entry && !queue_entry->info->skip_entry) { + + WARNF("Seed entry %d crashed, disabling...", state->calibration_idx); + queue_entry->info->skip_entry = 1; + + } + + } + afl_input_t crashing_input = {0}; AFL_TRY(afl_input_init(&crashing_input), { FATAL("Error initializing input for crash: %s", afl_ret_stringify(err)); }); @@ -781,7 +832,7 @@ int main(int argc, char **argv) { for (i = 0; i < thread_count; i++) { - afl_engine_t *engine = initialize_fuzzer(in_dir, queue_dirpath, argc, argv); + afl_engine_t *engine = initialize_fuzzer(in_dir, queue_dirpath, argc, argv, thread_count); if (!engine) { FATAL("Error initializing fuzzing engine"); } engines[i] = engine; @@ -813,6 +864,7 @@ int main(int argc, char **argv) { - all fuzzer instances (using fork()) */ llmp_broker_launch_clientloops(llmp_broker); + global_queue = afl_queue_global_new(); OKF("%u client%s started running.", thread_count, thread_count == 1 ? "" : "s"); sleep(1); diff --git a/include/aflpp.h b/include/aflpp.h index 3b96217..0afa87a 100644 --- a/include/aflpp.h +++ b/include/aflpp.h @@ -137,18 +137,20 @@ afl_ret_t fsrv_start(afl_executor_t *fsrv_executor); /* Function ptr for the harness */ typedef afl_exit_t (*harness_function_type)(afl_executor_t *executor, u8 *, size_t); -typedef struct in_memeory_executor { +typedef struct in_memory_executor { afl_executor_t base; harness_function_type harness; char ** argv; // These are to support the libfuzzer harnesses int argc; // To support libfuzzer harnesses + afl_stage_t * stage; + afl_queue_global_t * global_queue; } in_memory_executor_t; afl_exit_t in_memory_run_target(afl_executor_t *executor); u8 in_mem_executor_place_input(afl_executor_t *executor, afl_input_t *input); -void in_memory_executor_init(in_memory_executor_t *in_memeory_executor, harness_function_type harness); +void in_memory_executor_init(in_memory_executor_t *in_memory_executor, harness_function_type harness); #endif diff --git a/include/input.h b/include/input.h index b31f32f..a7d714f 100644 --- a/include/input.h +++ b/include/input.h @@ -50,8 +50,7 @@ struct afl_input_funcs { struct afl_input { u8 * bytes; // Raw input bytes - size_t len; // Length of the input field. C++ had strings, we have to make do - // with storing the lengths :/ + size_t len; // Length of the input struct afl_input_funcs funcs; diff --git a/include/llmp.h b/include/llmp.h index d29c66b..def28ff 100644 --- a/include/llmp.h +++ b/include/llmp.h @@ -210,6 +210,8 @@ struct llmp_broker_client_metadata { int pid; /* the client loop function */ llmp_clientloop_func clientloop; + /* the engine */ + afl_engine_t *engine; /* Additional data for this client loop */ void *data; diff --git a/include/queue.h b/include/queue.h index ced29c0..94ed434 100644 --- a/include/queue.h +++ b/include/queue.h @@ -56,10 +56,20 @@ struct afl_entry_funcs { }; +typedef struct __attribute__((__packed__)) afl_entry_info { + + u64 hash, exec_us; + u32 bytes_set, bits_set; + u8 trimmed, has_new_coverage, variable, skip_entry; + +} afl_entry_info_t; + struct afl_entry { + afl_entry_info_t *info; afl_input_t * input; - bool on_disk; + u8 * map; + bool on_disk, info_calloc; char filename[FILENAME_LEN_MAX]; struct afl_queue *queue; struct afl_entry *next; @@ -70,10 +80,13 @@ struct afl_entry { }; -afl_ret_t afl_entry_init(afl_entry_t *, afl_input_t *); +afl_ret_t afl_entry_init(afl_entry_t *, afl_input_t *, afl_entry_info_t *); void afl_entry_deinit(afl_entry_t *); -AFL_NEW_AND_DELETE_FOR_WITH_PARAMS(afl_entry, AFL_DECL_PARAMS(afl_input_t *input), AFL_CALL_PARAMS(input)) +AFL_NEW_AND_DELETE_FOR_WITH_PARAMS(afl_entry, AFL_DECL_PARAMS(afl_input_t *input, afl_entry_info_t *info), + AFL_CALL_PARAMS(input, info)) +// AFL_NEW_AND_DELETE_FOR_WITH_PARAMS(afl_queue_feedback, AFL_DECL_PARAMS(afl_feedback_t *feedback, char *name), +// AFL_CALL_PARAMS(feedback, name)); // Default implementations for the functions for queue_entry vtable afl_input_t *afl_entry_get_input(afl_entry_t *entry); @@ -115,7 +128,6 @@ struct afl_queue { size_t names_id; bool save_to_files; bool fuzz_started; - bool skip_entry; struct afl_queue_funcs funcs; }; diff --git a/src/engine.c b/src/engine.c index 985cce1..cc7c8aa 100644 --- a/src/engine.c +++ b/src/engine.c @@ -211,7 +211,7 @@ static bool afl_engine_handle_single_testcase_load(char *infile, void *data) { this is usually not a good idea.\n"); } */ /* We add the corpus to the global queue */ - afl_entry_t *entry = afl_entry_new(input); + afl_entry_t *entry = afl_entry_new(input, NULL); if (!entry) { DBG("Error allocating entry."); @@ -228,17 +228,6 @@ static bool afl_engine_handle_single_testcase_load(char *infile, void *data) { afl_ret_t afl_engine_load_testcases_from_dir(afl_engine_t *engine, char *dirpath) { - /* Since, this'll be the first execution, Let's start up the executor here */ - if ((engine->executions == 0) && engine->executor->funcs.init_cb) { - - AFL_TRY(engine->executor->funcs.init_cb(engine->executor), { - - return err; - - }); - - } - return afl_for_each_file(dirpath, afl_engine_handle_single_testcase_load, (void *)engine); } @@ -257,9 +246,9 @@ afl_ret_t afl_engine_handle_new_message(afl_engine_t *engine, llmp_message_t *ms input->bytes = msg->buf; input->len = msg->buf_len; - if (!input) { FATAL("Error creating a copy of input"); } + afl_entry_info_t *info_ptr = (afl_entry_info_t *)((u8 *)(msg->buf + msg->buf_len)); - afl_entry_t *new_entry = afl_entry_new(input); + afl_entry_t *new_entry = afl_entry_new(input, info_ptr); /* Users can experiment here, adding entries to different queues based on * the message tag. Right now, let's just add it to all queues*/ diff --git a/src/llmp.c b/src/llmp.c index 807f2af..a137967 100644 --- a/src/llmp.c +++ b/src/llmp.c @@ -786,6 +786,25 @@ static void *_llmp_client_wrapped_loop(void *llmp_client_broker_metadata_ptr) { /* Before doing anything else:, notify registered hooks about the new page we're about to use */ llmp_client_trigger_new_out_page_hooks(metadata->client_state); + if (metadata->data && (unsigned long int) metadata->data > 0x10000) { + + afl_engine_t *engine = (afl_engine_t *)metadata->data; + + if (engine->executor->funcs.init_cb) { + + DBG("Client init"); + + AFL_TRY(engine->executor->funcs.init_cb(engine->executor), { + + FATAL("could not execute custom init function of the child"); + + }); + + } + + } + + DBG("Client looping"); metadata->clientloop(metadata->client_state, metadata->data); WARNF("Client loop exited for client %d", metadata->client_state->id); @@ -831,6 +850,7 @@ bool llmp_broker_launch_client(llmp_broker_t *broker, llmp_broker_clientdata_t * /* in the child, start loop, exit afterwards. */ DBG("LLMP child process started"); + DBG("Fork child loop"); _llmp_client_wrapped_loop(clientdata); DBG("Fork child loop exited"); exit(1); diff --git a/src/queue.c b/src/queue.c index 5f1ecb8..21707d9 100644 --- a/src/queue.c +++ b/src/queue.c @@ -35,11 +35,20 @@ #include "config.h" // We start with the implementation of queue_entry functions here. -afl_ret_t afl_entry_init(afl_entry_t *entry, afl_input_t *input) { +afl_ret_t afl_entry_init(afl_entry_t *entry, afl_input_t *input, afl_entry_info_t *info) { entry->input = input; - entry->skip_entry = false; - memset(entry->filename, 0, FILENAME_LEN_MAX); + if (!info) { + + entry->info = calloc(1, sizeof(afl_entry_info_t)); + if (!entry->info) { return AFL_RET_ALLOC; } + entry->info_calloc = 1; + + } else { + + entry->info = info; + + } entry->funcs.get_input = afl_entry_get_input; entry->funcs.get_next = afl_entry_get_next; @@ -58,14 +67,21 @@ void afl_entry_deinit(afl_entry_t *entry) { if (entry->prev) { entry->prev->next = entry->next; } + /* we also delete the input associated with it */ + entry->input->funcs.delete(entry->input); + + /* and the info structure */ + if (entry->info_calloc) { free(entry->info); } + + /* + // Unneeded as the structure is free'd via the macro entry->next = NULL; entry->prev = NULL; entry->queue = NULL; entry->parent = NULL; - - /* we also delete the input associated with it */ - entry->input->funcs.delete(entry->input); + entry->info = NULL; entry->input = NULL; + */ } @@ -281,7 +297,7 @@ afl_entry_t *afl_queue_next_base_queue(afl_queue_t *queue, int engine_id) { afl_entry_t *current = queue->entries[queue->current]; - if (engine_id != queue->engine_id && current->skip_entry == false) { return current; } + if (engine_id != queue->engine_id && current->info->skip_entry) { return current; } // If some other engine grabs from the queue, don't update the queue's // current entry diff --git a/src/stage.c b/src/stage.c index 8629d09..5746ad1 100644 --- a/src/stage.c +++ b/src/stage.c @@ -157,7 +157,7 @@ afl_ret_t afl_stage_perform(afl_stage_t *stage, afl_input_t *input) { if (interestingness >= 0.5) { /* TODO: Use queue abstraction instead */ - llmp_message_t *msg = llmp_client_alloc_next(stage->engine->llmp_client, copy->len); + llmp_message_t *msg = llmp_client_alloc_next(stage->engine->llmp_client, copy->len + sizeof(afl_entry_info_t)); if (!msg) { DBG("Error allocating llmp message"); @@ -166,6 +166,11 @@ afl_ret_t afl_stage_perform(afl_stage_t *stage, afl_input_t *input) { } memcpy(msg->buf, copy->bytes, copy->len); + + /* TODO FIXME - here we fill in the entry info structure on the queue */ + // afl_entry_info_t *info_ptr = (afl_entry_info_t*)((u8*)(msg->buf + copy->len)); + // e.g. fill map hash + msg->tag = LLMP_TAG_NEW_QUEUE_ENTRY_V1; if (!llmp_client_send(stage->engine->llmp_client, msg)) { @@ -189,7 +194,7 @@ afl_ret_t afl_stage_perform(afl_stage_t *stage, afl_input_t *input) { if (!input_copy) { return AFL_RET_ERROR_INPUT_COPY; } - afl_entry_t *entry = afl_entry_new(input_copy); + afl_entry_t *entry = afl_entry_new(input_copy, NULL); if (!entry) { return AFL_RET_ALLOC; }