Home | History | Annotate | Download | only in posix
      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