diff options
Diffstat (limited to 'honggfuzz.c')
-rw-r--r-- | honggfuzz.c | 221 |
1 files changed, 171 insertions, 50 deletions
diff --git a/honggfuzz.c b/honggfuzz.c index b529452b..0bffb99b 100644 --- a/honggfuzz.c +++ b/honggfuzz.c @@ -3,11 +3,10 @@ * honggfuzz - the main file * ----------------------------------------- * - * Author: - * Robert Swiecki <swiecki@google.com> - * Felix Gröbert <groebert@google.com> + * Authors: Robert Swiecki <swiecki@google.com> + * Felix Gröbert <groebert@google.com> * - * Copyright 2010-2015 by Google Inc. All Rights Reserved. + * Copyright 2010-2019 by Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain @@ -23,6 +22,7 @@ * */ +#include <errno.h> #include <getopt.h> #include <inttypes.h> #include <signal.h> @@ -30,6 +30,8 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <sys/resource.h> +#include <sys/time.h> #include <time.h> #include <unistd.h> @@ -37,10 +39,12 @@ #include "display.h" #include "fuzz.h" #include "input.h" -#include "libcommon/common.h" -#include "libcommon/files.h" -#include "libcommon/log.h" -#include "libcommon/util.h" +#include "libhfcommon/common.h" +#include "libhfcommon/files.h" +#include "libhfcommon/log.h" +#include "libhfcommon/util.h" +#include "socketfuzzer.h" +#include "subproc.h" static int sigReceived = 0; @@ -51,17 +55,31 @@ static int sigReceived = 0; honggfuzz_t hfuzz; static void exitWithMsg(const char* msg, int exit_code) { - UNUSED ssize_t sz = write(STDERR_FILENO, msg, strlen(msg)); - exit(exit_code); - abort(); + HF_ATTR_UNUSED ssize_t sz = write(STDERR_FILENO, msg, strlen(msg)); + for (;;) { + exit(exit_code); + _exit(exit_code); + abort(); + __builtin_trap(); + } } -void sigHandler(int sig) { +static bool showDisplay = true; +static void sigHandler(int sig) { /* We should not terminate upon SIGALRM delivery */ if (sig == SIGALRM) { if (fuzz_shouldTerminate()) { exitWithMsg("Terminating forcefully\n", EXIT_FAILURE); } + showDisplay = true; + return; + } + /* Do nothing with pings from the main thread */ + if (sig == SIGUSR1) { + return; + } + /* It's handled in the signal thread */ + if (sig == SIGCHLD) { return; } @@ -72,17 +90,45 @@ void sigHandler(int sig) { ATOMIC_SET(sigReceived, sig); } -static void setupTimer(void) { - struct itimerval it = { - .it_value = {.tv_sec = 1, .tv_usec = 0}, - .it_interval = {.tv_sec = 1, .tv_usec = 0}, +static void setupRLimits(void) { + struct rlimit rlim; + if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) { + PLOG_W("getrlimit(RLIMIT_NOFILE)"); + return; + } + if (rlim.rlim_cur >= 1024) { + return; + } + if (rlim.rlim_max < 1024) { + LOG_E("RLIMIT_NOFILE max limit < 1024 (%zu). Expect troubles!", (size_t)rlim.rlim_max); + return; + } + rlim.rlim_cur = MIN(1024, rlim.rlim_max); // we don't need more + if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { + PLOG_E("Couldn't setrlimit(RLIMIT_NOFILE, cur=%zu/max=%zu)", (size_t)rlim.rlim_cur, + (size_t)rlim.rlim_max); + } +} + +static void setupMainThreadTimer(void) { + const struct itimerval it = { + .it_value = + { + .tv_sec = 1, + .tv_usec = 0, + }, + .it_interval = + { + .tv_sec = 0, + .tv_usec = 1000ULL * 200ULL, + }, }; if (setitimer(ITIMER_REAL, &it, NULL) == -1) { PLOG_F("setitimer(ITIMER_REAL)"); } } -static void setupSignalsPreThr(void) { +static void setupSignalsPreThreads(void) { /* Block signals which should be handled or blocked in the main thread */ sigset_t ss; sigemptyset(&ss); @@ -91,14 +137,16 @@ static void setupSignalsPreThr(void) { sigaddset(&ss, SIGQUIT); sigaddset(&ss, SIGALRM); sigaddset(&ss, SIGPIPE); + /* Linux/arch uses it to discover events from persistent fuzzing processes */ sigaddset(&ss, SIGIO); + /* Let the signal thread catch SIGCHLD */ sigaddset(&ss, SIGCHLD); - if (sigprocmask(SIG_BLOCK, &ss, NULL) != 0) { - PLOG_F("pthread_sigmask(SIG_BLOCK)"); + /* This is checked for via sigwaitinfo/sigtimedwait */ + sigaddset(&ss, SIGUSR1); + if (sigprocmask(SIG_SETMASK, &ss, NULL) != 0) { + PLOG_F("pthread_sigmask(SIG_SETMASK)"); } -} -static void setupSignalsPostThr(void) { struct sigaction sa = { .sa_handler = sigHandler, .sa_flags = 0, @@ -116,6 +164,15 @@ static void setupSignalsPostThr(void) { if (sigaction(SIGALRM, &sa, NULL) == -1) { PLOG_F("sigaction(SIGQUIT) failed"); } + if (sigaction(SIGUSR1, &sa, NULL) == -1) { + PLOG_F("sigaction(SIGUSR1) failed"); + } + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + PLOG_F("sigaction(SIGCHLD) failed"); + } +} + +static void setupSignalsMainThread(void) { /* Unblock signals which should be handled by the main thread */ sigset_t ss; sigemptyset(&ss); @@ -128,12 +185,58 @@ static void setupSignalsPostThr(void) { } } +static void printSummary(honggfuzz_t* hfuzz) { + uint64_t exec_per_sec = 0; + uint64_t elapsed_sec = time(NULL) - hfuzz->timing.timeStart; + if (elapsed_sec) { + exec_per_sec = hfuzz->cnts.mutationsCnt / elapsed_sec; + } + LOG_I("Summary iterations:%zu time:%" PRIu64 " speed:%" PRIu64, hfuzz->cnts.mutationsCnt, + elapsed_sec, exec_per_sec); +} + +static void pingThreads(honggfuzz_t* hfuzz) { + for (size_t i = 0; i < hfuzz->threads.threadsMax; i++) { + if (pthread_kill(hfuzz->threads.threads[i], SIGUSR1) != 0 && errno != EINTR) { + PLOG_W("pthread_kill(thread=%zu, SIGUSR1)", i); + } + } +} + +static void* signalThread(void* arg) { + honggfuzz_t* hfuzz = (honggfuzz_t*)arg; + + sigset_t ss; + sigemptyset(&ss); + sigaddset(&ss, SIGCHLD); + if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) != 0) { + PLOG_F("Couldn't unblock SIGCHLD in the signal thread"); + } + + for (;;) { + int sig; + if (sigwait(&ss, &sig) != 0 && errno != EINTR) { + PLOG_F("sigwait(SIGCHLD)"); + } + if (fuzz_isTerminating()) { + break; + } + if (sig == SIGCHLD) { + pingThreads(hfuzz); + } + } + + return NULL; +} + int main(int argc, char** argv) { /* * Work around CygWin/MinGW */ char** myargs = (char**)util_Malloc(sizeof(char*) * (argc + 1)); - defer { free(myargs); }; + defer { + free(myargs); + }; int i; for (i = 0U; i < argc; i++) { @@ -145,21 +248,25 @@ int main(int argc, char** argv) { LOG_F("Parsing of the cmd-line arguments failed"); } - if (hfuzz.useScreen) { + if (hfuzz.display.useScreen) { display_init(); } - if (!input_init(&hfuzz)) { + if (hfuzz.socketFuzzer.enabled) { + LOG_I("No input file corpus loaded, the external socket_fuzzer is responsible for " + "creating the fuzz data"); + setupSocketFuzzer(&hfuzz); + } else if (!input_init(&hfuzz)) { LOG_F("Couldn't load input corpus"); exit(EXIT_FAILURE); } - if (hfuzz.dictionaryFile && (input_parseDictionary(&hfuzz) == false)) { - LOG_F("Couldn't parse dictionary file ('%s')", hfuzz.dictionaryFile); + if (hfuzz.mutate.dictionaryFile && (input_parseDictionary(&hfuzz) == false)) { + LOG_F("Couldn't parse dictionary file ('%s')", hfuzz.mutate.dictionaryFile); } - if (hfuzz.blacklistFile && (input_parseBlacklist(&hfuzz) == false)) { - LOG_F("Couldn't parse stackhash blacklist file ('%s')", hfuzz.blacklistFile); + if (hfuzz.feedback.blacklistFile && (input_parseBlacklist(&hfuzz) == false)) { + LOG_F("Couldn't parse stackhash blacklist file ('%s')", hfuzz.feedback.blacklistFile); } #define hfuzzl hfuzz.linux if (hfuzzl.symsBlFile && @@ -172,27 +279,30 @@ int main(int argc, char** argv) { LOG_F("Couldn't parse symbols whitelist file ('%s')", hfuzzl.symsWlFile); } - if (hfuzz.dynFileMethod != _HF_DYNFILE_NONE) { - hfuzz.feedback = files_mapSharedMem(sizeof(feedback_t), &hfuzz.bbFd, hfuzz.io.workDir); - if (hfuzz.feedback == MAP_FAILED) { + if (hfuzz.feedback.dynFileMethod != _HF_DYNFILE_NONE) { + if (!(hfuzz.feedback.feedbackMap = files_mapSharedMem( + sizeof(feedback_t), &hfuzz.feedback.bbFd, "hfuzz-feedback", hfuzz.io.workDir))) { LOG_F("files_mapSharedMem(sz=%zu, dir='%s') failed", sizeof(feedback_t), hfuzz.io.workDir); } } - /* - * So far, so good - */ - pthread_t threads[hfuzz.threads.threadsMax]; + setupRLimits(); + setupSignalsPreThreads(); + fuzz_threadsStart(&hfuzz); + + pthread_t sigthread; + if (!subproc_runThread(&hfuzz, &sigthread, signalThread)) { + LOG_F("Couldn't start the signal thread"); + } - setupSignalsPreThr(); - fuzz_threadsStart(&hfuzz, threads); - setupSignalsPostThr(); + setupSignalsMainThread(); + setupMainThreadTimer(); - setupTimer(); for (;;) { - if (hfuzz.useScreen) { + if (hfuzz.display.useScreen && showDisplay) { display_display(&hfuzz); + showDisplay = false; } if (ATOMIC_GET(sigReceived) > 0) { LOG_I("Signal %d (%s) received, terminating", ATOMIC_GET(sigReceived), @@ -204,35 +314,46 @@ int main(int argc, char** argv) { } if (hfuzz.timing.runEndTime > 0 && (time(NULL) > hfuzz.timing.runEndTime)) { LOG_I("Maximum run time reached, terminating"); - fuzz_setTerminating(); break; } + pingThreads(&hfuzz); pause(); } fuzz_setTerminating(); - fuzz_threadsStop(&hfuzz, threads); + for (;;) { + if (ATOMIC_GET(hfuzz.threads.threadsFinished) >= hfuzz.threads.threadsMax) { + break; + } + pingThreads(&hfuzz); + usleep(50000); /* 50ms */ + } /* Clean-up global buffers */ - if (hfuzz.blacklist) { - free(hfuzz.blacklist); + if (hfuzz.feedback.blacklist) { + free(hfuzz.feedback.blacklist); } +#if defined(_HF_ARCH_LINUX) if (hfuzz.linux.symsBl) { free(hfuzz.linux.symsBl); } if (hfuzz.linux.symsWl) { free(hfuzz.linux.symsWl); } - if (hfuzz.sanOpts.asanOpts) { - free(hfuzz.sanOpts.asanOpts); +#elif defined(_HF_ARCH_NETBSD) + if (hfuzz.netbsd.symsBl) { + free(hfuzz.netbsd.symsBl); } - if (hfuzz.sanOpts.ubsanOpts) { - free(hfuzz.sanOpts.ubsanOpts); + if (hfuzz.netbsd.symsWl) { + free(hfuzz.netbsd.symsWl); } - if (hfuzz.sanOpts.msanOpts) { - free(hfuzz.sanOpts.msanOpts); +#endif + if (hfuzz.socketFuzzer.enabled) { + cleanupSocketFuzzer(); } + printSummary(&hfuzz); + return EXIT_SUCCESS; } |