Home | History | Annotate | Download | only in honggfuzz
      1 /*
      2  *
      3  * honggfuzz - the main file
      4  * -----------------------------------------
      5  *
      6  * Authors: Robert Swiecki <swiecki (at) google.com>
      7  *          Felix Grbert <groebert (at) google.com>
      8  *
      9  * Copyright 2010-2019 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 <errno.h>
     26 #include <getopt.h>
     27 #include <inttypes.h>
     28 #include <signal.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <sys/mman.h>
     33 #include <sys/resource.h>
     34 #include <sys/time.h>
     35 #include <time.h>
     36 #include <unistd.h>
     37 
     38 #include "cmdline.h"
     39 #include "display.h"
     40 #include "fuzz.h"
     41 #include "input.h"
     42 #include "libhfcommon/common.h"
     43 #include "libhfcommon/files.h"
     44 #include "libhfcommon/log.h"
     45 #include "libhfcommon/util.h"
     46 #include "socketfuzzer.h"
     47 #include "subproc.h"
     48 
     49 static int sigReceived = 0;
     50 
     51 /*
     52  * CygWin/MinGW incorrectly copies stack during fork(), so we need to keep some
     53  * structures in the data section
     54  */
     55 honggfuzz_t hfuzz;
     56 
     57 static void exitWithMsg(const char* msg, int exit_code) {
     58     HF_ATTR_UNUSED ssize_t sz = write(STDERR_FILENO, msg, strlen(msg));
     59     for (;;) {
     60         exit(exit_code);
     61         _exit(exit_code);
     62         abort();
     63         __builtin_trap();
     64     }
     65 }
     66 
     67 static bool showDisplay = true;
     68 static void sigHandler(int sig) {
     69     /* We should not terminate upon SIGALRM delivery */
     70     if (sig == SIGALRM) {
     71         if (fuzz_shouldTerminate()) {
     72             exitWithMsg("Terminating forcefully\n", EXIT_FAILURE);
     73         }
     74         showDisplay = true;
     75         return;
     76     }
     77     /* Do nothing with pings from the main thread */
     78     if (sig == SIGUSR1) {
     79         return;
     80     }
     81     /* It's handled in the signal thread */
     82     if (sig == SIGCHLD) {
     83         return;
     84     }
     85 
     86     if (ATOMIC_GET(sigReceived) != 0) {
     87         exitWithMsg("Repeated termination signal caugth\n", EXIT_FAILURE);
     88     }
     89 
     90     ATOMIC_SET(sigReceived, sig);
     91 }
     92 
     93 static void setupRLimits(void) {
     94     struct rlimit rlim;
     95     if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) {
     96         PLOG_W("getrlimit(RLIMIT_NOFILE)");
     97         return;
     98     }
     99     if (rlim.rlim_cur >= 1024) {
    100         return;
    101     }
    102     if (rlim.rlim_max < 1024) {
    103         LOG_E("RLIMIT_NOFILE max limit < 1024 (%zu). Expect troubles!", (size_t)rlim.rlim_max);
    104         return;
    105     }
    106     rlim.rlim_cur = MIN(1024, rlim.rlim_max);  // we don't need more
    107     if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
    108         PLOG_E("Couldn't setrlimit(RLIMIT_NOFILE, cur=%zu/max=%zu)", (size_t)rlim.rlim_cur,
    109             (size_t)rlim.rlim_max);
    110     }
    111 }
    112 
    113 static void setupMainThreadTimer(void) {
    114     const struct itimerval it = {
    115         .it_value =
    116             {
    117                 .tv_sec = 1,
    118                 .tv_usec = 0,
    119             },
    120         .it_interval =
    121             {
    122                 .tv_sec = 0,
    123                 .tv_usec = 1000ULL * 200ULL,
    124             },
    125     };
    126     if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
    127         PLOG_F("setitimer(ITIMER_REAL)");
    128     }
    129 }
    130 
    131 static void setupSignalsPreThreads(void) {
    132     /* Block signals which should be handled or blocked in the main thread */
    133     sigset_t ss;
    134     sigemptyset(&ss);
    135     sigaddset(&ss, SIGTERM);
    136     sigaddset(&ss, SIGINT);
    137     sigaddset(&ss, SIGQUIT);
    138     sigaddset(&ss, SIGALRM);
    139     sigaddset(&ss, SIGPIPE);
    140     /* Linux/arch uses it to discover events from persistent fuzzing processes */
    141     sigaddset(&ss, SIGIO);
    142     /* Let the signal thread catch SIGCHLD */
    143     sigaddset(&ss, SIGCHLD);
    144     /* This is checked for via sigwaitinfo/sigtimedwait */
    145     sigaddset(&ss, SIGUSR1);
    146     if (sigprocmask(SIG_SETMASK, &ss, NULL) != 0) {
    147         PLOG_F("pthread_sigmask(SIG_SETMASK)");
    148     }
    149 
    150     struct sigaction sa = {
    151         .sa_handler = sigHandler,
    152         .sa_flags = 0,
    153     };
    154     sigemptyset(&sa.sa_mask);
    155     if (sigaction(SIGTERM, &sa, NULL) == -1) {
    156         PLOG_F("sigaction(SIGTERM) failed");
    157     }
    158     if (sigaction(SIGINT, &sa, NULL) == -1) {
    159         PLOG_F("sigaction(SIGINT) failed");
    160     }
    161     if (sigaction(SIGQUIT, &sa, NULL) == -1) {
    162         PLOG_F("sigaction(SIGQUIT) failed");
    163     }
    164     if (sigaction(SIGALRM, &sa, NULL) == -1) {
    165         PLOG_F("sigaction(SIGQUIT) failed");
    166     }
    167     if (sigaction(SIGUSR1, &sa, NULL) == -1) {
    168         PLOG_F("sigaction(SIGUSR1) failed");
    169     }
    170     if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    171         PLOG_F("sigaction(SIGCHLD) failed");
    172     }
    173 }
    174 
    175 static void setupSignalsMainThread(void) {
    176     /* Unblock signals which should be handled by the main thread */
    177     sigset_t ss;
    178     sigemptyset(&ss);
    179     sigaddset(&ss, SIGTERM);
    180     sigaddset(&ss, SIGINT);
    181     sigaddset(&ss, SIGQUIT);
    182     sigaddset(&ss, SIGALRM);
    183     if (sigprocmask(SIG_UNBLOCK, &ss, NULL) != 0) {
    184         PLOG_F("pthread_sigmask(SIG_UNBLOCK)");
    185     }
    186 }
    187 
    188 static void printSummary(honggfuzz_t* hfuzz) {
    189     uint64_t exec_per_sec = 0;
    190     uint64_t elapsed_sec = time(NULL) - hfuzz->timing.timeStart;
    191     if (elapsed_sec) {
    192         exec_per_sec = hfuzz->cnts.mutationsCnt / elapsed_sec;
    193     }
    194     LOG_I("Summary iterations:%zu time:%" PRIu64 " speed:%" PRIu64, hfuzz->cnts.mutationsCnt,
    195         elapsed_sec, exec_per_sec);
    196 }
    197 
    198 static void pingThreads(honggfuzz_t* hfuzz) {
    199     for (size_t i = 0; i < hfuzz->threads.threadsMax; i++) {
    200         if (pthread_kill(hfuzz->threads.threads[i], SIGUSR1) != 0 && errno != EINTR) {
    201             PLOG_W("pthread_kill(thread=%zu, SIGUSR1)", i);
    202         }
    203     }
    204 }
    205 
    206 static void* signalThread(void* arg) {
    207     honggfuzz_t* hfuzz = (honggfuzz_t*)arg;
    208 
    209     sigset_t ss;
    210     sigemptyset(&ss);
    211     sigaddset(&ss, SIGCHLD);
    212     if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) != 0) {
    213         PLOG_F("Couldn't unblock SIGCHLD in the signal thread");
    214     }
    215 
    216     for (;;) {
    217         int sig;
    218         if (sigwait(&ss, &sig) != 0 && errno != EINTR) {
    219             PLOG_F("sigwait(SIGCHLD)");
    220         }
    221         if (fuzz_isTerminating()) {
    222             break;
    223         }
    224         if (sig == SIGCHLD) {
    225             pingThreads(hfuzz);
    226         }
    227     }
    228 
    229     return NULL;
    230 }
    231 
    232 int main(int argc, char** argv) {
    233     /*
    234      * Work around CygWin/MinGW
    235      */
    236     char** myargs = (char**)util_Malloc(sizeof(char*) * (argc + 1));
    237     defer {
    238         free(myargs);
    239     };
    240 
    241     int i;
    242     for (i = 0U; i < argc; i++) {
    243         myargs[i] = argv[i];
    244     }
    245     myargs[i] = NULL;
    246 
    247     if (cmdlineParse(argc, myargs, &hfuzz) == false) {
    248         LOG_F("Parsing of the cmd-line arguments failed");
    249     }
    250 
    251     if (hfuzz.display.useScreen) {
    252         display_init();
    253     }
    254 
    255     if (hfuzz.socketFuzzer.enabled) {
    256         LOG_I("No input file corpus loaded, the external socket_fuzzer is responsible for "
    257               "creating the fuzz data");
    258         setupSocketFuzzer(&hfuzz);
    259     } else if (!input_init(&hfuzz)) {
    260         LOG_F("Couldn't load input corpus");
    261         exit(EXIT_FAILURE);
    262     }
    263 
    264     if (hfuzz.mutate.dictionaryFile && (input_parseDictionary(&hfuzz) == false)) {
    265         LOG_F("Couldn't parse dictionary file ('%s')", hfuzz.mutate.dictionaryFile);
    266     }
    267 
    268     if (hfuzz.feedback.blacklistFile && (input_parseBlacklist(&hfuzz) == false)) {
    269         LOG_F("Couldn't parse stackhash blacklist file ('%s')", hfuzz.feedback.blacklistFile);
    270     }
    271 #define hfuzzl hfuzz.linux
    272     if (hfuzzl.symsBlFile &&
    273         ((hfuzzl.symsBlCnt = files_parseSymbolFilter(hfuzzl.symsBlFile, &hfuzzl.symsBl)) == 0)) {
    274         LOG_F("Couldn't parse symbols blacklist file ('%s')", hfuzzl.symsBlFile);
    275     }
    276 
    277     if (hfuzzl.symsWlFile &&
    278         ((hfuzzl.symsWlCnt = files_parseSymbolFilter(hfuzzl.symsWlFile, &hfuzzl.symsWl)) == 0)) {
    279         LOG_F("Couldn't parse symbols whitelist file ('%s')", hfuzzl.symsWlFile);
    280     }
    281 
    282     if (hfuzz.feedback.dynFileMethod != _HF_DYNFILE_NONE) {
    283         if (!(hfuzz.feedback.feedbackMap = files_mapSharedMem(
    284                   sizeof(feedback_t), &hfuzz.feedback.bbFd, "hfuzz-feedback", hfuzz.io.workDir))) {
    285             LOG_F("files_mapSharedMem(sz=%zu, dir='%s') failed", sizeof(feedback_t),
    286                 hfuzz.io.workDir);
    287         }
    288     }
    289 
    290     setupRLimits();
    291     setupSignalsPreThreads();
    292     fuzz_threadsStart(&hfuzz);
    293 
    294     pthread_t sigthread;
    295     if (!subproc_runThread(&hfuzz, &sigthread, signalThread)) {
    296         LOG_F("Couldn't start the signal thread");
    297     }
    298 
    299     setupSignalsMainThread();
    300     setupMainThreadTimer();
    301 
    302     for (;;) {
    303         if (hfuzz.display.useScreen && showDisplay) {
    304             display_display(&hfuzz);
    305             showDisplay = false;
    306         }
    307         if (ATOMIC_GET(sigReceived) > 0) {
    308             LOG_I("Signal %d (%s) received, terminating", ATOMIC_GET(sigReceived),
    309                 strsignal(ATOMIC_GET(sigReceived)));
    310             break;
    311         }
    312         if (ATOMIC_GET(hfuzz.threads.threadsFinished) >= hfuzz.threads.threadsMax) {
    313             break;
    314         }
    315         if (hfuzz.timing.runEndTime > 0 && (time(NULL) > hfuzz.timing.runEndTime)) {
    316             LOG_I("Maximum run time reached, terminating");
    317             break;
    318         }
    319         pingThreads(&hfuzz);
    320         pause();
    321     }
    322 
    323     fuzz_setTerminating();
    324 
    325     for (;;) {
    326         if (ATOMIC_GET(hfuzz.threads.threadsFinished) >= hfuzz.threads.threadsMax) {
    327             break;
    328         }
    329         pingThreads(&hfuzz);
    330         usleep(50000); /* 50ms */
    331     }
    332 
    333     /* Clean-up global buffers */
    334     if (hfuzz.feedback.blacklist) {
    335         free(hfuzz.feedback.blacklist);
    336     }
    337 #if defined(_HF_ARCH_LINUX)
    338     if (hfuzz.linux.symsBl) {
    339         free(hfuzz.linux.symsBl);
    340     }
    341     if (hfuzz.linux.symsWl) {
    342         free(hfuzz.linux.symsWl);
    343     }
    344 #elif defined(_HF_ARCH_NETBSD)
    345     if (hfuzz.netbsd.symsBl) {
    346         free(hfuzz.netbsd.symsBl);
    347     }
    348     if (hfuzz.netbsd.symsWl) {
    349         free(hfuzz.netbsd.symsWl);
    350     }
    351 #endif
    352     if (hfuzz.socketFuzzer.enabled) {
    353         cleanupSocketFuzzer();
    354     }
    355 
    356     printSummary(&hfuzz);
    357 
    358     return EXIT_SUCCESS;
    359 }
    360