blob: 31ef3fb5c9d05b3e880d861c905d7bba7895dbf4 [file] [log] [blame]
/*
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "common.h"
#include "log.h"
#include "files.h"
#include "fuzz.h"
#include "util.h"
#define AB ANSI_BOLD
#define AC ANSI_CLEAR
#define ANSI_BOLD "\033[1m"
#define ANSI_CLEAR "\033[0m"
static bool checkFor_FILE_PLACEHOLDER(char **args)
{
for (int x = 0; args[x]; x++) {
if (!strcmp(args[x], _HF_FILE_PLACEHOLDER))
return true;
}
return false;
}
static void usage(bool exit_success)
{
/* *INDENT-OFF* */
printf("%s",
" <" AB "-f val" AC "> : directory with input files (or a path to a single input file)\n"
" [" AB "-h" AC "] : this help\n"
" [" AB "-q" AC "] : null-ify children's stdin, stdout, stderr; make them quiet\n"
" (default: " AB "false" AC ")\n"
" [" AB "-s" AC "] : provide fuzzing input on STDIN, instead a file argument\n"
" (default: " AB "false" AC ")\n"
" [" AB "-u" AC "] : save unique test-cases only, otherwise (if not used) append\n"
" current timestamp to the output filenames (default: " AB "false" AC ")\n"
" [" AB "-d val" AC "] : debug level (0 - FATAL ... 4 - DEBUG), (default: '" AB "3" AC
"' [INFO])\n"
" [" AB "-e val" AC "] : file extension (e.g swf), (default: '" AB "fuzz" AC "')\n"
" [" AB "-r val" AC "] : flip rate, (default: '" AB "0.001" AC "')\n"
" [" AB "-c val" AC "] : external command modifying the input corpus of files,\n"
" instead of -r/-m (default: " AB "none" AC "\n"
" [" AB "-t val" AC "] : timeout (in secs), (default: '" AB "3" AC "' [0 - no timeout])\n"
" [" AB "-a val" AC "] : address limit (from si.si_addr) below which crashes\n"
" are not reported, (default: '" AB "0" AC "' [suggested: 65535])\n"
" [" AB "-n val" AC "] : number of concurrent fuzzing processes, (default: '" AB "5" AC "')\n"
" [" AB "-N val" AC "] : number of fuzzing mutations, (default: '" AB "0" AC "' [infinte])\n"
" [" AB "-l val" AC "] : per process memory limit in MiB, (default: '" AB "0" AC "' [no limit])\n"
" [" AB "-R val" AC "] : write report to this file, (default: '" AB _HF_REPORT_FILE AC "')\n"
#if _HF_ARCH == LINUX
" [" AB "-p val" AC "] : [Linux] attach to a pid (and its thread group), instead of \n"
" monitoring a previously created process, default: '" AB "0" AC "' (none)\n"
" [" AB "-D val" AC "] : [Linux] create a file dynamically with Linux perf counters,\n"
" can be used with or without the '-f' flag (initial file contents)\n"
" (default: " AB " none " AC ")\n"
" Available counters: \n"
" " AB "'i' " AC "- PERF_COUNT_HW_INSTRUCTIONS (total)\n"
" " AB "'b' " AC "- PERF_COUNT_HW_BRANCH_INSTRUCTIONS (total)\n"
" " AB "'p' " AC "- PERF_SAMPLE_IP (unique IPs) (newer Intel CPUs)\n"
" [" AB "-F val" AC "] : [Linux] Maximal size of a dynamic file (-D)\n"
#endif /* _HF_ARCH == "LINUX" */
"Usage:"
AB " " PROG_NAME " -f input_dir -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER AC "\n");
/* *INDENT-ON* */
if (exit_success) {
exit(EXIT_SUCCESS);
} else {
exit(EXIT_FAILURE);
}
}
int main(int argc, char **argv)
{
int c;
int ll = l_INFO;
honggfuzz_t hfuzz = {
.cmdline = NULL,
.inputFile = NULL,
.nullifyStdio = false,
.fuzzStdin = false,
.saveUnique = false,
.fileExtn = "fuzz",
.flipRate = 0.001f,
.externalCommand = NULL,
.maxFileSz = (1024 * 1024 * 8),
.tmOut = 3,
.mutationsMax = 0,
.mutationsCnt = 0,
.threadsMax = 5,
.ignoreAddr = NULL,
.reportFile = _HF_REPORT_FILE,
.asLimit = 0UL,
.files = NULL,
.fileCnt = 0,
.pid = 0,
.dynFileMethod = _HF_DYNFILE_NONE,
.dynamicFileBest = NULL,
.dynamicFileBestSz = 1,
.branchBestCnt = 0,
.branchBestCntIni = 0,
.dynamicFile_mutex = PTHREAD_MUTEX_INITIALIZER,
};
printf(AB PROG_NAME " version " PROG_VERSION " by " PROG_AUTHORS AC "\n");
if (argc < 2) {
usage(true);
}
for (;;) {
c = getopt(argc, argv, "?hqsuf:d:e:r:c:F:D:t:a:R:n:N:l:p:b:");
if (c < 0)
break;
switch (c) {
case 'f':
hfuzz.inputFile = optarg;
break;
case 'h':
case '?':
usage(true);
break;
case 'q':
hfuzz.nullifyStdio = true;
break;
case 's':
hfuzz.fuzzStdin = true;
break;
case 'u':
hfuzz.saveUnique = true;
break;
case 'd':
ll = atoi(optarg);
break;
case 'e':
hfuzz.fileExtn = optarg;
break;
case 'r':
hfuzz.flipRate = strtod(optarg, NULL);
break;
case 'c':
hfuzz.externalCommand = optarg;
break;
case 'F':
hfuzz.maxFileSz = strtoul(optarg, NULL, 0);
break;
case 'D':
switch (optarg[0]) {
case 'i':
hfuzz.dynFileMethod = _HF_DYNFILE_INSTR_COUNT;
break;
case 'b':
hfuzz.dynFileMethod = _HF_DYNFILE_BRANCH_COUNT;
break;
case 'p':
hfuzz.dynFileMethod = _HF_DYNFILE_UNIQUE_PC_COUNT;
break;
default:
usage(EXIT_FAILURE);
break;
}
case 't':
hfuzz.tmOut = atol(optarg);
break;
case 'a':
hfuzz.ignoreAddr = (void *)strtoul(optarg, NULL, 0);
break;
case 'R':
hfuzz.reportFile = optarg;
break;
case 'n':
hfuzz.threadsMax = atol(optarg);
break;
case 'N':
hfuzz.mutationsMax = atol(optarg);
break;
case 'l':
hfuzz.asLimit = strtoul(optarg, NULL, 0);
break;
case 'p':
hfuzz.pid = atoi(optarg);
break;
case 'b':
hfuzz.branchBestCntIni = atoi(optarg);
break;
default:
break;
}
}
hfuzz.cmdline = &argv[optind];
log_setMinLevel(ll);
if ((hfuzz.dynamicFileBest = malloc(hfuzz.maxFileSz)) == NULL) {
LOGMSG(l_FATAL, "malloc(%zu) failed", hfuzz.maxFileSz);
}
if (!hfuzz.cmdline[0]) {
LOGMSG(l_FATAL, "Please specify a binary to fuzz");
usage(false);
}
if (!hfuzz.fuzzStdin && !checkFor_FILE_PLACEHOLDER(hfuzz.cmdline)) {
LOGMSG(l_FATAL,
"You must specify '" _HF_FILE_PLACEHOLDER
"' when the -s (stdin fuzzing) option is not set");
usage(false);
}
if (strchr(hfuzz.fileExtn, '/')) {
LOGMSG(l_FATAL, "The file extension contains the '/' character: '%s'", hfuzz.fileExtn);
usage(false);
}
LOGMSG(l_INFO,
"debugLevel: %d, inputFile '%s', nullifyStdio: %d, fuzzStdin: %d, saveUnique: %d, flipRate: %lf, "
"externalCommand: '%s', tmOut: %ld, mutationsMax: %ld, threadsMax: %ld, fileExtn '%s', ignoreAddr: %p, "
"memoryLimit: %lu (MiB), fuzzExe: '%s', fuzzedPid: %d",
ll, hfuzz.inputFile, hfuzz.nullifyStdio ? 1 : 0,
hfuzz.fuzzStdin ? 1 : 0, hfuzz.saveUnique ? 1 : 0,
hfuzz.flipRate,
hfuzz.externalCommand == NULL ? "NULL" : hfuzz.externalCommand,
hfuzz.tmOut, hfuzz.mutationsMax, hfuzz.threadsMax,
hfuzz.fileExtn, hfuzz.ignoreAddr, hfuzz.asLimit, hfuzz.cmdline[0], hfuzz.pid);
if (!files_init(&hfuzz)) {
LOGMSG(l_FATAL, "Couldn't load input files");
exit(EXIT_FAILURE);
}
/*
* So far so good
*/
fuzz_main(&hfuzz);
free(hfuzz.dynamicFileBest);
abort(); /* NOTREACHED */
return EXIT_SUCCESS;
}