summaryrefslogtreecommitdiff
path: root/posix/arch.c
diff options
context:
space:
mode:
Diffstat (limited to 'posix/arch.c')
-rw-r--r--posix/arch.c163
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;
}