blob: 06ac4e42206652ff16ae44b06ce0cb86934b2564 [file] [log] [blame]
Robert Swieckia88f96f2015-10-09 16:47:39 +02001/*
2
3 honggfuzz - cmdline parsing
4
5 -----------------------------------------
6
7 Copyright 2014 Google Inc. All Rights Reserved.
8
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15 Unless required by applicable law or agreed to in writing, software
16 distributed under the License is distributed on an "AS IS" BASIS,
17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 See the License for the specific language governing permissions and
19 limitations under the License.
20
21*/
22
23#include "cmdline.h"
24
25#include <ctype.h>
26#include <errno.h>
27#include <getopt.h>
Robert Swieckia88f96f2015-10-09 16:47:39 +020028#include <inttypes.h>
29#include <limits.h>
Robert Swiecki846ccd72017-01-12 17:52:23 +010030#if defined(_HF_ARCH_LINUX)
31#include <sched.h>
Robert Swiecki4e595fb2017-10-11 17:26:51 +020032#endif /* defined(_HF_ARCH_LINUX) */
Robert Swiecki846ccd72017-01-12 17:52:23 +010033#include <signal.h>
Robert Swieckia88f96f2015-10-09 16:47:39 +020034#include <stdio.h>
Robert Swieckid0fa62c2017-09-28 18:11:05 +020035#include <stdlib.h>
Robert Swieckia88f96f2015-10-09 16:47:39 +020036#include <string.h>
Robert Swiecki3bfc33c2016-03-14 18:12:41 +010037#include <sys/queue.h>
Robert Swieckia88f96f2015-10-09 16:47:39 +020038#include <unistd.h>
39
Robert Swiecki241a7412017-05-24 01:53:15 +020040#include "libcommon/common.h"
Robert Swiecki241a7412017-05-24 01:53:15 +020041#include "libcommon/files.h"
Robert Swieckid0fa62c2017-09-28 18:11:05 +020042#include "libcommon/log.h"
Robert Swiecki241a7412017-05-24 01:53:15 +020043#include "libcommon/util.h"
Robert Swieckia88f96f2015-10-09 16:47:39 +020044
45struct custom_option {
46 struct option opt;
Robert Swiecki4e595fb2017-10-11 17:26:51 +020047 const char* descr;
Robert Swieckia88f96f2015-10-09 16:47:39 +020048};
49
Robert Swieckid50ed422017-11-13 23:32:26 +010050static bool checkFor_FILE_PLACEHOLDER(char** args) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020051 for (int x = 0; args[x]; x++) {
Robert Swieckid50ed422017-11-13 23:32:26 +010052 if (strstr(args[x], _HF_FILE_PLACEHOLDER)) return true;
Robert Swieckia88f96f2015-10-09 16:47:39 +020053 }
54 return false;
55}
56
Robert Swiecki0b566112017-10-17 17:39:07 +020057static const char* cmdlineYesNo(bool yes) { return (yes ? "true" : "false"); }
Robert Swieckia88f96f2015-10-09 16:47:39 +020058
Robert Swieckid50ed422017-11-13 23:32:26 +010059static void cmdlineHelp(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020060 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
61 LOG_HELP_BOLD("Options:");
62 for (int i = 0; opts[i].opt.name; i++) {
Robert Swieckif3a5f6a2016-03-16 14:47:30 +010063 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) {
Robert Swiecki0b566112017-10-17 17:39:07 +020064 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020065 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020066 } else {
67 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020068 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020069 }
70 LOG_HELP("\t%s", opts[i].descr);
71 }
Jagger32127372015-10-09 23:07:38 +020072 LOG_HELP_BOLD("\nExamples:");
Robert Swieckid50ed422017-11-13 23:32:26 +010073 LOG_HELP(
74 " Run the binary over a mutated file chosen from the directory. Disable fuzzing "
75 "feedback (dry/static mode)");
Robert Swiecki930e12f2017-10-24 14:52:03 +020076 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Jagger32127372015-10-09 23:07:38 +020077 LOG_HELP(" As above, provide input over STDIN:");
Robert Swiecki930e12f2017-10-24 14:52:03 +020078 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -s -- /usr/bin/djpeg");
Jaggere848cc72016-09-19 02:28:52 +020079 LOG_HELP(" Use compile-time instrumentation (libhfuzz/instrument.c):");
Robert Swiecki930e12f2017-10-24 14:52:03 +020080 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
81 LOG_HELP(" Use SANCOV instrumentation:");
82 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
83 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:");
84 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/tiffinfo_persistent");
85 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:");
Jaggere848cc72016-09-19 02:28:52 +020086 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/tiffinfo_persistent");
Robert Swieckia88f96f2015-10-09 16:47:39 +020087#if defined(_HF_ARCH_LINUX)
Robert Swiecki930e12f2017-10-24 14:52:03 +020088 LOG_HELP(
89 " Run the binary with dynamically generate inputs, maximize total no. of instructions:");
Robert Swiecki0b566112017-10-17 17:39:07 +020090 LOG_HELP_BOLD(
91 " " PROG_NAME " --linux_perf_instr -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020092 LOG_HELP(" As above, maximize total no. of branches:");
Robert Swiecki0b566112017-10-17 17:39:07 +020093 LOG_HELP_BOLD(
94 " " PROG_NAME " --linux_perf_branch -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020095 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:");
Robert Swiecki0b566112017-10-17 17:39:07 +020096 LOG_HELP_BOLD(
97 " " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020098 LOG_HELP(
99 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):");
Robert Swiecki0b566112017-10-17 17:39:07 +0200100 LOG_HELP_BOLD(
101 " " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200102#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200103}
104
Robert Swieckid50ed422017-11-13 23:32:26 +0100105static void cmdlineUsage(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200106 cmdlineHelp(pname, opts);
107 exit(0);
108}
109
Robert Swieckid50ed422017-11-13 23:32:26 +0100110rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200111 struct rlimit cur;
112 if (getrlimit(res, &cur) == -1) {
113 PLOG_F("getrlimit(%d)", res);
114 }
115 if (strcasecmp(optarg, "max") == 0) {
116 return cur.rlim_max;
117 }
118 if (strcasecmp(optarg, "def") == 0) {
119 return cur.rlim_cur;
120 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200121 if (util_isANumber(optarg) == false) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200122 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg);
123 }
124 rlim_t val = strtoul(optarg, NULL, 0) * mul;
Jagger2bd61b72015-10-10 05:23:32 +0200125 if ((unsigned long)val == ULONG_MAX && errno != 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200126 PLOG_F("strtoul('%s', 0)", optarg);
127 }
128 return val;
129}
130
Robert Swieckid50ed422017-11-13 23:32:26 +0100131bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
132 honggfuzz_t tmp = {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200133 .cmdline = NULL,
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100134 .cmdline_txt[0] = '\0',
Robert Swiecki82c707c2017-11-14 16:36:23 +0100135 .io =
136 {
137 .inputDir = NULL,
138 .inputDirP = NULL,
139 .fileCnt = 0,
140 .fileCntDone = false,
141 .fileExtn = "fuzz",
142 .workDir = ".",
143 .covDir = NULL,
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100144 .saveUnique = true,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100145 },
Robert Swiecki4332ae92017-05-23 23:06:04 +0200146 .nullifyStdio = true,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200147 .fuzzStdin = false,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100148 .useScreen = true,
149 .useVerifier = false,
150 .timeStart = time(NULL),
Robert Swiecki10e93562017-11-04 00:57:47 +0100151 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200152 .externalCommand = NULL,
Robert Swieckiee266ac2016-10-03 02:25:59 +0200153 .postExternalCommand = NULL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200154 .blacklistFile = NULL,
155 .blacklistCnt = 0,
156 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200157 .maxFileSz = 0UL,
Jaggerba92b4b2016-03-16 02:24:17 +0100158 .tmOut = 10,
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200159 .runEndTime = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200160 .mutationsMax = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200161 .reportFile = NULL,
Robert Swiecki8954afd2017-11-14 18:14:22 +0100162 .asLimit = 0U,
163 .rssLimit = 0U,
164 .dataLimit = 0U,
Jagger80041fe2016-03-10 21:32:35 +0100165 .clearEnv = false,
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200166 .envs[0] = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200167 .persistent = false,
Robert Swieckie84b6452016-12-12 12:42:04 +0100168 .tmout_vtalrm = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100169 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200170 .enableSanitizers = false,
171#if defined(__ANDROID__)
172 .monitorSIGABRT = false,
173#else
174 .monitorSIGABRT = true,
175#endif
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200176 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200177
Robert Swieckid50ed422017-11-13 23:32:26 +0100178 .threads =
179 {
180 .threadsFinished = 0,
181 .threadsMax =
182 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
183 .threadsActiveCnt = 0,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100184 .mainThread = pthread_self(),
185 .mainPid = getpid(),
Robert Swieckid50ed422017-11-13 23:32:26 +0100186 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100187
Robert Swiecki531438a2016-09-13 19:05:11 +0200188 .dictionaryFile = NULL,
189 .dictionaryCnt = 0,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100190 .dictqCurrent = NULL,
Robert Swiecki531438a2016-09-13 19:05:11 +0200191
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100192 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200193 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200194 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100195
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100196 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100197 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100198
Robert Swiecki37498fd2017-03-12 21:12:54 +0100199 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
200
Robert Swiecki01a980e2017-11-14 03:36:50 +0100201 .cnts =
202 {
203 .mutationsCnt = 0,
204 .crashesCnt = 0,
205 .uniqueCrashesCnt = 0,
206 .verifiedCrashesCnt = 0,
207 .blCrashesCnt = 0,
208 .timeoutedCnt = 0,
209 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200210
Robert Swiecki930e12f2017-10-24 14:52:03 +0200211 .dynFileMethod = _HF_DYNFILE_SOFT,
Robert Swieckid50ed422017-11-13 23:32:26 +0100212 .sanCovCnts =
213 {
214 .hitBBCnt = 0ULL,
215 .totalBBCnt = 0ULL,
216 .dsoCnt = 0ULL,
217 .iDsoCnt = 0ULL,
218 .newBBCnt = 0ULL,
219 .crashesCnt = 0ULL,
220 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200221
Robert Swiecki66b65122017-11-11 02:55:55 +0100222 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swieckid50ed422017-11-13 23:32:26 +0100223 .sanOpts =
224 {
225 .asanOpts = NULL,
226 .msanOpts = NULL,
227 .ubsanOpts = NULL,
228 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100229 .useSanCov = false,
230 .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100231
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700232 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
233
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100234 /* Linux code */
Robert Swieckid50ed422017-11-13 23:32:26 +0100235 .linux =
236 {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200237 .exeFd = -1,
Robert Swieckid50ed422017-11-13 23:32:26 +0100238 .hwCnts =
239 {
240 .cpuInstrCnt = 0ULL,
241 .cpuBranchCnt = 0ULL,
242 .bbCnt = 0ULL,
243 .newBBCnt = 0ULL,
244 .softCntPc = 0ULL,
245 .softCntCmp = 0ULL,
246 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200247 .dynamicCutOffAddr = ~(0ULL),
248 .disableRandomization = true,
249 .ignoreAddr = NULL,
250 .numMajorFrames = 7,
251 .pid = 0,
252 .pidFile = NULL,
Robert Swiecki06a0d8c2017-11-29 02:29:26 +0100253 .pidCmd[0] = '\0',
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200254 .symsBlFile = NULL,
255 .symsBlCnt = 0,
256 .symsBl = NULL,
257 .symsWlFile = NULL,
258 .symsWlCnt = 0,
259 .symsWl = NULL,
260 .cloneFlags = 0,
261 .kernelOnly = false,
262 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100263 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200264 };
Robert Swieckid50ed422017-11-13 23:32:26 +0100265 *hfuzz = tmp;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200266
Robert Swieckib0e261a2017-11-09 01:30:54 +0100267 TAILQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100268 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100269
Robert Swiecki0b566112017-10-17 17:39:07 +0200270 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200271 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200272 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
273 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
274 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200275 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
276 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200277 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
278 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
279 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
280 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
281 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100282 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200283 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
284 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
285 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
286 { { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" },
287 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
288 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
289 { { "covdir", required_argument, NULL, 0x103 }, "New coverage is written to a separate directory (default: use the input directory)" },
290 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
291 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
292 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
293 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
294 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
295 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100296 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" },
297 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" },
298 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200299 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
300 { { "max_file_size", required_argument, NULL, 'F' }, "Maximal size of files processed by the fuzzer in bytes (default: '1048576')" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100301 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200302 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
303 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
304 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
305 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
306 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
307 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
308 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200309
310#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200311 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
312 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
313 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
314 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
315 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
316 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
317 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
318 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
319 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
320 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
321 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
322 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
323 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
324 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
325 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
326#endif // defined(_HF_ARCH_LINUX)
327 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200328 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200329 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200330
331 struct option opts[ARRAYSIZE(custom_opts)];
332 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
333 opts[i] = custom_opts[i].opt;
334 }
335
336 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200337 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200338 int opt_index = 0;
339 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200340 int c = getopt_long(
Robert Swiecki930e12f2017-10-24 14:52:03 +0200341 argc, argv, "-?hQvVsuPxf:d:e:W:r:c:F:t:R:n:N:l:p:g:E:w:B:CzTS", opts, &opt_index);
Robert Swieckid50ed422017-11-13 23:32:26 +0100342 if (c < 0) break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200343
344 switch (c) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100345 case 'h':
346 case '?':
347 cmdlineUsage(argv[0], custom_opts);
348 break;
349 case 'f':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100350 hfuzz->io.inputDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100351 break;
352 case 'x':
353 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
354 break;
355 case 'Q':
356 hfuzz->nullifyStdio = false;
357 break;
358 case 'v':
359 hfuzz->useScreen = false;
360 break;
361 case 'V':
362 hfuzz->useVerifier = true;
363 break;
364 case 's':
365 hfuzz->fuzzStdin = true;
366 break;
367 case 'u':
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100368 hfuzz->io.saveUnique = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100369 break;
370 case 'l':
371 logfile = optarg;
372 break;
373 case 'd':
374 ll = atoi(optarg);
375 break;
376 case 'e':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100377 hfuzz->io.fileExtn = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100378 break;
379 case 'W':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100380 hfuzz->io.workDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100381 break;
382 case 'r':
383 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
384 break;
385 case 'c':
386 hfuzz->externalCommand = optarg;
387 break;
388 case 'C':
389 hfuzz->useSanCov = true;
390 break;
391 case 'S':
392 hfuzz->enableSanitizers = true;
393 break;
394 case 'z':
395 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
396 break;
397 case 'F':
398 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
399 break;
400 case 't':
401 hfuzz->tmOut = atol(optarg);
402 break;
403 case 'R':
404 hfuzz->reportFile = optarg;
405 break;
406 case 'n':
407 hfuzz->threads.threadsMax = atol(optarg);
408 break;
409 case 0x109: {
410 time_t p = atol(optarg);
411 if (p > 0) {
412 hfuzz->runEndTime = time(NULL) + p;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200413 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100414 } break;
415 case 'N':
416 hfuzz->mutationsMax = atol(optarg);
417 break;
418 case 0x100:
419 hfuzz->asLimit = strtoull(optarg, NULL, 0);
420 break;
421 case 0x101:
Robert Swiecki8954afd2017-11-14 18:14:22 +0100422 hfuzz->rssLimit = strtoull(optarg, NULL, 0);
423 break;
424 case 0x102:
425 hfuzz->dataLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100426 break;
427 case 0x103:
Robert Swiecki82c707c2017-11-14 16:36:23 +0100428 hfuzz->io.covDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100429 break;
430 case 0x104:
431 hfuzz->postExternalCommand = optarg;
432 break;
433 case 0x105:
434 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
435 hfuzz->monitorSIGABRT = false;
436 } else {
437 hfuzz->monitorSIGABRT = true;
438 }
439 break;
440 case 0x106:
441 hfuzz->skipFeedbackOnTimeout = true;
442 break;
443 case 0x107:
444 hfuzz->exitUponCrash = true;
445 break;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100446 case 0x108:
447 hfuzz->clearEnv = true;
448 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100449 case 'P':
450 hfuzz->persistent = true;
451 break;
452 case 'T':
453 hfuzz->tmout_vtalrm = true;
454 break;
455 case 'p':
456 if (util_isANumber(optarg) == false) {
457 LOG_E("-p '%s' is not a number", optarg);
458 return false;
459 }
460 hfuzz->linux.pid = atoi(optarg);
461 if (hfuzz->linux.pid < 1) {
462 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
463 return false;
464 }
465 break;
466 case 0x502:
467 hfuzz->linux.pidFile = optarg;
468 break;
469 case 'E':
470 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs); i++) {
471 if (hfuzz->envs[i] == NULL) {
472 hfuzz->envs[i] = optarg;
473 break;
474 }
475 }
476 break;
477 case 'w':
478 hfuzz->dictionaryFile = optarg;
479 break;
480 case 'B':
481 hfuzz->blacklistFile = optarg;
482 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100483#if defined(_HF_ARCH_LINUX)
Robert Swieckid50ed422017-11-13 23:32:26 +0100484 case 0x500:
485 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
486 break;
487 case 0x501:
488 hfuzz->linux.disableRandomization = false;
489 break;
490 case 0x503:
491 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
492 break;
493 case 0x504:
494 hfuzz->linux.symsBlFile = optarg;
495 break;
496 case 0x505:
497 hfuzz->linux.symsWlFile = optarg;
498 break;
499 case 0x510:
500 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
501 break;
502 case 0x511:
503 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
504 break;
505 case 0x513:
506 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
507 break;
508 case 0x514:
509 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
510 break;
511 case 0x515:
512 hfuzz->linux.kernelOnly = true;
513 break;
514 case 0x530:
515 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
516 break;
517 case 0x531:
518 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
519 break;
520 case 0x532:
521 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
522 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200523#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckid50ed422017-11-13 23:32:26 +0100524 default:
525 cmdlineUsage(argv[0], custom_opts);
526 return false;
527 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200528 }
529 }
Jagger72f258b2015-10-09 23:09:01 +0200530
Robert Swieckia88f96f2015-10-09 16:47:39 +0200531 if (logInitLogFile(logfile, ll) == false) {
532 return false;
533 }
534
535 hfuzz->cmdline = &argv[optind];
536 if (hfuzz->cmdline[0] == NULL) {
537 LOG_E("No fuzz command provided");
538 cmdlineUsage(argv[0], custom_opts);
539 return false;
540 }
541
Robert Swiecki0f937af2016-03-30 18:19:16 +0200542 if (!hfuzz->fuzzStdin && !hfuzz->persistent && !checkFor_FILE_PLACEHOLDER(hfuzz->cmdline)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200543 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
Robert Swiecki0f937af2016-03-30 18:19:16 +0200544 "' when the -s (stdin fuzzing) or --persistent options are not set");
Robert Swieckia88f96f2015-10-09 16:47:39 +0200545 return false;
546 }
547
Robert Swiecki5b775b22017-04-28 16:19:15 +0200548 if (hfuzz->fuzzStdin && hfuzz->persistent) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200549 LOG_E(
550 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
Robert Swieckid633fe02017-04-28 17:40:27 +0200551 return false;
Robert Swiecki5b775b22017-04-28 16:19:15 +0200552 }
553
Robert Swiecki66b65122017-11-11 02:55:55 +0100554 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) {
555 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))",
556 hfuzz->threads.threadsMax, _HF_THREAD_MAX);
Robert Swiecki71b73722016-09-05 15:18:25 +0200557 return false;
558 }
559
Robert Swiecki82c707c2017-11-14 16:36:23 +0100560 if (strchr(hfuzz->io.fileExtn, '/')) {
561 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200562 return false;
563 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200564
Robert Swiecki82c707c2017-11-14 16:36:23 +0100565 if (hfuzz->io.workDir[0] != '.' || strlen(hfuzz->io.workDir) > 2) {
566 if (!files_exists(hfuzz->io.workDir)) {
567 LOG_E("Provided workspace directory '%s' doesn't exist", hfuzz->io.workDir);
Anestis Bechtsoudisc8e7f6e2015-12-26 14:48:48 +0200568 return false;
569 }
570 }
Robert Swieckia88f96f2015-10-09 16:47:39 +0200571
Jagger247c3b42016-03-21 23:24:05 +0100572 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
573 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200574 hfuzz->linux.pid);
Robert Swiecki66b65122017-11-11 02:55:55 +0100575 hfuzz->threads.threadsMax = 1;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200576 }
577
Robert Swiecki13d95022017-11-04 12:15:41 +0100578 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
Robert Swiecki10e93562017-11-04 00:57:47 +0100579 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200580 }
581
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200582 /*
583 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
584 * better to let user know about the features that each flag control.
585 */
586 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
587 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
588 return false;
589 }
590
Robert Swieckid50ed422017-11-13 23:32:26 +0100591 LOG_I(
592 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
593 "mutationsPerRun: %u, "
594 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, "
595 "threads.threadsMax: %zu, "
596 "fileExtn: '%s', "
Robert Swiecki8954afd2017-11-14 18:14:22 +0100597 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64
598 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki82c707c2017-11-14 16:36:23 +0100599 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->nullifyStdio),
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100600 cmdlineYesNo(hfuzz->fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique), hfuzz->mutationsPerRun,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200601 hfuzz->externalCommand == NULL ? "NULL" : hfuzz->externalCommand, (int)hfuzz->runEndTime,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100602 hfuzz->tmOut, hfuzz->mutationsMax, hfuzz->threads.threadsMax, hfuzz->io.fileExtn,
Robert Swiecki8954afd2017-11-14 18:14:22 +0100603 hfuzz->asLimit, hfuzz->rssLimit, hfuzz->dataLimit, hfuzz->cmdline[0], hfuzz->linux.pid,
604 cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200605
Robert Swiecki2aaa52b2016-01-19 14:40:47 +0100606 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->cmdline[0]);
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100607 for (size_t i = 1; hfuzz->cmdline[i]; i++) {
608 util_ssnprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100609 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
Robert Swiecki6e885112017-11-22 00:32:24 +0100610 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' ';
611 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100612 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
613 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
Robert Swiecki6e885112017-11-22 00:32:24 +0100614 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100615 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100616 }
617
Robert Swieckia88f96f2015-10-09 16:47:39 +0200618 return true;
619}