1 /* 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> 28 #include <inttypes.h> 29 #include <limits.h> 30 #if defined(_HF_ARCH_LINUX) 31 #include <sched.h> 32 #endif /* defined(_HF_ARCH_LINUX) */ 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/queue.h> 38 #include <sys/stat.h> 39 #include <sys/types.h> 40 #include <unistd.h> 41 42 #include "libcommon/common.h" 43 #include "libcommon/files.h" 44 #include "libcommon/log.h" 45 #include "libcommon/util.h" 46 47 struct custom_option { 48 struct option opt; 49 const char* descr; 50 }; 51 52 static bool checkFor_FILE_PLACEHOLDER(const char* const* args) { 53 for (int x = 0; args[x]; x++) { 54 if (strstr(args[x], _HF_FILE_PLACEHOLDER)) return true; 55 } 56 return false; 57 } 58 59 static const char* cmdlineYesNo(bool yes) { return (yes ? "true" : "false"); } 60 61 static void cmdlineHelp(const char* pname, struct custom_option* opts) { 62 LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname); 63 LOG_HELP_BOLD("Options:"); 64 for (int i = 0; opts[i].opt.name; i++) { 65 if (isprint(opts[i].opt.val) && opts[i].opt.val < 0x80) { 66 LOG_HELP_BOLD(" --%s%s%c %s", opts[i].opt.name, "|-", opts[i].opt.val, 67 opts[i].opt.has_arg == required_argument ? "VALUE" : ""); 68 } else { 69 LOG_HELP_BOLD(" --%s %s", opts[i].opt.name, 70 opts[i].opt.has_arg == required_argument ? "VALUE" : ""); 71 } 72 LOG_HELP("\t%s", opts[i].descr); 73 } 74 LOG_HELP_BOLD("\nExamples:"); 75 LOG_HELP( 76 " Run the binary over a mutated file chosen from the directory. Disable fuzzing " 77 "feedback (dry/static mode)"); 78 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 79 LOG_HELP(" As above, provide input over STDIN:"); 80 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -x -s -- /usr/bin/djpeg"); 81 LOG_HELP(" Use compile-time instrumentation (libhfuzz/instrument.c):"); 82 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 83 LOG_HELP(" Use SANCOV instrumentation:"); 84 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -C -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 85 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) w/o instrumentation:"); 86 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -x -- /usr/bin/djpeg_persistent_mode"); 87 LOG_HELP(" Use persistent mode (libhfuzz/persistent.c) and compile-time instrumentation:"); 88 LOG_HELP_BOLD(" " PROG_NAME " -f input_dir -P -- /usr/bin/djpeg_persistent_mode"); 89 #if defined(_HF_ARCH_LINUX) 90 LOG_HELP( 91 " Run the binary with dynamically generate inputs, maximize total no. of instructions:"); 92 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_instr -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 93 LOG_HELP(" As above, maximize total no. of branches:"); 94 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_branch -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 95 LOG_HELP(" As above, maximize unique branches (edges) via Intel BTS:"); 96 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_bts_edge -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 97 LOG_HELP( 98 " As above, maximize unique code blocks via Intel Processor Trace (requires libipt.so):"); 99 LOG_HELP_BOLD(" " PROG_NAME " --linux_perf_ipt_block -- /usr/bin/djpeg " _HF_FILE_PLACEHOLDER); 100 #endif /* defined(_HF_ARCH_LINUX) */ 101 } 102 103 static void cmdlineUsage(const char* pname, struct custom_option* opts) { 104 cmdlineHelp(pname, opts); 105 exit(0); 106 } 107 108 rlim_t cmdlineParseRLimit(int res, const char* optarg, unsigned long mul) { 109 struct rlimit cur; 110 if (getrlimit(res, &cur) == -1) { 111 PLOG_F("getrlimit(%d)", res); 112 } 113 if (strcasecmp(optarg, "max") == 0) { 114 return cur.rlim_max; 115 } 116 if (strcasecmp(optarg, "def") == 0) { 117 return cur.rlim_cur; 118 } 119 if (util_isANumber(optarg) == false) { 120 LOG_F("RLIMIT %d needs a numeric or 'max'/'def' value ('%s' provided)", res, optarg); 121 } 122 rlim_t val = strtoul(optarg, NULL, 0) * mul; 123 if ((unsigned long)val == ULONG_MAX && errno != 0) { 124 PLOG_F("strtoul('%s', 0)", optarg); 125 } 126 return val; 127 } 128 129 static bool cmdlineVerify(honggfuzz_t* hfuzz) { 130 if (!hfuzz->exe.fuzzStdin && !hfuzz->persistent && 131 !checkFor_FILE_PLACEHOLDER(hfuzz->exe.cmdline)) { 132 LOG_E("You must specify '" _HF_FILE_PLACEHOLDER 133 "' when the -s (stdin fuzzing) or --persistent options are not set"); 134 return false; 135 } 136 137 if (hfuzz->exe.fuzzStdin && hfuzz->persistent) { 138 LOG_E( 139 "Stdin fuzzing (-s) and persistent fuzzing (-P) cannot be specified at the same time"); 140 return false; 141 } 142 143 if (hfuzz->threads.threadsMax >= _HF_THREAD_MAX) { 144 LOG_E("Too many fuzzing threads specified %zu (>= _HF_THREAD_MAX (%u))", 145 hfuzz->threads.threadsMax, _HF_THREAD_MAX); 146 return false; 147 } 148 149 if (strchr(hfuzz->io.fileExtn, '/')) { 150 LOG_E("The file extension contains the '/' character: '%s'", hfuzz->io.fileExtn); 151 return false; 152 } 153 154 if (hfuzz->io.workDir == NULL) { 155 hfuzz->io.workDir = "."; 156 } 157 if (mkdir(hfuzz->io.workDir, 0700) == -1 && errno != EEXIST) { 158 PLOG_E("Couldn't create the workspace directory '%s'", hfuzz->io.workDir); 159 return false; 160 } 161 if (hfuzz->io.crashDir == NULL) { 162 hfuzz->io.crashDir = hfuzz->io.workDir; 163 } 164 if (mkdir(hfuzz->io.crashDir, 0700) && errno != EEXIST) { 165 PLOG_E("Couldn't create the crash directory '%s'", hfuzz->io.crashDir); 166 return false; 167 } 168 169 if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) { 170 LOG_I("PID=%d specified, lowering maximum number of concurrent threads to 1", 171 hfuzz->linux.pid); 172 hfuzz->threads.threadsMax = 1; 173 } 174 175 if (hfuzz->mutationsPerRun == 0U && hfuzz->useVerifier) { 176 LOG_I("Verifier enabled with mutationsPerRun == 0, activating the dry run mode"); 177 } 178 179 /* 180 * 'enableSanitizers' can be auto enabled when 'useSanCov', although it's probably 181 * better to let user know about the features that each flag control. 182 */ 183 if (hfuzz->useSanCov == true && hfuzz->enableSanitizers == false) { 184 LOG_E("Sanitizer coverage cannot be used without enabling sanitizers '-S/--sanitizers'"); 185 return false; 186 } 187 188 return true; 189 } 190 191 bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { 192 honggfuzz_t tmp = { 193 .io = 194 { 195 .inputDir = NULL, 196 .inputDirPtr = NULL, 197 .fileCnt = 0, 198 .fileCntDone = false, 199 .fileExtn = "fuzz", 200 .workDir = NULL, 201 .crashDir = NULL, 202 .covDirAll = NULL, 203 .covDirNew = NULL, 204 .saveUnique = true, 205 }, 206 .exe = 207 { 208 .cmdline = NULL, 209 .nullifyStdio = true, 210 .fuzzStdin = false, 211 .externalCommand = NULL, 212 .postExternalCommand = NULL, 213 .asLimit = 0U, 214 .rssLimit = 0U, 215 .dataLimit = 0U, 216 .clearEnv = false, 217 .envs[0] = NULL, 218 }, 219 .timing = 220 { 221 .timeStart = time(NULL), 222 .runEndTime = 0, 223 .tmOut = 10, 224 .tmoutVTALRM = false, 225 }, 226 .cmdline_txt[0] = '\0', 227 .useScreen = true, 228 .useVerifier = false, 229 .mutationsPerRun = 6U, 230 .blacklistFile = NULL, 231 .blacklistCnt = 0, 232 .blacklist = NULL, 233 .maxFileSz = 0UL, 234 .mutationsMax = 0, 235 .reportFile = NULL, 236 .persistent = false, 237 .skipFeedbackOnTimeout = false, 238 .enableSanitizers = false, 239 #if defined(__ANDROID__) 240 .monitorSIGABRT = false, 241 #else 242 .monitorSIGABRT = true, 243 #endif 244 .exitUponCrash = false, 245 246 .threads = 247 { 248 .threadsFinished = 0, 249 .threadsMax = 250 (sysconf(_SC_NPROCESSORS_ONLN) <= 1) ? 1 : sysconf(_SC_NPROCESSORS_ONLN) / 2, 251 .threadsActiveCnt = 0, 252 .mainThread = pthread_self(), 253 .mainPid = getpid(), 254 }, 255 256 .dictionaryFile = NULL, 257 .dictionaryCnt = 0, 258 .dictqCurrent = NULL, 259 260 .state = _HF_STATE_UNSET, 261 .feedback = NULL, 262 .bbFd = -1, 263 264 .dynfileqCnt = 0U, 265 .dynfileq_mutex = PTHREAD_RWLOCK_INITIALIZER, 266 267 .feedback_mutex = PTHREAD_MUTEX_INITIALIZER, 268 269 .cnts = 270 { 271 .mutationsCnt = 0, 272 .crashesCnt = 0, 273 .uniqueCrashesCnt = 0, 274 .verifiedCrashesCnt = 0, 275 .blCrashesCnt = 0, 276 .timeoutedCnt = 0, 277 }, 278 279 .dynFileMethod = _HF_DYNFILE_SOFT, 280 .sanCovCnts = 281 { 282 .hitBBCnt = 0ULL, 283 .totalBBCnt = 0ULL, 284 .dsoCnt = 0ULL, 285 .iDsoCnt = 0ULL, 286 .newBBCnt = 0ULL, 287 .crashesCnt = 0ULL, 288 }, 289 290 .sanCov_mutex = PTHREAD_MUTEX_INITIALIZER, 291 .sanOpts = 292 { 293 .asanOpts = NULL, 294 .msanOpts = NULL, 295 .ubsanOpts = NULL, 296 }, 297 .useSanCov = false, 298 .covMetadata = NULL, 299 300 .report_mutex = PTHREAD_MUTEX_INITIALIZER, 301 302 /* Linux code */ 303 .linux = 304 { 305 .exeFd = -1, 306 .hwCnts = 307 { 308 .cpuInstrCnt = 0ULL, 309 .cpuBranchCnt = 0ULL, 310 .bbCnt = 0ULL, 311 .newBBCnt = 0ULL, 312 .softCntPc = 0ULL, 313 .softCntCmp = 0ULL, 314 }, 315 .dynamicCutOffAddr = ~(0ULL), 316 .disableRandomization = true, 317 .ignoreAddr = NULL, 318 .numMajorFrames = 7, 319 .pid = 0, 320 .pidFile = NULL, 321 .pidCmd[0] = '\0', 322 .symsBlFile = NULL, 323 .symsBlCnt = 0, 324 .symsBl = NULL, 325 .symsWlFile = NULL, 326 .symsWlCnt = 0, 327 .symsWl = NULL, 328 .cloneFlags = 0, 329 .kernelOnly = false, 330 .useClone = true, 331 }, 332 }; 333 *hfuzz = tmp; 334 335 TAILQ_INIT(&hfuzz->dynfileq); 336 TAILQ_INIT(&hfuzz->dictq); 337 338 // clang-format off 339 struct custom_option custom_opts[] = { 340 { { "help", no_argument, NULL, 'h' }, "Help plz.." }, 341 { { "input", required_argument, NULL, 'f' }, "Path to a directory containing initial file corpus" }, 342 { { "persistent", no_argument, NULL, 'P' }, "Enable persistent fuzzing (use hfuzz_cc/hfuzz-clang to compile code)" }, 343 { { "instrument", no_argument, NULL, 'z' }, "*DEFAULT-MODE-BY-DEFAULT* Enable compile-time instrumentation (use hfuzz_cc/hfuzz-clang to compile code)" }, 344 { { "noinst", no_argument, NULL, 'x' }, "Static mode (dry-mode), disable any instrumentation (hw/sw)" }, 345 { { "sancov", no_argument, NULL, 'C' }, "Enable sanitizer coverage feedback" }, 346 { { "keep_output", no_argument, NULL, 'Q' }, "Don't close children's stdin, stdout, stderr; can be noisy" }, 347 { { "timeout", required_argument, NULL, 't' }, "Timeout in seconds (default: '10')" }, 348 { { "threads", required_argument, NULL, 'n' }, "Number of concurrent fuzzing threads (default: number of CPUs / 2)" }, 349 { { "stdin_input", no_argument, NULL, 's' }, "Provide fuzzing input on STDIN, instead of ___FILE___" }, 350 { { "mutations_per_run", required_argument, NULL, 'r' }, "Maximal number of mutations per one run (default: '6')" }, 351 { { "logfile", required_argument, NULL, 'l' }, "Log file" }, 352 { { "verbose", no_argument, NULL, 'v' }, "Disable ANSI console; use simple log output" }, 353 { { "verifier", no_argument, NULL, 'V' }, "Enable crashes verifier" }, 354 { { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" }, 355 { { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" }, 356 { { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" }, 357 { { "crashdir", required_argument, NULL, 0x600 }, "Directory where crashes are saved to (default: workspace directory)" }, 358 { { "covdir_all", required_argument, NULL, 0x601 }, "Coverage is written to a separate directory (default: input directory)" }, 359 { { "covdir_new", required_argument, NULL, 0x602 }, "New coverage (beyond the dry-run fuzzing phase) is written to this separate directory" }, 360 { { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" }, 361 { { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" }, 362 { { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" }, 363 { { "pprocess_cmd", required_argument, NULL, 0x104 }, "External command postprocessing files produced by internal mutators" }, 364 { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: '0' [no limit])" }, 365 { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: '0' [no limit])" }, 366 { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: '0' [no limit])" }, 367 { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: '0' [no limit])" }, 368 { { "rlimit_data", required_argument, NULL, 0x102 }, "Per process RLIMIT_DATA in MiB (default: '0' [no limit])" }, 369 { { "report", required_argument, NULL, 'R' }, "Write report to this file (default: '" _HF_REPORT_FILE "')" }, 370 { { "max_file_size", required_argument, NULL, 'F' }, "Maximal size of files processed by the fuzzer in bytes (default: '1048576')" }, 371 { { "clear_env", no_argument, NULL, 0x108 }, "Clear all environment variables before executing the binary" }, 372 { { "env", required_argument, NULL, 'E' }, "Pass this environment variable, can be used multiple times" }, 373 { { "save_all", no_argument, NULL, 'u' }, "Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames" }, 374 { { "tmout_sigvtalrm", no_argument, NULL, 'T' }, "Use SIGVTALRM to kill timeouting processes (default: use SIGKILL)" }, 375 { { "sanitizers", no_argument, NULL, 'S' }, "Enable sanitizers settings (default: false)" }, 376 { { "monitor_sigabrt", required_argument, NULL, 0x105 }, "Monitor SIGABRT (default: 'false for Android - 'true for other platforms)" }, 377 { { "no_fb_timeout", required_argument, NULL, 0x106 }, "Skip feedback if the process has timeouted (default: 'false')" }, 378 { { "exit_upon_crash", no_argument, NULL, 0x107 }, "Exit upon seeing the first crash (default: 'false')" }, 379 380 #if defined(_HF_ARCH_LINUX) 381 { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blacklist filter file (one entry per line)" }, 382 { { "linux_symbols_wl", required_argument, NULL, 0x505 }, "Symbols whitelist filter file (one entry per line)" }, 383 { { "linux_pid", required_argument, NULL, 'p' }, "Attach to a pid (and its thread group)" }, 384 { { "linux_file_pid", required_argument, NULL, 0x502 }, "Attach to pid (and its thread group) read from file" }, 385 { { "linux_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: '0')" }, 386 { { "linux_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" }, 387 { { "linux_perf_ignore_above", required_argument, NULL, 0x503 }, "Ignore perf events which report IPs above this address" }, 388 { { "linux_perf_instr", no_argument, NULL, 0x510 }, "Use PERF_COUNT_HW_INSTRUCTIONS perf" }, 389 { { "linux_perf_branch", no_argument, NULL, 0x511 }, "Use PERF_COUNT_HW_BRANCH_INSTRUCTIONS perf" }, 390 { { "linux_perf_bts_edge", no_argument, NULL, 0x513 }, "Use Intel BTS to count unique edges" }, 391 { { "linux_perf_ipt_block", no_argument, NULL, 0x514 }, "Use Intel Processor Trace to count unique blocks (requires libipt.so)" }, 392 { { "linux_perf_kernel_only", no_argument, NULL, 0x515 }, "Gather kernel-only coverage with Intel PT and with Intel BTS" }, 393 { { "linux_ns_net", no_argument, NULL, 0x0530 }, "Use Linux NET namespace isolation" }, 394 { { "linux_ns_pid", no_argument, NULL, 0x0531 }, "Use Linux PID namespace isolation" }, 395 { { "linux_ns_ipc", no_argument, NULL, 0x0532 }, "Use Linux IPC namespace isolation" }, 396 #endif // defined(_HF_ARCH_LINUX) 397 { { 0, 0, 0, 0 }, NULL }, 398 }; 399 // clang-format on 400 401 struct option opts[ARRAYSIZE(custom_opts)]; 402 for (unsigned i = 0; i < ARRAYSIZE(custom_opts); i++) { 403 opts[i] = custom_opts[i].opt; 404 } 405 406 enum llevel_t ll = INFO; 407 const char* logfile = NULL; 408 int opt_index = 0; 409 for (;;) { 410 int c = getopt_long( 411 argc, argv, "-?hQvVsuPxf:d:e:W:r:c:F:t:R:n:N:l:p:g:E:w:B:CzTS", opts, &opt_index); 412 if (c < 0) break; 413 414 switch (c) { 415 case 'h': 416 case '?': 417 cmdlineUsage(argv[0], custom_opts); 418 break; 419 case 'f': 420 hfuzz->io.inputDir = optarg; 421 if (hfuzz->io.covDirAll == NULL) { 422 hfuzz->io.covDirAll = optarg; 423 } 424 break; 425 case 'x': 426 hfuzz->dynFileMethod = _HF_DYNFILE_NONE; 427 break; 428 case 'Q': 429 hfuzz->exe.nullifyStdio = false; 430 break; 431 case 'v': 432 hfuzz->useScreen = false; 433 break; 434 case 'V': 435 hfuzz->useVerifier = true; 436 break; 437 case 's': 438 hfuzz->exe.fuzzStdin = true; 439 break; 440 case 'u': 441 hfuzz->io.saveUnique = false; 442 break; 443 case 'l': 444 logfile = optarg; 445 break; 446 case 'd': 447 ll = atoi(optarg); 448 break; 449 case 'e': 450 hfuzz->io.fileExtn = optarg; 451 break; 452 case 'W': 453 hfuzz->io.workDir = optarg; 454 break; 455 case 0x600: 456 hfuzz->io.crashDir = optarg; 457 break; 458 case 0x601: 459 hfuzz->io.covDirAll = optarg; 460 break; 461 case 0x602: 462 hfuzz->io.covDirNew = optarg; 463 break; 464 case 'r': 465 hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10); 466 break; 467 case 'c': 468 hfuzz->exe.externalCommand = optarg; 469 break; 470 case 'C': 471 hfuzz->useSanCov = true; 472 break; 473 case 'S': 474 hfuzz->enableSanitizers = true; 475 break; 476 case 'z': 477 hfuzz->dynFileMethod |= _HF_DYNFILE_SOFT; 478 break; 479 case 'F': 480 hfuzz->maxFileSz = strtoul(optarg, NULL, 0); 481 break; 482 case 't': 483 hfuzz->timing.tmOut = atol(optarg); 484 break; 485 case 'R': 486 hfuzz->reportFile = optarg; 487 break; 488 case 'n': 489 hfuzz->threads.threadsMax = atol(optarg); 490 break; 491 case 0x109: { 492 time_t p = atol(optarg); 493 if (p > 0) { 494 hfuzz->timing.runEndTime = time(NULL) + p; 495 } 496 } break; 497 case 'N': 498 hfuzz->mutationsMax = atol(optarg); 499 break; 500 case 0x100: 501 hfuzz->exe.asLimit = strtoull(optarg, NULL, 0); 502 break; 503 case 0x101: 504 hfuzz->exe.rssLimit = strtoull(optarg, NULL, 0); 505 break; 506 case 0x102: 507 hfuzz->exe.dataLimit = strtoull(optarg, NULL, 0); 508 break; 509 case 0x104: 510 hfuzz->exe.postExternalCommand = optarg; 511 break; 512 case 0x105: 513 if ((strcasecmp(optarg, "0") == 0) || (strcasecmp(optarg, "false") == 0)) { 514 hfuzz->monitorSIGABRT = false; 515 } else { 516 hfuzz->monitorSIGABRT = true; 517 } 518 break; 519 case 0x106: 520 hfuzz->skipFeedbackOnTimeout = true; 521 break; 522 case 0x107: 523 hfuzz->exitUponCrash = true; 524 break; 525 case 0x108: 526 hfuzz->exe.clearEnv = true; 527 break; 528 case 'P': 529 hfuzz->persistent = true; 530 break; 531 case 'T': 532 hfuzz->timing.tmoutVTALRM = true; 533 break; 534 case 'p': 535 if (util_isANumber(optarg) == false) { 536 LOG_E("-p '%s' is not a number", optarg); 537 return false; 538 } 539 hfuzz->linux.pid = atoi(optarg); 540 if (hfuzz->linux.pid < 1) { 541 LOG_E("-p '%d' is invalid", hfuzz->linux.pid); 542 return false; 543 } 544 break; 545 case 0x502: 546 hfuzz->linux.pidFile = optarg; 547 break; 548 case 'E': 549 for (size_t i = 0; i < ARRAYSIZE(hfuzz->exe.envs); i++) { 550 if (hfuzz->exe.envs[i] == NULL) { 551 hfuzz->exe.envs[i] = optarg; 552 break; 553 } 554 } 555 break; 556 case 'w': 557 hfuzz->dictionaryFile = optarg; 558 break; 559 case 'B': 560 hfuzz->blacklistFile = optarg; 561 break; 562 #if defined(_HF_ARCH_LINUX) 563 case 0x500: 564 hfuzz->linux.ignoreAddr = (void*)strtoul(optarg, NULL, 0); 565 break; 566 case 0x501: 567 hfuzz->linux.disableRandomization = false; 568 break; 569 case 0x503: 570 hfuzz->linux.dynamicCutOffAddr = strtoull(optarg, NULL, 0); 571 break; 572 case 0x504: 573 hfuzz->linux.symsBlFile = optarg; 574 break; 575 case 0x505: 576 hfuzz->linux.symsWlFile = optarg; 577 break; 578 case 0x510: 579 hfuzz->dynFileMethod |= _HF_DYNFILE_INSTR_COUNT; 580 break; 581 case 0x511: 582 hfuzz->dynFileMethod |= _HF_DYNFILE_BRANCH_COUNT; 583 break; 584 case 0x513: 585 hfuzz->dynFileMethod |= _HF_DYNFILE_BTS_EDGE; 586 break; 587 case 0x514: 588 hfuzz->dynFileMethod |= _HF_DYNFILE_IPT_BLOCK; 589 break; 590 case 0x515: 591 hfuzz->linux.kernelOnly = true; 592 break; 593 case 0x530: 594 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWNET); 595 break; 596 case 0x531: 597 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWPID); 598 break; 599 case 0x532: 600 hfuzz->linux.cloneFlags |= (CLONE_NEWUSER | CLONE_NEWIPC); 601 break; 602 #endif /* defined(_HF_ARCH_LINUX) */ 603 default: 604 cmdlineUsage(argv[0], custom_opts); 605 return false; 606 break; 607 } 608 } 609 610 if (!logInitLogFile(logfile, ll)) { 611 return false; 612 } 613 hfuzz->exe.cmdline = (const char* const*)&argv[optind]; 614 if (hfuzz->exe.cmdline[0] == NULL) { 615 LOG_E("No fuzz command provided"); 616 cmdlineUsage(argv[0], custom_opts); 617 return false; 618 } 619 if (!cmdlineVerify(hfuzz)) { 620 return false; 621 } 622 623 LOG_I( 624 "PID: %d, inputDir '%s', nullifyStdio: %s, fuzzStdin: %s, saveUnique: %s, " 625 "mutationsPerRun: %u, " 626 "externalCommand: '%s', runEndTime: %d tmOut: %ld, mutationsMax: %zu, " 627 "threads.threadsMax: %zu, " 628 "fileExtn: '%s', " 629 "ASLimit: 0x%" PRIx64 "(MiB), RSSLimit: 0x%" PRIx64 ", DATALimit: 0x%" PRIx64 630 ", fuzzExe: '%s', fuzzedPid: %d, monitorSIGABRT: '%s'", 631 (int)getpid(), hfuzz->io.inputDir, cmdlineYesNo(hfuzz->exe.nullifyStdio), 632 cmdlineYesNo(hfuzz->exe.fuzzStdin), cmdlineYesNo(hfuzz->io.saveUnique), 633 hfuzz->mutationsPerRun, 634 hfuzz->exe.externalCommand == NULL ? "NULL" : hfuzz->exe.externalCommand, 635 (int)hfuzz->timing.runEndTime, hfuzz->timing.tmOut, hfuzz->mutationsMax, 636 hfuzz->threads.threadsMax, hfuzz->io.fileExtn, hfuzz->exe.asLimit, hfuzz->exe.rssLimit, 637 hfuzz->exe.dataLimit, hfuzz->exe.cmdline[0], hfuzz->linux.pid, 638 cmdlineYesNo(hfuzz->monitorSIGABRT)); 639 640 snprintf(hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), "%s", hfuzz->exe.cmdline[0]); 641 for (size_t i = 1; hfuzz->exe.cmdline[i]; i++) { 642 util_ssnprintf( 643 hfuzz->cmdline_txt, sizeof(hfuzz->cmdline_txt), " %s", hfuzz->exe.cmdline[i]); 644 if (strlen(hfuzz->cmdline_txt) == (sizeof(hfuzz->cmdline_txt) - 1)) { 645 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 5] = ' '; 646 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 4] = '.'; 647 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 3] = '.'; 648 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 2] = '.'; 649 hfuzz->cmdline_txt[sizeof(hfuzz->cmdline_txt) - 1] = '\0'; 650 } 651 } 652 653 return true; 654 } 655