1 /* 2 * 3 * honggfuzz - architecture dependent code (POSIX / SIGNAL) 4 * ----------------------------------------- 5 * 6 * Author: Robert Swiecki <swiecki (at) google.com> 7 * 8 * Copyright 2010-2018 by Google Inc. All Rights Reserved. 9 * 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may 11 * not use this file except in compliance with the License. You may obtain 12 * a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software 17 * distributed under the License is distributed on an "AS IS" BASIS, 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 * implied. See the License for the specific language governing 20 * permissions and limitations under the License. 21 * 22 */ 23 24 #include "arch.h" 25 26 #include <ctype.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <locale.h> 30 #include <poll.h> 31 #include <signal.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/cdefs.h> 36 #include <sys/resource.h> 37 #include <sys/stat.h> 38 #include <sys/time.h> 39 #include <sys/types.h> 40 #include <sys/wait.h> 41 #include <time.h> 42 #include <unistd.h> 43 44 #include "fuzz.h" 45 #include "libhfcommon/common.h" 46 #include "libhfcommon/files.h" 47 #include "libhfcommon/log.h" 48 #include "libhfcommon/util.h" 49 #include "subproc.h" 50 51 struct { 52 bool important; 53 const char* descr; 54 } arch_sigs[NSIG] = { 55 [0 ...(NSIG - 1)].important = false, 56 [0 ...(NSIG - 1)].descr = "UNKNOWN", 57 58 [SIGILL].important = true, 59 [SIGILL].descr = "SIGILL", 60 61 [SIGFPE].important = true, 62 [SIGFPE].descr = "SIGFPE", 63 64 [SIGSEGV].important = true, 65 [SIGSEGV].descr = "SIGSEGV", 66 67 [SIGBUS].important = true, 68 [SIGBUS].descr = "SIGBUS", 69 70 /* Is affected from monitorSIGABRT flag */ 71 [SIGABRT].important = false, 72 [SIGABRT].descr = "SIGABRT", 73 74 /* Is affected from tmout_vtalrm flag */ 75 [SIGVTALRM].important = false, 76 [SIGVTALRM].descr = "SIGVTALRM-TMOUT", 77 }; 78 79 /* 80 * Returns true if a process exited (so, presumably, we can delete an input 81 * file) 82 */ 83 static void arch_analyzeSignal(run_t* run, int status) { 84 /* 85 * Resumed by delivery of SIGCONT 86 */ 87 if (WIFCONTINUED(status)) { 88 return; 89 } 90 91 /* 92 * Boring, the process just exited 93 */ 94 if (WIFEXITED(status)) { 95 LOG_D("Process (pid %d) exited normally with status %d", run->pid, WEXITSTATUS(status)); 96 return; 97 } 98 99 /* 100 * Shouldn't really happen, but, well.. 101 */ 102 if (!WIFSIGNALED(status)) { 103 LOG_E("Process (pid %d) exited with the following status %d, please report that as a bug", 104 run->pid, status); 105 return; 106 } 107 108 int termsig = WTERMSIG(status); 109 LOG_D("Process (pid %d) killed by signal %d '%s'", run->pid, termsig, strsignal(termsig)); 110 if (!arch_sigs[termsig].important) { 111 LOG_D("It's not that important signal, skipping"); 112 return; 113 } 114 115 char localtmstr[PATH_MAX]; 116 util_getLocalTime("%F.%H.%M.%S", localtmstr, sizeof(localtmstr), time(NULL)); 117 118 char newname[PATH_MAX]; 119 120 /* If dry run mode, copy file with same name into workspace */ 121 if (run->global->mutate.mutationsPerRun == 0U && run->global->cfg.useVerifier) { 122 snprintf(newname, sizeof(newname), "%s", run->origFileName); 123 } else { 124 snprintf(newname, sizeof(newname), "%s/%s.PID.%d.TIME.%s.%s", run->global->io.crashDir, 125 arch_sigs[termsig].descr, run->pid, localtmstr, run->global->io.fileExtn); 126 } 127 128 LOG_I("Ok, that's interesting, saving input '%s'", newname); 129 130 /* 131 * All crashes are marked as unique due to lack of information in POSIX arch 132 */ 133 ATOMIC_POST_INC(run->global->cnts.crashesCnt); 134 ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt); 135 136 if (files_writeBufToFile( 137 newname, run->dynamicFile, run->dynamicFileSz, O_CREAT | O_EXCL | O_WRONLY) == false) { 138 LOG_E("Couldn't save crash to '%s'", run->crashFileName); 139 } 140 } 141 142 pid_t arch_fork(run_t* fuzzer HF_ATTR_UNUSED) { 143 return fork(); 144 } 145 146 bool arch_launchChild(run_t* run) { 147 #define ARGS_MAX 512 148 const char* args[ARGS_MAX + 2]; 149 char argData[PATH_MAX]; 150 151 char inputFile[PATH_MAX]; 152 snprintf(inputFile, sizeof(inputFile), "/dev/fd/%d", run->dynamicFileCopyFd); 153 154 int x; 155 for (x = 0; x < ARGS_MAX && x < run->global->exe.argc; x++) { 156 if (run->global->exe.persistent || run->global->exe.fuzzStdin) { 157 args[x] = run->global->exe.cmdline[x]; 158 } else if (!strcmp(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER)) { 159 args[x] = inputFile; 160 } else if (strstr(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER)) { 161 const char* off = strstr(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER); 162 snprintf(argData, sizeof(argData), "%.*s%s", (int)(off - run->global->exe.cmdline[x]), 163 run->global->exe.cmdline[x], inputFile); 164 args[x] = argData; 165 } else { 166 args[x] = run->global->exe.cmdline[x]; 167 } 168 } 169 args[x++] = NULL; 170 171 LOG_D("Launching '%s' on file '%s'", args[0], inputFile); 172 173 /* alarm persists across forks, so disable it here */ 174 alarm(0); 175 execvp(args[0], (char* const*)args); 176 alarm(1); 177 178 return false; 179 } 180 181 void arch_prepareParent(run_t* fuzzer HF_ATTR_UNUSED) { 182 } 183 184 void arch_prepareParentAfterFork(run_t* fuzzer HF_ATTR_UNUSED) { 185 } 186 187 static bool arch_checkWait(run_t* run) { 188 /* All queued wait events must be tested when SIGCHLD was delivered */ 189 for (;;) { 190 int status; 191 int wflags = WNOHANG; 192 #if defined(__WNOTHREAD) 193 wflags |= __WNOTHREAD; 194 #endif /* defined(__WNOTHREAD) */ 195 #if defined(__WALL) 196 wflags |= __WALL; 197 #endif /* defined(__WALL) */ 198 199 pid_t pid = TEMP_FAILURE_RETRY(waitpid(run->pid, &status, wflags)); 200 if (pid == 0) { 201 return false; 202 } 203 if (pid == -1 && errno == ECHILD) { 204 LOG_D("No more processes to track"); 205 return true; 206 } 207 if (pid == -1) { 208 PLOG_F("waitpid() failed"); 209 } 210 211 char statusStr[4096]; 212 LOG_D("pid=%d returned with status: %s", pid, 213 subproc_StatusToStr(status, statusStr, sizeof(statusStr))); 214 215 arch_analyzeSignal(run, status); 216 217 if (pid == run->pid && (WIFEXITED(status) || WIFSIGNALED(status))) { 218 if (run->global->exe.persistent) { 219 if (!fuzz_isTerminating()) { 220 LOG_W("Persistent mode: pid=%d exited with status: %s", (int)run->pid, 221 subproc_StatusToStr(status, statusStr, sizeof(statusStr))); 222 } 223 } 224 return true; 225 } 226 } 227 } 228 229 void arch_reapChild(run_t* run) { 230 for (;;) { 231 if (subproc_persistentModeStateMachine(run)) { 232 break; 233 } 234 235 subproc_checkTimeLimit(run); 236 subproc_checkTermination(run); 237 238 if (run->global->exe.persistent) { 239 struct pollfd pfd = { 240 .fd = run->persistentSock, 241 .events = POLLIN, 242 }; 243 int r = poll(&pfd, 1, 250 /* 0.25s */); 244 if (r == -1 && errno != EINTR) { 245 PLOG_F("poll(fd=%d)", run->persistentSock); 246 } 247 } else { 248 /* Return with SIGIO, SIGCHLD and with SIGUSR1 */ 249 const struct timespec ts = { 250 .tv_sec = 0ULL, 251 .tv_nsec = (1000ULL * 1000ULL * 250ULL), 252 }; 253 int sig = sigtimedwait(&run->global->exe.waitSigSet, NULL, &ts /* 0.25s */); 254 if (sig == -1 && (errno != EAGAIN && errno != EINTR)) { 255 PLOG_F("sigtimedwait(SIGIO|SIGCHLD|SIGUSR1)"); 256 } 257 } 258 259 if (arch_checkWait(run)) { 260 run->pid = 0; 261 break; 262 } 263 } 264 } 265 266 bool arch_archInit(honggfuzz_t* hfuzz) { 267 /* Default is true for all platforms except Android */ 268 arch_sigs[SIGABRT].important = hfuzz->cfg.monitorSIGABRT; 269 /* Default is false */ 270 arch_sigs[SIGVTALRM].important = hfuzz->timing.tmoutVTALRM; 271 272 /* Make %'d work */ 273 setlocale(LC_NUMERIC, "en_US.UTF-8"); 274 275 return true; 276 } 277 278 void arch_sigFunc(int sig HF_ATTR_UNUSED) { 279 return; 280 } 281 282 bool arch_archThreadInit(run_t* fuzzer HF_ATTR_UNUSED) { 283 return true; 284 } 285