blob: 01ed3dc6a8a216859c2e6fd5aa80e1c5a3945707 [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) {
Robert Swieckic3d5d5b2018-01-11 02:29:11 +010074 PLOG_W("munmap(%p, %zu)", map, (size_t)fileSz);
Robert Swieckif8292582018-01-10 16:19:18 +010075 }
76 close(fd);
77 return ret;
78}
79
Robert Swiecki3ab16642018-01-12 18:08:37 +010080static const char* cmdlineYesNo(bool yes) {
81 return (yes ? "true" : "false");
82}
Robert Swieckia88f96f2015-10-09 16:47:39 +020083
Robert Swieckid50ed422017-11-13 23:32:26 +010084static void cmdlineHelp(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020085 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
86 LOG_HELP_BOLD("Options:");
87 for (int i = 0; opts[i].opt.name; i++) {
Robert Swieckif3a5f6a2016-03-16 14:47:30 +010088 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) {
Robert Swiecki0b566112017-10-17 17:39:07 +020089 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020090 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020091 } else {
92 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020093 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020094 }
95 LOG_HELP("\t%s", opts[i].descr);
96 }
Jagger32127372015-10-09 23:07:38 +020097 LOG_HELP_BOLD("\nExamples:");
Robert Swieckid50ed422017-11-13 23:32:26 +010098 LOG_HELP(
99 " Run the binary over a mutated file chosen from the directory. Disable fuzzing "
100 "feedback (dry/static mode)");
Robert Swiecki216a4362017-12-13 13:02:52 +0100101 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Jagger32127372015-10-09 23:07:38 +0200102 LOG_HELP(" As above, provide input over STDIN:");
Robert Swiecki930e12f2017-10-24 14:52:03 +0200103 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -s -- /usr/bin/djpeg");
Jaggere848cc72016-09-19 02:28:52 +0200104 LOG_HELP(" Use compile-time instrumentation (libhfuzz/instrument.c):");
Robert Swiecki216a4362017-12-13 13:02:52 +0100105 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200106 LOG_HELP(" Use SANCOV instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100107 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200108 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100109 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/djpeg_persistent_mode");
Robert Swiecki930e12f2017-10-24 14:52:03 +0200110 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100111 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/djpeg_persistent_mode");
Robert Swieckia88f96f2015-10-09 16:47:39 +0200112#if defined(_HF_ARCH_LINUX)
Robert Swiecki930e12f2017-10-24 14:52:03 +0200113 LOG_HELP(
114 " Run the binary with dynamically generate inputs, maximize total no. of instructions:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100115 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_instr -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200116 LOG_HELP(" As above, maximize total no. of branches:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100117 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_branch -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200118 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100119 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200120 LOG_HELP(
121 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):");
Robert Swiecki216a4362017-12-13 13:02:52 +0100122 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200123#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200124}
125
Robert Swieckid50ed422017-11-13 23:32:26 +0100126static void cmdlineUsage(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200127 cmdlineHelp(pname, opts);
128 exit(0);
129}
130
Robert Swieckid50ed422017-11-13 23:32:26 +0100131rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200132 struct rlimit cur;
133 if (getrlimit(res, &cur) == -1) {
134 PLOG_F("getrlimit(%d)", res);
135 }
136 if (strcasecmp(optarg, "max") == 0) {
137 return cur.rlim_max;
138 }
139 if (strcasecmp(optarg, "def") == 0) {
140 return cur.rlim_cur;
141 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200142 if (util_isANumber(optarg) == false) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200143 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg);
144 }
145 rlim_t val = strtoul(optarg, NULL, 0) * mul;
Jagger2bd61b72015-10-10 05:23:32 +0200146 if ((unsigned long)val == ULONG_MAX && errno != 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200147 PLOG_F("strtoul('%s', 0)", optarg);
148 }
149 return val;
150}
151
Robert Swieckia35d9d82017-12-15 22:00:41 +0100152static bool cmdlineVerify(honggfuzz_t* hfuzz) {
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100153 if (!hfuzz->exe.fuzzStdin && !hfuzz->persistent &&
154 !checkFor_FILE_PLACEHOLDER(hfuzz->exe.cmdline)) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100155 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
156 "' when the -s (stdin fuzzing) or --persistent options are not set");
157 return false;
158 }
159
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100160 if (hfuzz->exe.fuzzStdin && hfuzz->persistent) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100161 LOG_E(
162 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
163 return false;
164 }
165
166 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) {
167 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))",
168 hfuzz->threads.threadsMax, _HF_THREAD_MAX);
169 return false;
170 }
171
172 if (strchr(hfuzz->io.fileExtn, '/')) {
173 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn);
174 return false;
175 }
176
177 if (hfuzz->io.workDir == NULL) {
178 hfuzz->io.workDir = ".";
179 }
180 if (mkdir(hfuzz->io.workDir, 0700) == -1 && errno != EEXIST) {
181 PLOG_E("Couldn't create the workspace directory '%s'", hfuzz->io.workDir);
182 return false;
183 }
184 if (hfuzz->io.crashDir == NULL) {
185 hfuzz->io.crashDir = hfuzz->io.workDir;
186 }
187 if (mkdir(hfuzz->io.crashDir, 0700) && errno != EEXIST) {
188 PLOG_E("Couldn't create the crash directory '%s'", hfuzz->io.crashDir);
189 return false;
190 }
191
192 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
193 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
194 hfuzz->linux.pid);
195 hfuzz->threads.threadsMax = 1;
196 }
197
198 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
199 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
200 }
201
202 /*
203 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
204 * better to let user know about the features that each flag control.
205 */
206 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
207 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
208 return false;
209 }
210
Robert Swiecki0a01ea72018-01-11 01:50:18 +0100211 if (hfuzz->maxFileSz > _HF_INPUT_MAX_SIZE) {
212 LOG_E("Maximum file size '%zu' bigger than the maximum size '%zu'", hfuzz->maxFileSz,
213 (size_t)_HF_INPUT_MAX_SIZE);
214 return false;
215 }
216
Robert Swieckia35d9d82017-12-15 22:00:41 +0100217 return true;
218}
219
Robert Swieckid50ed422017-11-13 23:32:26 +0100220bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
221 honggfuzz_t tmp = {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100222 .io =
223 {
224 .inputDir = NULL,
Robert Swieckia35d9d82017-12-15 22:00:41 +0100225 .inputDirPtr = NULL,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100226 .fileCnt = 0,
227 .fileCntDone = false,
228 .fileExtn = "fuzz",
Robert Swieckiced3eba2017-12-15 15:33:03 +0100229 .workDir = NULL,
230 .crashDir = NULL,
231 .covDirAll = NULL,
232 .covDirNew = NULL,
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100233 .saveUnique = true,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100234 },
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100235 .exe =
236 {
Robert Swiecki2aeff252018-01-10 14:58:44 +0100237 .argc = 0,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100238 .cmdline = NULL,
239 .nullifyStdio = true,
240 .fuzzStdin = false,
241 .externalCommand = NULL,
242 .postExternalCommand = NULL,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100243 .asLimit = 0U,
244 .rssLimit = 0U,
245 .dataLimit = 0U,
246 .clearEnv = false,
247 .envs[0] = NULL,
248 },
Robert Swiecki371e1292017-12-18 01:10:33 +0100249 .timing =
250 {
251 .timeStart = time(NULL),
252 .runEndTime = 0,
253 .tmOut = 10,
Robert Swieckieba27172017-12-18 01:12:02 +0100254 .tmoutVTALRM = false,
Robert Swiecki371e1292017-12-18 01:10:33 +0100255 },
Robert Swieckif4cbd8b2018-01-10 23:28:01 +0100256 .cmdline_txt[0] = '\0',
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100257 .useScreen = true,
258 .useVerifier = false,
Robert Swiecki10e93562017-11-04 00:57:47 +0100259 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200260 .blacklistFile = NULL,
261 .blacklistCnt = 0,
262 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200263 .maxFileSz = 0UL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200264 .mutationsMax = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200265 .reportFile = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200266 .persistent = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100267 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200268 .enableSanitizers = false,
269#if defined(__ANDROID__)
270 .monitorSIGABRT = false,
271#else
272 .monitorSIGABRT = true,
273#endif
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200274 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200275
Robert Swieckid50ed422017-11-13 23:32:26 +0100276 .threads =
277 {
278 .threadsFinished = 0,
279 .threadsMax =
280 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
281 .threadsActiveCnt = 0,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100282 .mainThread = pthread_self(),
283 .mainPid = getpid(),
Robert Swieckid50ed422017-11-13 23:32:26 +0100284 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100285
Robert Swiecki531438a2016-09-13 19:05:11 +0200286 .dictionaryFile = NULL,
287 .dictionaryCnt = 0,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100288 .dictqCurrent = NULL,
Robert Swiecki531438a2016-09-13 19:05:11 +0200289
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100290 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200291 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200292 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100293
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100294 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100295 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100296
Robert Swiecki37498fd2017-03-12 21:12:54 +0100297 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
298
Robert Swiecki01a980e2017-11-14 03:36:50 +0100299 .cnts =
300 {
301 .mutationsCnt = 0,
302 .crashesCnt = 0,
303 .uniqueCrashesCnt = 0,
304 .verifiedCrashesCnt = 0,
305 .blCrashesCnt = 0,
306 .timeoutedCnt = 0,
307 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200308
Robert Swiecki930e12f2017-10-24 14:52:03 +0200309 .dynFileMethod = _HF_DYNFILE_SOFT,
Robert Swieckid50ed422017-11-13 23:32:26 +0100310 .sanCovCnts =
311 {
312 .hitBBCnt = 0ULL,
313 .totalBBCnt = 0ULL,
314 .dsoCnt = 0ULL,
315 .iDsoCnt = 0ULL,
316 .newBBCnt = 0ULL,
317 .crashesCnt = 0ULL,
318 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200319
Robert Swiecki66b65122017-11-11 02:55:55 +0100320 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swiecki97d88932018-01-10 19:29:34 +0100321 .extSanOpts = NULL,
Robert Swiecki66b65122017-11-11 02:55:55 +0100322 .useSanCov = false,
323 .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100324
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700325 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
326
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100327 /* Linux code */
Robert Swieckid50ed422017-11-13 23:32:26 +0100328 .linux =
329 {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200330 .exeFd = -1,
Robert Swieckid50ed422017-11-13 23:32:26 +0100331 .hwCnts =
332 {
333 .cpuInstrCnt = 0ULL,
334 .cpuBranchCnt = 0ULL,
335 .bbCnt = 0ULL,
336 .newBBCnt = 0ULL,
337 .softCntPc = 0ULL,
338 .softCntCmp = 0ULL,
339 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200340 .dynamicCutOffAddr = ~(0ULL),
341 .disableRandomization = true,
342 .ignoreAddr = NULL,
343 .numMajorFrames = 7,
344 .pid = 0,
345 .pidFile = NULL,
Robert Swiecki06008f72017-12-27 18:40:34 +0100346 .pidCmd = {},
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200347 .symsBlFile = NULL,
348 .symsBlCnt = 0,
349 .symsBl = NULL,
350 .symsWlFile = NULL,
351 .symsWlCnt = 0,
352 .symsWl = NULL,
353 .cloneFlags = 0,
354 .kernelOnly = false,
355 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100356 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200357 };
Robert Swieckid50ed422017-11-13 23:32:26 +0100358 *hfuzz = tmp;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200359
Robert Swieckib0e261a2017-11-09 01:30:54 +0100360 TAILQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100361 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100362
Robert Swiecki0b566112017-10-17 17:39:07 +0200363 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200364 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200365 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
366 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
Robert Swieckie46d8af2018-01-12 03:20:04 +0100367 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code). This will be auto-detected!!!" },
Robert Swiecki930e12f2017-10-24 14:52:03 +0200368 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
369 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200370 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
371 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
372 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
373 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
374 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100375 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200376 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
377 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
378 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
Robert Swiecki97cd6242017-12-27 21:02:47 +0100379 { { "debug", no_argument, NULL, 'd' }, "Show debug messages (level >= 4)" },
380 { { "quiet", no_argument, NULL, 'q' }, "Show only warnings and more serious messages (level <= 1)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200381 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
382 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
Robert Swieckia35d9d82017-12-15 22:00:41 +0100383 { { "crashdir", required_argument, NULL, 0x600 }, "Directory where crashes are saved to (default: workspace directory)" },
384 { { "covdir_all", required_argument, NULL, 0x601 }, "Coverage is written to a separate directory (default: input directory)" },
385 { { "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 +0200386 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
387 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
388 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
389 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
390 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
391 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100392 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" },
393 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" },
394 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200395 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
396 { { "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 +0100397 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200398 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
399 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
400 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
401 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
Robert Swiecki97d88932018-01-10 19:29:34 +0100402 { { "san_opts", required_argument, NULL, 0x10A }, "Options appended to the regular *SAN_OPTIONS (default: empty)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200403 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
404 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
405 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200406
407#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200408 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
409 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
410 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
411 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
412 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
413 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
414 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
415 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
416 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
417 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
418 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
419 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
420 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
421 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
422 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
423#endif // defined(_HF_ARCH_LINUX)
424 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200425 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200426 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200427
428 struct option opts[ARRAYSIZE(custom_opts)];
429 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
430 opts[i] = custom_opts[i].opt;
431 }
432
433 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200434 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200435 int opt_index = 0;
436 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200437 int c = getopt_long(
Robert Swiecki97cd6242017-12-27 21:02:47 +0100438 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 +0100439 if (c < 0) break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200440
441 switch (c) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100442 case 'h':
443 case '?':
444 cmdlineUsage(argv[0], custom_opts);
445 break;
446 case 'f':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100447 hfuzz->io.inputDir = optarg;
Robert Swieckiced3eba2017-12-15 15:33:03 +0100448 if (hfuzz->io.covDirAll == NULL) {
449 hfuzz->io.covDirAll = optarg;
450 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100451 break;
452 case 'x':
453 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
454 break;
455 case 'Q':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100456 hfuzz->exe.nullifyStdio = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100457 break;
458 case 'v':
459 hfuzz->useScreen = false;
460 break;
461 case 'V':
462 hfuzz->useVerifier = true;
463 break;
464 case 's':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100465 hfuzz->exe.fuzzStdin = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100466 break;
467 case 'u':
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100468 hfuzz->io.saveUnique = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100469 break;
470 case 'l':
471 logfile = optarg;
472 break;
473 case 'd':
Robert Swiecki97cd6242017-12-27 21:02:47 +0100474 ll = DEBUG;
475 break;
476 case 'q':
477 ll = WARNING;
Robert Swieckid50ed422017-11-13 23:32:26 +0100478 break;
479 case 'e':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100480 hfuzz->io.fileExtn = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100481 break;
482 case 'W':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100483 hfuzz->io.workDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100484 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100485 case 0x600:
Robert Swieckiced3eba2017-12-15 15:33:03 +0100486 hfuzz->io.crashDir = optarg;
487 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100488 case 0x601:
489 hfuzz->io.covDirAll = optarg;
490 break;
491 case 0x602:
492 hfuzz->io.covDirNew = optarg;
493 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100494 case 'r':
495 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
496 break;
497 case 'c':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100498 hfuzz->exe.externalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100499 break;
500 case 'C':
501 hfuzz->useSanCov = true;
502 break;
503 case 'S':
504 hfuzz->enableSanitizers = true;
505 break;
Robert Swiecki97d88932018-01-10 19:29:34 +0100506 case 0x10A:
507 hfuzz->extSanOpts = optarg;
508 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100509 case 'z':
510 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
511 break;
512 case 'F':
513 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
514 break;
515 case 't':
Robert Swiecki371e1292017-12-18 01:10:33 +0100516 hfuzz->timing.tmOut = atol(optarg);
Robert Swieckid50ed422017-11-13 23:32:26 +0100517 break;
518 case 'R':
519 hfuzz->reportFile = optarg;
520 break;
521 case 'n':
522 hfuzz->threads.threadsMax = atol(optarg);
523 break;
524 case 0x109: {
525 time_t p = atol(optarg);
526 if (p > 0) {
Robert Swiecki371e1292017-12-18 01:10:33 +0100527 hfuzz->timing.runEndTime = time(NULL) + p;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200528 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100529 } break;
530 case 'N':
531 hfuzz->mutationsMax = atol(optarg);
532 break;
533 case 0x100:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100534 hfuzz->exe.asLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100535 break;
536 case 0x101:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100537 hfuzz->exe.rssLimit = strtoull(optarg, NULL, 0);
Robert Swiecki8954afd2017-11-14 18:14:22 +0100538 break;
539 case 0x102:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100540 hfuzz->exe.dataLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100541 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100542 case 0x104:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100543 hfuzz->exe.postExternalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100544 break;
545 case 0x105:
546 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
547 hfuzz->monitorSIGABRT = false;
548 } else {
549 hfuzz->monitorSIGABRT = true;
550 }
551 break;
552 case 0x106:
553 hfuzz->skipFeedbackOnTimeout = true;
554 break;
555 case 0x107:
556 hfuzz->exitUponCrash = true;
557 break;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100558 case 0x108:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100559 hfuzz->exe.clearEnv = true;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100560 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100561 case 'P':
562 hfuzz->persistent = true;
563 break;
564 case 'T':
Robert Swieckieba27172017-12-18 01:12:02 +0100565 hfuzz->timing.tmoutVTALRM = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100566 break;
567 case 'p':
568 if (util_isANumber(optarg) == false) {
569 LOG_E("-p '%s' is not a number", optarg);
570 return false;
571 }
572 hfuzz->linux.pid = atoi(optarg);
573 if (hfuzz->linux.pid < 1) {
574 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
575 return false;
576 }
577 break;
578 case 0x502:
579 hfuzz->linux.pidFile = optarg;
580 break;
581 case 'E':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100582 for (size_t i = 0; i < ARRAYSIZE(hfuzz->exe.envs); i++) {
583 if (hfuzz->exe.envs[i] == NULL) {
584 hfuzz->exe.envs[i] = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100585 break;
586 }
587 }
588 break;
589 case 'w':
590 hfuzz->dictionaryFile = optarg;
591 break;
592 case 'B':
593 hfuzz->blacklistFile = optarg;
594 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100595#if defined(_HF_ARCH_LINUX)
Robert Swieckid50ed422017-11-13 23:32:26 +0100596 case 0x500:
597 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
598 break;
599 case 0x501:
600 hfuzz->linux.disableRandomization = false;
601 break;
602 case 0x503:
603 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
604 break;
605 case 0x504:
606 hfuzz->linux.symsBlFile = optarg;
607 break;
608 case 0x505:
609 hfuzz->linux.symsWlFile = optarg;
610 break;
611 case 0x510:
612 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
613 break;
614 case 0x511:
615 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
616 break;
617 case 0x513:
618 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
619 break;
620 case 0x514:
621 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
622 break;
623 case 0x515:
624 hfuzz->linux.kernelOnly = true;
625 break;
626 case 0x530:
627 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
628 break;
629 case 0x531:
630 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
631 break;
632 case 0x532:
633 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
634 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200635#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckid50ed422017-11-13 23:32:26 +0100636 default:
637 cmdlineUsage(argv[0], custom_opts);
638 return false;
639 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200640 }
641 }
Jagger72f258b2015-10-09 23:09:01 +0200642
Robert Swieckia35d9d82017-12-15 22:00:41 +0100643 if (!logInitLogFile(logfile, ll)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200644 return false;
645 }
Robert Swiecki2aeff252018-01-10 14:58:44 +0100646 hfuzz->exe.argc = argc - optind;
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100647 hfuzz->exe.cmdline = (const char* const*)&argv[optind];
Robert Swiecki2aeff252018-01-10 14:58:44 +0100648 if (hfuzz->exe.argc <= 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200649 LOG_E("No fuzz command provided");
650 cmdlineUsage(argv[0], custom_opts);
651 return false;
652 }
Robert Swiecki32ae3892018-01-10 16:20:28 +0100653 if (!hfuzz->persistent && cmdlineCheckIfPersistent(hfuzz->exe.cmdline[0])) {
Robert Swieckif8292582018-01-10 16:19:18 +0100654 LOG_I("Persistent signature detected, assume it's a persistent fuzzing-mode binary");
655 hfuzz->persistent = true;
656 }
Robert Swieckia35d9d82017-12-15 22:00:41 +0100657 if (!cmdlineVerify(hfuzz)) {
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200658 return false;
659 }
660
Robert Swieckid50ed422017-11-13 23:32:26 +0100661 LOG_I(
662 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
663 "mutationsPerRun: %u, "
664 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, "
665 "threads.threadsMax: %zu, "
666 "fileExtn: '%s', "
Robert Swiecki8954afd2017-11-14 18:14:22 +0100667 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64
668 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100669 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->exe.nullifyStdio),
670 cmdlineYesNo(hfuzz->exe.fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique),
671 hfuzz->mutationsPerRun,
672 hfuzz->exe.externalCommand == NULL ? "NULL" : hfuzz->exe.externalCommand,
Robert Swiecki371e1292017-12-18 01:10:33 +0100673 (int)hfuzz->timing.runEndTime, hfuzz->timing.tmOut, hfuzz->mutationsMax,
674 hfuzz->threads.threadsMax, hfuzz->io.fileExtn, hfuzz->exe.asLimit, hfuzz->exe.rssLimit,
675 hfuzz->exe.dataLimit, hfuzz->exe.cmdline[0], hfuzz->linux.pid,
676 cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200677
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100678 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->exe.cmdline[0]);
679 for (size_t i = 1; hfuzz->exe.cmdline[i]; i++) {
680 util_ssnprintf(
681 hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->exe.cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100682 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
Robert Swiecki6e885112017-11-22 00:32:24 +0100683 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' ';
684 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100685 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
686 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
Robert Swiecki6e885112017-11-22 00:32:24 +0100687 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100688 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100689 }
690
Robert Swieckia88f96f2015-10-09 16:47:39 +0200691 return true;
692}