blob: f9801229830542fd600c9d4779fa0ff1ee14451c [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 Swieckif8292582018-01-10 16:19:18 +010037#include <sys/mman.h>
Robert Swiecki3bfc33c2016-03-14 18:12:41 +010038#include <sys/queue.h>
Robert Swieckia35d9d82017-12-15 22:00:41 +010039#include <sys/stat.h>
40#include <sys/types.h>
Robert Swieckia88f96f2015-10-09 16:47:39 +020041#include <unistd.h>
42
Robert Swiecki246af3e2018-01-05 14:56:32 +010043#include "libhfcommon/common.h"
44#include "libhfcommon/files.h"
45#include "libhfcommon/log.h"
46#include "libhfcommon/util.h"
Robert Swieckia88f96f2015-10-09 16:47:39 +020047
48struct custom_option {
49 struct option opt;
Robert Swiecki4e595fb2017-10-11 17:26:51 +020050 const char* descr;
Robert Swieckia88f96f2015-10-09 16:47:39 +020051};
52
Robert Swiecki97d0cee2017-12-18 00:17:50 +010053static bool checkFor_FILE_PLACEHOLDER(const char* const* args) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020054 for (int x = 0; args[x]; x++) {
Robert Swieckid50ed422017-11-13 23:32:26 +010055 if (strstr(args[x], _HF_FILE_PLACEHOLDER)) return true;
Robert Swieckia88f96f2015-10-09 16:47:39 +020056 }
57 return false;
58}
59
Robert Swieckif8292582018-01-10 16:19:18 +010060static bool cmdlineCheckIfPersistent(const char* fname) {
61 int fd;
62 off_t fileSz;
63 int ret = false;
64
65 uint8_t* map = files_mapFile(fname, &fileSz, &fd, /* isWriteable= */ false);
66 if (map == MAP_FAILED) {
67 LOG_W("Couldn't map file '%s' to check whether it's a persistent binary", fname);
68 return false;
69 }
70 if (memmem(map, fileSz, _HF_PERSISTENT_SIG, strlen(_HF_PERSISTENT_SIG))) {
71 ret = true;
72 }
73 if (munmap(map, fileSz) == -1) {
74 PLOG_W("munmap(%p, %zu)", map, fileSz);
75 }
76 close(fd);
77 return ret;
78}
79
Robert Swiecki0b566112017-10-17 17:39:07 +020080static const char* cmdlineYesNo(bool yes) { return (yes ? "true" : "false"); }
Robert Swieckia88f96f2015-10-09 16:47:39 +020081
Robert Swieckid50ed422017-11-13 23:32:26 +010082static void cmdlineHelp(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020083 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
84 LOG_HELP_BOLD("Options:");
85 for (int i = 0; opts[i].opt.name; i++) {
Robert Swieckif3a5f6a2016-03-16 14:47:30 +010086 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) {
Robert Swiecki0b566112017-10-17 17:39:07 +020087 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020088 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020089 } else {
90 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020091 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020092 }
93 LOG_HELP("\t%s", opts[i].descr);
94 }
Jagger32127372015-10-09 23:07:38 +020095 LOG_HELP_BOLD("\nExamples:");
Robert Swieckid50ed422017-11-13 23:32:26 +010096 LOG_HELP(
97 " Run the binary over a mutated file chosen from the directory. Disable fuzzing "
98 "feedback (dry/static mode)");
Robert Swiecki216a4362017-12-13 13:02:52 +010099 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Jagger32127372015-10-09 23:07:38 +0200100 LOG_HELP(" As above, provide input over STDIN:");
Robert Swiecki930e12f2017-10-24 14:52:03 +0200101 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -s -- /usr/bin/djpeg");
Jaggere848cc72016-09-19 02:28:52 +0200102 LOG_HELP(" Use compile-time instrumentation (libhfuzz/instrument.c):");
Robert Swiecki216a4362017-12-13 13:02:52 +0100103 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200104 LOG_HELP(" Use SANCOV instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100105 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200106 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100107 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/djpeg_persistent_mode");
Robert Swiecki930e12f2017-10-24 14:52:03 +0200108 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100109 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/djpeg_persistent_mode");
Robert Swieckia88f96f2015-10-09 16:47:39 +0200110#if defined(_HF_ARCH_LINUX)
Robert Swiecki930e12f2017-10-24 14:52:03 +0200111 LOG_HELP(
112 " Run the binary with dynamically generate inputs, maximize total no. of instructions:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100113 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_instr -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200114 LOG_HELP(" As above, maximize total no. of branches:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100115 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_branch -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200116 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100117 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200118 LOG_HELP(
119 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):");
Robert Swiecki216a4362017-12-13 13:02:52 +0100120 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200121#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200122}
123
Robert Swieckid50ed422017-11-13 23:32:26 +0100124static void cmdlineUsage(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200125 cmdlineHelp(pname, opts);
126 exit(0);
127}
128
Robert Swieckid50ed422017-11-13 23:32:26 +0100129rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200130 struct rlimit cur;
131 if (getrlimit(res, &cur) == -1) {
132 PLOG_F("getrlimit(%d)", res);
133 }
134 if (strcasecmp(optarg, "max") == 0) {
135 return cur.rlim_max;
136 }
137 if (strcasecmp(optarg, "def") == 0) {
138 return cur.rlim_cur;
139 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200140 if (util_isANumber(optarg) == false) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200141 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg);
142 }
143 rlim_t val = strtoul(optarg, NULL, 0) * mul;
Jagger2bd61b72015-10-10 05:23:32 +0200144 if ((unsigned long)val == ULONG_MAX && errno != 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200145 PLOG_F("strtoul('%s', 0)", optarg);
146 }
147 return val;
148}
149
Robert Swieckia35d9d82017-12-15 22:00:41 +0100150static bool cmdlineVerify(honggfuzz_t* hfuzz) {
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100151 if (!hfuzz->exe.fuzzStdin && !hfuzz->persistent &&
152 !checkFor_FILE_PLACEHOLDER(hfuzz->exe.cmdline)) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100153 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
154 "' when the -s (stdin fuzzing) or --persistent options are not set");
155 return false;
156 }
157
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100158 if (hfuzz->exe.fuzzStdin && hfuzz->persistent) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100159 LOG_E(
160 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
161 return false;
162 }
163
164 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) {
165 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))",
166 hfuzz->threads.threadsMax, _HF_THREAD_MAX);
167 return false;
168 }
169
170 if (strchr(hfuzz->io.fileExtn, '/')) {
171 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn);
172 return false;
173 }
174
175 if (hfuzz->io.workDir == NULL) {
176 hfuzz->io.workDir = ".";
177 }
178 if (mkdir(hfuzz->io.workDir, 0700) == -1 && errno != EEXIST) {
179 PLOG_E("Couldn't create the workspace directory '%s'", hfuzz->io.workDir);
180 return false;
181 }
182 if (hfuzz->io.crashDir == NULL) {
183 hfuzz->io.crashDir = hfuzz->io.workDir;
184 }
185 if (mkdir(hfuzz->io.crashDir, 0700) && errno != EEXIST) {
186 PLOG_E("Couldn't create the crash directory '%s'", hfuzz->io.crashDir);
187 return false;
188 }
189
190 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
191 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
192 hfuzz->linux.pid);
193 hfuzz->threads.threadsMax = 1;
194 }
195
196 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
197 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
198 }
199
200 /*
201 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
202 * better to let user know about the features that each flag control.
203 */
204 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
205 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
206 return false;
207 }
208
209 return true;
210}
211
Robert Swieckid50ed422017-11-13 23:32:26 +0100212bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
213 honggfuzz_t tmp = {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100214 .io =
215 {
216 .inputDir = NULL,
Robert Swieckia35d9d82017-12-15 22:00:41 +0100217 .inputDirPtr = NULL,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100218 .fileCnt = 0,
219 .fileCntDone = false,
220 .fileExtn = "fuzz",
Robert Swieckiced3eba2017-12-15 15:33:03 +0100221 .workDir = NULL,
222 .crashDir = NULL,
223 .covDirAll = NULL,
224 .covDirNew = NULL,
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100225 .saveUnique = true,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100226 },
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100227 .exe =
228 {
Robert Swiecki2aeff252018-01-10 14:58:44 +0100229 .argc = 0,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100230 .cmdline = NULL,
231 .nullifyStdio = true,
232 .fuzzStdin = false,
233 .externalCommand = NULL,
234 .postExternalCommand = NULL,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100235 .asLimit = 0U,
236 .rssLimit = 0U,
237 .dataLimit = 0U,
238 .clearEnv = false,
239 .envs[0] = NULL,
240 },
Robert Swiecki371e1292017-12-18 01:10:33 +0100241 .timing =
242 {
243 .timeStart = time(NULL),
244 .runEndTime = 0,
245 .tmOut = 10,
Robert Swieckieba27172017-12-18 01:12:02 +0100246 .tmoutVTALRM = false,
Robert Swiecki371e1292017-12-18 01:10:33 +0100247 },
Robert Swiecki06008f72017-12-27 18:40:34 +0100248 .cmdline_txt = {},
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100249 .useScreen = true,
250 .useVerifier = false,
Robert Swiecki10e93562017-11-04 00:57:47 +0100251 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200252 .blacklistFile = NULL,
253 .blacklistCnt = 0,
254 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200255 .maxFileSz = 0UL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200256 .mutationsMax = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200257 .reportFile = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200258 .persistent = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100259 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200260 .enableSanitizers = false,
261#if defined(__ANDROID__)
262 .monitorSIGABRT = false,
263#else
264 .monitorSIGABRT = true,
265#endif
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200266 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200267
Robert Swieckid50ed422017-11-13 23:32:26 +0100268 .threads =
269 {
270 .threadsFinished = 0,
271 .threadsMax =
272 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
273 .threadsActiveCnt = 0,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100274 .mainThread = pthread_self(),
275 .mainPid = getpid(),
Robert Swieckid50ed422017-11-13 23:32:26 +0100276 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100277
Robert Swiecki531438a2016-09-13 19:05:11 +0200278 .dictionaryFile = NULL,
279 .dictionaryCnt = 0,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100280 .dictqCurrent = NULL,
Robert Swiecki531438a2016-09-13 19:05:11 +0200281
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100282 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200283 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200284 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100285
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100286 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100287 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100288
Robert Swiecki37498fd2017-03-12 21:12:54 +0100289 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
290
Robert Swiecki01a980e2017-11-14 03:36:50 +0100291 .cnts =
292 {
293 .mutationsCnt = 0,
294 .crashesCnt = 0,
295 .uniqueCrashesCnt = 0,
296 .verifiedCrashesCnt = 0,
297 .blCrashesCnt = 0,
298 .timeoutedCnt = 0,
299 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200300
Robert Swiecki930e12f2017-10-24 14:52:03 +0200301 .dynFileMethod = _HF_DYNFILE_SOFT,
Robert Swieckid50ed422017-11-13 23:32:26 +0100302 .sanCovCnts =
303 {
304 .hitBBCnt = 0ULL,
305 .totalBBCnt = 0ULL,
306 .dsoCnt = 0ULL,
307 .iDsoCnt = 0ULL,
308 .newBBCnt = 0ULL,
309 .crashesCnt = 0ULL,
310 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200311
Robert Swiecki66b65122017-11-11 02:55:55 +0100312 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swieckid50ed422017-11-13 23:32:26 +0100313 .sanOpts =
314 {
Robert Swiecki06008f72017-12-27 18:40:34 +0100315 .asanOpts = {},
316 .msanOpts = {},
317 .ubsanOpts = {},
Robert Swiecki97d88932018-01-10 19:29:34 +0100318 .lsanOpts = {},
Robert Swieckid50ed422017-11-13 23:32:26 +0100319 },
Robert Swiecki97d88932018-01-10 19:29:34 +0100320 .extSanOpts = NULL,
Robert Swiecki66b65122017-11-11 02:55:55 +0100321 .useSanCov = false,
322 .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100323
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700324 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
325
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100326 /* Linux code */
Robert Swieckid50ed422017-11-13 23:32:26 +0100327 .linux =
328 {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200329 .exeFd = -1,
Robert Swieckid50ed422017-11-13 23:32:26 +0100330 .hwCnts =
331 {
332 .cpuInstrCnt = 0ULL,
333 .cpuBranchCnt = 0ULL,
334 .bbCnt = 0ULL,
335 .newBBCnt = 0ULL,
336 .softCntPc = 0ULL,
337 .softCntCmp = 0ULL,
338 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200339 .dynamicCutOffAddr = ~(0ULL),
340 .disableRandomization = true,
341 .ignoreAddr = NULL,
342 .numMajorFrames = 7,
343 .pid = 0,
344 .pidFile = NULL,
Robert Swiecki06008f72017-12-27 18:40:34 +0100345 .pidCmd = {},
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200346 .symsBlFile = NULL,
347 .symsBlCnt = 0,
348 .symsBl = NULL,
349 .symsWlFile = NULL,
350 .symsWlCnt = 0,
351 .symsWl = NULL,
352 .cloneFlags = 0,
353 .kernelOnly = false,
354 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100355 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200356 };
Robert Swieckid50ed422017-11-13 23:32:26 +0100357 *hfuzz = tmp;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200358
Robert Swieckib0e261a2017-11-09 01:30:54 +0100359 TAILQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100360 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100361
Robert Swiecki0b566112017-10-17 17:39:07 +0200362 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200363 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200364 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
365 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
366 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200367 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
368 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200369 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
370 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
371 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
372 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
373 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100374 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200375 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
376 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
377 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
Robert Swiecki97cd6242017-12-27 21:02:47 +0100378 { { "debug", no_argument, NULL, 'd' }, "Show debug messages (level >= 4)" },
379 { { "quiet", no_argument, NULL, 'q' }, "Show only warnings and more serious messages (level <= 1)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200380 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
381 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
Robert Swieckia35d9d82017-12-15 22:00:41 +0100382 { { "crashdir", required_argument, NULL, 0x600 }, "Directory where crashes are saved to (default: workspace directory)" },
383 { { "covdir_all", required_argument, NULL, 0x601 }, "Coverage is written to a separate directory (default: input directory)" },
384 { { "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 +0200385 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
386 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
387 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
388 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
389 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
390 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100391 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" },
392 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" },
393 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200394 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
395 { { "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 +0100396 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200397 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
398 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
399 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
400 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
Robert Swiecki97d88932018-01-10 19:29:34 +0100401 { { "san_opts", required_argument, NULL, 0x10A }, "Options appended to the regular *SAN_OPTIONS (default: empty)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200402 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
403 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
404 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200405
406#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200407 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
408 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
409 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
410 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
411 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
412 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
413 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
414 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
415 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
416 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
417 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
418 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
419 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
420 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
421 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
422#endif // defined(_HF_ARCH_LINUX)
423 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200424 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200425 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200426
427 struct option opts[ARRAYSIZE(custom_opts)];
428 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
429 opts[i] = custom_opts[i].opt;
430 }
431
432 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200433 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200434 int opt_index = 0;
435 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200436 int c = getopt_long(
Robert Swiecki97cd6242017-12-27 21:02:47 +0100437 argc, argv, "-?hQvVsuPxf:dqe: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 +0100438 if (c < 0) break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200439
440 switch (c) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100441 case 'h':
442 case '?':
443 cmdlineUsage(argv[0], custom_opts);
444 break;
445 case 'f':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100446 hfuzz->io.inputDir = optarg;
Robert Swieckiced3eba2017-12-15 15:33:03 +0100447 if (hfuzz->io.covDirAll == NULL) {
448 hfuzz->io.covDirAll = optarg;
449 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100450 break;
451 case 'x':
452 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
453 break;
454 case 'Q':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100455 hfuzz->exe.nullifyStdio = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100456 break;
457 case 'v':
458 hfuzz->useScreen = false;
459 break;
460 case 'V':
461 hfuzz->useVerifier = true;
462 break;
463 case 's':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100464 hfuzz->exe.fuzzStdin = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100465 break;
466 case 'u':
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100467 hfuzz->io.saveUnique = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100468 break;
469 case 'l':
470 logfile = optarg;
471 break;
472 case 'd':
Robert Swiecki97cd6242017-12-27 21:02:47 +0100473 ll = DEBUG;
474 break;
475 case 'q':
476 ll = WARNING;
Robert Swieckid50ed422017-11-13 23:32:26 +0100477 break;
478 case 'e':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100479 hfuzz->io.fileExtn = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100480 break;
481 case 'W':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100482 hfuzz->io.workDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100483 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100484 case 0x600:
Robert Swieckiced3eba2017-12-15 15:33:03 +0100485 hfuzz->io.crashDir = optarg;
486 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100487 case 0x601:
488 hfuzz->io.covDirAll = optarg;
489 break;
490 case 0x602:
491 hfuzz->io.covDirNew = optarg;
492 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100493 case 'r':
494 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
495 break;
496 case 'c':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100497 hfuzz->exe.externalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100498 break;
499 case 'C':
500 hfuzz->useSanCov = true;
501 break;
502 case 'S':
503 hfuzz->enableSanitizers = true;
504 break;
Robert Swiecki97d88932018-01-10 19:29:34 +0100505 case 0x10A:
506 hfuzz->extSanOpts = optarg;
507 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100508 case 'z':
509 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
510 break;
511 case 'F':
512 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
513 break;
514 case 't':
Robert Swiecki371e1292017-12-18 01:10:33 +0100515 hfuzz->timing.tmOut = atol(optarg);
Robert Swieckid50ed422017-11-13 23:32:26 +0100516 break;
517 case 'R':
518 hfuzz->reportFile = optarg;
519 break;
520 case 'n':
521 hfuzz->threads.threadsMax = atol(optarg);
522 break;
523 case 0x109: {
524 time_t p = atol(optarg);
525 if (p > 0) {
Robert Swiecki371e1292017-12-18 01:10:33 +0100526 hfuzz->timing.runEndTime = time(NULL) + p;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200527 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100528 } break;
529 case 'N':
530 hfuzz->mutationsMax = atol(optarg);
531 break;
532 case 0x100:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100533 hfuzz->exe.asLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100534 break;
535 case 0x101:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100536 hfuzz->exe.rssLimit = strtoull(optarg, NULL, 0);
Robert Swiecki8954afd2017-11-14 18:14:22 +0100537 break;
538 case 0x102:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100539 hfuzz->exe.dataLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100540 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100541 case 0x104:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100542 hfuzz->exe.postExternalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100543 break;
544 case 0x105:
545 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
546 hfuzz->monitorSIGABRT = false;
547 } else {
548 hfuzz->monitorSIGABRT = true;
549 }
550 break;
551 case 0x106:
552 hfuzz->skipFeedbackOnTimeout = true;
553 break;
554 case 0x107:
555 hfuzz->exitUponCrash = true;
556 break;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100557 case 0x108:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100558 hfuzz->exe.clearEnv = true;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100559 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100560 case 'P':
561 hfuzz->persistent = true;
562 break;
563 case 'T':
Robert Swieckieba27172017-12-18 01:12:02 +0100564 hfuzz->timing.tmoutVTALRM = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100565 break;
566 case 'p':
567 if (util_isANumber(optarg) == false) {
568 LOG_E("-p '%s' is not a number", optarg);
569 return false;
570 }
571 hfuzz->linux.pid = atoi(optarg);
572 if (hfuzz->linux.pid < 1) {
573 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
574 return false;
575 }
576 break;
577 case 0x502:
578 hfuzz->linux.pidFile = optarg;
579 break;
580 case 'E':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100581 for (size_t i = 0; i < ARRAYSIZE(hfuzz->exe.envs); i++) {
582 if (hfuzz->exe.envs[i] == NULL) {
583 hfuzz->exe.envs[i] = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100584 break;
585 }
586 }
587 break;
588 case 'w':
589 hfuzz->dictionaryFile = optarg;
590 break;
591 case 'B':
592 hfuzz->blacklistFile = optarg;
593 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100594#if defined(_HF_ARCH_LINUX)
Robert Swieckid50ed422017-11-13 23:32:26 +0100595 case 0x500:
596 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
597 break;
598 case 0x501:
599 hfuzz->linux.disableRandomization = false;
600 break;
601 case 0x503:
602 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
603 break;
604 case 0x504:
605 hfuzz->linux.symsBlFile = optarg;
606 break;
607 case 0x505:
608 hfuzz->linux.symsWlFile = optarg;
609 break;
610 case 0x510:
611 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
612 break;
613 case 0x511:
614 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
615 break;
616 case 0x513:
617 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
618 break;
619 case 0x514:
620 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
621 break;
622 case 0x515:
623 hfuzz->linux.kernelOnly = true;
624 break;
625 case 0x530:
626 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
627 break;
628 case 0x531:
629 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
630 break;
631 case 0x532:
632 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
633 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200634#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckid50ed422017-11-13 23:32:26 +0100635 default:
636 cmdlineUsage(argv[0], custom_opts);
637 return false;
638 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200639 }
640 }
Jagger72f258b2015-10-09 23:09:01 +0200641
Robert Swieckia35d9d82017-12-15 22:00:41 +0100642 if (!logInitLogFile(logfile, ll)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200643 return false;
644 }
Robert Swiecki2aeff252018-01-10 14:58:44 +0100645 hfuzz->exe.argc = argc - optind;
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100646 hfuzz->exe.cmdline = (const char* const*)&argv[optind];
Robert Swiecki2aeff252018-01-10 14:58:44 +0100647 if (hfuzz->exe.argc <= 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200648 LOG_E("No fuzz command provided");
649 cmdlineUsage(argv[0], custom_opts);
650 return false;
651 }
Robert Swiecki32ae3892018-01-10 16:20:28 +0100652 if (!hfuzz->persistent && cmdlineCheckIfPersistent(hfuzz->exe.cmdline[0])) {
Robert Swieckif8292582018-01-10 16:19:18 +0100653 LOG_I("Persistent signature detected, assume it's a persistent fuzzing-mode binary");
654 hfuzz->persistent = true;
655 }
Robert Swieckia35d9d82017-12-15 22:00:41 +0100656 if (!cmdlineVerify(hfuzz)) {
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200657 return false;
658 }
659
Robert Swieckid50ed422017-11-13 23:32:26 +0100660 LOG_I(
661 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
662 "mutationsPerRun: %u, "
663 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, "
664 "threads.threadsMax: %zu, "
665 "fileExtn: '%s', "
Robert Swiecki8954afd2017-11-14 18:14:22 +0100666 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64
667 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100668 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->exe.nullifyStdio),
669 cmdlineYesNo(hfuzz->exe.fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique),
670 hfuzz->mutationsPerRun,
671 hfuzz->exe.externalCommand == NULL ? "NULL" : hfuzz->exe.externalCommand,
Robert Swiecki371e1292017-12-18 01:10:33 +0100672 (int)hfuzz->timing.runEndTime, hfuzz->timing.tmOut, hfuzz->mutationsMax,
673 hfuzz->threads.threadsMax, hfuzz->io.fileExtn, hfuzz->exe.asLimit, hfuzz->exe.rssLimit,
674 hfuzz->exe.dataLimit, hfuzz->exe.cmdline[0], hfuzz->linux.pid,
675 cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200676
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100677 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->exe.cmdline[0]);
678 for (size_t i = 1; hfuzz->exe.cmdline[i]; i++) {
679 util_ssnprintf(
680 hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->exe.cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100681 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
Robert Swiecki6e885112017-11-22 00:32:24 +0100682 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' ';
683 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100684 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
685 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
Robert Swiecki6e885112017-11-22 00:32:24 +0100686 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100687 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100688 }
689
Robert Swieckia88f96f2015-10-09 16:47:39 +0200690 return true;
691}