blob: b0957982ef453083dccaac19e6c0d37a7b42b23a [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 Swiecki4e595fb2017-10-11 17:26:51 +020050static bool checkFor_FILE_PLACEHOLDER(char** args)
Robert Swieckia88f96f2015-10-09 16:47:39 +020051{
52 for (int x = 0; args[x]; x++) {
53 if (strstr(args[x], _HF_FILE_PLACEHOLDER))
54 return true;
55 }
56 return false;
57}
58
Robert Swiecki0b566112017-10-17 17:39:07 +020059static const char* cmdlineYesNo(bool yes) { return (yes ? "true" : "false"); }
Robert Swieckia88f96f2015-10-09 16:47:39 +020060
Robert Swiecki4e595fb2017-10-11 17:26:51 +020061static void cmdlineHelp(const char* pname, struct custom_option* opts)
Robert Swieckia88f96f2015-10-09 16:47:39 +020062{
63 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
64 LOG_HELP_BOLD("Options:");
65 for (int i = 0; opts[i].opt.name; i++) {
Robert Swieckif3a5f6a2016-03-16 14:47:30 +010066 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) {
Robert Swiecki0b566112017-10-17 17:39:07 +020067 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020068 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020069 } else {
70 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020071 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020072 }
73 LOG_HELP("\t%s", opts[i].descr);
74 }
Jagger32127372015-10-09 23:07:38 +020075 LOG_HELP_BOLD("\nExamples:");
Robert Swiecki930e12f2017-10-24 14:52:03 +020076 LOG_HELP(" Run the binary over a mutated file chosen from the directory. Disable fuzzing "
77 "feedback (dry/static mode)");
78 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Jagger32127372015-10-09 23:07:38 +020079 LOG_HELP(" As above, provide input over STDIN:");
Robert Swiecki930e12f2017-10-24 14:52:03 +020080 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -s -- /usr/bin/djpeg");
Jaggere848cc72016-09-19 02:28:52 +020081 LOG_HELP(" Use compile-time instrumentation (libhfuzz/instrument.c):");
Robert Swiecki930e12f2017-10-24 14:52:03 +020082 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
83 LOG_HELP(" Use SANCOV instrumentation:");
84 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
85 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:");
86 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/tiffinfo_persistent");
87 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:");
Jaggere848cc72016-09-19 02:28:52 +020088 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/tiffinfo_persistent");
Robert Swieckia88f96f2015-10-09 16:47:39 +020089#if defined(_HF_ARCH_LINUX)
Robert Swiecki930e12f2017-10-24 14:52:03 +020090 LOG_HELP(
91 " Run the binary with dynamically generate inputs, maximize total no. of instructions:");
Robert Swiecki0b566112017-10-17 17:39:07 +020092 LOG_HELP_BOLD(
93 " " PROG_NAME " --linux_perf_instr -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020094 LOG_HELP(" As above, maximize total no. of branches:");
Robert Swiecki0b566112017-10-17 17:39:07 +020095 LOG_HELP_BOLD(
96 " " PROG_NAME " --linux_perf_branch -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020097 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:");
Robert Swiecki0b566112017-10-17 17:39:07 +020098 LOG_HELP_BOLD(
99 " " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200100 LOG_HELP(
101 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):");
Robert Swiecki0b566112017-10-17 17:39:07 +0200102 LOG_HELP_BOLD(
103 " " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200104#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200105}
106
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200107static void cmdlineUsage(const char* pname, struct custom_option* opts)
Robert Swieckia88f96f2015-10-09 16:47:39 +0200108{
109 cmdlineHelp(pname, opts);
110 exit(0);
111}
112
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200113rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul)
Robert Swieckia88f96f2015-10-09 16:47:39 +0200114{
115 struct rlimit cur;
116 if (getrlimit(res, &cur) == -1) {
117 PLOG_F("getrlimit(%d)", res);
118 }
119 if (strcasecmp(optarg, "max") == 0) {
120 return cur.rlim_max;
121 }
122 if (strcasecmp(optarg, "def") == 0) {
123 return cur.rlim_cur;
124 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200125 if (util_isANumber(optarg) == false) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200126 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg);
127 }
128 rlim_t val = strtoul(optarg, NULL, 0) * mul;
Jagger2bd61b72015-10-10 05:23:32 +0200129 if ((unsigned long)val == ULONG_MAX && errno != 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200130 PLOG_F("strtoul('%s', 0)", optarg);
131 }
132 return val;
133}
134
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200135bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz)
Robert Swieckia88f96f2015-10-09 16:47:39 +0200136{
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200137 (*hfuzz) = (honggfuzz_t)
138 {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200139 .cmdline = NULL,
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100140 .cmdline_txt[0] = '\0',
Jagger1b2d4822016-09-25 16:19:45 +0200141 .inputDir = NULL,
Robert Swiecki92a31362017-02-24 16:21:40 +0100142 .inputDirP = NULL,
143 .fileCnt = 0,
144 .fileCntDone = false,
Robert Swiecki4332ae92017-05-23 23:06:04 +0200145 .nullifyStdio = true,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200146 .fuzzStdin = false,
147 .saveUnique = true,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100148 .useScreen = true,
149 .useVerifier = false,
150 .timeStart = time(NULL),
Robert Swieckia88f96f2015-10-09 16:47:39 +0200151 .fileExtn = "fuzz",
152 .workDir = ".",
Jagger1b2d4822016-09-25 16:19:45 +0200153 .covDir = NULL,
Robert Swiecki10e93562017-11-04 00:57:47 +0100154 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200155 .externalCommand = NULL,
Robert Swieckiee266ac2016-10-03 02:25:59 +0200156 .postExternalCommand = NULL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200157 .blacklistFile = NULL,
158 .blacklistCnt = 0,
159 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200160 .maxFileSz = 0UL,
Jaggerba92b4b2016-03-16 02:24:17 +0100161 .tmOut = 10,
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200162 .runEndTime = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200163 .mutationsMax = 0,
164 .threadsFinished = 0,
Jagger2664f542016-09-28 14:37:00 +0200165 .threadsMax = (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200166 .reportFile = NULL,
167 .asLimit = 0ULL,
Jagger80041fe2016-03-10 21:32:35 +0100168 .clearEnv = false,
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200169 .envs[0] = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200170 .persistent = false,
Robert Swieckie84b6452016-12-12 12:42:04 +0100171 .tmout_vtalrm = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100172 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200173 .enableSanitizers = false,
174#if defined(__ANDROID__)
175 .monitorSIGABRT = false,
176#else
177 .monitorSIGABRT = true,
178#endif
Robert Swiecki0ec98112017-02-03 02:08:14 +0100179 .threadsActiveCnt = 0,
Robert Swiecki89b84472017-02-12 22:20:10 +0100180 .mainPid = getpid(),
Robert Swiecki8d01b012017-02-19 15:48:11 +0100181 .terminating = false,
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200182 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200183
Robert Swiecki531438a2016-09-13 19:05:11 +0200184 .dictionaryFile = NULL,
185 .dictionaryCnt = 0,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100186 .dictqCurrent = NULL,
Robert Swiecki531438a2016-09-13 19:05:11 +0200187
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100188 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200189 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200190 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100191
Robert Swieckie586c1f2016-03-14 18:46:03 +0100192 .dynfileq_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100193 .dynfileqCnt = 0U,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100194 .dynfileqCurrent = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100195
Robert Swiecki37498fd2017-03-12 21:12:54 +0100196 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
197
Robert Swieckia88f96f2015-10-09 16:47:39 +0200198 .mutationsCnt = 0,
199 .crashesCnt = 0,
200 .uniqueCrashesCnt = 0,
Anestis Bechtsoudis79b799e2015-11-01 00:02:25 +0200201 .verifiedCrashesCnt = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200202 .blCrashesCnt = 0,
203 .timeoutedCnt = 0,
204
Robert Swiecki930e12f2017-10-24 14:52:03 +0200205 .dynFileMethod = _HF_DYNFILE_SOFT,
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200206 .sanCovCnts = {
Jaggerab26e702016-03-22 04:28:00 +0100207 .hitBBCnt = 0ULL,
208 .totalBBCnt = 0ULL,
209 .dsoCnt = 0ULL,
210 .iDsoCnt = 0ULL,
211 .newBBCnt = 0ULL,
212 .crashesCnt = 0ULL,
213 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200214
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200215 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER, .sanOpts = {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200216 .asanOpts = NULL,
217 .msanOpts = NULL,
218 .ubsanOpts = NULL,
Anestis Bechtsoudis61b5ab12016-01-08 16:07:02 +0200219 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200220 .useSanCov = false, .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100221
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700222 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
223
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100224 /* Linux code */
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200225 .linux = {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200226 .exeFd = -1,
227 .hwCnts = {
228 .cpuInstrCnt = 0ULL,
229 .cpuBranchCnt = 0ULL,
230 .bbCnt = 0ULL,
231 .newBBCnt = 0ULL,
232 .softCntPc = 0ULL,
233 .softCntCmp = 0ULL,
234 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200235 .dynamicCutOffAddr = ~(0ULL),
236 .disableRandomization = true,
237 .ignoreAddr = NULL,
238 .numMajorFrames = 7,
239 .pid = 0,
240 .pidFile = NULL,
241 .pidCmd = NULL,
242 .symsBlFile = NULL,
243 .symsBlCnt = 0,
244 .symsBl = NULL,
245 .symsWlFile = NULL,
246 .symsWlCnt = 0,
247 .symsWl = NULL,
248 .cloneFlags = 0,
249 .kernelOnly = false,
250 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100251 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200252 };
Robert Swieckia88f96f2015-10-09 16:47:39 +0200253
Robert Swieckiafb16102017-03-13 22:14:31 +0100254 TAILQ_INIT(&hfuzz->dynfileq);
255 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100256
Robert Swiecki0b566112017-10-17 17:39:07 +0200257 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200258 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200259 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
260 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
261 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200262 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
263 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200264 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
265 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
266 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
267 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
268 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki10e93562017-11-04 00:57:47 +0100269 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run, (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200270 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
271 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
272 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
273 { { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" },
274 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
275 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
276 { { "covdir", required_argument, NULL, 0x103 }, "New coverage is written to a separate directory (default: use the input directory)" },
277 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
278 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
279 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
280 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
281 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
282 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
283 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process memory limit in MiB (default: '0' [no limit])" },
284 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
285 { { "max_file_size", required_argument, NULL, 'F' }, "Maximal size of files processed by the fuzzer in bytes (default: '1048576')" },
286 { { "clear_env", no_argument, NULL, 0x101 }, "Clear all environment variables before executing the binary" },
287 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
288 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
289 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
290 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
291 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
292 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
293 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200294
295#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200296 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
297 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
298 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
299 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
300 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
301 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
302 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
303 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
304 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
305 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
306 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
307 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
308 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
309 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
310 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
311#endif // defined(_HF_ARCH_LINUX)
312 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200313 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200314 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200315
316 struct option opts[ARRAYSIZE(custom_opts)];
317 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
318 opts[i] = custom_opts[i].opt;
319 }
320
321 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200322 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200323 int opt_index = 0;
324 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200325 int c = getopt_long(
Robert Swiecki930e12f2017-10-24 14:52:03 +0200326 argc, argv, "-?hQvVsuPxf:d:e:W:r:c:F:t:R:n:N:l:p:g:E:w:B:CzTS", opts, &opt_index);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200327 if (c < 0)
328 break;
329
330 switch (c) {
331 case 'h':
332 case '?':
333 cmdlineUsage(argv[0], custom_opts);
334 break;
335 case 'f':
Jagger1b2d4822016-09-25 16:19:45 +0200336 hfuzz->inputDir = optarg;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200337 break;
Robert Swiecki930e12f2017-10-24 14:52:03 +0200338 case 'x':
339 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
340 break;
Robert Swiecki4332ae92017-05-23 23:06:04 +0200341 case 'Q':
342 hfuzz->nullifyStdio = false;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200343 break;
344 case 'v':
345 hfuzz->useScreen = false;
346 break;
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700347 case 'V':
348 hfuzz->useVerifier = true;
349 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200350 case 's':
351 hfuzz->fuzzStdin = true;
352 break;
353 case 'u':
354 hfuzz->saveUnique = false;
355 break;
Robert Swiecki03ef5312015-10-09 18:25:40 +0200356 case 'l':
357 logfile = optarg;
358 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200359 case 'd':
360 ll = atoi(optarg);
361 break;
362 case 'e':
363 hfuzz->fileExtn = optarg;
364 break;
365 case 'W':
366 hfuzz->workDir = optarg;
367 break;
368 case 'r':
Robert Swiecki10e93562017-11-04 00:57:47 +0100369 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200370 break;
371 case 'c':
372 hfuzz->externalCommand = optarg;
373 break;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200374 case 'C':
375 hfuzz->useSanCov = true;
376 break;
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200377 case 'S':
378 hfuzz->enableSanitizers = true;
379 break;
Jagger4aac9fe2016-08-28 17:35:48 +0200380 case 'z':
381 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
382 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200383 case 'F':
384 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
385 break;
386 case 't':
387 hfuzz->tmOut = atol(optarg);
388 break;
389 case 'R':
390 hfuzz->reportFile = optarg;
391 break;
392 case 'n':
393 hfuzz->threadsMax = atol(optarg);
394 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200395 case 0x109: {
396 time_t p = atol(optarg);
397 if (p > 0) {
398 hfuzz->runEndTime = time(NULL) + p;
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200399 }
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200400 } break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200401 case 'N':
402 hfuzz->mutationsMax = atol(optarg);
403 break;
Robert Swiecki03ef5312015-10-09 18:25:40 +0200404 case 0x100:
Robert Swieckia88f96f2015-10-09 16:47:39 +0200405 hfuzz->asLimit = strtoull(optarg, NULL, 0);
406 break;
Jagger80041fe2016-03-10 21:32:35 +0100407 case 0x101:
408 hfuzz->clearEnv = true;
409 break;
Robert Swieckidac8cf12016-09-22 15:36:28 +0200410 case 0x103:
Jagger1b2d4822016-09-25 16:19:45 +0200411 hfuzz->covDir = optarg;
Robert Swieckidac8cf12016-09-22 15:36:28 +0200412 break;
Robert Swieckiee266ac2016-10-03 02:25:59 +0200413 case 0x104:
414 hfuzz->postExternalCommand = optarg;
415 break;
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200416 case 0x105:
417 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
418 hfuzz->monitorSIGABRT = false;
419 } else {
420 hfuzz->monitorSIGABRT = true;
421 }
422 break;
Robert Swiecki44f6b192017-02-15 20:24:55 +0100423 case 0x106:
424 hfuzz->skipFeedbackOnTimeout = true;
425 break;
Robert Swiecki069b48f2017-05-31 01:00:08 +0200426 case 0x107:
427 hfuzz->exitUponCrash = true;
428 break;
Robert Swieckifab69162016-03-31 15:41:36 +0200429 case 'P':
Robert Swiecki0f937af2016-03-30 18:19:16 +0200430 hfuzz->persistent = true;
431 break;
Gergely Nagy5d47c732016-12-12 23:51:51 +0100432 case 'T':
Robert Swieckie84b6452016-12-12 12:42:04 +0100433 hfuzz->tmout_vtalrm = true;
434 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200435 case 'p':
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200436 if (util_isANumber(optarg) == false) {
Jagger9c4d1622015-10-16 01:40:17 +0200437 LOG_E("-p '%s' is not a number", optarg);
438 return false;
439 }
Jagger247c3b42016-03-21 23:24:05 +0100440 hfuzz->linux.pid = atoi(optarg);
441 if (hfuzz->linux.pid < 1) {
442 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
Jagger9c4d1622015-10-16 01:40:17 +0200443 return false;
444 }
Robert Swieckia88f96f2015-10-09 16:47:39 +0200445 break;
Robert Swieckifab69162016-03-31 15:41:36 +0200446 case 0x502:
Jagger247c3b42016-03-21 23:24:05 +0100447 hfuzz->linux.pidFile = optarg;
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200448 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200449 case 'E':
450 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs); i++) {
451 if (hfuzz->envs[i] == NULL) {
452 hfuzz->envs[i] = optarg;
453 break;
454 }
455 }
456 break;
457 case 'w':
458 hfuzz->dictionaryFile = optarg;
459 break;
460 case 'B':
461 hfuzz->blacklistFile = optarg;
462 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100463#if defined(_HF_ARCH_LINUX)
Robert Swieckia88f96f2015-10-09 16:47:39 +0200464 case 0x500:
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200465 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200466 break;
467 case 0x501:
Jagger247c3b42016-03-21 23:24:05 +0100468 hfuzz->linux.disableRandomization = false;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200469 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200470 case 0x503:
Jagger247c3b42016-03-21 23:24:05 +0100471 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200472 break;
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300473 case 0x504:
474 hfuzz->linux.symsBlFile = optarg;
475 break;
476 case 0x505:
477 hfuzz->linux.symsWlFile = optarg;
478 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200479 case 0x510:
480 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
481 break;
482 case 0x511:
483 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
484 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200485 case 0x513:
Jagger3abc5602016-02-04 00:53:43 +0100486 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200487 break;
488 case 0x514:
Jagger39bd2b02016-02-04 01:16:15 +0100489 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
490 break;
Robert Swiecki37d27ca2017-03-30 14:43:54 +0200491 case 0x515:
492 hfuzz->linux.kernelOnly = true;
493 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100494 case 0x530:
495 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
496 break;
497 case 0x531:
498 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
499 break;
500 case 0x532:
501 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
502 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200503#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200504 default:
505 cmdlineUsage(argv[0], custom_opts);
506 return false;
507 break;
508 }
509 }
Jagger72f258b2015-10-09 23:09:01 +0200510
Robert Swieckia88f96f2015-10-09 16:47:39 +0200511 if (logInitLogFile(logfile, ll) == false) {
512 return false;
513 }
514
515 hfuzz->cmdline = &argv[optind];
516 if (hfuzz->cmdline[0] == NULL) {
517 LOG_E("No fuzz command provided");
518 cmdlineUsage(argv[0], custom_opts);
519 return false;
520 }
521
Robert Swiecki0f937af2016-03-30 18:19:16 +0200522 if (!hfuzz->fuzzStdin && !hfuzz->persistent && !checkFor_FILE_PLACEHOLDER(hfuzz->cmdline)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200523 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
Robert Swiecki0f937af2016-03-30 18:19:16 +0200524 "' when the -s (stdin fuzzing) or --persistent options are not set");
Robert Swieckia88f96f2015-10-09 16:47:39 +0200525 return false;
526 }
527
Robert Swiecki5b775b22017-04-28 16:19:15 +0200528 if (hfuzz->fuzzStdin && hfuzz->persistent) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200529 LOG_E(
530 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
Robert Swieckid633fe02017-04-28 17:40:27 +0200531 return false;
Robert Swiecki5b775b22017-04-28 16:19:15 +0200532 }
533
Robert Swiecki71b73722016-09-05 15:18:25 +0200534 if (hfuzz->threadsMax >= _HF_THREAD_MAX) {
535 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))", hfuzz->threadsMax,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200536 _HF_THREAD_MAX);
Robert Swiecki71b73722016-09-05 15:18:25 +0200537 return false;
538 }
539
Robert Swieckia88f96f2015-10-09 16:47:39 +0200540 if (strchr(hfuzz->fileExtn, '/')) {
541 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->fileExtn);
542 return false;
543 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200544
Anestis Bechtsoudis8f4aa612015-12-27 12:06:19 +0200545 if (hfuzz->workDir[0] != '.' || strlen(hfuzz->workDir) > 2) {
Anestis Bechtsoudisc8e7f6e2015-12-26 14:48:48 +0200546 if (!files_exists(hfuzz->workDir)) {
547 LOG_E("Provided workspace directory '%s' doesn't exist", hfuzz->workDir);
548 return false;
549 }
550 }
Robert Swieckia88f96f2015-10-09 16:47:39 +0200551
Jagger247c3b42016-03-21 23:24:05 +0100552 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
553 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200554 hfuzz->linux.pid);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200555 hfuzz->threadsMax = 1;
556 }
557
Robert Swiecki13d95022017-11-04 12:15:41 +0100558 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
Robert Swiecki10e93562017-11-04 00:57:47 +0100559 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200560 }
561
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200562 /*
563 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
564 * better to let user know about the features that each flag control.
565 */
566 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
567 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
568 return false;
569 }
570
Robert Swiecki10e93562017-11-04 00:57:47 +0100571 LOG_I("PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
572 "mutationsPerRun: %u, "
Robert Swiecki0b566112017-10-17 17:39:07 +0200573 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, threadsMax: %zu, "
574 "fileExtn: '%s', "
Anestis Bechtsoudisecab7762016-12-27 18:27:30 +0200575 "memoryLimit: 0x%" PRIx64 "(MiB), fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki0b566112017-10-17 17:39:07 +0200576 (int)getpid(), hfuzz->inputDir, cmdlineYesNo(hfuzz->nullifyStdio),
Robert Swiecki10e93562017-11-04 00:57:47 +0100577 cmdlineYesNo(hfuzz->fuzzStdin), cmdlineYesNo(hfuzz->saveUnique), hfuzz->mutationsPerRun,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200578 hfuzz->externalCommand == NULL ? "NULL" : hfuzz->externalCommand, (int)hfuzz->runEndTime,
579 hfuzz->tmOut, hfuzz->mutationsMax, hfuzz->threadsMax, hfuzz->fileExtn, hfuzz->asLimit,
580 hfuzz->cmdline[0], hfuzz->linux.pid, cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200581
Robert Swiecki2aaa52b2016-01-19 14:40:47 +0100582 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->cmdline[0]);
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100583 for (size_t i = 1; hfuzz->cmdline[i]; i++) {
584 util_ssnprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100585 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
586 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
587 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
588 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '.';
589 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100590 }
591
Robert Swieckia88f96f2015-10-09 16:47:39 +0200592 return true;
593}