diff --git a/examples/forking-fuzzer.c b/examples/forking-fuzzer.c index edffc57..213123f 100644 --- a/examples/forking-fuzzer.c +++ b/examples/forking-fuzzer.c @@ -340,7 +340,7 @@ void fuzzer_process_main(llmp_client_t *client, void *data) { /* Check for engine to be configured properly */ if (afl_engine_check_configuration(engine) != AFL_RET_SUCCESS) { FATAL("Engine configured incompletely"); }; /* Now we can simply load the testcases from the directory given */ - AFL_TRY(engine->funcs.load_testcases_from_dir(engine, engine->in_dir, NULL), + AFL_TRY(engine->funcs.load_testcases_from_dir(engine, engine->in_dir), { PFATAL("Error loading testcase dir: %s", afl_ret_stringify(err)); }); OKF("Processed %llu input files.", engine->executions); diff --git a/examples/libaflfuzzer.c b/examples/libaflfuzzer.c index 08ce8e6..b0fed33 100644 --- a/examples/libaflfuzzer.c +++ b/examples/libaflfuzzer.c @@ -438,9 +438,9 @@ void fuzzer_process_main(llmp_client_t *llmp_client, void *data) { afl_feedback_cov_t *coverage_feedback = (afl_feedback_cov_t *)(engine->feedbacks[0]); - engine->funcs.load_testcases_from_dir(engine, queue_dirpath, NULL); // ignore if it fails. + engine->funcs.load_testcases_from_dir(engine, queue_dirpath); // ignore if it fails. /* Now we can simply load the testcases from the directory given */ - AFL_TRY(engine->funcs.load_testcases_from_dir(engine, engine->in_dir, NULL), + AFL_TRY(engine->funcs.load_testcases_from_dir(engine, engine->in_dir), { PFATAL("Error loading testcase dir: %s", afl_ret_stringify(err)); }); /* The actual fuzzing */ diff --git a/include/engine.h b/include/engine.h index fe3f6de..4734105 100644 --- a/include/engine.h +++ b/include/engine.h @@ -51,7 +51,7 @@ struct afl_engine_func { u8 (*execute)(afl_engine_t *, afl_input_t *); afl_ret_t (*handle_new_message)(afl_engine_t *, llmp_message_t *); - afl_ret_t (*load_testcases_from_dir)(afl_engine_t *, char *, afl_input_t *(*custom_input_init)(void)); + afl_ret_t (*load_testcases_from_dir)(afl_engine_t *, char *); void (*load_zero_testcase)(size_t); afl_ret_t (*loop)(afl_engine_t *); @@ -91,7 +91,7 @@ afl_ret_t afl_engine_add_feedback(afl_engine_t *, afl_feedback_t *); void afl_set_global_queue(afl_engine_t *engine, afl_queue_global_t *global_queue); u8 afl_engine_execute(afl_engine_t *, afl_input_t *); -afl_ret_t afl_engine_load_testcases_from_dir(afl_engine_t *, char *, afl_input_t *(*custom_input_init)()); +afl_ret_t afl_engine_load_testcases_from_dir(afl_engine_t *, char *); void afl_engine_load_zero_testcase(size_t); afl_ret_t afl_engine_handle_new_message(afl_engine_t *, llmp_message_t *); diff --git a/include/os.h b/include/os.h index 20002b7..27e40db 100644 --- a/include/os.h +++ b/include/os.h @@ -77,5 +77,10 @@ void afl_proc_suspend(afl_os_t *); void afl_proc_resume(afl_os_t *); afl_exit_t afl_proc_wait(afl_os_t *, bool); +/* Run `handle_file` for each file in the dirpath, recursively. +void *data will be passed to handle_file as 2nd param. +if handle_file returns false, further execution stops. */ +afl_ret_t afl_for_each_file(char *dirpath, bool (*handle_file)(char *filename, void *data), void *data); + #endif diff --git a/src/engine.c b/src/engine.c index 0316769..840968d 100644 --- a/src/engine.c +++ b/src/engine.c @@ -154,116 +154,65 @@ afl_ret_t afl_engine_add_feedback(afl_engine_t *engine, afl_feedback_t *feedback } -afl_ret_t __afl_engine_load_testcases_from_dir(afl_engine_t *engine, char *dirpath, - afl_input_t *(*custom_input_new)(void)) { +static bool afl_engine_handle_single_testcase_load(char *infile, void *data) { - DIR * dir_in = NULL; - struct dirent *dir_ent = NULL; - char infile[PATH_MAX]; - size_t i; - uint32_t ok = 0; + afl_engine_t *engine = (afl_engine_t *)data; - afl_input_t *input; - if (!(dir_in = opendir(dirpath))) { return AFL_RET_FILE_OPEN_ERROR; } - - while ((dir_ent = readdir(dir_in))) { - - if (dir_ent->d_name[0] == '.') { - - continue; // skip anything that starts with '.' - - } - - snprintf((char *)infile, sizeof(infile), "%s/%s", dirpath, dir_ent->d_name); - infile[sizeof(infile) - 1] = '\0'; - - /* TODO: Error handling? */ - struct stat st; - if (access(infile, R_OK) != 0 || stat(infile, &st) != 0) continue; - if (S_ISDIR(st.st_mode)) { - - if (__afl_engine_load_testcases_from_dir(engine, infile, custom_input_new) == AFL_RET_SUCCESS) ok = 1; - continue; - - } - - if (!S_ISREG(st.st_mode)) continue; - - /* TODO: Not sure if this makes any sense at all? */ - if (custom_input_new) { - - input = custom_input_new(); - - } else { - - input = afl_input_new(); + size_t i; - } + afl_input_t *input = afl_input_new(); - if (!input) { + if (!input) { - closedir(dir_in); - if (engine->executor->funcs.destroy_cb) { engine->executor->funcs.destroy_cb(engine->executor); }; + DBG("Error allocating input %s", infile); + return true; - return AFL_RET_ALLOC; + } - } + AFL_TRY(input->funcs.load_from_file(input, infile), { - AFL_TRY(input->funcs.load_from_file(input, infile), { + WARNF("Error loading seed %s: %s", infile, afl_ret_stringify(err)); + free(input); + return true; - WARNF("Error loading seed %s: %s", infile, afl_ret_stringify(err)); - free(input); - continue; + }); - }); + afl_ret_t run_result = engine->funcs.execute(engine, input); - afl_ret_t run_result = engine->funcs.execute(engine, input); + if (run_result == AFL_RET_SUCCESS) { - if (run_result == AFL_RET_SUCCESS) { + if (engine->verbose) OKF("Loaded seed %s", infile); + return true; - if (engine->verbose) OKF("Loaded seed %s", infile); - ok = 1; + } else { - } else { + WARNF("Error loading seed %s", infile); - WARNF("Error loading seed %s", infile); - - } + } - /* We add the corpus to the queue initially for all the feedback queues */ + /* We add the corpus to the queue initially for all the feedback queues */ - for (i = 0; i < engine->feedbacks_count; ++i) { + for (i = 0; i < engine->feedbacks_count; ++i) { - afl_input_t *copy = input->funcs.copy(input); - if (!copy) { return AFL_RET_ERROR_INPUT_COPY; } + afl_entry_t *entry = afl_entry_new(input); + if (!entry) { - afl_entry_t *entry = afl_entry_new(copy); - engine->feedbacks[i]->queue->base.funcs.insert(&engine->feedbacks[i]->queue->base, entry); + DBG("Error allocating entry."); + return true; } - if (run_result == AFL_RET_WRITE_TO_CRASH) { SAYF("Crashing input found in initial corpus\n"); } - - afl_input_delete(input); - input = NULL; + engine->feedbacks[i]->queue->base.funcs.insert(&engine->feedbacks[i]->queue->base, entry); } - closedir(dir_in); + if (run_result == AFL_RET_WRITE_TO_CRASH) { SAYF("Crashing input found in initial corpus\n"); } - if (ok) - return AFL_RET_SUCCESS; - else - return AFL_RET_EMPTY; + return true; } -afl_ret_t afl_engine_load_testcases_from_dir(afl_engine_t *engine, char *dirpath, - afl_input_t *(*custom_input_new)(void)) { - - size_t dir_name_size = strlen(dirpath); - if (dirpath[dir_name_size - 1] == '/') { dirpath[dir_name_size - 1] = 0; } - if (access(dirpath, R_OK | X_OK) != 0) return AFL_RET_FILE_OPEN_ERROR; +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) { @@ -276,7 +225,7 @@ afl_ret_t afl_engine_load_testcases_from_dir(afl_engine_t *engine, char *dirpath } - return __afl_engine_load_testcases_from_dir(engine, dirpath, custom_input_new); + return afl_for_each_file(dirpath, afl_engine_handle_single_testcase_load, (void *)engine); } diff --git a/src/os.c b/src/os.c index b67776c..617d703 100644 --- a/src/os.c +++ b/src/os.c @@ -1,9 +1,12 @@ #include #include #include -#include #include +#include +#include #include +#include +#include #include "os.h" #include "engine.h" @@ -91,3 +94,75 @@ afl_exit_t afl_proc_wait(afl_os_t *afl_os, bool untraced) { } +static afl_ret_t __afl_for_each_file(char *dirpath, bool (*handle_file)(char *filename, void *data), void *data) { + + DIR * dir_in = NULL; + struct dirent *dir_ent = NULL; + char infile[PATH_MAX]; + uint32_t ok = 0; + + if (!(dir_in = opendir(dirpath))) { return AFL_RET_FILE_OPEN_ERROR; } + + while ((dir_ent = readdir(dir_in))) { + + if (dir_ent->d_name[0] == '.') { + + continue; // skip anything that starts with '.' + + } + + snprintf((char *)infile, sizeof(infile), "%s/%s", dirpath, dir_ent->d_name); + infile[sizeof(infile) - 1] = '\0'; + + /* TODO: Error handling? */ + struct stat st; + if (access(infile, R_OK) != 0 || stat(infile, &st) != 0) { continue; } + if (S_ISDIR(st.st_mode)) { + + if (__afl_for_each_file(infile, handle_file, data) == AFL_RET_SUCCESS) { ok = 1; } + continue; + + } + + if (!S_ISREG(st.st_mode)) { continue; } + + if (!handle_file(infile, data)) { + + DBG("Finishing recursive file read"); + break; + + } else { + + ok = 1; + + } + + } + + closedir(dir_in); + + if (ok) { + + return AFL_RET_SUCCESS; + + } else { + + return AFL_RET_EMPTY; + + } + +} + +/* Run `handle_file` for each file in the dirpath, recursively. +void *data will be passed to handle_file as 2nd param. +if handle_file returns false, further execution stops. */ +afl_ret_t afl_for_each_file(char *dirpath, bool (*handle_file)(char *filename, void *data), void *data) { + + size_t dir_name_size = strlen(dirpath); + if (dirpath[dir_name_size - 1] == '/') { dirpath[dir_name_size - 1] = '\0'; } + if (access(dirpath, R_OK | X_OK) != 0) return AFL_RET_FILE_OPEN_ERROR; + + return __afl_for_each_file(dirpath, handle_file, data); + +} +