blob: 8f17e2a6873739f206e3074933d5a557ba0b3242 [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 Swiecki97d0cee2017-12-18 00:17:50 +010052static bool checkFor_FILE_PLACEHOLDER(const char* const* 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) {
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100130 if (!hfuzz->exe.fuzzStdin && !hfuzz->persistent &&
131 !checkFor_FILE_PLACEHOLDER(hfuzz->exe.cmdline)) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100132 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
133 "' when the -s (stdin fuzzing) or --persistent options are not set");
134 return false;
135 }
136
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100137 if (hfuzz->exe.fuzzStdin && hfuzz->persistent) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100138 LOG_E(
139 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
140 return false;
141 }
142
143 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) {
144 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))",
145 hfuzz->threads.threadsMax, _HF_THREAD_MAX);
146 return false;
147 }
148
149 if (strchr(hfuzz->io.fileExtn, '/')) {
150 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn);
151 return false;
152 }
153
154 if (hfuzz->io.workDir == NULL) {
155 hfuzz->io.workDir = ".";
156 }
157 if (mkdir(hfuzz->io.workDir, 0700) == -1 && errno != EEXIST) {
158 PLOG_E("Couldn't create the workspace directory '%s'", hfuzz->io.workDir);
159 return false;
160 }
161 if (hfuzz->io.crashDir == NULL) {
162 hfuzz->io.crashDir = hfuzz->io.workDir;
163 }
164 if (mkdir(hfuzz->io.crashDir, 0700) && errno != EEXIST) {
165 PLOG_E("Couldn't create the crash directory '%s'", hfuzz->io.crashDir);
166 return false;
167 }
168
169 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
170 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
171 hfuzz->linux.pid);
172 hfuzz->threads.threadsMax = 1;
173 }
174
175 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
176 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
177 }
178
179 /*
180 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
181 * better to let user know about the features that each flag control.
182 */
183 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
184 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
185 return false;
186 }
187
188 return true;
189}
190
Robert Swieckid50ed422017-11-13 23:32:26 +0100191bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
192 honggfuzz_t tmp = {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100193 .io =
194 {
195 .inputDir = NULL,
Robert Swieckia35d9d82017-12-15 22:00:41 +0100196 .inputDirPtr = NULL,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100197 .fileCnt = 0,
198 .fileCntDone = false,
199 .fileExtn = "fuzz",
Robert Swieckiced3eba2017-12-15 15:33:03 +0100200 .workDir = NULL,
201 .crashDir = NULL,
202 .covDirAll = NULL,
203 .covDirNew = NULL,
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100204 .saveUnique = true,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100205 },
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100206 .exe =
207 {
208 .cmdline = NULL,
209 .nullifyStdio = true,
210 .fuzzStdin = false,
211 .externalCommand = NULL,
212 .postExternalCommand = NULL,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100213 .asLimit = 0U,
214 .rssLimit = 0U,
215 .dataLimit = 0U,
216 .clearEnv = false,
217 .envs[0] = NULL,
218 },
Robert Swiecki371e1292017-12-18 01:10:33 +0100219 .timing =
220 {
221 .timeStart = time(NULL),
222 .runEndTime = 0,
223 .tmOut = 10,
Robert Swieckieba27172017-12-18 01:12:02 +0100224 .tmoutVTALRM = false,
Robert Swiecki371e1292017-12-18 01:10:33 +0100225 },
226 .cmdline_txt[0] = '\0',
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100227 .useScreen = true,
228 .useVerifier = false,
Robert Swiecki10e93562017-11-04 00:57:47 +0100229 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200230 .blacklistFile = NULL,
231 .blacklistCnt = 0,
232 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200233 .maxFileSz = 0UL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200234 .mutationsMax = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200235 .reportFile = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200236 .persistent = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100237 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200238 .enableSanitizers = false,
239#if defined(__ANDROID__)
240 .monitorSIGABRT = false,
241#else
242 .monitorSIGABRT = true,
243#endif
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200244 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200245
Robert Swieckid50ed422017-11-13 23:32:26 +0100246 .threads =
247 {
248 .threadsFinished = 0,
249 .threadsMax =
250 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
251 .threadsActiveCnt = 0,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100252 .mainThread = pthread_self(),
253 .mainPid = getpid(),
Robert Swieckid50ed422017-11-13 23:32:26 +0100254 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100255
Robert Swiecki531438a2016-09-13 19:05:11 +0200256 .dictionaryFile = NULL,
257 .dictionaryCnt = 0,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100258 .dictqCurrent = NULL,
Robert Swiecki531438a2016-09-13 19:05:11 +0200259
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100260 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200261 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200262 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100263
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100264 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100265 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100266
Robert Swiecki37498fd2017-03-12 21:12:54 +0100267 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
268
Robert Swiecki01a980e2017-11-14 03:36:50 +0100269 .cnts =
270 {
271 .mutationsCnt = 0,
272 .crashesCnt = 0,
273 .uniqueCrashesCnt = 0,
274 .verifiedCrashesCnt = 0,
275 .blCrashesCnt = 0,
276 .timeoutedCnt = 0,
277 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200278
Robert Swiecki930e12f2017-10-24 14:52:03 +0200279 .dynFileMethod = _HF_DYNFILE_SOFT,
Robert Swieckid50ed422017-11-13 23:32:26 +0100280 .sanCovCnts =
281 {
282 .hitBBCnt = 0ULL,
283 .totalBBCnt = 0ULL,
284 .dsoCnt = 0ULL,
285 .iDsoCnt = 0ULL,
286 .newBBCnt = 0ULL,
287 .crashesCnt = 0ULL,
288 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200289
Robert Swiecki66b65122017-11-11 02:55:55 +0100290 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swieckid50ed422017-11-13 23:32:26 +0100291 .sanOpts =
292 {
293 .asanOpts = NULL,
294 .msanOpts = NULL,
295 .ubsanOpts = NULL,
296 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100297 .useSanCov = false,
298 .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100299
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700300 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
301
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100302 /* Linux code */
Robert Swieckid50ed422017-11-13 23:32:26 +0100303 .linux =
304 {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200305 .exeFd = -1,
Robert Swieckid50ed422017-11-13 23:32:26 +0100306 .hwCnts =
307 {
308 .cpuInstrCnt = 0ULL,
309 .cpuBranchCnt = 0ULL,
310 .bbCnt = 0ULL,
311 .newBBCnt = 0ULL,
312 .softCntPc = 0ULL,
313 .softCntCmp = 0ULL,
314 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200315 .dynamicCutOffAddr = ~(0ULL),
316 .disableRandomization = true,
317 .ignoreAddr = NULL,
318 .numMajorFrames = 7,
319 .pid = 0,
320 .pidFile = NULL,
Robert Swiecki06a0d8c2017-11-29 02:29:26 +0100321 .pidCmd[0] = '\0',
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200322 .symsBlFile = NULL,
323 .symsBlCnt = 0,
324 .symsBl = NULL,
325 .symsWlFile = NULL,
326 .symsWlCnt = 0,
327 .symsWl = NULL,
328 .cloneFlags = 0,
329 .kernelOnly = false,
330 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100331 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200332 };
Robert Swieckid50ed422017-11-13 23:32:26 +0100333 *hfuzz = tmp;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200334
Robert Swieckib0e261a2017-11-09 01:30:54 +0100335 TAILQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100336 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100337
Robert Swiecki0b566112017-10-17 17:39:07 +0200338 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200339 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200340 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
341 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
342 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200343 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
344 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200345 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
346 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
347 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
348 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
349 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100350 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200351 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
352 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
353 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
354 { { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" },
355 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
356 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
Robert Swieckia35d9d82017-12-15 22:00:41 +0100357 { { "crashdir", required_argument, NULL, 0x600 }, "Directory where crashes are saved to (default: workspace directory)" },
358 { { "covdir_all", required_argument, NULL, 0x601 }, "Coverage is written to a separate directory (default: input directory)" },
359 { { "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 +0200360 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
361 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
362 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
363 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
364 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
365 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100366 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" },
367 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" },
368 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200369 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
370 { { "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 +0100371 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200372 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
373 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
374 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
375 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
376 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
377 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
378 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200379
380#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200381 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
382 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
383 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
384 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
385 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
386 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
387 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
388 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
389 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
390 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
391 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
392 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
393 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
394 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
395 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
396#endif // defined(_HF_ARCH_LINUX)
397 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200398 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200399 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200400
401 struct option opts[ARRAYSIZE(custom_opts)];
402 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
403 opts[i] = custom_opts[i].opt;
404 }
405
406 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200407 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200408 int opt_index = 0;
409 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200410 int c = getopt_long(
Robert Swiecki930e12f2017-10-24 14:52:03 +0200411 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 +0100412 if (c < 0) break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200413
414 switch (c) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100415 case 'h':
416 case '?':
417 cmdlineUsage(argv[0], custom_opts);
418 break;
419 case 'f':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100420 hfuzz->io.inputDir = optarg;
Robert Swieckiced3eba2017-12-15 15:33:03 +0100421 if (hfuzz->io.covDirAll == NULL) {
422 hfuzz->io.covDirAll = optarg;
423 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100424 break;
425 case 'x':
426 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
427 break;
428 case 'Q':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100429 hfuzz->exe.nullifyStdio = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100430 break;
431 case 'v':
432 hfuzz->useScreen = false;
433 break;
434 case 'V':
435 hfuzz->useVerifier = true;
436 break;
437 case 's':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100438 hfuzz->exe.fuzzStdin = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100439 break;
440 case 'u':
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100441 hfuzz->io.saveUnique = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100442 break;
443 case 'l':
444 logfile = optarg;
445 break;
446 case 'd':
447 ll = atoi(optarg);
448 break;
449 case 'e':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100450 hfuzz->io.fileExtn = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100451 break;
452 case 'W':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100453 hfuzz->io.workDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100454 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100455 case 0x600:
Robert Swieckiced3eba2017-12-15 15:33:03 +0100456 hfuzz->io.crashDir = optarg;
457 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100458 case 0x601:
459 hfuzz->io.covDirAll = optarg;
460 break;
461 case 0x602:
462 hfuzz->io.covDirNew = optarg;
463 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100464 case 'r':
465 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
466 break;
467 case 'c':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100468 hfuzz->exe.externalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100469 break;
470 case 'C':
471 hfuzz->useSanCov = true;
472 break;
473 case 'S':
474 hfuzz->enableSanitizers = true;
475 break;
476 case 'z':
477 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
478 break;
479 case 'F':
480 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
481 break;
482 case 't':
Robert Swiecki371e1292017-12-18 01:10:33 +0100483 hfuzz->timing.tmOut = atol(optarg);
Robert Swieckid50ed422017-11-13 23:32:26 +0100484 break;
485 case 'R':
486 hfuzz->reportFile = optarg;
487 break;
488 case 'n':
489 hfuzz->threads.threadsMax = atol(optarg);
490 break;
491 case 0x109: {
492 time_t p = atol(optarg);
493 if (p > 0) {
Robert Swiecki371e1292017-12-18 01:10:33 +0100494 hfuzz->timing.runEndTime = time(NULL) + p;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200495 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100496 } break;
497 case 'N':
498 hfuzz->mutationsMax = atol(optarg);
499 break;
500 case 0x100:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100501 hfuzz->exe.asLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100502 break;
503 case 0x101:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100504 hfuzz->exe.rssLimit = strtoull(optarg, NULL, 0);
Robert Swiecki8954afd2017-11-14 18:14:22 +0100505 break;
506 case 0x102:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100507 hfuzz->exe.dataLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100508 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100509 case 0x104:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100510 hfuzz->exe.postExternalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100511 break;
512 case 0x105:
513 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
514 hfuzz->monitorSIGABRT = false;
515 } else {
516 hfuzz->monitorSIGABRT = true;
517 }
518 break;
519 case 0x106:
520 hfuzz->skipFeedbackOnTimeout = true;
521 break;
522 case 0x107:
523 hfuzz->exitUponCrash = true;
524 break;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100525 case 0x108:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100526 hfuzz->exe.clearEnv = true;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100527 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100528 case 'P':
529 hfuzz->persistent = true;
530 break;
531 case 'T':
Robert Swieckieba27172017-12-18 01:12:02 +0100532 hfuzz->timing.tmoutVTALRM = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100533 break;
534 case 'p':
535 if (util_isANumber(optarg) == false) {
536 LOG_E("-p '%s' is not a number", optarg);
537 return false;
538 }
539 hfuzz->linux.pid = atoi(optarg);
540 if (hfuzz->linux.pid < 1) {
541 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
542 return false;
543 }
544 break;
545 case 0x502:
546 hfuzz->linux.pidFile = optarg;
547 break;
548 case 'E':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100549 for (size_t i = 0; i < ARRAYSIZE(hfuzz->exe.envs); i++) {
550 if (hfuzz->exe.envs[i] == NULL) {
551 hfuzz->exe.envs[i] = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100552 break;
553 }
554 }
555 break;
556 case 'w':
557 hfuzz->dictionaryFile = optarg;
558 break;
559 case 'B':
560 hfuzz->blacklistFile = optarg;
561 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100562#if defined(_HF_ARCH_LINUX)
Robert Swieckid50ed422017-11-13 23:32:26 +0100563 case 0x500:
564 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
565 break;
566 case 0x501:
567 hfuzz->linux.disableRandomization = false;
568 break;
569 case 0x503:
570 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
571 break;
572 case 0x504:
573 hfuzz->linux.symsBlFile = optarg;
574 break;
575 case 0x505:
576 hfuzz->linux.symsWlFile = optarg;
577 break;
578 case 0x510:
579 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
580 break;
581 case 0x511:
582 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
583 break;
584 case 0x513:
585 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
586 break;
587 case 0x514:
588 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
589 break;
590 case 0x515:
591 hfuzz->linux.kernelOnly = true;
592 break;
593 case 0x530:
594 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
595 break;
596 case 0x531:
597 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
598 break;
599 case 0x532:
600 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
601 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200602#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckid50ed422017-11-13 23:32:26 +0100603 default:
604 cmdlineUsage(argv[0], custom_opts);
605 return false;
606 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200607 }
608 }
Jagger72f258b2015-10-09 23:09:01 +0200609
Robert Swieckia35d9d82017-12-15 22:00:41 +0100610 if (!logInitLogFile(logfile, ll)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200611 return false;
612 }
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100613 hfuzz->exe.cmdline = (const char* const*)&argv[optind];
614 if (hfuzz->exe.cmdline[0] == NULL) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200615 LOG_E("No fuzz command provided");
616 cmdlineUsage(argv[0], custom_opts);
617 return false;
618 }
Robert Swieckia35d9d82017-12-15 22:00:41 +0100619 if (!cmdlineVerify(hfuzz)) {
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200620 return false;
621 }
622
Robert Swieckid50ed422017-11-13 23:32:26 +0100623 LOG_I(
624 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
625 "mutationsPerRun: %u, "
626 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, "
627 "threads.threadsMax: %zu, "
628 "fileExtn: '%s', "
Robert Swiecki8954afd2017-11-14 18:14:22 +0100629 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64
630 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100631 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->exe.nullifyStdio),
632 cmdlineYesNo(hfuzz->exe.fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique),
633 hfuzz->mutationsPerRun,
634 hfuzz->exe.externalCommand == NULL ? "NULL" : hfuzz->exe.externalCommand,
Robert Swiecki371e1292017-12-18 01:10:33 +0100635 (int)hfuzz->timing.runEndTime, hfuzz->timing.tmOut, hfuzz->mutationsMax,
636 hfuzz->threads.threadsMax, hfuzz->io.fileExtn, hfuzz->exe.asLimit, hfuzz->exe.rssLimit,
637 hfuzz->exe.dataLimit, hfuzz->exe.cmdline[0], hfuzz->linux.pid,
638 cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200639
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100640 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->exe.cmdline[0]);
641 for (size_t i = 1; hfuzz->exe.cmdline[i]; i++) {
642 util_ssnprintf(
643 hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->exe.cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100644 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
Robert Swiecki6e885112017-11-22 00:32:24 +0100645 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' ';
646 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100647 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
648 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
Robert Swiecki6e885112017-11-22 00:32:24 +0100649 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100650 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100651 }
652
Robert Swieckia88f96f2015-10-09 16:47:39 +0200653 return true;
654}