From eefd98f3741b5feca32c75b34a8d7b33e34044d0 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Fri, 14 Apr 2023 02:25:33 +0200 Subject: add Nyx support in various tools (like afl-cmin) --- src/afl-showmap.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 3 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 29abeb13..3ddebaad 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -434,6 +434,20 @@ static u32 read_file(u8 *in_file) { } +#ifdef __linux__ +/* Execute the target application with an empty input (in Nyx mode). */ +static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) { + + afl_fsrv_write_to_testcase(fsrv, NULL, 0); + + if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) == + FSRV_RUN_ERROR) { + + FATAL("Error running target in Nyx mode"); + } +} +#endif + /* Execute target application. */ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { @@ -797,6 +811,7 @@ static void usage(u8 *argv0) { " -W - use qemu-based instrumentation with Wine (Wine mode)\n" " (Not necessary, here for consistency with other afl-* " "tools)\n" + " -X - use Nyx mode\n" #endif "\n" "Other settings:\n" @@ -875,7 +890,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshX")) > 0) { switch (opt) { @@ -1063,6 +1078,22 @@ int main(int argc, char **argv_orig, char **envp) { break; + #ifdef __linux__ + case 'X': /* NYX mode */ + + if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } + + fsrv->nyx_mode = 1; + fsrv->nyx_parent = true; + fsrv->nyx_standalone = true; + + break; + #else + case 'X': + FATAL("Nyx mode is only availabe on linux..."); + break; + #endif + case 'b': /* Secret undocumented mode. Writes output in raw binary format @@ -1134,7 +1165,17 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); +#ifdef __linux__ + if(!fsrv->nyx_mode){ + fsrv->target_path = find_binary(argv[optind]); + } + else{ + fsrv->target_path = ck_strdup(argv[optind]); + } +#else fsrv->target_path = find_binary(argv[optind]); +#endif + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); if (!quiet_mode) { @@ -1190,6 +1231,26 @@ int main(int argc, char **argv_orig, char **envp) { use_argv = get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); +#ifdef __linux__ + } else if (fsrv->nyx_mode) { + + use_argv = ck_alloc(sizeof(char *) * (1)); + use_argv[0] = argv[0]; + + fsrv->nyx_id = 0; + + u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so"); + fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); + if (fsrv->nyx_handlers == NULL) { + + FATAL("failed to initialize libnyx.so..."); + + } + + fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_bind_cpu_id = 0; +#endif + } else { use_argv = argv + optind; @@ -1226,7 +1287,13 @@ int main(int argc, char **argv_orig, char **envp) { } +#ifdef __linux__ + if(!fsrv->nyx_mode && in_dir){ + (void)check_binary_signatures(fsrv->target_path); + } +#else if (in_dir) { (void)check_binary_signatures(fsrv->target_path); } +#endif shm_fuzz = ck_alloc(sizeof(sharedmem_t)); @@ -1247,7 +1314,13 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->shmem_fuzz = map + sizeof(u32); configure_afl_kill_signals( - fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM); + fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode + #ifdef __linux__ + || fsrv->nyx_mode + #endif + ) + ? SIGKILL + : SIGTERM); if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) { @@ -1370,6 +1443,12 @@ int main(int argc, char **argv_orig, char **envp) { if (execute_testcases(in_dir) == 0) { +#ifdef __linux__ + if (fsrv->nyx_mode) { + remove_nyx_tmp_workdir(fsrv->out_dir_path); + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } +#endif FATAL("could not read input testcases from %s", in_dir); } @@ -1390,7 +1469,15 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - showmap_run_target(fsrv, use_argv); +#ifdef __linux__ + if(!fsrv->nyx_mode){ +#endif + showmap_run_target(fsrv, use_argv); +#ifdef __linux__ + } else { + showmap_run_target_nyx_mode(fsrv); + } +#endif tcnt = write_results_to_file(fsrv, out_file); if (!quiet_mode) { @@ -1441,6 +1528,12 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->target_path) { ck_free(fsrv->target_path); } +#ifdef __linux__ + if (fsrv->nyx_mode) { + remove_nyx_tmp_workdir(fsrv->out_dir_path); + } +#endif + afl_fsrv_deinit(fsrv); if (stdin_file) { ck_free(stdin_file); } -- cgit 1.4.1 From 059d470e8dd0a5339daefe0842f4ad5014717838 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Sun, 16 Apr 2023 04:42:09 +0200 Subject: improved Nyx tmp dir handling (additional sanity checks) --- include/forkserver.h | 2 ++ src/afl-analyze.c | 7 +--- src/afl-forkserver.c | 97 +++++++++++++++++++++++++++++++++++----------------- src/afl-fuzz.c | 8 ----- src/afl-showmap.c | 13 +------ src/afl-tmin.c | 7 +--- 6 files changed, 71 insertions(+), 63 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/include/forkserver.h b/include/forkserver.h index 7cbad8c8..ba280d38 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -190,6 +190,8 @@ typedef struct afl_forkserver { u32 nyx_id; /* nyx runner id (0 -> master) */ u32 nyx_bind_cpu_id; /* nyx runner cpu id */ char *nyx_aux_string; + bool nyx_use_tmp_workdir; + char *nyx_tmp_workdir_path; #endif } afl_forkserver_t; diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 0bdadfdc..0a4e7fb5 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -1058,7 +1058,7 @@ int main(int argc, char **argv_orig, char **envp) { FATAL("failed to initialize libnyx.so..."); } - fsrv.out_dir_path = create_nyx_tmp_workdir(); + fsrv.nyx_use_tmp_workdir = true; fsrv.nyx_bind_cpu_id = 0; use_argv = argv + optind; @@ -1119,11 +1119,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); -#ifdef __linux__ - if (fsrv.nyx_mode) { - remove_nyx_tmp_workdir(fsrv.out_dir_path); - } -#endif afl_shm_deinit(&shm); afl_fsrv_deinit(&fsrv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index ae2adc3d..0e705c63 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -126,11 +126,39 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { fail: FATAL("failed to load libnyx: %s\n", dlerror()); - free(plugin); + ck_free(plugin); return NULL; } +void afl_nyx_runner_kill(afl_forkserver_t *fsrv){ + if (fsrv->nyx_mode) { + + if (fsrv->nyx_aux_string){ + ck_free(fsrv->nyx_aux_string); + } + + /* check if we actually got a valid nyx runner */ + if (fsrv->nyx_runner) { + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } + + /* if we have use a tmp work dir we need to remove it */ + if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) { + remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path); + } + } +} + +/* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp + * files) before exiting. Used before "afl_fsrv_killall()" is registered as + * an atexit() handler. */ +#define NYX_PRE_FATAL(fsrv, x...) \ + do { \ + afl_nyx_runner_kill(fsrv); \ + FATAL(x); \ + } while (0) + #endif /** @@ -168,6 +196,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->nyx_runner = NULL; fsrv->nyx_id = 0xFFFFFFFF; fsrv->nyx_bind_cpu_id = 0xFFFFFFFF; + fsrv->nyx_use_tmp_workdir = false; + fsrv->nyx_tmp_workdir_path = NULL; #endif // this structure needs default so we initialize it if this was not done @@ -481,21 +511,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the NYX backend..."); } - if (fsrv->out_dir_path == NULL) { FATAL("Nyx workdir path not found..."); } + if (fsrv->nyx_use_tmp_workdir){ + fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir(); + fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path; + } else { + if (fsrv->out_dir_path == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); } + } - char *x = alloc_printf("%s/workdir", fsrv->out_dir_path); + char *workdir_path = alloc_printf("%s/workdir", fsrv->out_dir_path); - if (fsrv->nyx_id == 0xFFFFFFFF) { FATAL("Nyx ID is not set..."); } + if (fsrv->nyx_id == 0xFFFFFFFF) {NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); } if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) { - - FATAL("Nyx CPU ID is not set..."); - + NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set..."); } void* nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); - fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, x); + fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path); fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE); fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, true); @@ -512,22 +545,36 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (getenv("NYX_REUSE_SNAPSHOT") != NULL){ if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) { - FATAL("NYX_REUSE_SNAPSHOT path does not exist"); + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist"); } /* stupid sanity check to avoid passing an empty or invalid snapshot directory */ char* snapshot_file_path = alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); if (access(snapshot_file_path, R_OK) == -1) { - FATAL("NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); } - free(snapshot_file_path); + ck_free(snapshot_file_path); + + /* another sanity check to avoid passing a snapshot directory that is + * located in the current workdir (the workdir will be wiped by libnyx on startup) */ + char* outdir_path_real = realpath(fsrv->out_dir_path, NULL); + char* workdir_snapshot_path = alloc_printf("%s/workdir/snapshot", outdir_path_real); + char* reuse_snapshot_path_real = realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); + + if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0){ + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path is located in current workdir (use another output directory)"); + } + + ck_free(reuse_snapshot_path_real); + ck_free(workdir_snapshot_path); + ck_free(outdir_path_real); fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(nyx_config, getenv("NYX_REUSE_SNAPSHOT")); } fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); - ck_free(x); + ck_free(workdir_path); if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); } @@ -555,13 +602,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) { case Abort: - FATAL("Error: Nyx abort occured..."); + NYX_PRE_FATAL(fsrv, "Error: Nyx abort occured..."); break; case IoError: - FATAL("Error: QEMU-Nyx has died..."); + NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died..."); break; case Error: - FATAL("Error: Nyx runtime error has occured..."); + NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occured..."); break; default: break; @@ -571,7 +618,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* autodict in Nyx mode */ if (!ignore_autodict) { - x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); + char* x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); int nyx_autodict_fd = open(x, O_RDONLY); ck_free(x); @@ -584,7 +631,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u8 *dict = ck_alloc(f_len); if (dict == NULL) { - FATAL("Could not allocate %u bytes of autodictionary memory", + NYX_PRE_FATAL(fsrv, "Could not allocate %u bytes of autodictionary memory", f_len); } @@ -602,7 +649,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } else { - FATAL( + NYX_PRE_FATAL(fsrv, "Reading autodictionary fail at position %u with %u bytes " "left.", offset, len); @@ -1289,19 +1336,7 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) { fsrv->child_pid = -1; #ifdef __linux__ - if (fsrv->nyx_mode) { - - if (fsrv->nyx_aux_string){ - free(fsrv->nyx_aux_string); - } - - /* check if we actually got a valid nyx runner */ - if (fsrv->nyx_runner) { - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); - } - - } - + afl_nyx_runner_kill(fsrv); #endif } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8b4fe1e5..0e380f73 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2191,14 +2191,6 @@ int main(int argc, char **argv_orig, char **envp) { 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!"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 3ddebaad..832730fd 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1247,7 +1247,7 @@ int main(int argc, char **argv_orig, char **envp) { } - fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_use_tmp_workdir = true; fsrv->nyx_bind_cpu_id = 0; #endif @@ -1443,12 +1443,6 @@ int main(int argc, char **argv_orig, char **envp) { if (execute_testcases(in_dir) == 0) { -#ifdef __linux__ - if (fsrv->nyx_mode) { - remove_nyx_tmp_workdir(fsrv->out_dir_path); - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); - } -#endif FATAL("could not read input testcases from %s", in_dir); } @@ -1528,11 +1522,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->target_path) { ck_free(fsrv->target_path); } -#ifdef __linux__ - if (fsrv->nyx_mode) { - remove_nyx_tmp_workdir(fsrv->out_dir_path); - } -#endif afl_fsrv_deinit(fsrv); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 942525d4..98403049 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1130,7 +1130,7 @@ int main(int argc, char **argv_orig, char **envp) { FATAL("failed to initialize libnyx.so..."); } - fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_use_tmp_workdir = true; fsrv->nyx_bind_cpu_id = 0; use_argv = argv + optind; @@ -1316,11 +1316,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); -#ifdef __linux__ - if (fsrv->nyx_mode) { - remove_nyx_tmp_workdir(fsrv->out_dir_path); - } -#endif remove_shm = 0; afl_shm_deinit(&shm); -- cgit 1.4.1 From 56f7e3aa088e715b054f10c01b6b5a7e5acf8931 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 16 Apr 2023 12:42:32 +0200 Subject: hidden -Y option for nyx, code format --- afl-cmin | 10 +-- afl-cmin.bash | 30 +++++--- include/common.h | 4 +- include/forkserver.h | 13 +++- src/afl-analyze.c | 29 +++++--- src/afl-common.c | 26 +++++-- src/afl-forkserver.c | 151 +++++++++++++++++++++++++++----------- src/afl-showmap.c | 54 +++++++++----- src/afl-tmin.c | 27 ++++--- utils/aflpp_driver/aflpp_driver.c | 23 +++--- 10 files changed, 243 insertions(+), 124 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/afl-cmin b/afl-cmin index 12791584..c5e64410 100755 --- a/afl-cmin +++ b/afl-cmin @@ -124,9 +124,9 @@ function usage() { "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \ -"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on termination\n" \ -" (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is set,\n" \ -" this will be set to the same value as AFL_KILL_SIGNAL.\n" \ +"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on\n" \ +" termination (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is\n" \ +" set, this will be set to the same value as AFL_KILL_SIGNAL.\n" \ "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \ "AFL_CMIN_ALLOW_ANY: write tuples for crashing inputs also\n" \ "AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \ @@ -157,7 +157,7 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUX?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -219,7 +219,7 @@ BEGIN { unicorn_mode = 1 continue } else - if (_go_c == "X") { + if (_go_c == "X" || _go_c == "Y") { if (nyx_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} extra_par = extra_par " -X" nyx_mode = 1 diff --git a/afl-cmin.bash b/afl-cmin.bash index 10c9477a..bcf62eba 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \ export AFL_QUIET=1 -while getopts "+i:o:f:m:t:eOQUACh" opt; do +while getopts "+i:o:f:m:t:eOQUAChXY" opt; do case "$opt" in @@ -94,6 +94,14 @@ while getopts "+i:o:f:m:t:eOQUACh" opt; do EXTRA_PAR="$EXTRA_PAR -Q" QEMU_MODE=1 ;; + "Y") + EXTRA_PAR="$EXTRA_PAR -X" + NYX_MODE=1 + ;; + "X") + EXTRA_PAR="$EXTRA_PAR -X" + NYX_MODE=1 + ;; "U") EXTRA_PAR="$EXTRA_PAR -U" UNICORN_MODE=1 @@ -128,6 +136,7 @@ Execution control settings: -O - use binary-only instrumentation (FRIDA mode) -Q - use binary-only instrumentation (QEMU mode) -U - use unicorn-based instrumentation (Unicorn mode) + -X - use Nyx mode Minimization settings: @@ -206,16 +215,19 @@ if [ ! "$TIMEOUT" = "none" ]; then fi -if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then +if [ "$NYX_MODE" = "" ]; then + if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then - TNEW="`which "$TARGET_BIN" 2>/dev/null`" + TNEW="`which "$TARGET_BIN" 2>/dev/null`" - if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then - echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2 - exit 1 - fi + if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then + echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2 + exit 1 + fi + + TARGET_BIN="$TNEW" - TARGET_BIN="$TNEW" + fi fi @@ -228,7 +240,7 @@ grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && { } } -if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then +if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" -a "$NYX_MODE" = "" ]; then if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2 diff --git a/include/common.h b/include/common.h index e03566de..8d85d201 100644 --- a/include/common.h +++ b/include/common.h @@ -149,8 +149,8 @@ void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, #ifdef __linux__ /* Nyx helper functions to create and remove tmp workdirs */ -char* create_nyx_tmp_workdir(void); -void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path); +char *create_nyx_tmp_workdir(void); +void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path); #endif #endif diff --git a/include/forkserver.h b/include/forkserver.h index ba280d38..f5069ce2 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -52,20 +52,25 @@ typedef enum NyxReturnValue { } NyxReturnValue; typedef enum NyxProcessRole { + StandAlone, Parent, Child, + } NyxProcessRole; typedef struct { void *(*nyx_config_load)(const char *sharedir); void (*nyx_config_set_workdir_path)(void *config, const char *workdir); - void (*nyx_config_set_input_buffer_size)(void *config, uint32_t input_buffer_size); - void (*nyx_config_set_input_buffer_write_protection)(void *config, bool input_buffer_write_protection); + void (*nyx_config_set_input_buffer_size)(void *config, + uint32_t input_buffer_size); + void (*nyx_config_set_input_buffer_write_protection)( + void *config, bool input_buffer_write_protection); void (*nyx_config_set_hprintf_fd)(void *config, int32_t hprintf_fd); void (*nyx_config_set_process_role)(void *config, enum NyxProcessRole role); - void (*nyx_config_set_reuse_snapshot_path)(void *config, const char *reuse_snapshot_path); + void (*nyx_config_set_reuse_snapshot_path)(void *config, + const char *reuse_snapshot_path); void *(*nyx_new)(void *config, uint32_t worker_id); void (*nyx_shutdown)(void *qemu_process); @@ -191,7 +196,7 @@ typedef struct afl_forkserver { u32 nyx_bind_cpu_id; /* nyx runner cpu id */ char *nyx_aux_string; bool nyx_use_tmp_workdir; - char *nyx_tmp_workdir_path; + char *nyx_tmp_workdir_path; #endif } afl_forkserver_t; diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 0a4e7fb5..5b122741 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -815,7 +815,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_init(&fsrv); - while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXh")) > 0) { + while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) { switch (opt) { @@ -966,8 +966,9 @@ int main(int argc, char **argv_orig, char **envp) { fsrv.mem_limit = mem_limit; break; - - #ifdef __linux__ + + case 'Y': // fallthough +#ifdef __linux__ case 'X': /* NYX mode */ if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); } @@ -977,11 +978,11 @@ int main(int argc, char **argv_orig, char **envp) { fsrv.nyx_standalone = true; break; - #else +#else case 'X': FATAL("Nyx mode is only availabe on linux..."); break; - #endif +#endif case 'h': usage(argv[0]); @@ -1015,12 +1016,16 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(argv); #ifdef __linux__ - if(!fsrv.nyx_mode){ + if (!fsrv.nyx_mode) { + fsrv.target_path = find_binary(argv[optind]); - } - else{ + + } else { + fsrv.target_path = ck_strdup(argv[optind]); + } + #else fsrv.target_path = find_binary(argv[optind]); #endif @@ -1048,6 +1053,7 @@ int main(int argc, char **argv_orig, char **envp) { use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind); #ifdef __linux__ + } else if (fsrv.nyx_mode) { fsrv.nyx_id = 0; @@ -1055,7 +1061,9 @@ int main(int argc, char **argv_orig, char **envp) { u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); if (fsrv.nyx_handlers == NULL) { + FATAL("failed to initialize libnyx.so..."); + } fsrv.nyx_use_tmp_workdir = true; @@ -1090,9 +1098,7 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); #ifdef __linux__ - if(!fsrv.nyx_mode){ - (void)check_binary_signatures(fsrv.target_path); - } + if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); } #else (void)check_binary_signatures(fsrv.target_path); #endif @@ -1119,7 +1125,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); - afl_shm_deinit(&shm); afl_fsrv_deinit(&fsrv); if (fsrv.target_path) { ck_free(fsrv.target_path); } diff --git a/src/afl-common.c b/src/afl-common.c index 5692e277..a5c48e80 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1365,36 +1365,46 @@ s32 create_file(u8 *fn) { * etc.). This helper function basically creates both a path to a tmp workdir * and the workdir itself. If the environment variable TMPDIR is set, we use * that as the base directory, otherwise we use /tmp. */ -char* create_nyx_tmp_workdir(void) { +char *create_nyx_tmp_workdir(void) { char *tmpdir = getenv("TMPDIR"); if (!tmpdir) { tmpdir = "/tmp"; } - char* nyx_out_dir_path = alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid()); + char *nyx_out_dir_path = + alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid()); - if (mkdir(nyx_out_dir_path, 0700)) { - PFATAL("Unable to create nyx workdir"); - } + if (mkdir(nyx_out_dir_path, 0700)) { PFATAL("Unable to create nyx workdir"); } return nyx_out_dir_path; + } /* Vice versa, we remove the tmp workdir for nyx with this helper function. */ -void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path) { - char* workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path); +void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path) { + + char *workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path); if (access(workdir_path, R_OK) == 0) { - if(fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) { + + if (fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) { + WARNF("Unable to remove nyx workdir (%s)", workdir_path); + } + } if (rmdir(nyx_out_dir_path)) { + WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path); + } ck_free(workdir_path); ck_free(nyx_out_dir_path); + } + #endif + diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index fd4e213d..aa8c8622 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -50,7 +50,7 @@ #include #ifdef __linux__ -#include + #include /* function to load nyx_helper function from libnyx.so */ @@ -66,22 +66,32 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { plugin->nyx_config_load = dlsym(handle, "nyx_config_load"); if (plugin->nyx_config_load == NULL) { goto fail; } - plugin->nyx_config_set_workdir_path = dlsym(handle, "nyx_config_set_workdir_path"); + plugin->nyx_config_set_workdir_path = + dlsym(handle, "nyx_config_set_workdir_path"); if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; } - plugin->nyx_config_set_input_buffer_size = dlsym(handle, "nyx_config_set_input_buffer_size"); + plugin->nyx_config_set_input_buffer_size = + dlsym(handle, "nyx_config_set_input_buffer_size"); if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; } - plugin->nyx_config_set_input_buffer_write_protection = dlsym(handle, "nyx_config_set_input_buffer_write_protection"); - if (plugin->nyx_config_set_input_buffer_write_protection == NULL) { goto fail; } + plugin->nyx_config_set_input_buffer_write_protection = + dlsym(handle, "nyx_config_set_input_buffer_write_protection"); + if (plugin->nyx_config_set_input_buffer_write_protection == NULL) { - plugin->nyx_config_set_hprintf_fd = dlsym(handle, "nyx_config_set_hprintf_fd"); + goto fail; + + } + + plugin->nyx_config_set_hprintf_fd = + dlsym(handle, "nyx_config_set_hprintf_fd"); if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; } - plugin->nyx_config_set_process_role = dlsym(handle, "nyx_config_set_process_role"); + plugin->nyx_config_set_process_role = + dlsym(handle, "nyx_config_set_process_role"); if (plugin->nyx_config_set_process_role == NULL) { goto fail; } - plugin->nyx_config_set_reuse_snapshot_path = dlsym(handle, "nyx_config_set_reuse_snapshot_path"); + plugin->nyx_config_set_reuse_snapshot_path = + dlsym(handle, "nyx_config_set_reuse_snapshot_path"); if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; } plugin->nyx_new = dlsym(handle, "nyx_new"); @@ -119,7 +129,6 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir"); if (plugin->nyx_remove_work_dir == NULL) { goto fail; } - OKF("libnyx plugin is ready!"); return plugin; @@ -131,33 +140,40 @@ fail: } -void afl_nyx_runner_kill(afl_forkserver_t *fsrv){ +void afl_nyx_runner_kill(afl_forkserver_t *fsrv) { + if (fsrv->nyx_mode) { - if (fsrv->nyx_aux_string){ - ck_free(fsrv->nyx_aux_string); - } + if (fsrv->nyx_aux_string) { ck_free(fsrv->nyx_aux_string); } /* check if we actually got a valid nyx runner */ if (fsrv->nyx_runner) { + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } /* if we have use a tmp work dir we need to remove it */ if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) { + remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path); + } + } + } -/* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp - * files) before exiting. Used before "afl_fsrv_killall()" is registered as - * an atexit() handler. */ -#define NYX_PRE_FATAL(fsrv, x...) \ - do { \ - afl_nyx_runner_kill(fsrv); \ - FATAL(x); \ - } while (0) + /* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp + * files) before exiting. Used before "afl_fsrv_killall()" is registered as + * an atexit() handler. */ + #define NYX_PRE_FATAL(fsrv, x...) \ + do { \ + \ + afl_nyx_runner_kill(fsrv); \ + FATAL(x); \ + \ + } while (0) #endif @@ -511,70 +527,116 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the NYX backend..."); } - if (fsrv->nyx_use_tmp_workdir){ + if (fsrv->nyx_use_tmp_workdir) { + fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir(); fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path; + } else { - if (fsrv->out_dir_path == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); } + + if (fsrv->out_dir_path == NULL) { + + NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); + + } + } /* libnyx expects an absolute path */ - char* outdir_path_absolute = realpath(fsrv->out_dir_path, NULL); - if (outdir_path_absolute == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ..."); } + char *outdir_path_absolute = realpath(fsrv->out_dir_path, NULL); + if (outdir_path_absolute == NULL) { + + NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ..."); + + } char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute); - if (fsrv->nyx_id == 0xFFFFFFFF) {NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); } + if (fsrv->nyx_id == 0xFFFFFFFF) { + + NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); + + } if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) { + NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set..."); + } - void* nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); + void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path); fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE); - fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, true); + fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, + true); if (fsrv->nyx_standalone) { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone); + } else { + if (fsrv->nyx_parent) { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent); + } else { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child); + } + } - if (getenv("NYX_REUSE_SNAPSHOT") != NULL){ + if (getenv("NYX_REUSE_SNAPSHOT") != NULL) { if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) { + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist"); + } - /* stupid sanity check to avoid passing an empty or invalid snapshot directory */ - char* snapshot_file_path = alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); + /* stupid sanity check to avoid passing an empty or invalid snapshot + * directory */ + char *snapshot_file_path = + alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); if (access(snapshot_file_path, R_OK) == -1) { - NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + + NYX_PRE_FATAL( + fsrv, + "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + } + ck_free(snapshot_file_path); /* another sanity check to avoid passing a snapshot directory that is - * located in the current workdir (the workdir will be wiped by libnyx on startup) */ - char* workdir_snapshot_path = alloc_printf("%s/workdir/snapshot", outdir_path_absolute); - char* reuse_snapshot_path_real = realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); + * located in the current workdir (the workdir will be wiped by libnyx on + * startup) */ + char *workdir_snapshot_path = + alloc_printf("%s/workdir/snapshot", outdir_path_absolute); + char *reuse_snapshot_path_real = + realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); + + if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0) { + + NYX_PRE_FATAL(fsrv, + "NYX_REUSE_SNAPSHOT path is located in current workdir " + "(use another output directory)"); - if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0){ - NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path is located in current workdir (use another output directory)"); } ck_free(reuse_snapshot_path_real); ck_free(workdir_snapshot_path); - fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(nyx_config, getenv("NYX_REUSE_SNAPSHOT")); + fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path( + nyx_config, getenv("NYX_REUSE_SNAPSHOT")); + } - fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); + fsrv->nyx_runner = + fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); ck_free(workdir_path); ck_free(outdir_path_absolute); @@ -621,7 +683,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* autodict in Nyx mode */ if (!ignore_autodict) { - char* x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); + char *x = + alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); int nyx_autodict_fd = open(x, O_RDONLY); ck_free(x); @@ -634,8 +697,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u8 *dict = ck_alloc(f_len); if (dict == NULL) { - NYX_PRE_FATAL(fsrv, "Could not allocate %u bytes of autodictionary memory", - f_len); + NYX_PRE_FATAL( + fsrv, "Could not allocate %u bytes of autodictionary memory", + f_len); } @@ -652,7 +716,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } else { - NYX_PRE_FATAL(fsrv, + NYX_PRE_FATAL( + fsrv, "Reading autodictionary fail at position %u with %u bytes " "left.", offset, len); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 832730fd..df030672 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -444,8 +444,11 @@ static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) { FSRV_RUN_ERROR) { FATAL("Error running target in Nyx mode"); + } + } + #endif /* Execute target application. */ @@ -890,7 +893,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshX")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { switch (opt) { @@ -1078,7 +1081,8 @@ int main(int argc, char **argv_orig, char **envp) { break; - #ifdef __linux__ + case 'Y': // fallthough +#ifdef __linux__ case 'X': /* NYX mode */ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } @@ -1088,11 +1092,11 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->nyx_standalone = true; break; - #else +#else case 'X': FATAL("Nyx mode is only availabe on linux..."); break; - #endif +#endif case 'b': @@ -1166,12 +1170,16 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); #ifdef __linux__ - if(!fsrv->nyx_mode){ + if (!fsrv->nyx_mode) { + fsrv->target_path = find_binary(argv[optind]); - } - else{ + + } else { + fsrv->target_path = ck_strdup(argv[optind]); + } + #else fsrv->target_path = find_binary(argv[optind]); #endif @@ -1232,11 +1240,12 @@ int main(int argc, char **argv_orig, char **envp) { get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); #ifdef __linux__ + } else if (fsrv->nyx_mode) { use_argv = ck_alloc(sizeof(char *) * (1)); use_argv[0] = argv[0]; - + fsrv->nyx_id = 0; u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so"); @@ -1288,9 +1297,12 @@ int main(int argc, char **argv_orig, char **envp) { } #ifdef __linux__ - if(!fsrv->nyx_mode && in_dir){ + if (!fsrv->nyx_mode && in_dir) { + (void)check_binary_signatures(fsrv->target_path); + } + #else if (in_dir) { (void)check_binary_signatures(fsrv->target_path); } #endif @@ -1313,14 +1325,14 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); - configure_afl_kill_signals( - fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode - #ifdef __linux__ - || fsrv->nyx_mode - #endif - ) - ? SIGKILL - : SIGTERM); + configure_afl_kill_signals(fsrv, NULL, NULL, + (fsrv->qemu_mode || unicorn_mode +#ifdef __linux__ + || fsrv->nyx_mode +#endif + ) + ? SIGKILL + : SIGTERM); if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) { @@ -1464,13 +1476,18 @@ int main(int argc, char **argv_orig, char **envp) { shm_fuzz = deinit_shmem(fsrv, shm_fuzz); #ifdef __linux__ - if(!fsrv->nyx_mode){ + if (!fsrv->nyx_mode) { + #endif showmap_run_target(fsrv, use_argv); #ifdef __linux__ + } else { + showmap_run_target_nyx_mode(fsrv); + } + #endif tcnt = write_results_to_file(fsrv, out_file); if (!quiet_mode) { @@ -1522,7 +1539,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->target_path) { ck_free(fsrv->target_path); } - afl_fsrv_deinit(fsrv); if (stdin_file) { ck_free(stdin_file); } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 98403049..e7442d1d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -846,7 +846,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) { switch (opt) { @@ -1004,7 +1004,8 @@ int main(int argc, char **argv_orig, char **envp) { break; - #ifdef __linux__ + case 'Y': // fallthough +#ifdef __linux__ case 'X': /* NYX mode */ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } @@ -1014,11 +1015,11 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->nyx_standalone = true; break; - #else +#else case 'X': FATAL("Nyx mode is only availabe on linux..."); break; - #endif +#endif case 'H': /* Hang Mode */ @@ -1086,12 +1087,16 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); #ifdef __linux__ - if(!fsrv->nyx_mode){ + if (!fsrv->nyx_mode) { + fsrv->target_path = find_binary(argv[optind]); - } - else{ + + } else { + fsrv->target_path = ck_strdup(argv[optind]); + } + #else fsrv->target_path = find_binary(argv[optind]); #endif @@ -1120,6 +1125,7 @@ int main(int argc, char **argv_orig, char **envp) { get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); #ifdef __linux__ + } else if (fsrv->nyx_mode) { fsrv->nyx_id = 0; @@ -1127,7 +1133,9 @@ int main(int argc, char **argv_orig, char **envp) { u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); if (fsrv->nyx_handlers == NULL) { + FATAL("failed to initialize libnyx.so..."); + } fsrv->nyx_use_tmp_workdir = true; @@ -1207,9 +1215,7 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); #ifdef __linux__ - if(!fsrv->nyx_mode){ - (void)check_binary_signatures(fsrv->target_path); - } + if (!fsrv->nyx_mode) { (void)check_binary_signatures(fsrv->target_path); } #else (void)check_binary_signatures(fsrv->target_path); #endif @@ -1316,7 +1322,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); - remove_shm = 0; afl_shm_deinit(&shm); if (fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index 34294809..4e8f466d 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -78,10 +78,10 @@ extern unsigned int __afl_map_size; on the other hand this is what Google needs to make LLVMFuzzerRunDriver() work. Choose your poison Google! */ /*__attribute__((weak))*/ int LLVMFuzzerTestOneInput(const uint8_t *Data, - size_t Size); -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); -__attribute__((weak)) int LLVMFuzzerRunDriver( - int *argc, char ***argv, int (*callback)(const uint8_t *data, size_t size)); + size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); +__attribute__((weak)) int LLVMFuzzerRunDriver( + int *argc, char ***argv, int (*callback)(const uint8_t *data, size_t size)); // Default nop ASan hooks for manual poisoning when not linking the ASan // runtime @@ -268,15 +268,16 @@ static int ExecuteFilesOnyByOne(int argc, char **argv, __attribute__((weak)) int main(int argc, char **argv) { -// Enable if LLVMFuzzerTestOneInput() has the weak attribute -/* - if (!LLVMFuzzerTestOneInput) { + // Enable if LLVMFuzzerTestOneInput() has the weak attribute + /* + if (!LLVMFuzzerTestOneInput) { - fprintf(stderr, "Error: function LLVMFuzzerTestOneInput() not found!\n"); - abort(); + fprintf(stderr, "Error: function LLVMFuzzerTestOneInput() not found!\n"); + abort(); - } -*/ + } + + */ if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) printf( -- cgit 1.4.1 From 4e5f42cab6b8c501eeaf76ec7ca920089f6e0f3a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 20 Apr 2023 10:39:23 +0200 Subject: afl-showmap custom mutator support --- GNUmakefile | 2 +- TODO.md | 4 +-- afl-cmin | 2 ++ afl-cmin.bash | 2 ++ docs/Changelog.md | 3 +- include/afl-fuzz.h | 8 +++-- src/afl-showmap.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 107 insertions(+), 7 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/GNUmakefile b/GNUmakefile index 5bc3f9d5..0f890308 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -453,7 +453,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) diff --git a/TODO.md b/TODO.md index e7789cf6..dba75070 100644 --- a/TODO.md +++ b/TODO.md @@ -3,14 +3,14 @@ ## Should - splicing selection weighted? - - support afl_custom_{send,post_process}, persistent and deferred fork - server in afl-showmap + - support persistent and deferred fork server in afl-showmap? - better autodetection of shifting runtime timeout values - Update afl->pending_not_fuzzed for MOpt - afl-plot to support multiple plot_data - parallel builds for source-only targets - get rid of check_binary, replace with more forkserver communication - first fuzzer should be a main automatically? not sure. + - reload fuzz binary on signal ## Maybe diff --git a/afl-cmin b/afl-cmin index c5e64410..e2c26d91 100755 --- a/afl-cmin +++ b/afl-cmin @@ -133,6 +133,8 @@ function usage() { "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ "printed to stdout\n" \ "AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n" +"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n" +"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n" exit 1 } diff --git a/afl-cmin.bash b/afl-cmin.bash index bcf62eba..5258758e 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -151,6 +151,8 @@ AFL_KEEP_TRACES: leave the temporary \.traces directory AFL_NO_FORKSRV: run target via execve instead of using the forkserver AFL_PATH: last resort location to find the afl-showmap binary AFL_SKIP_BIN_CHECK: skip check for target binary +AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send) +AFL_PYTHON_MODULE: custom mutator library (post_process and send) _EOF_ exit 1 fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 30e76f2c..5ed5ef2b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,7 +4,8 @@ release of the tool. See README.md for the general instruction manual. ### Version ++4.07a (dev) - - soon :) + - afl-showmap: + - added custom mutator post_process and send support ### Version ++4.06c (release) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8b6502b4..ec69ba17 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1103,7 +1103,6 @@ u32 count_bits(afl_state_t *, u8 *); u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); void simplify_trace(afl_state_t *, u8 *); -void classify_counts(afl_forkserver_t *); #ifdef WORD_SIZE_64 void discover_word(u8 *ret, u64 *current, u64 *virgin); #else @@ -1117,6 +1116,9 @@ u8 *describe_op(afl_state_t *, u8, size_t); u8 save_if_interesting(afl_state_t *, void *, u32, u8); u8 has_new_bits(afl_state_t *, u8 *); u8 has_new_bits_unclassified(afl_state_t *, u8 *); +#ifndef AFL_SHOWMAP +void classify_counts(afl_forkserver_t *); +#endif /* Extras */ @@ -1192,11 +1194,13 @@ void fix_up_sync(afl_state_t *); void check_asan_opts(afl_state_t *); void check_binary(afl_state_t *, u8 *); void check_if_tty(afl_state_t *); -void setup_signal_handlers(void); void save_cmdline(afl_state_t *, u32, char **); void read_foreign_testcases(afl_state_t *, int); void write_crash_readme(afl_state_t *afl); u8 check_if_text_buf(u8 *buf, u32 len); +#ifndef AFL_SHOWMAP +void setup_signal_handlers(void); +#endif /* CmpLog */ diff --git a/src/afl-showmap.c b/src/afl-showmap.c index df030672..b5a61de5 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -30,8 +30,10 @@ */ #define AFL_MAIN +#define AFL_SHOWMAP #include "config.h" +#include "afl-fuzz.h" #include "types.h" #include "debug.h" #include "alloc-inl.h" @@ -62,6 +64,8 @@ #include #include +static afl_state_t *afl; + static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ @@ -308,12 +312,73 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { } +void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) { + + static u8 buf[MAX_FILE]; + u32 sent = 0; + + if (unlikely(afl->custom_mutators_count)) { + + ssize_t new_size = len; + u8 *new_mem = mem; + u8 *new_buf = NULL; + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_post_process) { + + new_size = + el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); + + if (unlikely(!new_buf || new_size <= 0)) { + + return; + + } else { + + new_mem = new_buf; + len = new_size; + + } + + } + + }); + + if (new_mem != mem && new_mem != NULL) { + + mem = buf; + memcpy(mem, new_mem, new_size); + + } + + if (unlikely(afl->custom_mutators_count)) { + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_fuzz_send) { + + el->afl_custom_fuzz_send(el->data, mem, len); + sent = 1; + + } + + }); + + } + + } + + if (likely(!sent)) { afl_fsrv_write_to_testcase(fsrv, mem, len); } + +} + /* Execute target application. */ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, u32 len) { - afl_fsrv_write_to_testcase(fsrv, mem, len); + pre_afl_fsrv_write_to_testcase(fsrv, mem, len); if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); } @@ -835,6 +900,10 @@ static void usage(u8 *argv0) { "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" + "If you use -i mode, then custom mutator post_process send send " + "functionality\n" + "is supported.\n\n" + "Environment variables used:\n" "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n" "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " @@ -1266,6 +1335,8 @@ int main(int argc, char **argv_orig, char **envp) { } + afl = calloc(1, sizeof(afl_state_t)); + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); @@ -1380,6 +1451,26 @@ int main(int argc, char **argv_orig, char **envp) { } + if (in_dir) { + + afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); + afl->afl_env.afl_custom_mutator_library = + getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE"); + setup_custom_mutators(afl); + + } else { + + if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) { + + WARNF( + "Custom mutator environment detected, this is only supported in -i " + "mode!\n"); + + } + + } + if (in_dir) { DIR *dir_in, *dir_out = NULL; -- cgit 1.4.1 From 0a297ed9ef48c1eaf69fdc13bd1016f8f29124be Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 Apr 2023 15:09:35 +0200 Subject: dummy function for afl-showmap --- src/afl-showmap.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/afl-showmap.c') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index b5a61de5..affad7d6 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -140,6 +140,15 @@ static void kill_child() { } +/* dummy function */ +u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) { + + (void)afl; + (void)mem; + return a + b; + +} + static void classify_counts(afl_forkserver_t *fsrv) { u8 *mem = fsrv->trace_bits; -- cgit 1.4.1 From 7a8d0a10ce25d20bdd2021920b0b5ebbc0d3f3a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 Apr 2023 15:21:11 +0200 Subject: add dummy functions to afl-showmap for old gcc compilers --- src/afl-showmap.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index affad7d6..0b9fc211 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -140,7 +140,7 @@ static void kill_child() { } -/* dummy function */ +/* dummy functions */ u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) { (void)afl; @@ -149,7 +149,30 @@ u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) { } -static void classify_counts(afl_forkserver_t *fsrv) { +void show_stats(afl_state_t *afl) { + + (void)afl; + +} + +void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { + + (void)afl; + (void)q; + +} + +fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, + u32 i) { + + (void)afl; + (void)fsrv; + (void)i; + return 0; + +} + +void classify_counts(afl_forkserver_t *fsrv) { u8 *mem = fsrv->trace_bits; const u8 *map = binary_mode ? count_class_binary : count_class_human; -- cgit 1.4.1 From 8c228b0d23e303499dccf3df77c5d0b3a8b59b7b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 24 Apr 2023 18:08:27 +0200 Subject: afl-showmap -I option --- afl-cmin | 2 +- docs/Changelog.md | 1 + src/afl-showmap.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 156 insertions(+), 22 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/afl-cmin b/afl-cmin index e2c26d91..6b36c261 100755 --- a/afl-cmin +++ b/afl-cmin @@ -234,7 +234,7 @@ BEGIN { } # while options if (!mem_limit) mem_limit = "none" - if (!timeout) timeout = "none" + if (!timeout) timeout = "5000" # get program args i = 0 diff --git a/docs/Changelog.md b/docs/Changelog.md index f33acff9..d4e68036 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ data before post process on finds - afl-showmap: - added custom mutator post_process and send support + - add `-I filelist` option, an alternative to `-i in_dir` - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0b9fc211..09a1d2dc 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -69,7 +69,9 @@ static afl_state_t *afl; static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ - *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ + *out_file = NULL, /* output file or directory */ + *at_file = NULL, /* Substitution string for @@ */ + *in_filelist = NULL; /* input file list */ static u8 outfile[PATH_MAX]; @@ -878,6 +880,104 @@ u32 execute_testcases(u8 *dir) { } +u32 execute_testcases_filelist(u8 *fn) { + + u32 done = 0; + u8 buf[4096]; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + FILE *f; + + if (!be_quiet) { ACTF("Reading from '%s'...", fn); } + + if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); } + + while (fgets(buf, sizeof(buf), f) != NULL) { + + struct stat st; + + u8 *fn2 = buf, *fn3; + ; + + while (*fn2 == ' ') { + + ++fn2; + + } + + if (*fn2) { + + while (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || + fn2[strlen(fn2) - 1] == ' ') { + + fn2[strlen(fn2) - 1] = 0; + + } + + } + + if (debug) { printf("Getting coverage for '%s'\n", fn2); } + + if (!*fn2) { continue; } + + if (lstat(fn2, &st) || access(fn2, R_OK)) { + + WARNF("Unable to access '%s'", fn2); + continue; + + } + + if (!S_ISREG(st.st_mode) || !st.st_size) { continue; } + + if ((fn3 = strrchr(fn2, '/'))) { + + ++fn3; + + } else { + + fn3 = fn2; + + } + + if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) { + + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + + } + + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3); + + if (read_file(fn2)) { + + if (wait_for_gdb) { + + fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); + fprintf(stderr, "exec: kill -CONT %d\n", getpid()); + kill(0, SIGSTOP); + + } + + showmap_run_target_forkserver(fsrv, in_data, in_len); + ck_free(in_data); + ++done; + + if (child_crashed && debug) { WARNF("crashed: %s", fn2); } + + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); + + } + + } + + return done; + +} + /* Show banner. */ static void show_banner(void) { @@ -920,6 +1020,7 @@ static void usage(u8 *argv0) { " With -C, -o is a file, without -C it must be a " "directory\n" " and each bitmap will be written there individually.\n" + " -I filelist - alternatively to -i, -I is a list of files\n" " -C - collect coverage, writes all edges to -o and gives a " "summary\n" " Must be combined with -i.\n" @@ -932,7 +1033,7 @@ static void usage(u8 *argv0) { "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" - "If you use -i mode, then custom mutator post_process send send " + "If you use -i/-I mode, then custom mutator post_process send send " "functionality\n" "is supported.\n\n" @@ -994,7 +1095,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { + while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { switch (opt) { @@ -1012,6 +1113,11 @@ int main(int argc, char **argv_orig, char **envp) { in_dir = optarg; break; + case 'I': + if (in_filelist) { FATAL("Multiple -I options not supported"); } + in_filelist = optarg; + break; + case 'o': if (out_file) { FATAL("Multiple -o options not supported"); } @@ -1234,10 +1340,12 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !out_file) { usage(argv[0]); } - if (in_dir) { + if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); } + + if (in_dir || in_filelist) { if (!out_file && !collect_coverage) - FATAL("for -i you need to specify either -C and/or -o"); + FATAL("for -i/-I you need to specify either -C and/or -o"); } @@ -1294,7 +1402,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { + if (in_dir || in_filelist) { /* If we don't have a file name chosen yet, use a safe default. */ u8 *use_dir = "."; @@ -1400,7 +1508,7 @@ int main(int argc, char **argv_orig, char **envp) { } #ifdef __linux__ - if (!fsrv->nyx_mode && in_dir) { + if (!fsrv->nyx_mode && (in_dir || in_filelist)) { (void)check_binary_signatures(fsrv->target_path); @@ -1483,7 +1591,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { + if (in_dir || in_filelist) { afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); afl->afl_env.afl_custom_mutator_library = @@ -1496,33 +1604,46 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) { WARNF( - "Custom mutator environment detected, this is only supported in -i " - "mode!\n"); + "Custom mutator environment detected, this is only supported in " + "-i/-I mode!\n"); } } - if (in_dir) { + if (in_dir || in_filelist) { DIR *dir_in, *dir_out = NULL; + u8 *dn = NULL; if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - // if a queue subdirectory exists switch to that - u8 *dn = alloc_printf("%s/queue", in_dir); - if ((dir_in = opendir(dn)) != NULL) { + if (in_filelist) { + + if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist); + + } else { + + // if a queue subdirectory exists switch to that + dn = alloc_printf("%s/queue", in_dir); + + if ((dir_in = opendir(dn)) != NULL) { + + closedir(dir_in); + in_dir = dn; + + } else { + + ck_free(dn); - closedir(dir_in); - in_dir = dn; + } - } else + if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); - ck_free(dn); - if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); + } if (!collect_coverage) { @@ -1576,9 +1697,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - if (execute_testcases(in_dir) == 0) { + if (in_dir) { + + if (execute_testcases(in_dir) == 0) { + + FATAL("could not read input testcases from %s", in_dir); + + } + + } else { - FATAL("could not read input testcases from %s", in_dir); + if (execute_testcases_filelist(in_filelist) == 0) { + + FATAL("could not read input testcases from %s", in_filelist); + + } } -- cgit 1.4.1 From d822181467ec41f1ee2d840c3c5b1918c72ffc86 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 13:13:43 +0200 Subject: afl-cmin -T support --- afl-cmin | 143 ++++++++++++++++++++++++++++++++++++++++++------------ docs/Changelog.md | 2 +- src/afl-showmap.c | 23 +++++---- 3 files changed, 124 insertions(+), 44 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/afl-cmin b/afl-cmin index 6b36c261..c8bbd8d7 100755 --- a/afl-cmin +++ b/afl-cmin @@ -103,9 +103,10 @@ function usage() { " -o dir - output directory for minimized files\n" \ "\n" \ "Execution control settings:\n" \ +" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\n" \ " -f file - location read by the fuzzed program (stdin)\n" \ " -m megs - memory limit for child process ("mem_limit" MB)\n" \ -" -t msec - run time limit for child process (default: none)\n" \ +" -t msec - run time limit for child process (default: 5000)\n" \ " -O - use binary-only instrumentation (FRIDA mode)\n" \ " -Q - use binary-only instrumentation (QEMU mode)\n" \ " -U - use unicorn-based instrumentation (unicorn mode)\n" \ @@ -119,7 +120,6 @@ function usage() { "For additional tips, please consult README.md\n" \ "\n" \ "Environment variables used:\n" \ -"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ @@ -159,13 +159,19 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} in_dir = Optarg continue } else + if (_go_c == "T") { + if (!Optarg) usage() + if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} + threads = Optarg + continue + } else if (_go_c == "o") { if (!Optarg) usage() if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -253,21 +259,30 @@ BEGIN { # Do a sanity check to discourage the use of /tmp, since we can't really # handle this safely from an awk script. - if (!ENVIRON["AFL_ALLOW_TMP"]) { - dirlist[0] = in_dir - dirlist[1] = target_bin - dirlist[2] = out_dir - dirlist[3] = stdin_file - "pwd" | getline dirlist[4] # current directory - for (dirind in dirlist) { - dir = dirlist[dirind] - - if (dir ~ /^(\/var)?\/tmp/) { - print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr" - exit 1 - } - } - delete dirlist + #if (!ENVIRON["AFL_ALLOW_TMP"]) { + # dirlist[0] = in_dir + # dirlist[1] = target_bin + # dirlist[2] = out_dir + # dirlist[3] = stdin_file + # "pwd" | getline dirlist[4] # current directory + # for (dirind in dirlist) { + # dir = dirlist[dirind] + # + # if (dir ~ /^(\/var)?\/tmp/) { + # print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr" + # exit 1 + # } + # } + # delete dirlist + #} + + if (threads && stdin_file) { + print "[-] Error: -T and -f cannot be used together." > "/dev/stderr" + exit 1 + } + + if (!threads && !stdin_file) { + print "[*] Are you aware of the '-T all' parallelize option that massively improves the speed for large corpuses?" } # If @@ is specified, but there's no -f, let's come up with a temporary input @@ -350,6 +365,18 @@ BEGIN { exit 1 } + if (threads) { + "nproc" | getline nproc + if (threads == "all") { + threads = nproc + } else { + if (!(threads > 1 && threads <= nproc)) { + print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/dev/stderr" + exit 1 + } + } + } + # Check for the more efficient way to copy files... if (0 != system("mkdir -p -m 0700 "trace_dir)) { print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr" @@ -459,27 +486,81 @@ BEGIN { # STEP 1: Collecting traces # ############################# + if (threads) { + + inputsperfile = in_count / threads + if (in_count % threads) { + inputsperfile++; + } + + cnt = 0; + tmpfile=out_dir "/.filelist" + for (instance = 1; instance < threads; instance++) { + for (i = 0; i < inputsperfile; i++) { + print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance + cnt++ + } + } + for (; cnt < in_count; cnt++) { + print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads + } + + print "ls -l "tmpfile"*" + + } + print "[*] Obtaining traces for "in_count" input files in '"in_dir"'." cur = 0; - if (!stdin_file) { - print " Processing "in_count" files (forkserver mode)..." -# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string - retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string) + + if (threads > 1) { + + print "[*] Creating " threads " parallel tasks with about " inputsperfile " each." + for (i = 1; i <= threads; i++) { + + if (!stdin_file) { +# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &" + retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &") + } else { + stdin_file=tmpfile"."i".stdin" +# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" "tmpfile"."i".done ; } &" + retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" "tmpfile"."i".done ; } &") + } + } + print "[*] Waiting for parallel tasks to complete ..." + # wait for all processes to finish + ok=0 + while (ok < threads) { + ok=0 + for (i = 1; i <= threads; i++) { + if (system("test -f "tmpfile"."i".done") == 0) { + ok++ + } + } + } + print "[*] Done!" + system("rm -f "tmpfile"*") } else { - print " Processing "in_count" files (forkserver mode)..." + if (!stdin_file) { + print " Processing "in_count" files (forkserver mode)..." +# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string + retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string) + } else { + print " Processing "in_count" files (forkserver mode)..." # print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" /dev/null") - system("rmdir "out_dir) + if (!ENVIRON["AFL_KEEP_TRACES"]) { + system("rm -rf "trace_dir" 2>/dev/null") + system("rmdir "out_dir) + } + exit retval } - exit retval + } ####################################################### diff --git a/docs/Changelog.md b/docs/Changelog.md index 816a864d..667fd634 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,7 +14,7 @@ - afl-showmap: - added custom mutator post_process and send support - add `-I filelist` option, an alternative to `-i in_dir` - - afl-cmin.bash: + - afl-cmin + afl-cmin.bash: - `-T threads` parallel task support, huge speedup! - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 09a1d2dc..d0e01cb1 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -894,9 +894,7 @@ u32 execute_testcases_filelist(u8 *fn) { while (fgets(buf, sizeof(buf), f) != NULL) { struct stat st; - - u8 *fn2 = buf, *fn3; - ; + u8 *fn2 = buf, *fn3; while (*fn2 == ' ') { @@ -904,14 +902,11 @@ u32 execute_testcases_filelist(u8 *fn) { } - if (*fn2) { - - while (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || - fn2[strlen(fn2) - 1] == ' ') { - - fn2[strlen(fn2) - 1] = 0; + while (*fn2 && + (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || + fn2[strlen(fn2) - 1] == ' ')) { - } + fn2[strlen(fn2) - 1] = 0; } @@ -926,6 +921,8 @@ u32 execute_testcases_filelist(u8 *fn) { } + ++done; + if (!S_ISREG(st.st_mode) || !st.st_size) { continue; } if ((fn3 = strrchr(fn2, '/'))) { @@ -946,9 +943,12 @@ u32 execute_testcases_filelist(u8 *fn) { } - if (!collect_coverage) + if (!collect_coverage) { + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3); + } + if (read_file(fn2)) { if (wait_for_gdb) { @@ -961,7 +961,6 @@ u32 execute_testcases_filelist(u8 *fn) { showmap_run_target_forkserver(fsrv, in_data, in_len); ck_free(in_data); - ++done; if (child_crashed && debug) { WARNF("crashed: %s", fn2); } -- cgit 1.4.1 From 6cad585bdc5c335cc2894c97e9aaf6d5fff88e1f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 27 Apr 2023 18:57:28 +0200 Subject: nits --- src/afl-showmap.c | 2 +- test/test-llvm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index d0e01cb1..f60acb2d 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1287,7 +1287,7 @@ int main(int argc, char **argv_orig, char **envp) { break; - case 'Y': // fallthough + case 'Y': // fallthrough #ifdef __linux__ case 'X': /* NYX mode */ diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 0e66cc97..714bda93 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -263,7 +263,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { { mkdir -p in echo 00000000000000000000000000000000 > in/in - AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -m none -V15 -i in -o out -c./test-cmplog -- ./test-c >>errors 2>&1 + AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -m none -V30 -i in -o out -c./test-cmplog -- ./test-c >>errors 2>&1 } >>errors 2>&1 test -n "$( ls out/default/crashes/id:000000* out/default/hangs/id:000000* 2>/dev/null )" && { $ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode cmplog" -- cgit 1.4.1 From 41b0fe7280372031753fc5f11b9a03b214189155 Mon Sep 17 00:00:00 2001 From: Nick Potenski Date: Thu, 27 Apr 2023 11:57:55 -0500 Subject: afl-showmap: Start a only a single fork server (#1718) A forkserver is started by afl_fsrv_get_mapsize() when dynamically finding the map size. When an input directory option is specified a second fork server was also started. This commit re-arranges the inits for several forkserver struct members so that we can re-use the server started by the get_mapsize() call when not in coresight/qemu/unicorn modes and just start the server otherwise. --- src/afl-showmap.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'src/afl-showmap.c') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index f60acb2d..9c029035 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1421,6 +1421,14 @@ int main(int argc, char **argv_orig, char **envp) { // If @@ are in the target args, replace them and also set use_stdin=false. detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin); + fsrv->dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + + fsrv->out_file = stdin_file; + fsrv->out_fd = + open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", stdin_file); } + } else { // If @@ are in the target args, replace them and also set use_stdin=false. @@ -1588,6 +1596,14 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->map_size = map_size; + } else { + + afl_fsrv_start(fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || + get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); + } if (in_dir || in_filelist) { @@ -1617,9 +1633,6 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; - fsrv->dev_null_fd = open("/dev/null", O_RDWR); - if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - if (in_filelist) { if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist); @@ -1666,10 +1679,6 @@ int main(int argc, char **argv_orig, char **envp) { } atexit(at_exit_handler); - fsrv->out_file = stdin_file; - fsrv->out_fd = - open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); - if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } if (get_afl_env("AFL_DEBUG")) { @@ -1685,12 +1694,6 @@ int main(int argc, char **argv_orig, char **envp) { } - afl_fsrv_start(fsrv, use_argv, &stop_soon, - (get_afl_env("AFL_DEBUG_CHILD") || - get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) - ? 1 - : 0); - map_size = fsrv->map_size; if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) -- cgit 1.4.1