/* * * honggfuzz - the main file * ----------------------------------------- * * Author: * Robert Swiecki <swiecki@google.com> * Felix Gröbert <groebert@google.com> * * Copyright 2010-2015 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 * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * */ #include <getopt.h> #include <inttypes.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <time.h> #include <unistd.h> #include "cmdline.h" #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" static int sigReceived = 0; /* * CygWin/MinGW incorrectly copies stack during fork(), so we need to keep some * structures in the data section */ 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(); } void sigHandler(int sig) { /* We should not terminate upon SIGALRM delivery */ if (sig == SIGALRM) { if (fuzz_shouldTerminate()) { exitWithMsg("Terminating forcefully\n", EXIT_FAILURE); } return; } if (ATOMIC_GET(sigReceived) != 0) { exitWithMsg("Repeated termination signal caugth\n", EXIT_FAILURE); } 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}, }; if (setitimer(ITIMER_REAL, &it, NULL) == -1) { PLOG_F("setitimer(ITIMER_REAL)"); } } static void setupSignalsPreThr(void) { /* Block signals which should be handled or blocked in the main thread */ sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGTERM); sigaddset(&ss, SIGINT); sigaddset(&ss, SIGQUIT); sigaddset(&ss, SIGALRM); sigaddset(&ss, SIGPIPE); sigaddset(&ss, SIGIO); sigaddset(&ss, SIGCHLD); if (sigprocmask(SIG_BLOCK, &ss, NULL) != 0) { PLOG_F("pthread_sigmask(SIG_BLOCK)"); } } static void setupSignalsPostThr(void) { struct sigaction sa = { .sa_handler = sigHandler, .sa_flags = 0, }; sigemptyset(&sa.sa_mask); if (sigaction(SIGTERM, &sa, NULL) == -1) { PLOG_F("sigaction(SIGTERM) failed"); } if (sigaction(SIGINT, &sa, NULL) == -1) { PLOG_F("sigaction(SIGINT) failed"); } if (sigaction(SIGQUIT, &sa, NULL) == -1) { PLOG_F("sigaction(SIGQUIT) failed"); } if (sigaction(SIGALRM, &sa, NULL) == -1) { PLOG_F("sigaction(SIGQUIT) failed"); } /* Unblock signals which should be handled by the main thread */ sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGTERM); sigaddset(&ss, SIGINT); sigaddset(&ss, SIGQUIT); sigaddset(&ss, SIGALRM); if (sigprocmask(SIG_UNBLOCK, &ss, NULL) != 0) { PLOG_F("pthread_sigmask(SIG_UNBLOCK)"); } } int main(int argc, char** argv) { /* * Work around CygWin/MinGW */ char** myargs = (char**)util_Malloc(sizeof(char*) * (argc + 1)); defer { free(myargs); }; int i; for (i = 0U; i < argc; i++) { myargs[i] = argv[i]; } myargs[i] = NULL; if (cmdlineParse(argc, myargs, &hfuzz) == false) { LOG_F("Parsing of the cmd-line arguments failed"); } if (hfuzz.useScreen) { display_init(); } 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.blacklistFile && (input_parseBlacklist(&hfuzz) == false)) { LOG_F("Couldn't parse stackhash blacklist file ('%s')", hfuzz.blacklistFile); } #define hfuzzl hfuzz.linux if (hfuzzl.symsBlFile && ((hfuzzl.symsBlCnt = files_parseSymbolFilter(hfuzzl.symsBlFile, &hfuzzl.symsBl)) == 0)) { LOG_F("Couldn't parse symbols blacklist file ('%s')", hfuzzl.symsBlFile); } if (hfuzzl.symsWlFile && ((hfuzzl.symsWlCnt = files_parseSymbolFilter(hfuzzl.symsWlFile, &hfuzzl.symsWl)) == 0)) { 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) { 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]; setupSignalsPreThr(); fuzz_threadsStart(&hfuzz, threads); setupSignalsPostThr(); setupTimer(); for (;;) { if (hfuzz.useScreen) { display_display(&hfuzz); } if (ATOMIC_GET(sigReceived) > 0) { LOG_I("Signal %d (%s) received, terminating", ATOMIC_GET(sigReceived), strsignal(ATOMIC_GET(sigReceived))); break; } if (ATOMIC_GET(hfuzz.threads.threadsFinished) >= hfuzz.threads.threadsMax) { break; } if (hfuzz.timing.runEndTime > 0 && (time(NULL) > hfuzz.timing.runEndTime)) { LOG_I("Maximum run time reached, terminating"); fuzz_setTerminating(); break; } pause(); } fuzz_setTerminating(); fuzz_threadsStop(&hfuzz, threads); /* Clean-up global buffers */ if (hfuzz.blacklist) { free(hfuzz.blacklist); } if (hfuzz.linux.symsBl) { free(hfuzz.linux.symsBl); } if (hfuzz.linux.symsWl) { free(hfuzz.linux.symsWl); } if (hfuzz.sanOpts.asanOpts) { free(hfuzz.sanOpts.asanOpts); } if (hfuzz.sanOpts.ubsanOpts) { free(hfuzz.sanOpts.ubsanOpts); } if (hfuzz.sanOpts.msanOpts) { free(hfuzz.sanOpts.msanOpts); } return EXIT_SUCCESS; }