Home | History | Annotate | Download | only in honggfuzz
      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