diff options
Diffstat (limited to 'src/afl-forkserver.c')
-rw-r--r-- | src/afl-forkserver.c | 292 |
1 files changed, 174 insertions, 118 deletions
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index c7a3475f..28f664fa 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -49,90 +49,11 @@ /* Describe integer as memory size. */ -extern u8 *doc_path; - -u8 *forkserver_DMS(u64 val) { - - static u8 tmp[12][16]; - static u8 cur; - -#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ - do { \ - \ - if (val < (_divisor) * (_limit_mult)) { \ - \ - sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ - return tmp[cur]; \ - \ - } \ - \ - } while (0) - - cur = (cur + 1) % 12; - - /* 0-9999 */ - CHK_FORMAT(1, 10000, "%llu B", u64); - - /* 10.0k - 99.9k */ - CHK_FORMAT(1024, 99.95, "%0.01f kB", double); - - /* 100k - 999k */ - CHK_FORMAT(1024, 1000, "%llu kB", u64); - - /* 1.00M - 9.99M */ - CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); - - /* 10.0M - 99.9M */ - CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); - - /* 100M - 999M */ - CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); - - /* 1.00G - 9.99G */ - CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); - - /* 10.0G - 99.9G */ - CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); - - /* 100G - 999G */ - CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); - - /* 1.00T - 9.99G */ - CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); - - /* 10.0T - 99.9T */ - CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); - -#undef CHK_FORMAT - - /* 100T+ */ - strcpy(tmp[cur], "infty"); - return tmp[cur]; - -} - list_t fsrv_list = {.element_prealloc_count = 0}; -/* the timeout handler */ - -void handle_timeout(int sig) { - - LIST_FOREACH(&fsrv_list, afl_forkserver_t, { - - // TODO: We need a proper timer to handle multiple timeouts - if (el->child_pid > 0) { +static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { - el->child_timed_out = 1; - kill(el->child_pid, SIGKILL); - - } else if (el->child_pid == -1 && el->fsrv_pid > 0) { - - el->child_timed_out = 1; - kill(el->fsrv_pid, SIGKILL); - - } - - }); + execv(fsrv->target_path, argv); } @@ -153,21 +74,51 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->exec_tmout = EXEC_TIMEOUT; fsrv->mem_limit = MEM_LIMIT; fsrv->child_pid = -1; - fsrv->out_dir_fd = -1; - + fsrv->map_size = MAP_SIZE; fsrv->use_fauxsrv = 0; + fsrv->prev_timed_out = 0; + + fsrv->init_child_func = fsrv_exec_child; list_append(&fsrv_list, fsrv); } +/* Initialize a new forkserver instance, duplicating "global" settings */ +void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { + + fsrv_to->use_stdin = from->use_stdin; + fsrv_to->dev_null_fd = from->dev_null_fd; + fsrv_to->exec_tmout = from->exec_tmout; + fsrv_to->mem_limit = from->mem_limit; + fsrv_to->map_size = from->map_size; + +#ifndef HAVE_ARC4RANDOM + fsrv_to->dev_urandom_fd = from->dev_urandom_fd; +#endif + + // These are forkserver specific. + fsrv_to->out_fd = -1; + fsrv_to->out_dir_fd = -1; + fsrv_to->child_pid = -1; + fsrv_to->use_fauxsrv = 0; + fsrv_to->prev_timed_out = 0; + + fsrv_to->init_child_func = fsrv_exec_child; + + list_append(&fsrv_list, fsrv_to); + +} + /* Internal forkserver for dumb_mode=1 and non-forkserver mode runs. It execvs for each fork, forwarding exit codes and child pids to afl. */ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { - static unsigned char tmp[4] = {0}; - pid_t child_pid = -1; + unsigned char tmp[4] = {0, 0, 0, 0}; + pid_t child_pid = -1; + + if (!be_quiet) ACTF("Using Fauxserver:"); /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ @@ -244,16 +195,25 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { cloning a stopped child. So, we just execute once, and then send commands through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ -void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { +void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, + volatile u8 *stop_soon_p, u8 debug_child_output) { + + int st_pipe[2], ctl_pipe[2]; + int status; + s32 rlen; + + if (!be_quiet) ACTF("Spinning up the fork server..."); + + if (fsrv->use_fauxsrv) { - struct timeval timeout; - int st_pipe[2], ctl_pipe[2]; - int status; - s32 rlen; + /* TODO: Come up with sone nice way to initalize this all */ - if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:"); + if (fsrv->init_child_func != fsrv_exec_child) + FATAL("Different forkserver not compatible with fauxserver"); - if (!getenv("AFL_QUIET")) ACTF("Spinning up the fork server..."); + fsrv->init_child_func = afl_fauxsrv_execv; + + } if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); @@ -305,7 +265,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { setsid(); - if (!get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) { + if (!(debug_child_output)) { dup2(fsrv->dev_null_fd, 1); dup2(fsrv->dev_null_fd, 2); @@ -338,7 +298,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { #ifndef HAVE_ARC4RANDOM close(fsrv->dev_urandom_fd); #endif - close(fsrv->plot_file == NULL ? -1 : fileno(fsrv->plot_file)); + if (fsrv->plot_file != NULL) fclose(fsrv->plot_file); /* This should improve performance a bit, since it stops the linker from doing extra work post-fork(). */ @@ -367,15 +327,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { "msan_track_origins=0", 0); - if (fsrv->use_fauxsrv) { - - afl_fauxsrv_execv(fsrv, argv); - - } else { - - execv(fsrv->target_path, argv); - - } + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() falling through. */ @@ -400,24 +352,22 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { rlen = 0; if (fsrv->exec_tmout) { - fd_set readfds; + u32 time = read_timed(fsrv->fsrv_st_fd, &status, 4, + fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p); - FD_ZERO(&readfds); - FD_SET(fsrv->fsrv_st_fd, &readfds); - timeout.tv_sec = ((fsrv->exec_tmout * FORK_WAIT_MULT) / 1000); - timeout.tv_usec = ((fsrv->exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; + if (!time) { - int sret = select(fsrv->fsrv_st_fd + 1, &readfds, NULL, NULL, &timeout); + kill(fsrv->fsrv_pid, SIGKILL); - if (sret == 0) { + } else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) { fsrv->child_timed_out = 1; - kill(fsrv->child_pid, SIGKILL); + kill(fsrv->fsrv_pid, SIGKILL); } else { - - rlen = read(fsrv->fsrv_st_fd, &status, 4); - + + rlen = 4; + } } else { @@ -431,7 +381,98 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { if (rlen == 4) { - if (!getenv("AFL_QUIET")) OKF("All right - fork server is up."); + if (!be_quiet) OKF("All right - fork server is up."); + + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { + + if (!be_quiet) + ACTF("Extended forkserver functions received (%08x).", status); + + if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + + fsrv->snapshot = 1; + if (!be_quiet) ACTF("Using SNAPSHOT feature."); + + } + + if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + + fsrv->map_size = FS_OPT_GET_MAPSIZE(status); + if (fsrv->map_size % 8) // should not happen + fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); + if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); + if (fsrv->map_size > MAP_SIZE) + FATAL( + "Target's coverage map size of %u is larger than the one this " + "afl++ is compiled with (%u)\n", + fsrv->map_size, MAP_SIZE); + + } + + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + + if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + + // this is not afl-fuzz - we deny and return + status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT)); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + return; + + } + + if (!be_quiet) ACTF("Using AUTODICT feature."); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) + FATAL("Reading from forkserver failed."); + + if (status < 2 || (u32)status > 0xffffff) + FATAL("Dictionary has an illegal size: %d", status); + + u32 len = status, offset = 0, count = 0; + u8 *dict = ck_alloc(len); + if (dict == NULL) + FATAL("Could not allocate %u bytes of autodictionary memmory", len); + + while (len != 0) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, len); + if (rlen > 0) { + + len -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, len); + + } + + } + + len = status; + offset = 0; + while (offset < status && (u8)dict[offset] + offset < status) { + + fsrv->function_ptr(fsrv->function_opt, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) ACTF("Loaded %u autodictionary entries", count); + ck_free(dict); + + } + + } + return; } @@ -476,6 +517,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { } else { + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " "before receiving any input\n" @@ -508,7 +551,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { "options\n" " fail, poke <afl-users@googlegroups.com> for troubleshooting " "tips.\n", - forkserver_DMS(fsrv->mem_limit << 20), fsrv->mem_limit - 1); + stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20), + fsrv->mem_limit - 1); } @@ -543,6 +587,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { } else { + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + SAYF( "\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " @@ -574,7 +620,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { "never\n" " reached before the program terminates.\n\n" : "", - forkserver_DMS(fsrv->mem_limit << 20), fsrv->mem_limit - 1); + stringify_int(val_buf, sizeof(val_buf), fsrv->mem_limit << 20), + fsrv->mem_limit - 1); } @@ -582,11 +629,19 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { } +static void afl_fsrv_kill(afl_forkserver_t *fsrv) { + + if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL); + if (fsrv->fsrv_pid > 0) kill(fsrv->fsrv_pid, SIGKILL); + if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } + +} + void afl_fsrv_killall() { LIST_FOREACH(&fsrv_list, afl_forkserver_t, { - if (el->child_pid > 0) kill(el->child_pid, SIGKILL); + afl_fsrv_kill(el); }); @@ -594,6 +649,7 @@ void afl_fsrv_killall() { void afl_fsrv_deinit(afl_forkserver_t *fsrv) { + afl_fsrv_kill(fsrv); list_remove(&fsrv_list, fsrv); } |