blob: d33bb6cbfc58dd20ff5143010bfb6ab859a51281 [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 Swiecki3bfc33c2016-03-14 18:12:41 +0100192 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100193 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100194
Robert Swiecki37498fd2017-03-12 21:12:54 +0100195 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
196
Robert Swieckia88f96f2015-10-09 16:47:39 +0200197 .mutationsCnt = 0,
198 .crashesCnt = 0,
199 .uniqueCrashesCnt = 0,
Anestis Bechtsoudis79b799e2015-11-01 00:02:25 +0200200 .verifiedCrashesCnt = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200201 .blCrashesCnt = 0,
202 .timeoutedCnt = 0,
203
Robert Swiecki930e12f2017-10-24 14:52:03 +0200204 .dynFileMethod = _HF_DYNFILE_SOFT,
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200205 .sanCovCnts = {
Jaggerab26e702016-03-22 04:28:00 +0100206 .hitBBCnt = 0ULL,
207 .totalBBCnt = 0ULL,
208 .dsoCnt = 0ULL,
209 .iDsoCnt = 0ULL,
210 .newBBCnt = 0ULL,
211 .crashesCnt = 0ULL,
212 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200213
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200214 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER, .sanOpts = {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200215 .asanOpts = NULL,
216 .msanOpts = NULL,
217 .ubsanOpts = NULL,
Anestis Bechtsoudis61b5ab12016-01-08 16:07:02 +0200218 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200219 .useSanCov = false, .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100220
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700221 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
222
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100223 /* Linux code */
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200224 .linux = {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200225 .exeFd = -1,
226 .hwCnts = {
227 .cpuInstrCnt = 0ULL,
228 .cpuBranchCnt = 0ULL,
229 .bbCnt = 0ULL,
230 .newBBCnt = 0ULL,
231 .softCntPc = 0ULL,
232 .softCntCmp = 0ULL,
233 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200234 .dynamicCutOffAddr = ~(0ULL),
235 .disableRandomization = true,
236 .ignoreAddr = NULL,
237 .numMajorFrames = 7,
238 .pid = 0,
239 .pidFile = NULL,
240 .pidCmd = NULL,
241 .symsBlFile = NULL,
242 .symsBlCnt = 0,
243 .symsBl = NULL,
244 .symsWlFile = NULL,
245 .symsWlCnt = 0,
246 .symsWl = NULL,
247 .cloneFlags = 0,
248 .kernelOnly = false,
249 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100250 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200251 };
Robert Swieckia88f96f2015-10-09 16:47:39 +0200252
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100253 CIRCLEQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100254 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100255
Robert Swiecki0b566112017-10-17 17:39:07 +0200256 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200257 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200258 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
259 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
260 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200261 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
262 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200263 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
264 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
265 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
266 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
267 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100268 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200269 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
270 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
271 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
272 { { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" },
273 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
274 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
275 { { "covdir", required_argument, NULL, 0x103 }, "New coverage is written to a separate directory (default: use the input directory)" },
276 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
277 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
278 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
279 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
280 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
281 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
282 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process memory limit in MiB (default: '0' [no limit])" },
283 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
284 { { "max_file_size", required_argument, NULL, 'F' }, "Maximal size of files processed by the fuzzer in bytes (default: '1048576')" },
285 { { "clear_env", no_argument, NULL, 0x101 }, "Clear all environment variables before executing the binary" },
286 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
287 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
288 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
289 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
290 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
291 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
292 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200293
294#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200295 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
296 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
297 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
298 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
299 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
300 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
301 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
302 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
303 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
304 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
305 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
306 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
307 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
308 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
309 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
310#endif // defined(_HF_ARCH_LINUX)
311 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200312 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200313 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200314
315 struct option opts[ARRAYSIZE(custom_opts)];
316 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
317 opts[i] = custom_opts[i].opt;
318 }
319
320 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200321 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200322 int opt_index = 0;
323 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200324 int c = getopt_long(
Robert Swiecki930e12f2017-10-24 14:52:03 +0200325 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 +0200326 if (c < 0)
327 break;
328
329 switch (c) {
330 case 'h':
331 case '?':
332 cmdlineUsage(argv[0], custom_opts);
333 break;
334 case 'f':
Jagger1b2d4822016-09-25 16:19:45 +0200335 hfuzz->inputDir = optarg;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200336 break;
Robert Swiecki930e12f2017-10-24 14:52:03 +0200337 case 'x':
338 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
339 break;
Robert Swiecki4332ae92017-05-23 23:06:04 +0200340 case 'Q':
341 hfuzz->nullifyStdio = false;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200342 break;
343 case 'v':
344 hfuzz->useScreen = false;
345 break;
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700346 case 'V':
347 hfuzz->useVerifier = true;
348 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200349 case 's':
350 hfuzz->fuzzStdin = true;
351 break;
352 case 'u':
353 hfuzz->saveUnique = false;
354 break;
Robert Swiecki03ef5312015-10-09 18:25:40 +0200355 case 'l':
356 logfile = optarg;
357 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200358 case 'd':
359 ll = atoi(optarg);
360 break;
361 case 'e':
362 hfuzz->fileExtn = optarg;
363 break;
364 case 'W':
365 hfuzz->workDir = optarg;
366 break;
367 case 'r':
Robert Swiecki10e93562017-11-04 00:57:47 +0100368 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200369 break;
370 case 'c':
371 hfuzz->externalCommand = optarg;
372 break;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200373 case 'C':
374 hfuzz->useSanCov = true;
375 break;
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200376 case 'S':
377 hfuzz->enableSanitizers = true;
378 break;
Jagger4aac9fe2016-08-28 17:35:48 +0200379 case 'z':
380 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
381 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200382 case 'F':
383 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
384 break;
385 case 't':
386 hfuzz->tmOut = atol(optarg);
387 break;
388 case 'R':
389 hfuzz->reportFile = optarg;
390 break;
391 case 'n':
392 hfuzz->threadsMax = atol(optarg);
393 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200394 case 0x109: {
395 time_t p = atol(optarg);
396 if (p > 0) {
397 hfuzz->runEndTime = time(NULL) + p;
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200398 }
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200399 } break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200400 case 'N':
401 hfuzz->mutationsMax = atol(optarg);
402 break;
Robert Swiecki03ef5312015-10-09 18:25:40 +0200403 case 0x100:
Robert Swieckia88f96f2015-10-09 16:47:39 +0200404 hfuzz->asLimit = strtoull(optarg, NULL, 0);
405 break;
Jagger80041fe2016-03-10 21:32:35 +0100406 case 0x101:
407 hfuzz->clearEnv = true;
408 break;
Robert Swieckidac8cf12016-09-22 15:36:28 +0200409 case 0x103:
Jagger1b2d4822016-09-25 16:19:45 +0200410 hfuzz->covDir = optarg;
Robert Swieckidac8cf12016-09-22 15:36:28 +0200411 break;
Robert Swieckiee266ac2016-10-03 02:25:59 +0200412 case 0x104:
413 hfuzz->postExternalCommand = optarg;
414 break;
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200415 case 0x105:
416 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
417 hfuzz->monitorSIGABRT = false;
418 } else {
419 hfuzz->monitorSIGABRT = true;
420 }
421 break;
Robert Swiecki44f6b192017-02-15 20:24:55 +0100422 case 0x106:
423 hfuzz->skipFeedbackOnTimeout = true;
424 break;
Robert Swiecki069b48f2017-05-31 01:00:08 +0200425 case 0x107:
426 hfuzz->exitUponCrash = true;
427 break;
Robert Swieckifab69162016-03-31 15:41:36 +0200428 case 'P':
Robert Swiecki0f937af2016-03-30 18:19:16 +0200429 hfuzz->persistent = true;
430 break;
Gergely Nagy5d47c732016-12-12 23:51:51 +0100431 case 'T':
Robert Swieckie84b6452016-12-12 12:42:04 +0100432 hfuzz->tmout_vtalrm = true;
433 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200434 case 'p':
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200435 if (util_isANumber(optarg) == false) {
Jagger9c4d1622015-10-16 01:40:17 +0200436 LOG_E("-p '%s' is not a number", optarg);
437 return false;
438 }
Jagger247c3b42016-03-21 23:24:05 +0100439 hfuzz->linux.pid = atoi(optarg);
440 if (hfuzz->linux.pid < 1) {
441 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
Jagger9c4d1622015-10-16 01:40:17 +0200442 return false;
443 }
Robert Swieckia88f96f2015-10-09 16:47:39 +0200444 break;
Robert Swieckifab69162016-03-31 15:41:36 +0200445 case 0x502:
Jagger247c3b42016-03-21 23:24:05 +0100446 hfuzz->linux.pidFile = optarg;
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200447 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200448 case 'E':
449 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs); i++) {
450 if (hfuzz->envs[i] == NULL) {
451 hfuzz->envs[i] = optarg;
452 break;
453 }
454 }
455 break;
456 case 'w':
457 hfuzz->dictionaryFile = optarg;
458 break;
459 case 'B':
460 hfuzz->blacklistFile = optarg;
461 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100462#if defined(_HF_ARCH_LINUX)
Robert Swieckia88f96f2015-10-09 16:47:39 +0200463 case 0x500:
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200464 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200465 break;
466 case 0x501:
Jagger247c3b42016-03-21 23:24:05 +0100467 hfuzz->linux.disableRandomization = false;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200468 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200469 case 0x503:
Jagger247c3b42016-03-21 23:24:05 +0100470 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200471 break;
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300472 case 0x504:
473 hfuzz->linux.symsBlFile = optarg;
474 break;
475 case 0x505:
476 hfuzz->linux.symsWlFile = optarg;
477 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200478 case 0x510:
479 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
480 break;
481 case 0x511:
482 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
483 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200484 case 0x513:
Jagger3abc5602016-02-04 00:53:43 +0100485 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200486 break;
487 case 0x514:
Jagger39bd2b02016-02-04 01:16:15 +0100488 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
489 break;
Robert Swiecki37d27ca2017-03-30 14:43:54 +0200490 case 0x515:
491 hfuzz->linux.kernelOnly = true;
492 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100493 case 0x530:
494 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
495 break;
496 case 0x531:
497 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
498 break;
499 case 0x532:
500 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
501 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200502#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200503 default:
504 cmdlineUsage(argv[0], custom_opts);
505 return false;
506 break;
507 }
508 }
Jagger72f258b2015-10-09 23:09:01 +0200509
Robert Swieckia88f96f2015-10-09 16:47:39 +0200510 if (logInitLogFile(logfile, ll) == false) {
511 return false;
512 }
513
514 hfuzz->cmdline = &argv[optind];
515 if (hfuzz->cmdline[0] == NULL) {
516 LOG_E("No fuzz command provided");
517 cmdlineUsage(argv[0], custom_opts);
518 return false;
519 }
520
Robert Swiecki0f937af2016-03-30 18:19:16 +0200521 if (!hfuzz->fuzzStdin && !hfuzz->persistent && !checkFor_FILE_PLACEHOLDER(hfuzz->cmdline)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200522 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
Robert Swiecki0f937af2016-03-30 18:19:16 +0200523 "' when the -s (stdin fuzzing) or --persistent options are not set");
Robert Swieckia88f96f2015-10-09 16:47:39 +0200524 return false;
525 }
526
Robert Swiecki5b775b22017-04-28 16:19:15 +0200527 if (hfuzz->fuzzStdin && hfuzz->persistent) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200528 LOG_E(
529 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
Robert Swieckid633fe02017-04-28 17:40:27 +0200530 return false;
Robert Swiecki5b775b22017-04-28 16:19:15 +0200531 }
532
Robert Swiecki71b73722016-09-05 15:18:25 +0200533 if (hfuzz->threadsMax >= _HF_THREAD_MAX) {
534 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))", hfuzz->threadsMax,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200535 _HF_THREAD_MAX);
Robert Swiecki71b73722016-09-05 15:18:25 +0200536 return false;
537 }
538
Robert Swieckia88f96f2015-10-09 16:47:39 +0200539 if (strchr(hfuzz->fileExtn, '/')) {
540 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->fileExtn);
541 return false;
542 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200543
Anestis Bechtsoudis8f4aa612015-12-27 12:06:19 +0200544 if (hfuzz->workDir[0] != '.' || strlen(hfuzz->workDir) > 2) {
Anestis Bechtsoudisc8e7f6e2015-12-26 14:48:48 +0200545 if (!files_exists(hfuzz->workDir)) {
546 LOG_E("Provided workspace directory '%s' doesn't exist", hfuzz->workDir);
547 return false;
548 }
549 }
Robert Swieckia88f96f2015-10-09 16:47:39 +0200550
Jagger247c3b42016-03-21 23:24:05 +0100551 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
552 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200553 hfuzz->linux.pid);
Robert Swieckia88f96f2015-10-09 16:47:39 +0200554 hfuzz->threadsMax = 1;
555 }
556
Robert Swiecki13d95022017-11-04 12:15:41 +0100557 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
Robert Swiecki10e93562017-11-04 00:57:47 +0100558 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200559 }
560
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200561 /*
562 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
563 * better to let user know about the features that each flag control.
564 */
565 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
566 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
567 return false;
568 }
569
Robert Swiecki10e93562017-11-04 00:57:47 +0100570 LOG_I("PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
571 "mutationsPerRun: %u, "
Robert Swiecki0b566112017-10-17 17:39:07 +0200572 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, threadsMax: %zu, "
573 "fileExtn: '%s', "
Anestis Bechtsoudisecab7762016-12-27 18:27:30 +0200574 "memoryLimit: 0x%" PRIx64 "(MiB), fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki0b566112017-10-17 17:39:07 +0200575 (int)getpid(), hfuzz->inputDir, cmdlineYesNo(hfuzz->nullifyStdio),
Robert Swiecki10e93562017-11-04 00:57:47 +0100576 cmdlineYesNo(hfuzz->fuzzStdin), cmdlineYesNo(hfuzz->saveUnique), hfuzz->mutationsPerRun,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200577 hfuzz->externalCommand == NULL ? "NULL" : hfuzz->externalCommand, (int)hfuzz->runEndTime,
578 hfuzz->tmOut, hfuzz->mutationsMax, hfuzz->threadsMax, hfuzz->fileExtn, hfuzz->asLimit,
579 hfuzz->cmdline[0], hfuzz->linux.pid, cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200580
Robert Swiecki2aaa52b2016-01-19 14:40:47 +0100581 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->cmdline[0]);
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100582 for (size_t i = 1; hfuzz->cmdline[i]; i++) {
583 util_ssnprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100584 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
585 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
586 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
587 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '.';
588 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100589 }
590
Robert Swieckia88f96f2015-10-09 16:47:39 +0200591 return true;
592}