diff options
Diffstat (limited to 'posix/arch.c')
-rw-r--r-- | posix/arch.c | 163 |
1 files changed, 76 insertions, 87 deletions
diff --git a/posix/arch.c b/posix/arch.c index cdc14293..c6090b0f 100644 --- a/posix/arch.c +++ b/posix/arch.c @@ -46,41 +46,42 @@ #include "libhfcommon/files.h" #include "libhfcommon/log.h" #include "libhfcommon/util.h" +#include "report.h" +#include "sanitizers.h" #include "subproc.h" struct { - bool important; + bool important; const char* descr; } arch_sigs[NSIG] = { [0 ...(NSIG - 1)].important = false, - [0 ...(NSIG - 1)].descr = "UNKNOWN", + [0 ...(NSIG - 1)].descr = "UNKNOWN", [SIGILL].important = true, - [SIGILL].descr = "SIGILL", + [SIGILL].descr = "SIGILL", [SIGFPE].important = true, - [SIGFPE].descr = "SIGFPE", + [SIGFPE].descr = "SIGFPE", [SIGSEGV].important = true, - [SIGSEGV].descr = "SIGSEGV", + [SIGSEGV].descr = "SIGSEGV", [SIGBUS].important = true, - [SIGBUS].descr = "SIGBUS", + [SIGBUS].descr = "SIGBUS", - /* Is affected from monitorSIGABRT flag */ - [SIGABRT].important = false, - [SIGABRT].descr = "SIGABRT", + [SIGABRT].important = true, + [SIGABRT].descr = "SIGABRT", /* Is affected from tmout_vtalrm flag */ [SIGVTALRM].important = false, - [SIGVTALRM].descr = "SIGVTALRM-TMOUT", + [SIGVTALRM].descr = "SIGVTALRM-TMOUT", }; /* * Returns true if a process exited (so, presumably, we can delete an input * file) */ -static void arch_analyzeSignal(run_t* run, int status) { +static void arch_analyzeSignal(run_t* run, pid_t pid, int status) { /* * Resumed by delivery of SIGCONT */ @@ -92,7 +93,7 @@ static void arch_analyzeSignal(run_t* run, int status) { * Boring, the process just exited */ if (WIFEXITED(status)) { - LOG_D("Process (pid %d) exited normally with status %d", run->pid, WEXITSTATUS(status)); + LOG_D("Process (pid %d) exited normally with status %d", pid, WEXITSTATUS(status)); return; } @@ -101,42 +102,77 @@ static void arch_analyzeSignal(run_t* run, int status) { */ if (!WIFSIGNALED(status)) { LOG_E("Process (pid %d) exited with the following status %d, please report that as a bug", - run->pid, status); + pid, status); return; } int termsig = WTERMSIG(status); - LOG_D("Process (pid %d) killed by signal %d '%s'", run->pid, termsig, strsignal(termsig)); + LOG_D("Process (pid %d) killed by signal %d '%s'", pid, termsig, strsignal(termsig)); if (!arch_sigs[termsig].important) { LOG_D("It's not that important signal, skipping"); return; } - char localtmstr[PATH_MAX]; - util_getLocalTime("%F.%H.%M.%S", localtmstr, sizeof(localtmstr), time(NULL)); + funcs_t* funcs = util_Calloc(_HF_MAX_FUNCS * sizeof(funcs_t)); + defer { + free(funcs); + }; + uint64_t pc = 0; + uint64_t crashAddr = 0; + char description[HF_STR_LEN] = {}; + size_t funcCnt = sanitizers_parseReport(run, pid, funcs, &pc, &crashAddr, description); - char newname[PATH_MAX]; + /* + * Calculate backtrace callstack hash signature + */ + run->backtrace = sanitizers_hashCallstack(run, funcs, funcCnt, false); + + /* + * If unique flag is set and single frame crash, disable uniqueness for this crash + * to always save (timestamp will be added to the filename) + */ + bool saveUnique = run->global->io.saveUnique; + if (saveUnique && (funcCnt == 0)) { + saveUnique = false; + } /* If dry run mode, copy file with same name into workspace */ if (run->global->mutate.mutationsPerRun == 0U && run->global->cfg.useVerifier) { - snprintf(newname, sizeof(newname), "%s", run->origFileName); + snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir, + run->dynfile->path); + } else if (saveUnique) { + snprintf(run->crashFileName, sizeof(run->crashFileName), + "%s/%s.PC.%" PRIx64 ".STACK.%" PRIx64 ".ADDR.%" PRIx64 ".%s", run->global->io.crashDir, + util_sigName(termsig), pc, run->backtrace, crashAddr, run->global->io.fileExtn); } else { - snprintf(newname, sizeof(newname), "%s/%s.PID.%d.TIME.%s.%s", run->global->io.crashDir, - arch_sigs[termsig].descr, run->pid, localtmstr, run->global->io.fileExtn); + char localtmstr[HF_STR_LEN]; + util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL)); + snprintf(run->crashFileName, sizeof(run->crashFileName), + "%s/%s.PC.%" PRIx64 ".STACK.%" PRIx64 ".ADDR.%" PRIx64 ".%s.%d.%s", + run->global->io.crashDir, util_sigName(termsig), pc, run->backtrace, crashAddr, + localtmstr, pid, run->global->io.fileExtn); } - LOG_I("Ok, that's interesting, saving input '%s'", newname); + if (files_exists(run->crashFileName)) { + LOG_I("Crash (dup): '%s' already exists, skipping", run->crashFileName); + /* Clear filename so that verifier can understand we hit a duplicate */ + memset(run->crashFileName, 0, sizeof(run->crashFileName)); + return; + } + + LOG_I("Ok, that's interesting, saving input '%s'", run->crashFileName); - /* - * All crashes are marked as unique due to lack of information in POSIX arch - */ ATOMIC_POST_INC(run->global->cnts.crashesCnt); ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt); + /* If unique crash found, reset dynFile counter */ + ATOMIC_CLEAR(run->global->cfg.dynFileIterExpire); - if (files_writeBufToFile( - newname, run->dynamicFile, run->dynamicFileSz, O_CREAT | O_EXCL | O_WRONLY) == false) { + if (!files_writeBufToFile(run->crashFileName, run->dynfile->data, run->dynfile->size, + O_CREAT | O_EXCL | O_WRONLY)) { LOG_E("Couldn't save crash to '%s'", run->crashFileName); } + + report_appendReport(pid, run, funcs, funcCnt, pc, crashAddr, termsig, "", description); } pid_t arch_fork(run_t* fuzzer HF_ATTR_UNUSED) { @@ -144,35 +180,9 @@ pid_t arch_fork(run_t* fuzzer HF_ATTR_UNUSED) { } bool arch_launchChild(run_t* run) { -#define ARGS_MAX 512 - const char* args[ARGS_MAX + 2]; - char argData[PATH_MAX]; - - char inputFile[PATH_MAX]; - snprintf(inputFile, sizeof(inputFile), "/dev/fd/%d", run->dynamicFileCopyFd); - - int x; - for (x = 0; x < ARGS_MAX && x < run->global->exe.argc; x++) { - if (run->global->exe.persistent || run->global->exe.fuzzStdin) { - args[x] = run->global->exe.cmdline[x]; - } else if (!strcmp(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER)) { - args[x] = inputFile; - } else if (strstr(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER)) { - const char* off = strstr(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER); - snprintf(argData, sizeof(argData), "%.*s%s", (int)(off - run->global->exe.cmdline[x]), - run->global->exe.cmdline[x], inputFile); - args[x] = argData; - } else { - args[x] = run->global->exe.cmdline[x]; - } - } - args[x++] = NULL; - - LOG_D("Launching '%s' on file '%s'", args[0], inputFile); - /* alarm persists across forks, so disable it here */ alarm(0); - execvp(args[0], (char* const*)args); + execvp(run->args[0], (char* const*)run->args); alarm(1); return false; @@ -187,16 +197,8 @@ void arch_prepareParentAfterFork(run_t* fuzzer HF_ATTR_UNUSED) { static bool arch_checkWait(run_t* run) { /* All queued wait events must be tested when SIGCHLD was delivered */ for (;;) { - int status; - int wflags = WNOHANG; -#if defined(__WNOTHREAD) - wflags |= __WNOTHREAD; -#endif /* defined(__WNOTHREAD) */ -#if defined(__WALL) - wflags |= __WALL; -#endif /* defined(__WALL) */ - - pid_t pid = TEMP_FAILURE_RETRY(waitpid(run->pid, &status, wflags)); + int status; + pid_t pid = TEMP_FAILURE_RETRY(waitpid(run->pid, &status, WNOHANG)); if (pid == 0) { return false; } @@ -208,17 +210,15 @@ static bool arch_checkWait(run_t* run) { PLOG_F("waitpid() failed"); } - char statusStr[4096]; - LOG_D("pid=%d returned with status: %s", pid, - subproc_StatusToStr(status, statusStr, sizeof(statusStr))); + LOG_D("pid=%d returned with status: %s", pid, subproc_StatusToStr(status)); - arch_analyzeSignal(run, status); + arch_analyzeSignal(run, pid, status); if (pid == run->pid && (WIFEXITED(status) || WIFSIGNALED(status))) { if (run->global->exe.persistent) { if (!fuzz_isTerminating()) { LOG_W("Persistent mode: pid=%d exited with status: %s", (int)run->pid, - subproc_StatusToStr(status, statusStr, sizeof(statusStr))); + subproc_StatusToStr(status)); } } return true; @@ -237,7 +237,7 @@ void arch_reapChild(run_t* run) { if (run->global->exe.persistent) { struct pollfd pfd = { - .fd = run->persistentSock, + .fd = run->persistentSock, .events = POLLIN, }; int r = poll(&pfd, 1, 250 /* 0.25s */); @@ -245,14 +245,12 @@ void arch_reapChild(run_t* run) { PLOG_F("poll(fd=%d)", run->persistentSock); } } else { - /* Return with SIGIO, SIGCHLD and with SIGUSR1 */ - const struct timespec ts = { - .tv_sec = 0ULL, - .tv_nsec = (1000ULL * 1000ULL * 250ULL), - }; - int sig = sigtimedwait(&run->global->exe.waitSigSet, NULL, &ts /* 0.25s */); - if (sig == -1 && (errno != EAGAIN && errno != EINTR)) { - PLOG_F("sigtimedwait(SIGIO|SIGCHLD|SIGUSR1)"); + /* Return with SIGIO, SIGCHLD */ + errno = 0; + int sig; + int ret = sigwait(&run->global->exe.waitSigSet, &sig); + if (ret != 0 && ret != EINTR) { + PLOG_F("sigwait(SIGIO|SIGCHLD)"); } } @@ -263,22 +261,13 @@ void arch_reapChild(run_t* run) { } } -bool arch_archInit(honggfuzz_t* hfuzz) { - /* Default is true for all platforms except Android */ - arch_sigs[SIGABRT].important = hfuzz->cfg.monitorSIGABRT; - /* Default is false */ - arch_sigs[SIGVTALRM].important = hfuzz->timing.tmoutVTALRM; - +bool arch_archInit(honggfuzz_t* hfuzz HF_ATTR_UNUSED) { /* Make %'d work */ setlocale(LC_NUMERIC, "en_US.UTF-8"); return true; } -void arch_sigFunc(int sig HF_ATTR_UNUSED) { - return; -} - bool arch_archThreadInit(run_t* fuzzer HF_ATTR_UNUSED) { return true; } |