blob: 6373a83d37ff4dddf9b85bb1f97062b71bf3b878 [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;
Robert Swieckif8292582018-01-10 16:19:18 +010063
64 uint8_t* map = files_mapFile(fname, &fileSz, &fd, /* isWriteable= */ false);
Robert Swiecki437280c2018-01-14 02:09:03 +010065 if (!map) {
Robert Swieckif8292582018-01-10 16:19:18 +010066 LOG_W("Couldn't map file '%s' to check whether it's a persistent binary", fname);
67 return false;
68 }
Robert Swiecki437280c2018-01-14 02:09:03 +010069 defer {
70 if (munmap(map, fileSz) == -1) {
71 PLOG_W("munmap(%p, %zu)", map, (size_t)fileSz);
72 }
73 close(fd);
74 };
75
Robert Swieckif8292582018-01-10 16:19:18 +010076 if (memmem(map, fileSz, _HF_PERSISTENT_SIG, strlen(_HF_PERSISTENT_SIG))) {
Robert Swiecki437280c2018-01-14 02:09:03 +010077 return true;
Robert Swieckif8292582018-01-10 16:19:18 +010078 }
Robert Swiecki437280c2018-01-14 02:09:03 +010079 return false;
Robert Swieckif8292582018-01-10 16:19:18 +010080}
81
Robert Swiecki3ab16642018-01-12 18:08:37 +010082static const char* cmdlineYesNo(bool yes) {
83 return (yes ? "true" : "false");
84}
Robert Swieckia88f96f2015-10-09 16:47:39 +020085
Robert Swieckid50ed422017-11-13 23:32:26 +010086static void cmdlineHelp(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +020087 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
88 LOG_HELP_BOLD("Options:");
89 for (int i = 0; opts[i].opt.name; i++) {
Robert Swieckif3a5f6a2016-03-16 14:47:30 +010090 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) {
Robert Swiecki0b566112017-10-17 17:39:07 +020091 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020092 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020093 } else {
94 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020095 opts[i].opt.has_arg == required_argument ? "VALUE" : "");
Robert Swieckia88f96f2015-10-09 16:47:39 +020096 }
97 LOG_HELP("\t%s", opts[i].descr);
98 }
Jagger32127372015-10-09 23:07:38 +020099 LOG_HELP_BOLD("\nExamples:");
Robert Swieckid50ed422017-11-13 23:32:26 +0100100 LOG_HELP(
101 " Run the binary over a mutated file chosen from the directory. Disable fuzzing "
102 "feedback (dry/static mode)");
Robert Swiecki216a4362017-12-13 13:02:52 +0100103 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Jagger32127372015-10-09 23:07:38 +0200104 LOG_HELP(" As above, provide input over STDIN:");
Robert Swiecki930e12f2017-10-24 14:52:03 +0200105 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -s -- /usr/bin/djpeg");
Jaggere848cc72016-09-19 02:28:52 +0200106 LOG_HELP(" Use compile-time instrumentation (libhfuzz/instrument.c):");
Robert Swiecki216a4362017-12-13 13:02:52 +0100107 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200108 LOG_HELP(" Use SANCOV instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100109 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200110 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100111 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/djpeg_persistent_mode");
Robert Swiecki930e12f2017-10-24 14:52:03 +0200112 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100113 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/djpeg_persistent_mode");
Robert Swieckia88f96f2015-10-09 16:47:39 +0200114#if defined(_HF_ARCH_LINUX)
Robert Swiecki930e12f2017-10-24 14:52:03 +0200115 LOG_HELP(
116 " Run the binary with dynamically generate inputs, maximize total no. of instructions:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100117 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_instr -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200118 LOG_HELP(" As above, maximize total no. of branches:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100119 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_branch -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200120 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:");
Robert Swiecki216a4362017-12-13 13:02:52 +0100121 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki930e12f2017-10-24 14:52:03 +0200122 LOG_HELP(
123 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):");
Robert Swiecki216a4362017-12-13 13:02:52 +0100124 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200125#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckia88f96f2015-10-09 16:47:39 +0200126}
127
Robert Swieckid50ed422017-11-13 23:32:26 +0100128static void cmdlineUsage(const char* pname, struct custom_option* opts) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200129 cmdlineHelp(pname, opts);
130 exit(0);
131}
132
Robert Swieckid50ed422017-11-13 23:32:26 +0100133rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200134 struct rlimit cur;
135 if (getrlimit(res, &cur) == -1) {
136 PLOG_F("getrlimit(%d)", res);
137 }
138 if (strcasecmp(optarg, "max") == 0) {
139 return cur.rlim_max;
140 }
141 if (strcasecmp(optarg, "def") == 0) {
142 return cur.rlim_cur;
143 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200144 if (util_isANumber(optarg) == false) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200145 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg);
146 }
147 rlim_t val = strtoul(optarg, NULL, 0) * mul;
Jagger2bd61b72015-10-10 05:23:32 +0200148 if ((unsigned long)val == ULONG_MAX && errno != 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200149 PLOG_F("strtoul('%s', 0)", optarg);
150 }
151 return val;
152}
153
Robert Swieckia35d9d82017-12-15 22:00:41 +0100154static bool cmdlineVerify(honggfuzz_t* hfuzz) {
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100155 if (!hfuzz->exe.fuzzStdin && !hfuzz->persistent &&
156 !checkFor_FILE_PLACEHOLDER(hfuzz->exe.cmdline)) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100157 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER
158 "' when the -s (stdin fuzzing) or --persistent options are not set");
159 return false;
160 }
161
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100162 if (hfuzz->exe.fuzzStdin && hfuzz->persistent) {
Robert Swieckia35d9d82017-12-15 22:00:41 +0100163 LOG_E(
164 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time");
165 return false;
166 }
167
168 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) {
169 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))",
170 hfuzz->threads.threadsMax, _HF_THREAD_MAX);
171 return false;
172 }
173
174 if (strchr(hfuzz->io.fileExtn, '/')) {
175 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn);
176 return false;
177 }
178
179 if (hfuzz->io.workDir == NULL) {
180 hfuzz->io.workDir = ".";
181 }
182 if (mkdir(hfuzz->io.workDir, 0700) == -1 && errno != EEXIST) {
183 PLOG_E("Couldn't create the workspace directory '%s'", hfuzz->io.workDir);
184 return false;
185 }
186 if (hfuzz->io.crashDir == NULL) {
187 hfuzz->io.crashDir = hfuzz->io.workDir;
188 }
189 if (mkdir(hfuzz->io.crashDir, 0700) && errno != EEXIST) {
190 PLOG_E("Couldn't create the crash directory '%s'", hfuzz->io.crashDir);
191 return false;
192 }
193
194 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
195 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1",
196 hfuzz->linux.pid);
197 hfuzz->threads.threadsMax = 1;
198 }
199
200 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) {
201 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode");
202 }
203
204 /*
205 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably
206 * better to let user know about the features that each flag control.
207 */
208 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) {
209 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'");
210 return false;
211 }
212
Robert Swiecki0a01ea72018-01-11 01:50:18 +0100213 if (hfuzz->maxFileSz > _HF_INPUT_MAX_SIZE) {
214 LOG_E("Maximum file size '%zu' bigger than the maximum size '%zu'", hfuzz->maxFileSz,
215 (size_t)_HF_INPUT_MAX_SIZE);
216 return false;
217 }
218
Robert Swieckia35d9d82017-12-15 22:00:41 +0100219 return true;
220}
221
Robert Swieckid50ed422017-11-13 23:32:26 +0100222bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) {
223 honggfuzz_t tmp = {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100224 .io =
225 {
226 .inputDir = NULL,
Robert Swieckia35d9d82017-12-15 22:00:41 +0100227 .inputDirPtr = NULL,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100228 .fileCnt = 0,
229 .fileCntDone = false,
230 .fileExtn = "fuzz",
Robert Swieckiced3eba2017-12-15 15:33:03 +0100231 .workDir = NULL,
232 .crashDir = NULL,
233 .covDirAll = NULL,
234 .covDirNew = NULL,
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100235 .saveUnique = true,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100236 },
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100237 .exe =
238 {
Robert Swiecki2aeff252018-01-10 14:58:44 +0100239 .argc = 0,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100240 .cmdline = NULL,
241 .nullifyStdio = true,
242 .fuzzStdin = false,
243 .externalCommand = NULL,
244 .postExternalCommand = NULL,
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100245 .asLimit = 0U,
246 .rssLimit = 0U,
247 .dataLimit = 0U,
248 .clearEnv = false,
249 .envs[0] = NULL,
250 },
Robert Swiecki371e1292017-12-18 01:10:33 +0100251 .timing =
252 {
253 .timeStart = time(NULL),
254 .runEndTime = 0,
255 .tmOut = 10,
Robert Swieckieba27172017-12-18 01:12:02 +0100256 .tmoutVTALRM = false,
Robert Swiecki371e1292017-12-18 01:10:33 +0100257 },
Robert Swieckif4cbd8b2018-01-10 23:28:01 +0100258 .cmdline_txt[0] = '\0',
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100259 .useScreen = true,
260 .useVerifier = false,
Robert Swiecki10e93562017-11-04 00:57:47 +0100261 .mutationsPerRun = 6U,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200262 .blacklistFile = NULL,
263 .blacklistCnt = 0,
264 .blacklist = NULL,
Jaggerf4a60562016-09-25 15:40:23 +0200265 .maxFileSz = 0UL,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200266 .mutationsMax = 0,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200267 .reportFile = NULL,
Robert Swiecki0f937af2016-03-30 18:19:16 +0200268 .persistent = false,
Robert Swiecki44f6b192017-02-15 20:24:55 +0100269 .skipFeedbackOnTimeout = false,
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200270 .enableSanitizers = false,
271#if defined(__ANDROID__)
272 .monitorSIGABRT = false,
273#else
274 .monitorSIGABRT = true,
275#endif
Robert Swieckic95cf2a2017-06-23 15:31:08 +0200276 .exitUponCrash = false,
Robert Swieckia88f96f2015-10-09 16:47:39 +0200277
Robert Swieckid50ed422017-11-13 23:32:26 +0100278 .threads =
279 {
280 .threadsFinished = 0,
281 .threadsMax =
282 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2,
283 .threadsActiveCnt = 0,
Robert Swiecki82c707c2017-11-14 16:36:23 +0100284 .mainThread = pthread_self(),
285 .mainPid = getpid(),
Robert Swieckid50ed422017-11-13 23:32:26 +0100286 },
Robert Swiecki66b65122017-11-11 02:55:55 +0100287
Robert Swiecki531438a2016-09-13 19:05:11 +0200288 .dictionaryFile = NULL,
289 .dictionaryCnt = 0,
290
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100291 .state = _HF_STATE_UNSET,
Jaggerb7fa3ee2016-08-21 19:46:26 +0200292 .feedback = NULL,
Robert Swieckibc7532e2016-08-20 00:34:17 +0200293 .bbFd = -1,
Robert Swiecki9f5f9432017-03-09 01:48:04 +0100294
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100295 .dynfileqCnt = 0U,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100296 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100297
Robert Swiecki37498fd2017-03-12 21:12:54 +0100298 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER,
299
Robert Swiecki01a980e2017-11-14 03:36:50 +0100300 .cnts =
301 {
302 .mutationsCnt = 0,
303 .crashesCnt = 0,
304 .uniqueCrashesCnt = 0,
305 .verifiedCrashesCnt = 0,
306 .blCrashesCnt = 0,
307 .timeoutedCnt = 0,
308 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200309
Robert Swiecki930e12f2017-10-24 14:52:03 +0200310 .dynFileMethod = _HF_DYNFILE_SOFT,
Robert Swieckid50ed422017-11-13 23:32:26 +0100311 .sanCovCnts =
312 {
313 .hitBBCnt = 0ULL,
314 .totalBBCnt = 0ULL,
315 .dsoCnt = 0ULL,
316 .iDsoCnt = 0ULL,
317 .newBBCnt = 0ULL,
318 .crashesCnt = 0ULL,
319 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200320
Robert Swiecki66b65122017-11-11 02:55:55 +0100321 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER,
Robert Swiecki97d88932018-01-10 19:29:34 +0100322 .extSanOpts = NULL,
Robert Swiecki66b65122017-11-11 02:55:55 +0100323 .useSanCov = false,
324 .covMetadata = NULL,
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100325
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700326 .report_mutex = PTHREAD_MUTEX_INITIALIZER,
327
Robert Swiecki6c9f6822016-03-14 16:12:27 +0100328 /* Linux code */
Robert Swieckid50ed422017-11-13 23:32:26 +0100329 .linux =
330 {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200331 .exeFd = -1,
Robert Swieckid50ed422017-11-13 23:32:26 +0100332 .hwCnts =
333 {
334 .cpuInstrCnt = 0ULL,
335 .cpuBranchCnt = 0ULL,
336 .bbCnt = 0ULL,
337 .newBBCnt = 0ULL,
338 .softCntPc = 0ULL,
339 .softCntCmp = 0ULL,
340 },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200341 .dynamicCutOffAddr = ~(0ULL),
342 .disableRandomization = true,
343 .ignoreAddr = NULL,
344 .numMajorFrames = 7,
345 .pid = 0,
346 .pidFile = NULL,
Robert Swiecki06008f72017-12-27 18:40:34 +0100347 .pidCmd = {},
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200348 .symsBlFile = NULL,
349 .symsBlCnt = 0,
350 .symsBl = NULL,
351 .symsWlFile = NULL,
352 .symsWlCnt = 0,
353 .symsWl = NULL,
354 .cloneFlags = 0,
355 .kernelOnly = false,
356 .useClone = true,
Jaggerab26e702016-03-22 04:28:00 +0100357 },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200358 };
Robert Swieckid50ed422017-11-13 23:32:26 +0100359 *hfuzz = tmp;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200360
Robert Swieckib0e261a2017-11-09 01:30:54 +0100361 TAILQ_INIT(&hfuzz->dynfileq);
Robert Swieckiafb16102017-03-13 22:14:31 +0100362 TAILQ_INIT(&hfuzz->dictq);
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100363
Robert Swiecki0b566112017-10-17 17:39:07 +0200364 // clang-format off
Robert Swieckia88f96f2015-10-09 16:47:39 +0200365 struct custom_option custom_opts[] = {
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200366 { { "help", no_argument, NULL, 'h' }, "Help plz.." },
367 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" },
Robert Swieckie46d8af2018-01-12 03:20:04 +0100368 { { "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 +0200369 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" },
370 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200371 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" },
372 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" },
373 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" },
374 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" },
375 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" },
Robert Swiecki5c673d62017-11-06 00:54:00 +0100376 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200377 { { "logfile", required_argument, NULL, 'l' }, "Log file" },
378 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" },
379 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" },
Robert Swiecki97cd6242017-12-27 21:02:47 +0100380 { { "debug", no_argument, NULL, 'd' }, "Show debug messages (level >= 4)" },
381 { { "quiet", no_argument, NULL, 'q' }, "Show only warnings and more serious messages (level <= 1)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200382 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
383 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
Robert Swieckia35d9d82017-12-15 22:00:41 +0100384 { { "crashdir", required_argument, NULL, 0x600 }, "Directory where crashes are saved to (default: workspace directory)" },
385 { { "covdir_all", required_argument, NULL, 0x601 }, "Coverage is written to a separate directory (default: input directory)" },
386 { { "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 +0200387 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
388 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
389 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
390 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" },
391 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" },
392 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" },
Robert Swiecki8954afd2017-11-14 18:14:22 +0100393 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" },
394 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" },
395 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200396 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" },
397 { { "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 +0100398 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200399 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" },
400 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" },
401 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" },
402 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" },
Robert Swiecki97d88932018-01-10 19:29:34 +0100403 { { "san_opts", required_argument, NULL, 0x10A }, "Options appended to the regular *SAN_OPTIONS (default: empty)" },
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200404 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" },
405 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" },
406 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200407
408#if defined(_HF_ARCH_LINUX)
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200409 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" },
410 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" },
411 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" },
412 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" },
413 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" },
414 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" },
415 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" },
416 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" },
417 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" },
418 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" },
419 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" },
420 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" },
421 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" },
422 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" },
423 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" },
424#endif // defined(_HF_ARCH_LINUX)
425 { { 0, 0, 0, 0 }, NULL },
Robert Swieckia88f96f2015-10-09 16:47:39 +0200426 };
Robert Swiecki0b566112017-10-17 17:39:07 +0200427 // clang-format on
Robert Swieckia88f96f2015-10-09 16:47:39 +0200428
429 struct option opts[ARRAYSIZE(custom_opts)];
430 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) {
431 opts[i] = custom_opts[i].opt;
432 }
433
434 enum llevel_t ll = INFO;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200435 const char* logfile = NULL;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200436 int opt_index = 0;
437 for (;;) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200438 int c = getopt_long(
Robert Swiecki97cd6242017-12-27 21:02:47 +0100439 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 +0100440 if (c < 0) break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200441
442 switch (c) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100443 case 'h':
444 case '?':
445 cmdlineUsage(argv[0], custom_opts);
446 break;
447 case 'f':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100448 hfuzz->io.inputDir = optarg;
Robert Swieckiced3eba2017-12-15 15:33:03 +0100449 if (hfuzz->io.covDirAll == NULL) {
450 hfuzz->io.covDirAll = optarg;
451 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100452 break;
453 case 'x':
454 hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
455 break;
456 case 'Q':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100457 hfuzz->exe.nullifyStdio = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100458 break;
459 case 'v':
460 hfuzz->useScreen = false;
461 break;
462 case 'V':
463 hfuzz->useVerifier = true;
464 break;
465 case 's':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100466 hfuzz->exe.fuzzStdin = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100467 break;
468 case 'u':
Robert Swiecki26fd6d52017-11-15 00:46:21 +0100469 hfuzz->io.saveUnique = false;
Robert Swieckid50ed422017-11-13 23:32:26 +0100470 break;
471 case 'l':
472 logfile = optarg;
473 break;
474 case 'd':
Robert Swiecki97cd6242017-12-27 21:02:47 +0100475 ll = DEBUG;
476 break;
477 case 'q':
478 ll = WARNING;
Robert Swieckid50ed422017-11-13 23:32:26 +0100479 break;
480 case 'e':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100481 hfuzz->io.fileExtn = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100482 break;
483 case 'W':
Robert Swiecki82c707c2017-11-14 16:36:23 +0100484 hfuzz->io.workDir = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100485 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100486 case 0x600:
Robert Swieckiced3eba2017-12-15 15:33:03 +0100487 hfuzz->io.crashDir = optarg;
488 break;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100489 case 0x601:
490 hfuzz->io.covDirAll = optarg;
491 break;
492 case 0x602:
493 hfuzz->io.covDirNew = optarg;
494 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100495 case 'r':
496 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
497 break;
498 case 'c':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100499 hfuzz->exe.externalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100500 break;
501 case 'C':
502 hfuzz->useSanCov = true;
503 break;
504 case 'S':
505 hfuzz->enableSanitizers = true;
506 break;
Robert Swiecki97d88932018-01-10 19:29:34 +0100507 case 0x10A:
508 hfuzz->extSanOpts = optarg;
509 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100510 case 'z':
511 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT;
512 break;
513 case 'F':
514 hfuzz->maxFileSz = strtoul(optarg, NULL, 0);
515 break;
516 case 't':
Robert Swiecki371e1292017-12-18 01:10:33 +0100517 hfuzz->timing.tmOut = atol(optarg);
Robert Swieckid50ed422017-11-13 23:32:26 +0100518 break;
519 case 'R':
520 hfuzz->reportFile = optarg;
521 break;
522 case 'n':
523 hfuzz->threads.threadsMax = atol(optarg);
524 break;
525 case 0x109: {
526 time_t p = atol(optarg);
527 if (p > 0) {
Robert Swiecki371e1292017-12-18 01:10:33 +0100528 hfuzz->timing.runEndTime = time(NULL) + p;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200529 }
Robert Swieckid50ed422017-11-13 23:32:26 +0100530 } break;
531 case 'N':
532 hfuzz->mutationsMax = atol(optarg);
533 break;
534 case 0x100:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100535 hfuzz->exe.asLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100536 break;
537 case 0x101:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100538 hfuzz->exe.rssLimit = strtoull(optarg, NULL, 0);
Robert Swiecki8954afd2017-11-14 18:14:22 +0100539 break;
540 case 0x102:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100541 hfuzz->exe.dataLimit = strtoull(optarg, NULL, 0);
Robert Swieckid50ed422017-11-13 23:32:26 +0100542 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100543 case 0x104:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100544 hfuzz->exe.postExternalCommand = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100545 break;
546 case 0x105:
547 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) {
548 hfuzz->monitorSIGABRT = false;
549 } else {
550 hfuzz->monitorSIGABRT = true;
551 }
552 break;
553 case 0x106:
554 hfuzz->skipFeedbackOnTimeout = true;
555 break;
556 case 0x107:
557 hfuzz->exitUponCrash = true;
558 break;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100559 case 0x108:
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100560 hfuzz->exe.clearEnv = true;
Robert Swiecki8954afd2017-11-14 18:14:22 +0100561 break;
Robert Swieckid50ed422017-11-13 23:32:26 +0100562 case 'P':
563 hfuzz->persistent = true;
564 break;
565 case 'T':
Robert Swieckieba27172017-12-18 01:12:02 +0100566 hfuzz->timing.tmoutVTALRM = true;
Robert Swieckid50ed422017-11-13 23:32:26 +0100567 break;
568 case 'p':
569 if (util_isANumber(optarg) == false) {
570 LOG_E("-p '%s' is not a number", optarg);
571 return false;
572 }
573 hfuzz->linux.pid = atoi(optarg);
574 if (hfuzz->linux.pid < 1) {
575 LOG_E("-p '%d' is invalid", hfuzz->linux.pid);
576 return false;
577 }
578 break;
579 case 0x502:
580 hfuzz->linux.pidFile = optarg;
581 break;
582 case 'E':
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100583 for (size_t i = 0; i < ARRAYSIZE(hfuzz->exe.envs); i++) {
584 if (hfuzz->exe.envs[i] == NULL) {
585 hfuzz->exe.envs[i] = optarg;
Robert Swieckid50ed422017-11-13 23:32:26 +0100586 break;
587 }
588 }
589 break;
590 case 'w':
591 hfuzz->dictionaryFile = optarg;
592 break;
593 case 'B':
594 hfuzz->blacklistFile = optarg;
595 break;
Robert Swiecki846ccd72017-01-12 17:52:23 +0100596#if defined(_HF_ARCH_LINUX)
Robert Swieckid50ed422017-11-13 23:32:26 +0100597 case 0x500:
598 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0);
599 break;
600 case 0x501:
601 hfuzz->linux.disableRandomization = false;
602 break;
603 case 0x503:
604 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0);
605 break;
606 case 0x504:
607 hfuzz->linux.symsBlFile = optarg;
608 break;
609 case 0x505:
610 hfuzz->linux.symsWlFile = optarg;
611 break;
612 case 0x510:
613 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT;
614 break;
615 case 0x511:
616 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT;
617 break;
618 case 0x513:
619 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE;
620 break;
621 case 0x514:
622 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK;
623 break;
624 case 0x515:
625 hfuzz->linux.kernelOnly = true;
626 break;
627 case 0x530:
628 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET);
629 break;
630 case 0x531:
631 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID);
632 break;
633 case 0x532:
634 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC);
635 break;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200636#endif /* defined(_HF_ARCH_LINUX) */
Robert Swieckid50ed422017-11-13 23:32:26 +0100637 default:
638 cmdlineUsage(argv[0], custom_opts);
639 return false;
640 break;
Robert Swieckia88f96f2015-10-09 16:47:39 +0200641 }
642 }
Jagger72f258b2015-10-09 23:09:01 +0200643
Robert Swieckia35d9d82017-12-15 22:00:41 +0100644 if (!logInitLogFile(logfile, ll)) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200645 return false;
646 }
Robert Swiecki2aeff252018-01-10 14:58:44 +0100647 hfuzz->exe.argc = argc - optind;
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100648 hfuzz->exe.cmdline = (const char* const*)&argv[optind];
Robert Swiecki2aeff252018-01-10 14:58:44 +0100649 if (hfuzz->exe.argc <= 0) {
Robert Swieckia88f96f2015-10-09 16:47:39 +0200650 LOG_E("No fuzz command provided");
651 cmdlineUsage(argv[0], custom_opts);
652 return false;
653 }
Robert Swiecki32ae3892018-01-10 16:20:28 +0100654 if (!hfuzz->persistent && cmdlineCheckIfPersistent(hfuzz->exe.cmdline[0])) {
Robert Swieckif8292582018-01-10 16:19:18 +0100655 LOG_I("Persistent signature detected, assume it's a persistent fuzzing-mode binary");
656 hfuzz->persistent = true;
657 }
Robert Swieckia35d9d82017-12-15 22:00:41 +0100658 if (!cmdlineVerify(hfuzz)) {
Anestis Bechtsoudisc1a0d9f2016-12-29 11:34:10 +0200659 return false;
660 }
661
Robert Swieckid50ed422017-11-13 23:32:26 +0100662 LOG_I(
663 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, "
664 "mutationsPerRun: %u, "
665 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, "
666 "threads.threadsMax: %zu, "
667 "fileExtn: '%s', "
Robert Swiecki8954afd2017-11-14 18:14:22 +0100668 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64
669 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'",
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100670 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->exe.nullifyStdio),
671 cmdlineYesNo(hfuzz->exe.fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique),
672 hfuzz->mutationsPerRun,
673 hfuzz->exe.externalCommand == NULL ? "NULL" : hfuzz->exe.externalCommand,
Robert Swiecki371e1292017-12-18 01:10:33 +0100674 (int)hfuzz->timing.runEndTime, hfuzz->timing.tmOut, hfuzz->mutationsMax,
675 hfuzz->threads.threadsMax, hfuzz->io.fileExtn, hfuzz->exe.asLimit, hfuzz->exe.rssLimit,
676 hfuzz->exe.dataLimit, hfuzz->exe.cmdline[0], hfuzz->linux.pid,
677 cmdlineYesNo(hfuzz->monitorSIGABRT));
Robert Swieckia88f96f2015-10-09 16:47:39 +0200678
Robert Swiecki97d0cee2017-12-18 00:17:50 +0100679 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->exe.cmdline[0]);
680 for (size_t i = 1; hfuzz->exe.cmdline[i]; i++) {
681 util_ssnprintf(
682 hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->exe.cmdline[i]);
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100683 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) {
Robert Swiecki6e885112017-11-22 00:32:24 +0100684 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' ';
685 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100686 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.';
687 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.';
Robert Swiecki6e885112017-11-22 00:32:24 +0100688 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0';
Robert Swieckif2d9c3a2016-11-03 02:13:54 +0100689 }
Robert Swiecki72d2bef2016-01-19 14:39:26 +0100690 }
691
Robert Swieckia88f96f2015-10-09 16:47:39 +0200692 return true;
693}