blob: ac97c1c09059dd9e8e3e3f225cc2bc41951574be [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 Swieckia35d9d82017-12-15 22:00:41 +010038#include <sys/stat.h>
39#include <sys/types.h>
Robert Swieckia88f96f2015-10-09 16:47:39 +020040#include <unistd.h>
41
Robert Swiecki241a7412017-05-24 01:53:15 +020042#include "libcommon/common.h"
Robert Swiecki241a7412017-05-24 01:53:15 +020043#include "libcommon/files.h"
Robert Swieckid0fa62c2017-09-28 18:11:05 +020044#include "libcommon/log.h"
Robert Swiecki241a7412017-05-24 01:53:15 +020045#include "libcommon/util.h"
Robert Swieckia88f96f2015-10-09 16:47:39 +020046
47struct custom_option {
48 struct option opt;
Robert Swiecki4e595fb2017-10-11 17:26:51 +020049 const char* descr;
Robert Swieckia88f96f2015-10-09 16:47:39 +020050};
51
Robert Swieckid50ed422017-11-13 23:32:26 +010052static bool checkFor_FILE_PLACEHOLDER(char** args) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020053 for (int x = 0; args[x]; x++) {
Robert Swieckid50ed422017-11-13 23:32:26 +010054 if (strstr(args[x], _HF_FILE_PLACEHOLDER)) return true;
Robert Swieckia88f96f2015-10-09 16:47:39 +020055 }
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 Swieckid50ed422017-11-13 23:32:26 +010061static void cmdlineHelp(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020062 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
63 LOG_HELP_BOLD("Options:");
64 for (int i = 0; opts[i].opt.name; i++) {
Robert Swieckif3a5f6a2016-03-16 14:47:30 +010065 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) {
Robert Swiecki0b566112017-10-17 17:39:07 +020066 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020067 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020068 } else {
69 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020070 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020071 }
72 LOG_HELP("\t%s", opts[i].descr);
73 }
Jagger32127372015-10-09 23:07:38 +020074 LOG_HELP_BOLD("\nExamples:");
Robert Swieckid50ed422017-11-13 23:32:26 +010075 LOG_HELP(
76 " Run the binary over a mutated file chosen from the directory. Disable fuzzing "
77 "feedback (dry/static mode)");
Robert Swiecki216a4362017-12-13 13:02:52 +010078 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/djpeg " _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 Swiecki216a4362017-12-13 13:02:52 +010082 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020083 LOG_HELP(" Use SANCOV instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +010084 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020085 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +010086 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/djpeg_persistent_mode");
Robert Swiecki930e12f2017-10-24 14:52:03 +020087 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +010088 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/djpeg_persistent_mode");
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 Swiecki216a4362017-12-13 13:02:52 +010092 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_instr -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020093 LOG_HELP(" As above, maximize total no. of branches:");
Robert Swiecki216a4362017-12-13 13:02:52 +010094 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_branch -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020095 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:");
Robert Swiecki216a4362017-12-13 13:02:52 +010096 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +020097 LOG_HELP(
98 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):");
Robert Swiecki216a4362017-12-13 13:02:52 +010099 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200100#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200101}
102
Robert Swieckid50ed422017-11-13 23:32:26 +0100103static void cmdlineUsage(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200104 cmdlineHelp(pname, opts);
105 exit(0);
106}
107
Robert Swieckid50ed422017-11-13 23:32:26 +0100108rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200109 struct rlimit cur;
110 if (getrlimit(res, &cur) == -1) {
111 PLOG_F("getrlimit(%d)", res);
112 }
113 if (strcasecmp(optarg, "max") == 0) {
114 return cur.rlim_max;
115 }
116 if (strcasecmp(optarg, "def") == 0) {
117 return cur.rlim_cur;
118 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200119 if (util_isANumber(optarg) == false) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200120 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg);
121 }
122 rlim_t val = strtoul(optarg, NULL, 0) * mul;
Jagger2bd61b72015-10-10 05:23:32 +0200123 if ((unsigned long)val == ULONG_MAX && errno != 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200124 PLOG_F("strtoul('%s', 0)", optarg);
125 }
126 return val;
127}
128
Robert Swieckia35d9d82017-12-15 22:00:41 +0100129static bool cmdlineVerify(honggfuzz_t* hfuzz) {
130 if (!hfuzz->fuzzStdin && !hfuzz->persistent && !checkFor_FILE_PLACEHOLDER(hfuzz->cmdline)) {
131 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
132 "' when the -s (stdin fuzzing) or --persistent options are not set");
133 return false;
134 }
135
136 if (hfuzz->fuzzStdin && hfuzz->persistent) {
137 LOG_E(
138 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
139 return false;
140 }
141
142 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) {
143 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))",
144 hfuzz->threads.threadsMax, _HF_THREAD_MAX);
145 return false;
146 }
147
148 if (strchr(hfuzz->io.fileExtn, '/')) {
149 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn);
150 return false;
151 }
152
153 if (hfuzz->io.workDir == NULL) {
154 hfuzz->io.workDir = ".";
155 }
156 if (mkdir(hfuzz->io.workDir, 0700) == -1 && errno != EEXIST) {
157 PLOG_E("Couldn't create the workspace directory '%s'", hfuzz->io.workDir);
158 return false;
159 }
160 if (hfuzz->io.crashDir == NULL) {
161 hfuzz->io.crashDir = hfuzz->io.workDir;
162 }
163 if (mkdir(hfuzz->io.crashDir, 0700) && errno != EEXIST) {
164 PLOG_E("Couldn't create the crash directory '%s'", hfuzz->io.crashDir);
165 return false;
166 }
167
168 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
169 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
170 hfuzz->linux.pid);
171 hfuzz->threads.threadsMax = 1;
172 }
173
174 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
175 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
176 }
177
178 /*
179 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
180 * better to let user know about the features that each flag control.
181 */
182 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
183 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
184 return false;
185 }
186
187 return true;
188}
189
Robert Swieckid50ed422017-11-13 23:32:26 +0100190bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
191 honggfuzz_t tmp = {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200192 .cmdline = NULL,
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100193 .cmdline_txt[0] = '\0',
Robert Swiecki82c707c2017-11-14 16:36:23 +0100194 .io =
195 {
196 .inputDir = NULL,
Robert Swieckia35d9d82017-12-15 22:00:41 +0100197 .inputDirPtr = NULL,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100198 .fileCnt = 0,
199 .fileCntDone = false,
200 .fileExtn = "fuzz",
Robert Swieckiced3eba2017-12-15 15:33:03 +0100201 .workDir = NULL,
202 .crashDir = NULL,
203 .covDirAll = NULL,
204 .covDirNew = NULL,
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100205 .saveUnique = true,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100206 },
Robert Swiecki4332ae92017-05-23 23:06:04 +0200207 .nullifyStdio = true,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200208 .fuzzStdin = false,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100209 .useScreen = true,
210 .useVerifier = false,
211 .timeStart = time(NULL),
Robert Swiecki10e93562017-11-04 00:57:47 +0100212 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200213 .externalCommand = NULL,
Robert Swieckiee266ac2016-10-03 02:25:59 +0200214 .postExternalCommand = NULL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200215 .blacklistFile = NULL,
216 .blacklistCnt = 0,
217 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200218 .maxFileSz = 0UL,
Jaggerba92b4b2016-03-16 02:24:17 +0100219 .tmOut = 10,
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200220 .runEndTime = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200221 .mutationsMax = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200222 .reportFile = NULL,
Robert Swiecki8954afd2017-11-14 18:14:22 +0100223 .asLimit = 0U,
224 .rssLimit = 0U,
225 .dataLimit = 0U,
Jagger80041fe2016-03-10 21:32:35 +0100226 .clearEnv = false,
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200227 .envs[0] = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200228 .persistent = false,
Robert Swieckie84b6452016-12-12 12:42:04 +0100229 .tmout_vtalrm = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100230 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200231 .enableSanitizers = false,
232#if defined(__ANDROID__)
233 .monitorSIGABRT = false,
234#else
235 .monitorSIGABRT = true,
236#endif
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200237 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200238
Robert Swieckid50ed422017-11-13 23:32:26 +0100239 .threads =
240 {
241 .threadsFinished = 0,
242 .threadsMax =
243 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
244 .threadsActiveCnt = 0,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100245 .mainThread = pthread_self(),
246 .mainPid = getpid(),
Robert Swieckid50ed422017-11-13 23:32:26 +0100247 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100248
Robert Swiecki531438a2016-09-13 19:05:11 +0200249 .dictionaryFile = NULL,
250 .dictionaryCnt = 0,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100251 .dictqCurrent = NULL,
Robert Swiecki531438a2016-09-13 19:05:11 +0200252
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100253 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200254 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200255 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100256
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100257 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100258 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100259
Robert Swiecki37498fd2017-03-12 21:12:54 +0100260 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
261
Robert Swiecki01a980e2017-11-14 03:36:50 +0100262 .cnts =
263 {
264 .mutationsCnt = 0,
265 .crashesCnt = 0,
266 .uniqueCrashesCnt = 0,
267 .verifiedCrashesCnt = 0,
268 .blCrashesCnt = 0,
269 .timeoutedCnt = 0,
270 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200271
Robert Swiecki930e12f2017-10-24 14:52:03 +0200272 .dynFileMethod = _HF_DYNFILE_SOFT,
Robert Swieckid50ed422017-11-13 23:32:26 +0100273 .sanCovCnts =
274 {
275 .hitBBCnt = 0ULL,
276 .totalBBCnt = 0ULL,
277 .dsoCnt = 0ULL,
278 .iDsoCnt = 0ULL,
279 .newBBCnt = 0ULL,
280 .crashesCnt = 0ULL,
281 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200282
Robert Swiecki66b65122017-11-11 02:55:55 +0100283 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swieckid50ed422017-11-13 23:32:26 +0100284 .sanOpts =
285 {
286 .asanOpts = NULL,
287 .msanOpts = NULL,
288 .ubsanOpts = NULL,
289 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100290 .useSanCov = false,
291 .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100292
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700293 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
294
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100295 /* Linux code */
Robert Swieckid50ed422017-11-13 23:32:26 +0100296 .linux =
297 {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200298 .exeFd = -1,
Robert Swieckid50ed422017-11-13 23:32:26 +0100299 .hwCnts =
300 {
301 .cpuInstrCnt = 0ULL,
302 .cpuBranchCnt = 0ULL,
303 .bbCnt = 0ULL,
304 .newBBCnt = 0ULL,
305 .softCntPc = 0ULL,
306 .softCntCmp = 0ULL,
307 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200308 .dynamicCutOffAddr = ~(0ULL),
309 .disableRandomization = true,
310 .ignoreAddr = NULL,
311 .numMajorFrames = 7,
312 .pid = 0,
313 .pidFile = NULL,
Robert Swiecki06a0d8c2017-11-29 02:29:26 +0100314 .pidCmd[0] = '\0',
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200315 .symsBlFile = NULL,
316 .symsBlCnt = 0,
317 .symsBl = NULL,
318 .symsWlFile = NULL,
319 .symsWlCnt = 0,
320 .symsWl = NULL,
321 .cloneFlags = 0,
322 .kernelOnly = false,
323 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100324 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200325 };
Robert Swieckid50ed422017-11-13 23:32:26 +0100326 *hfuzz = tmp;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200327
Robert Swieckib0e261a2017-11-09 01:30:54 +0100328 TAILQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100329 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100330
Robert Swiecki0b566112017-10-17 17:39:07 +0200331 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200332 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200333 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
334 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
335 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200336 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
337 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200338 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
339 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
340 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
341 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
342 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100343 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200344 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
345 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
346 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
347 { { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" },
348 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
349 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
Robert Swieckia35d9d82017-12-15 22:00:41 +0100350 { { "crashdir", required_argument, NULL, 0x600 }, "Directory where crashes are saved to (default: workspace directory)" },
351 { { "covdir_all", required_argument, NULL, 0x601 }, "Coverage is written to a separate directory (default: input directory)" },
352 { { "covdir_new", required_argument, NULL, 0x602 }, "New coverage (beyond the dry-run fuzzing phase) is written to this separate directory" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200353 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
354 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
355 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
356 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
357 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
358 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100359 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" },
360 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" },
361 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200362 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
363 { { "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 +0100364 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200365 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
366 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
367 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
368 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
369 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
370 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
371 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200372
373#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200374 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
375 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
376 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
377 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
378 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
379 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
380 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
381 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
382 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
383 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
384 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
385 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
386 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
387 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
388 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
389#endif // defined(_HF_ARCH_LINUX)
390 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200391 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200392 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200393
394 struct option opts[ARRAYSIZE(custom_opts)];
395 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
396 opts[i] = custom_opts[i].opt;
397 }
398
399 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200400 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200401 int opt_index = 0;
402 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200403 int c = getopt_long(
Robert Swiecki930e12f2017-10-24 14:52:03 +0200404 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 +0100405 if (c < 0) break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200406
407 switch (c) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100408 case 'h':
409 case '?':
410 cmdlineUsage(argv[0], custom_opts);
411 break;
412 case 'f':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100413 hfuzz->io.inputDir = optarg;
Robert Swieckiced3eba2017-12-15 15:33:03 +0100414 if (hfuzz->io.covDirAll == NULL) {
415 hfuzz->io.covDirAll = optarg;
416 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100417 break;
418 case 'x':
419 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
420 break;
421 case 'Q':
422 hfuzz->nullifyStdio = false;
423 break;
424 case 'v':
425 hfuzz->useScreen = false;
426 break;
427 case 'V':
428 hfuzz->useVerifier = true;
429 break;
430 case 's':
431 hfuzz->fuzzStdin = true;
432 break;
433 case 'u':
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100434 hfuzz->io.saveUnique = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100435 break;
436 case 'l':
437 logfile = optarg;
438 break;
439 case 'd':
440 ll = atoi(optarg);
441 break;
442 case 'e':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100443 hfuzz->io.fileExtn = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100444 break;
445 case 'W':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100446 hfuzz->io.workDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100447 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100448 case 0x600:
Robert Swieckiced3eba2017-12-15 15:33:03 +0100449 hfuzz->io.crashDir = optarg;
450 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100451 case 0x601:
452 hfuzz->io.covDirAll = optarg;
453 break;
454 case 0x602:
455 hfuzz->io.covDirNew = optarg;
456 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100457 case 'r':
458 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
459 break;
460 case 'c':
461 hfuzz->externalCommand = optarg;
462 break;
463 case 'C':
464 hfuzz->useSanCov = true;
465 break;
466 case 'S':
467 hfuzz->enableSanitizers = true;
468 break;
469 case 'z':
470 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
471 break;
472 case 'F':
473 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
474 break;
475 case 't':
476 hfuzz->tmOut = atol(optarg);
477 break;
478 case 'R':
479 hfuzz->reportFile = optarg;
480 break;
481 case 'n':
482 hfuzz->threads.threadsMax = atol(optarg);
483 break;
484 case 0x109: {
485 time_t p = atol(optarg);
486 if (p > 0) {
487 hfuzz->runEndTime = time(NULL) + p;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200488 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100489 } break;
490 case 'N':
491 hfuzz->mutationsMax = atol(optarg);
492 break;
493 case 0x100:
494 hfuzz->asLimit = strtoull(optarg, NULL, 0);
495 break;
496 case 0x101:
Robert Swiecki8954afd2017-11-14 18:14:22 +0100497 hfuzz->rssLimit = strtoull(optarg, NULL, 0);
498 break;
499 case 0x102:
500 hfuzz->dataLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100501 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100502 case 0x104:
503 hfuzz->postExternalCommand = optarg;
504 break;
505 case 0x105:
506 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
507 hfuzz->monitorSIGABRT = false;
508 } else {
509 hfuzz->monitorSIGABRT = true;
510 }
511 break;
512 case 0x106:
513 hfuzz->skipFeedbackOnTimeout = true;
514 break;
515 case 0x107:
516 hfuzz->exitUponCrash = true;
517 break;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100518 case 0x108:
519 hfuzz->clearEnv = true;
520 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100521 case 'P':
522 hfuzz->persistent = true;
523 break;
524 case 'T':
525 hfuzz->tmout_vtalrm = true;
526 break;
527 case 'p':
528 if (util_isANumber(optarg) == false) {
529 LOG_E("-p '%s' is not a number", optarg);
530 return false;
531 }
532 hfuzz->linux.pid = atoi(optarg);
533 if (hfuzz->linux.pid < 1) {
534 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
535 return false;
536 }
537 break;
538 case 0x502:
539 hfuzz->linux.pidFile = optarg;
540 break;
541 case 'E':
542 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs); i++) {
543 if (hfuzz->envs[i] == NULL) {
544 hfuzz->envs[i] = optarg;
545 break;
546 }
547 }
548 break;
549 case 'w':
550 hfuzz->dictionaryFile = optarg;
551 break;
552 case 'B':
553 hfuzz->blacklistFile = optarg;
554 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100555#if defined(_HF_ARCH_LINUX)
Robert Swieckid50ed422017-11-13 23:32:26 +0100556 case 0x500:
557 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
558 break;
559 case 0x501:
560 hfuzz->linux.disableRandomization = false;
561 break;
562 case 0x503:
563 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
564 break;
565 case 0x504:
566 hfuzz->linux.symsBlFile = optarg;
567 break;
568 case 0x505:
569 hfuzz->linux.symsWlFile = optarg;
570 break;
571 case 0x510:
572 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
573 break;
574 case 0x511:
575 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
576 break;
577 case 0x513:
578 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
579 break;
580 case 0x514:
581 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
582 break;
583 case 0x515:
584 hfuzz->linux.kernelOnly = true;
585 break;
586 case 0x530:
587 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
588 break;
589 case 0x531:
590 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
591 break;
592 case 0x532:
593 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
594 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200595#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckid50ed422017-11-13 23:32:26 +0100596 default:
597 cmdlineUsage(argv[0], custom_opts);
598 return false;
599 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200600 }
601 }
Jagger72f258b2015-10-09 23:09:01 +0200602
Robert Swieckia35d9d82017-12-15 22:00:41 +0100603 if (!logInitLogFile(logfile, ll)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200604 return false;
605 }
Robert Swieckia88f96f2015-10-09 16:47:39 +0200606 hfuzz->cmdline = &argv[optind];
607 if (hfuzz->cmdline[0] == NULL) {
608 LOG_E("No fuzz command provided");
609 cmdlineUsage(argv[0], custom_opts);
610 return false;
611 }
Robert Swieckia35d9d82017-12-15 22:00:41 +0100612 if (!cmdlineVerify(hfuzz)) {
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200613 return false;
614 }
615
Robert Swieckid50ed422017-11-13 23:32:26 +0100616 LOG_I(
617 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
618 "mutationsPerRun: %u, "
619 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, "
620 "threads.threadsMax: %zu, "
621 "fileExtn: '%s', "
Robert Swiecki8954afd2017-11-14 18:14:22 +0100622 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64
623 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki82c707c2017-11-14 16:36:23 +0100624 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->nullifyStdio),
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100625 cmdlineYesNo(hfuzz->fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique), hfuzz->mutationsPerRun,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200626 hfuzz->externalCommand == NULL ? "NULL" : hfuzz->externalCommand, (int)hfuzz->runEndTime,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100627 hfuzz->tmOut, hfuzz->mutationsMax, hfuzz->threads.threadsMax, hfuzz->io.fileExtn,
Robert Swiecki8954afd2017-11-14 18:14:22 +0100628 hfuzz->asLimit, hfuzz->rssLimit, hfuzz->dataLimit, hfuzz->cmdline[0], hfuzz->linux.pid,
629 cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200630
Robert Swiecki2aaa52b2016-01-19 14:40:47 +0100631 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->cmdline[0]);
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100632 for (size_t i = 1; hfuzz->cmdline[i]; i++) {
633 util_ssnprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100634 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
Robert Swiecki6e885112017-11-22 00:32:24 +0100635 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' ';
636 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100637 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
638 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
Robert Swiecki6e885112017-11-22 00:32:24 +0100639 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100640 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100641 }
642
Robert Swieckia88f96f2015-10-09 16:47:39 +0200643 return true;
644}