"Fossies" - the Fresh Open Source Software Archive

Member "honggfuzz-2.2/subproc.c" (23 Apr 2020, 19368 Bytes) of package /linux/privat/honggfuzz-2.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "subproc.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.1_vs_2.2.

    1 /*
    2  *
    3  * honggfuzz - routines dealing with subprocesses
    4  * -----------------------------------------
    5  *
    6  * Author: Robert Swiecki <swiecki@google.com>
    7  *         Felix Gröbert <groebert@google.com>
    8  *
    9  * Copyright 2010-2018 by Google Inc. All Rights Reserved.
   10  *
   11  * Licensed under the Apache License, Version 2.0 (the "License"); you may
   12  * not use this file except in compliance with the License. You may obtain
   13  * a copy of the License at
   14  *
   15  * http://www.apache.org/licenses/LICENSE-2.0
   16  *
   17  * Unless required by applicable law or agreed to in writing, software
   18  * distributed under the License is distributed on an "AS IS" BASIS,
   19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   20  * implied. See the License for the specific language governing
   21  * permissions and limitations under the License.
   22  *
   23  */
   24 
   25 #include "subproc.h"
   26 
   27 #include <errno.h>
   28 #include <fcntl.h>
   29 #include <inttypes.h>
   30 #include <signal.h>
   31 #include <stdio.h>
   32 #include <stdlib.h>
   33 #include <string.h>
   34 #include <sys/resource.h>
   35 #include <sys/socket.h>
   36 #include <sys/time.h>
   37 #include <sys/types.h>
   38 #include <sys/wait.h>
   39 #include <unistd.h>
   40 
   41 #include "arch.h"
   42 #include "fuzz.h"
   43 #include "libhfcommon/common.h"
   44 #include "libhfcommon/files.h"
   45 #include "libhfcommon/log.h"
   46 #include "libhfcommon/util.h"
   47 
   48 extern char** environ;
   49 
   50 const char* subproc_StatusToStr(int status, char* str, size_t len) {
   51     if (WIFEXITED(status)) {
   52         snprintf(str, len, "EXITED, exit code: %d", WEXITSTATUS(status));
   53         return str;
   54     }
   55 
   56     if (WIFSIGNALED(status)) {
   57         snprintf(
   58             str, len, "SIGNALED, signal: %d (%s)", WTERMSIG(status), strsignal(WTERMSIG(status)));
   59         return str;
   60     }
   61     if (WIFCONTINUED(status)) {
   62         snprintf(str, len, "CONTINUED");
   63         return str;
   64     }
   65 
   66     if (!WIFSTOPPED(status)) {
   67         snprintf(str, len, "UNKNOWN STATUS: %d", status);
   68         return str;
   69     }
   70 
   71     /* Must be in a stopped state */
   72     if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
   73         snprintf(str, len, "STOPPED (linux syscall): %d (%s)", WSTOPSIG(status),
   74             strsignal(WSTOPSIG(status)));
   75         return str;
   76     }
   77 #if defined(PTRACE_EVENT_STOP)
   78 #define __LINUX_WPTRACEEVENT(x) ((x & 0xff0000) >> 16)
   79     if (WSTOPSIG(status) == SIGTRAP && __LINUX_WPTRACEEVENT(status) != 0) {
   80         switch (__LINUX_WPTRACEEVENT(status)) {
   81             case PTRACE_EVENT_FORK:
   82                 snprintf(str, len, "EVENT (Linux) - fork - with signal: %d (%s)", WSTOPSIG(status),
   83                     strsignal(WSTOPSIG(status)));
   84                 return str;
   85             case PTRACE_EVENT_VFORK:
   86                 snprintf(str, len, "EVENT (Linux) - vfork - with signal: %d (%s)", WSTOPSIG(status),
   87                     strsignal(WSTOPSIG(status)));
   88                 return str;
   89             case PTRACE_EVENT_CLONE:
   90                 snprintf(str, len, "EVENT (Linux) - clone - with signal: %d (%s)", WSTOPSIG(status),
   91                     strsignal(WSTOPSIG(status)));
   92                 return str;
   93             case PTRACE_EVENT_EXEC:
   94                 snprintf(str, len, "EVENT (Linux) - exec - with signal: %d (%s)", WSTOPSIG(status),
   95                     strsignal(WSTOPSIG(status)));
   96                 return str;
   97             case PTRACE_EVENT_VFORK_DONE:
   98                 snprintf(str, len, "EVENT (Linux) - vfork_done - with signal: %d (%s)",
   99                     WSTOPSIG(status), strsignal(WSTOPSIG(status)));
  100                 return str;
  101             case PTRACE_EVENT_EXIT:
  102                 snprintf(str, len, "EVENT (Linux) - exit - with signal: %d (%s)", WSTOPSIG(status),
  103                     strsignal(WSTOPSIG(status)));
  104                 return str;
  105             case PTRACE_EVENT_SECCOMP:
  106                 snprintf(str, len, "EVENT (Linux) - seccomp - with signal: %d (%s)",
  107                     WSTOPSIG(status), strsignal(WSTOPSIG(status)));
  108                 return str;
  109             case PTRACE_EVENT_STOP:
  110                 snprintf(str, len, "EVENT (Linux) - stop - with signal: %d (%s)", WSTOPSIG(status),
  111                     strsignal(WSTOPSIG(status)));
  112                 return str;
  113             default:
  114                 snprintf(str, len, "EVENT (Linux) UNKNOWN (%d): with signal: %d (%s)",
  115                     __LINUX_WPTRACEEVENT(status), WSTOPSIG(status), strsignal(WSTOPSIG(status)));
  116                 return str;
  117         }
  118     }
  119 #endif /*  defined(PTRACE_EVENT_STOP)  */
  120 
  121     snprintf(
  122         str, len, "STOPPED with signal: %d (%s)", WSTOPSIG(status), strsignal(WSTOPSIG(status)));
  123     return str;
  124 }
  125 
  126 static bool subproc_persistentSendFileIndicator(run_t* run) {
  127     uint64_t len = (uint64_t)run->dynfile->size;
  128     if (!files_sendToSocketNB(run->persistentSock, (uint8_t*)&len, sizeof(len))) {
  129         PLOG_W("files_sendToSocketNB(len=%zu)", sizeof(len));
  130         return false;
  131     }
  132     return true;
  133 }
  134 
  135 static bool subproc_persistentGetReady(run_t* run) {
  136     uint8_t rcv;
  137     if (recv(run->persistentSock, &rcv, sizeof(rcv), MSG_DONTWAIT) != sizeof(rcv)) {
  138         return false;
  139     }
  140     if (rcv != HFReadyTag) {
  141         LOG_E("Received invalid message from the persistent process: '%c' (0x%" PRIx8
  142               ") , expected '%c' (0x%" PRIx8 ")",
  143             rcv, rcv, HFReadyTag, HFReadyTag);
  144         return false;
  145     }
  146     return true;
  147 }
  148 
  149 bool subproc_persistentModeStateMachine(run_t* run) {
  150     if (!run->global->exe.persistent) {
  151         return false;
  152     }
  153 
  154     for (;;) {
  155         switch (run->runState) {
  156             case _HF_RS_WAITING_FOR_INITIAL_READY: {
  157                 if (!subproc_persistentGetReady(run)) {
  158                     return false;
  159                 }
  160                 run->runState = _HF_RS_SEND_DATA;
  161             }; break;
  162             case _HF_RS_SEND_DATA: {
  163                 if (!subproc_persistentSendFileIndicator(run)) {
  164                     LOG_E("Could not send the file size indicator to the persistent process. "
  165                           "Killing the process pid=%d",
  166                         (int)run->pid);
  167                     kill(run->pid, SIGKILL);
  168                     return false;
  169                 }
  170                 run->runState = _HF_RS_WAITING_FOR_READY;
  171             }; break;
  172             case _HF_RS_WAITING_FOR_READY: {
  173                 if (!subproc_persistentGetReady(run)) {
  174                     return false;
  175                 }
  176                 run->runState = _HF_RS_SEND_DATA;
  177                 /* The current persistent round is done */
  178                 return true;
  179             }; break;
  180             default:
  181                 LOG_F("Unknown runState: %d", run->runState);
  182         }
  183     }
  184 }
  185 
  186 static void subproc_prepareExecvArgs(run_t* run) {
  187     size_t x = 0;
  188     for (x = 0; x < _HF_ARGS_MAX && x < (size_t)run->global->exe.argc; x++) {
  189         const char* ph_str = strstr(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER);
  190         if (!strcmp(run->global->exe.cmdline[x], _HF_FILE_PLACEHOLDER)) {
  191             run->args[x] = _HF_INPUT_FILE_PATH;
  192         } else if (ph_str) {
  193             static __thread char argData[PATH_MAX];
  194             snprintf(argData, sizeof(argData), "%.*s%s",
  195                 (int)(ph_str - run->global->exe.cmdline[x]), run->global->exe.cmdline[x],
  196                 _HF_INPUT_FILE_PATH);
  197             run->args[x] = argData;
  198         } else {
  199             run->args[x] = (char*)run->global->exe.cmdline[x];
  200         }
  201     }
  202     run->args[x] = NULL;
  203 }
  204 
  205 static bool subproc_PrepareExecv(run_t* run) {
  206     /*
  207      * The address space limit. If big enough - roughly the size of RAM used
  208      */
  209 #ifdef RLIMIT_AS
  210     if (run->global->exe.asLimit) {
  211         const struct rlimit rl = {
  212             .rlim_cur = run->global->exe.asLimit * 1024ULL * 1024ULL,
  213             .rlim_max = run->global->exe.asLimit * 1024ULL * 1024ULL,
  214         };
  215         if (setrlimit(RLIMIT_AS, &rl) == -1) {
  216             PLOG_W("Couldn't enforce the RLIMIT_AS resource limit, ignoring");
  217         }
  218     }
  219 #endif /* ifdef RLIMIT_AS */
  220 #ifdef RLIMIT_RSS
  221     if (run->global->exe.rssLimit) {
  222         const struct rlimit rl = {
  223             .rlim_cur = run->global->exe.rssLimit * 1024ULL * 1024ULL,
  224             .rlim_max = run->global->exe.rssLimit * 1024ULL * 1024ULL,
  225         };
  226         if (setrlimit(RLIMIT_RSS, &rl) == -1) {
  227             PLOG_W("Couldn't enforce the RLIMIT_RSS resource limit, ignoring");
  228         }
  229     }
  230 #endif /* ifdef RLIMIT_RSS */
  231 #ifdef RLIMIT_DATA
  232     if (run->global->exe.dataLimit) {
  233         const struct rlimit rl = {
  234             .rlim_cur = run->global->exe.dataLimit * 1024ULL * 1024ULL,
  235             .rlim_max = run->global->exe.dataLimit * 1024ULL * 1024ULL,
  236         };
  237         if (setrlimit(RLIMIT_DATA, &rl) == -1) {
  238             PLOG_W("Couldn't enforce the RLIMIT_DATA resource limit, ignoring");
  239         }
  240     }
  241 #endif /* ifdef RLIMIT_DATA */
  242 #ifdef RLIMIT_CORE
  243     const struct rlimit rl = {
  244         .rlim_cur = run->global->exe.coreLimit * 1024ULL * 1024ULL,
  245         .rlim_max = run->global->exe.coreLimit * 1024ULL * 1024ULL,
  246     };
  247     if (setrlimit(RLIMIT_CORE, &rl) == -1) {
  248         PLOG_W("Couldn't enforce the RLIMIT_CORE resource limit, ignoring");
  249     }
  250 #endif /* ifdef RLIMIT_CORE */
  251 #ifdef RLIMIT_STACK
  252     if (run->global->exe.stackLimit) {
  253         const struct rlimit rl = {
  254             .rlim_cur = run->global->exe.stackLimit * 1024ULL * 1024ULL,
  255             .rlim_max = run->global->exe.stackLimit * 1024ULL * 1024ULL,
  256         };
  257         if (setrlimit(RLIMIT_STACK, &rl) == -1) {
  258             PLOG_W("Couldn't enforce the RLIMIT_STACK resource limit, ignoring");
  259         }
  260     }
  261 #endif /* ifdef RLIMIT_STACK */
  262 
  263     if (run->global->exe.clearEnv) {
  264         environ = NULL;
  265     }
  266     for (size_t i = 0; i < ARRAYSIZE(run->global->exe.env_ptrs) && run->global->exe.env_ptrs[i];
  267          i++) {
  268         putenv(run->global->exe.env_ptrs[i]);
  269     }
  270     char fuzzNo[128];
  271     snprintf(fuzzNo, sizeof(fuzzNo), "%" PRId32, run->fuzzNo);
  272     setenv(_HF_THREAD_NO_ENV, fuzzNo, 1);
  273     if (run->global->exe.netDriver) {
  274         setenv(_HF_THREAD_NETDRIVER_ENV, "1", 1);
  275     }
  276 
  277     /* Make sure it's a new process group / session, so waitpid can wait for -(run->pid) */
  278     setsid();
  279 
  280     util_closeStdio(/* close_stdin= */ run->global->exe.nullifyStdio,
  281         /* close_stdout= */ run->global->exe.nullifyStdio,
  282         /* close_stderr= */ run->global->exe.nullifyStdio);
  283 
  284     /* The coverage bitmap/feedback structure */
  285     if (TEMP_FAILURE_RETRY(dup2(run->global->feedback.covFeedbackFd, _HF_COV_BITMAP_FD)) == -1) {
  286         PLOG_E("dup2(%d, _HF_COV_BITMAP_FD=%d)", run->global->feedback.covFeedbackFd,
  287             _HF_COV_BITMAP_FD);
  288         return false;
  289     }
  290     /* The const comparison bitmap/feedback structure */
  291     if (run->global->feedback.cmpFeedback &&
  292         TEMP_FAILURE_RETRY(dup2(run->global->feedback.cmpFeedbackFd, _HF_CMP_BITMAP_FD)) == -1) {
  293         PLOG_E("dup2(%d, _HF_CMP_BITMAP_FD=%d)", run->global->feedback.cmpFeedbackFd,
  294             _HF_CMP_BITMAP_FD);
  295         return false;
  296     }
  297 
  298     /* The per-thread coverage feedback bitmap */
  299     if (TEMP_FAILURE_RETRY(dup2(run->perThreadCovFeedbackFd, _HF_PERTHREAD_BITMAP_FD)) == -1) {
  300         PLOG_E("dup2(%d, _HF_CMP_PERTHREAD_FD=%d)", run->perThreadCovFeedbackFd,
  301             _HF_PERTHREAD_BITMAP_FD);
  302         return false;
  303     }
  304 
  305     /* Do not try to handle input files with socketfuzzer */
  306     if (!run->global->socketFuzzer.enabled) {
  307         /* The input file to _HF_INPUT_FD */
  308         if (TEMP_FAILURE_RETRY(dup2(run->dynfile->fd, _HF_INPUT_FD)) == -1) {
  309             PLOG_E("dup2('%d', _HF_INPUT_FD='%d')", run->dynfile->fd, _HF_INPUT_FD);
  310             return false;
  311         }
  312         if (lseek(_HF_INPUT_FD, 0, SEEK_SET) == (off_t)-1) {
  313             PLOG_E("lseek(_HF_INPUT_FD=%d, 0, SEEK_SET)", _HF_INPUT_FD);
  314             return false;
  315         }
  316         if (run->global->exe.fuzzStdin &&
  317             TEMP_FAILURE_RETRY(dup2(run->dynfile->fd, STDIN_FILENO)) == -1) {
  318             PLOG_E("dup2(_HF_INPUT_FD=%d, STDIN_FILENO=%d)", run->dynfile->fd, STDIN_FILENO);
  319             return false;
  320         }
  321     }
  322 
  323     /* The log FD */
  324     if ((run->global->exe.netDriver || run->global->exe.persistent)) {
  325         if (TEMP_FAILURE_RETRY(dup2(logFd(), _HF_LOG_FD)) == -1) {
  326             PLOG_E("dup2(%d, _HF_LOG_FD=%d)", logFd(), _HF_LOG_FD);
  327             return false;
  328         }
  329         char llstr[32];
  330         snprintf(llstr, sizeof(llstr), "%d", logGetLevel());
  331         setenv(_HF_LOG_LEVEL_ENV, llstr, 1);
  332     }
  333 
  334     sigset_t sset;
  335     sigemptyset(&sset);
  336     if (sigprocmask(SIG_SETMASK, &sset, NULL) == -1) {
  337         PLOG_W("sigprocmask(empty_set)");
  338     }
  339 
  340     subproc_prepareExecvArgs(run);
  341     return true;
  342 }
  343 
  344 static bool subproc_New(run_t* run) {
  345     if (run->pid) {
  346         return true;
  347     }
  348 
  349     int sv[2];
  350     if (run->global->exe.persistent) {
  351         if (run->persistentSock != -1) {
  352             close(run->persistentSock);
  353         }
  354 
  355         int sock_type = SOCK_STREAM;
  356 #if defined(SOCK_CLOEXEC)
  357         sock_type |= SOCK_CLOEXEC;
  358 #endif
  359         if (socketpair(AF_UNIX, sock_type, 0, sv) == -1) {
  360             PLOG_W("socketpair(AF_UNIX, SOCK_STREAM, 0, sv)");
  361             return false;
  362         }
  363         run->persistentSock = sv[0];
  364     }
  365 
  366     LOG_D("Forking new process for thread: %" PRId32, run->fuzzNo);
  367 
  368     run->pid = arch_fork(run);
  369     if (run->pid == -1) {
  370         PLOG_E("Couldn't fork");
  371         run->pid = 0;
  372         return false;
  373     }
  374     /* The child process */
  375     if (!run->pid) {
  376         logMutexReset();
  377         /*
  378          * Reset sighandlers, and set alarm(1). It's a guarantee against dead-locks
  379          * in the child, where we ensure here that the child process will either
  380          * execve or get signaled by SIGALRM within 1 second.
  381          *
  382          * Those deadlocks typically stem from the fact, that malloc() can behave weirdly
  383          * when fork()-ing a single thread of a process: e.g. with glibc < 2.24
  384          * (or, Ubuntu's 2.23-0ubuntu6). For more see
  385          * http://changelogs.ubuntu.com/changelogs/pool/main/g/glibc/glibc_2.23-0ubuntu7/changelog
  386          */
  387         alarm(1);
  388         signal(SIGALRM, SIG_DFL);
  389 
  390         if (run->global->exe.persistent) {
  391             if (TEMP_FAILURE_RETRY(dup2(sv[1], _HF_PERSISTENT_FD)) == -1) {
  392                 PLOG_F("dup2('%d', '%d')", sv[1], _HF_PERSISTENT_FD);
  393             }
  394             close(sv[0]);
  395             close(sv[1]);
  396         }
  397 
  398         if (!subproc_PrepareExecv(run)) {
  399             LOG_E("subproc_PrepareExecv() failed");
  400             exit(EXIT_FAILURE);
  401         }
  402 
  403         LOG_D("Launching '%s' on file '%s' (%s mode)", run->args[0],
  404             run->global->exe.persistent ? "PERSISTENT_MODE" : _HF_INPUT_FILE_PATH,
  405             run->global->exe.fuzzStdin ? "stdin" : "file");
  406 
  407         if (!arch_launchChild(run)) {
  408             LOG_E("Error launching child process");
  409             kill(run->global->threads.mainPid, SIGTERM);
  410             _exit(1);
  411         }
  412         abort();
  413     }
  414 
  415     /* Parent */
  416     LOG_D("Launched new process, pid=%d, thread: %" PRId32 " (concurrency: %zd)", (int)run->pid,
  417         run->fuzzNo, run->global->threads.threadsMax);
  418 
  419     arch_prepareParentAfterFork(run);
  420 
  421     if (run->global->exe.persistent) {
  422         close(sv[1]);
  423         run->runState = _HF_RS_WAITING_FOR_INITIAL_READY;
  424         LOG_I("Persistent mode: Launched new persistent pid=%d", (int)run->pid);
  425     }
  426 
  427     return true;
  428 }
  429 
  430 bool subproc_Run(run_t* run) {
  431     if (!subproc_New(run)) {
  432         LOG_E("subproc_New()");
  433         return false;
  434     }
  435 
  436     arch_prepareParent(run);
  437     arch_reapChild(run);
  438 
  439     int64_t diffUSecs = util_timeNowUSecs() - run->timeStartedUSecs;
  440 
  441     {
  442         static pthread_mutex_t local_mutex = PTHREAD_MUTEX_INITIALIZER;
  443         MX_SCOPED_LOCK(&local_mutex);
  444         if (diffUSecs >= ATOMIC_GET(run->global->timing.timeOfLongestUnitUSecs)) {
  445             ATOMIC_SET(run->global->timing.timeOfLongestUnitUSecs, diffUSecs);
  446         }
  447     }
  448 
  449     return true;
  450 }
  451 
  452 uint8_t subproc_System(run_t* run, const char* const argv[]) {
  453     pid_t pid = arch_fork(run);
  454     if (pid == -1) {
  455         PLOG_E("Couldn't fork");
  456         return 255;
  457     }
  458     if (!pid) {
  459         logMutexReset();
  460 
  461         setsid();
  462         util_closeStdio(
  463             /* close_stdin= */ true, /* close_stdout= */ false, /* close_stderr= */ false);
  464 
  465         sigset_t sset;
  466         sigemptyset(&sset);
  467         if (sigprocmask(SIG_SETMASK, &sset, NULL) == -1) {
  468             PLOG_W("sigprocmask(empty_set)");
  469         }
  470 
  471         execv(argv[0], (char* const*)&argv[0]);
  472         PLOG_F("Couldn't execute '%s'", argv[0]);
  473         return 255;
  474     }
  475 
  476     int flags = 0;
  477 #if defined(__WNOTHREAD)
  478     flags |= __WNOTHREAD;
  479 #endif /* defined(__WNOTHREAD) */
  480 #if defined(__WALL)
  481     flags |= __WALL;
  482 #endif /* defined(__WALL) */
  483 
  484     for (;;) {
  485         int status;
  486         int ret = TEMP_FAILURE_RETRY(wait4(pid, &status, flags, NULL));
  487         if (ret == -1) {
  488             PLOG_E("wait4() for process pid=%d", (int)pid);
  489             return 255;
  490         }
  491         if (ret != pid) {
  492             LOG_E("wait4() returned %d, but waited for %d", ret, (int)pid);
  493             return 255;
  494         }
  495         if (WIFSIGNALED(status)) {
  496             LOG_E("Command '%s' terminated with signal: %d", argv[0], WTERMSIG(status));
  497             return (100 + WTERMSIG(status));
  498         }
  499         if (WIFEXITED(status)) {
  500             if (WEXITSTATUS(status) == 0) {
  501                 return 0U;
  502             }
  503             LOG_E("Command '%s' returned with exit code %d", argv[0], WEXITSTATUS(status));
  504             return 1U;
  505         }
  506 
  507         LOG_D("wait4() returned with status: %d", status);
  508     }
  509 }
  510 
  511 void subproc_checkTimeLimit(run_t* run) {
  512     if (!run->global->timing.tmOut) {
  513         return;
  514     }
  515 
  516     int64_t curUSecs = util_timeNowUSecs();
  517     int64_t diffUSecs = curUSecs - run->timeStartedUSecs;
  518 
  519     if (run->tmOutSignaled && (diffUSecs > ((run->global->timing.tmOut + 1) * 1000000))) {
  520         /* Has this instance been already signaled due to timeout? Just, SIGKILL it */
  521         LOG_W("pid=%d has already been signaled due to timeout. Killing it with SIGKILL", run->pid);
  522         kill(run->pid, SIGKILL);
  523         return;
  524     }
  525 
  526     if ((diffUSecs > (run->global->timing.tmOut * 1000000)) && !run->tmOutSignaled) {
  527         run->tmOutSignaled = true;
  528         LOG_W("pid=%d took too much time (limit %ld s). Killing it with %s", (int)run->pid,
  529             (long)run->global->timing.tmOut,
  530             run->global->timing.tmoutVTALRM ? "SIGVTALRM" : "SIGKILL");
  531         if (run->global->timing.tmoutVTALRM) {
  532             kill(run->pid, SIGVTALRM);
  533         } else {
  534             kill(run->pid, SIGKILL);
  535         }
  536         ATOMIC_POST_INC(run->global->cnts.timeoutedCnt);
  537     }
  538 }
  539 
  540 void subproc_checkTermination(run_t* run) {
  541     if (fuzz_isTerminating()) {
  542         LOG_D("Killing pid=%d", (int)run->pid);
  543         kill(run->pid, SIGKILL);
  544     }
  545 }
  546 
  547 bool subproc_runThread(
  548     honggfuzz_t* hfuzz, pthread_t* thread, void* (*thread_func)(void*), bool joinable) {
  549     pthread_attr_t attr;
  550 
  551     pthread_attr_init(&attr);
  552     pthread_attr_setdetachstate(
  553         &attr, joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED);
  554     pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
  555     pthread_attr_setguardsize(&attr, (size_t)sysconf(_SC_PAGESIZE));
  556 
  557     if (pthread_create(thread, &attr, thread_func, (void*)hfuzz) < 0) {
  558         PLOG_W("Couldn't create a new thread");
  559         return false;
  560     }
  561 
  562     pthread_attr_destroy(&attr);
  563 
  564     return true;
  565 }