diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/afl-forkserver.c | 140 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 32 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 23 | ||||
-rw-r--r-- | src/afl-fuzz.c | 157 |
4 files changed, 343 insertions, 9 deletions
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index b871ea8c..6604de3a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -71,6 +71,17 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { void afl_fsrv_init(afl_forkserver_t *fsrv) { +#ifdef __linux__ + fsrv->nyx_handlers = NULL; + fsrv->out_dir_path = NULL; + fsrv->nyx_mode = 0; + fsrv->nyx_parent = false; + fsrv->nyx_standalone = false; + fsrv->nyx_runner = NULL; + fsrv->nyx_id = 0xFFFFFFFF; + fsrv->nyx_bind_cpu_id = 0xFFFFFFFF; +#endif + // this structure needs default so we initialize it if this was not done // already fsrv->out_fd = -1; @@ -375,6 +386,72 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, s32 rlen; char *ignore_autodict = getenv("AFL_NO_AUTODICT"); +#ifdef __linux__ + if (fsrv->nyx_mode) { + + if(fsrv->nyx_runner != NULL){ + return; + } + + if (!be_quiet) { ACTF("Spinning up the NYX backend..."); } + + if(fsrv->out_dir_path == NULL){ + FATAL("Nyx workdir path not found..."); + } + + char *x = alloc_printf("%s/workdir", fsrv->out_dir_path); + + if(fsrv->nyx_id == 0xFFFFFFFF){ + FATAL("Nyx ID is not set..."); + } + + if(fsrv->nyx_bind_cpu_id == 0xFFFFFFFF){ + FATAL("Nyx CPU ID is not set..."); + } + + if (fsrv->nyx_parent){ + fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(fsrv->target_path, x, fsrv->nyx_id, fsrv->nyx_bind_cpu_id, !fsrv->nyx_standalone); + } + else{ + fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(fsrv->target_path, x, fsrv->nyx_id, fsrv->nyx_bind_cpu_id, true); + } + + if(fsrv->nyx_runner == NULL){ + FATAL("Something went wrong ..."); + } + + fsrv->map_size = fsrv->nyx_handlers->nyx_get_bitmap_buffer_size(fsrv->nyx_runner);; + fsrv->real_map_size = fsrv->map_size; + + fsrv->trace_bits = fsrv->nyx_handlers->nyx_get_bitmap_buffer(fsrv->nyx_runner); + + fsrv->nyx_handlers->nyx_option_set_reload_mode(fsrv->nyx_runner, getenv("NYX_DISABLE_SNAPSHOT_MODE") == NULL); + fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner); + + fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, 2, 0); + fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner); + + /* dry run */ + fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, "INIT", 4); + switch(fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)){ + case Abort: + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + FATAL("Error: Nyx abort occured..."); + break; + case IoError: + FATAL("Error: QEMU-Nyx has died..."); + break; + case Error: + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + FATAL("Error: Nyx runtime error has occured..."); + break; + default: + break; + } + return; + } +#endif + if (!be_quiet) { ACTF("Spinning up the fork server..."); } #ifdef AFL_PERSISTENT_RECORD @@ -1085,6 +1162,11 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) { fsrv->fsrv_pid = -1; fsrv->child_pid = -1; +#ifdef __linux__ + if(fsrv->nyx_mode){ + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } +#endif } /* Get the map size from the target forkserver */ @@ -1101,6 +1183,12 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv, void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { +#ifdef __linux__ + if(fsrv->nyx_mode){ + fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, buf, len); + return; + } +#endif #ifdef AFL_PERSISTENT_RECORD if (unlikely(fsrv->persistent_record)) { @@ -1214,12 +1302,62 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, u32 exec_ms; u32 write_value = fsrv->last_run_timed_out; +#ifdef __linux__ + if(fsrv->nyx_mode){ + + static uint32_t last_timeout_value = 0; + + if (last_timeout_value != timeout){ + fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, timeout/1000, (timeout%1000) * 1000); + fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner); + last_timeout_value = timeout; + } + + enum NyxReturnValue ret_val = fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner); + + fsrv->total_execs++; + + switch(ret_val){ + case Normal: + return FSRV_RUN_OK; + case Crash: + case Asan: + return FSRV_RUN_CRASH; + case Timout: + return FSRV_RUN_TMOUT; + case InvalidWriteToPayload: + /* ??? */ + FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing"); + break; + case Abort: + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + FATAL("Error: Nyx abort occured..."); + case IoError: + if (*stop_soon_p){ + return 0; + } + else{ + FATAL("Error: QEMU-Nyx has died..."); + } + break; + case Error: + FATAL("Error: Nyx runtime error has occured..."); + break; + } + return FSRV_RUN_OK; + } +#endif /* After this memset, fsrv->trace_bits[] are effectively volatile, so we must prevent any earlier operations from venturing into that territory. */ +#ifdef __linux__ + if(!fsrv->nyx_mode){ + memset(fsrv->trace_bits, 0, fsrv->map_size); + } +#else memset(fsrv->trace_bits, 0, fsrv->map_size); - +#endif MEM_BARRIER(); /* we have the fork server (or faux server) up and running diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 7a8bd674..b6de3712 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -411,7 +411,11 @@ void bind_to_free_cpu(afl_state_t *afl) { OKF("Found a free CPU core, try binding to #%u.", i); if (bind_cpu(afl, i)) { - +#ifdef __linux__ + if(afl->fsrv.nyx_mode){ + afl->fsrv.nyx_bind_cpu_id = i; + } +#endif /* Success :) */ break; @@ -1090,6 +1094,11 @@ void perform_dry_run(afl_state_t *afl) { FATAL("Unable to execute target application ('%s')", afl->argv[0]); case FSRV_RUN_NOINST: +#ifdef __linux__ + if(afl->fsrv.nyx_mode && afl->fsrv.nyx_runner != NULL){ + afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner); + } +#endif FATAL("No instrumentation detected"); case FSRV_RUN_NOBITS: @@ -2443,6 +2452,11 @@ void fix_up_sync(afl_state_t *afl) { x = alloc_printf("%s/%s", afl->out_dir, afl->sync_id); +#ifdef __linux__ + if(afl->fsrv.nyx_mode){ + afl->fsrv.out_dir_path = afl->out_dir; + } +#endif afl->sync_dir = afl->out_dir; afl->out_dir = x; @@ -2580,6 +2594,19 @@ void check_binary(afl_state_t *afl, u8 *fname) { if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { afl->fsrv.target_path = ck_strdup(fname); +#ifdef __linux__ + if(afl->fsrv.nyx_mode){ + /* check if target_path is a nyx sharedir */ + if (stat(afl->fsrv.target_path, &st) || S_ISDIR(st.st_mode)){ + char* tmp = alloc_printf("%s/config.ron", afl->fsrv.target_path); + if (stat(tmp, &st) || S_ISREG(st.st_mode)){ + free(tmp); + return; + } + } + FATAL("Directory '%s' not found or is not a nyx share directory", afl->fsrv.target_path); + } +#endif if (stat(afl->fsrv.target_path, &st) || !S_ISREG(st.st_mode) || !(st.st_mode & 0111) || (f_len = st.st_size) < 4) { @@ -2719,6 +2746,9 @@ void check_binary(afl_state_t *afl, u8 *fname) { #endif /* ^!__APPLE__ */ if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode && +#ifdef __linux__ + !afl->fsrv.nyx_mode && +#endif !afl->fsrv.cs_mode && !afl->non_instrumented_mode && !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 289f7e09..5f035762 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -679,12 +679,25 @@ void show_stats(afl_state_t *afl) { banner_pad = (79 - banner_len) / 2; memset(banner, ' ', banner_pad); - sprintf(banner + banner_pad, - "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", - afl->crash_mode ? cPIN "peruvian were-rabbit" - : cYEL "american fuzzy lop", - si, afl->use_banner, afl->power_name); +#ifdef __linux__ + if(afl->fsrv.nyx_mode){ + sprintf(banner + banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx", + afl->crash_mode ? cPIN "peruvian were-rabbit" + : cYEL "american fuzzy lop", + si, afl->use_banner, afl->power_name); + } + else{ +#endif + sprintf(banner + banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", + afl->crash_mode ? cPIN "peruvian were-rabbit" + : cYEL "american fuzzy lop", + si, afl->use_banner, afl->power_name); +#ifdef __linux__ + } +#endif } SAYF("\n%s\n", banner); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f52637f5..7ab2c60e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -124,6 +124,8 @@ static void usage(u8 *argv0, int more_help) { " -W - use qemu-based instrumentation with Wine (Wine " "mode)\n" #endif + " -X - use VM fuzzing (NYX mode)\n" + " -Y - use VM fuzzing (NYX mode - Multiprocessing)\n" "\n" "Mutator settings:\n" @@ -385,6 +387,75 @@ static void fasan_check_afl_preload(char *afl_preload) { } +#ifdef __linux__ +#include <dlfcn.h> + +nyx_plugin_handler_t* afl_load_libnyx_plugin(u8* libnyx_binary){ + void *handle; + nyx_plugin_handler_t* plugin = calloc(1, sizeof(nyx_plugin_handler_t)); + + ACTF("Trying to load libnyx.so plugin..."); + handle = dlopen((char*) libnyx_binary, RTLD_NOW); + if (!handle) { + goto fail; + } + + plugin->nyx_new = dlsym(handle, "nyx_new"); + if (plugin->nyx_new == NULL){ + goto fail; + } + + plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown"); + if (plugin->nyx_shutdown == NULL){ + goto fail; + } + + plugin->nyx_option_set_reload_mode = dlsym(handle, "nyx_option_set_reload_mode"); + if (plugin->nyx_option_set_reload_mode == NULL){ + goto fail; + } + + plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout"); + if (plugin->nyx_option_set_timeout == NULL){ + goto fail; + } + + plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply"); + if (plugin->nyx_option_apply == NULL){ + goto fail; + } + + plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input"); + if (plugin->nyx_set_afl_input == NULL){ + goto fail; + } + + plugin->nyx_exec = dlsym(handle, "nyx_exec"); + if (plugin->nyx_exec == NULL){ + goto fail; + } + + plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer"); + if (plugin->nyx_get_bitmap_buffer == NULL){ + goto fail; + } + + plugin->nyx_get_bitmap_buffer_size = dlsym(handle, "nyx_get_bitmap_buffer_size"); + if (plugin->nyx_get_bitmap_buffer_size == NULL){ + goto fail; + } + + OKF("libnyx plugin is ready!"); + return plugin; + + fail: + + FATAL("failed to load libnyx: %s\n", dlerror()); + free(plugin); + return NULL; +} +#endif + /* Main entry point */ int main(int argc, char **argv_orig, char **envp) { @@ -441,7 +512,7 @@ int main(int argc, char **argv_orig, char **envp) { while ((opt = getopt( argc, argv, - "+Ab:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > + "+Ab:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOXYo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { switch (opt) { @@ -845,6 +916,36 @@ int main(int argc, char **argv_orig, char **envp) { afl->use_banner = optarg; break; +#ifdef __linux__ + case 'X': /* NYX mode */ + + if (afl->fsrv.nyx_mode) { + FATAL("Multiple -X options not supported"); + + } + + afl->fsrv.nyx_parent = true; + afl->fsrv.nyx_standalone = true; + afl->fsrv.nyx_mode = 1; + afl->fsrv.nyx_id = 0; + + break; + + case 'Y': /* NYX distributed mode */ + if (afl->fsrv.nyx_mode) { + + FATAL("Multiple -X options not supported"); + + } + afl->fsrv.nyx_mode = 1; + + break; +#else + case 'X': + case 'Y': + FATAL("Nyx mode is only availabe on linux..."); + break; +#endif case 'A': /* CoreSight mode */ #if !defined(__aarch64__) || !defined(__linux__) @@ -1185,6 +1286,13 @@ int main(int argc, char **argv_orig, char **envp) { OKF("NOTE: This is v3.x which changes defaults and behaviours - see " "README.md"); +#ifdef __linux__ + if (afl->fsrv.nyx_mode){ + OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)"); + OKF("Nyx is open source, get it at " + "https://github.com/Nyx-Fuzz"); + } +#endif if (afl->sync_id && afl->is_main_node && afl->afl_env.afl_custom_mutator_only) { @@ -1227,6 +1335,33 @@ int main(int argc, char **argv_orig, char **envp) { } +#ifdef __linux__ + if (afl->fsrv.nyx_mode) { + + if (afl->fsrv.nyx_standalone && strncmp(afl->sync_id, "default", strlen("default")) != 0){ + FATAL("distributed fuzzing is not supported in this Nyx mode (use -Y instead)"); + } + + if (!afl->fsrv.nyx_standalone){ + if (afl->is_main_node){ + if(strncmp("0", afl->sync_id, strlen("0") != 0)){ + FATAL("afl->sync_id has to be 0 in Nyx mode (-M 0)"); + } + afl->fsrv.nyx_id = 0; + } + + if (afl->is_secondary_node){ + long nyx_id = strtol(afl->sync_id, NULL, 10); + + if (nyx_id == 0 || nyx_id == LONG_MAX){ + FATAL("afl->sync_id has to be numberic and >= 1 (-S id)"); + } + afl->fsrv.nyx_id = nyx_id; + } + } + } +#endif + if (afl->sync_id) { if (strlen(afl->sync_id) > 24) { @@ -1450,8 +1585,22 @@ int main(int argc, char **argv_orig, char **envp) { afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver; +#ifdef __linux__ + if (!afl->fsrv.nyx_mode){ + check_crash_handling(); + check_cpu_governor(afl); + } + else{ + u8* libnyx_binary = find_afl_binary(argv[0], "nyx_mode/libnyx.so"); + afl->fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); + if(afl->fsrv.nyx_handlers == NULL){ + FATAL("failed to initialize libnyx.so..."); + } + } +#else check_crash_handling(); check_cpu_governor(afl); +#endif if (getenv("LD_PRELOAD")) { @@ -1934,7 +2083,11 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->queue_buf[entry]->disabled) { ++valid_seeds; } if (!afl->pending_not_fuzzed || !valid_seeds) { - +#ifdef __linux__ + if(afl->fsrv.nyx_mode){ + afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner); + } +#endif FATAL("We need at least one valid input seed that does not crash!"); } |