// Copyright 2023 The Centipede Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Definitions of the Centipede flags to be expanded in different contexts. // Each flag is defined as: // // CENTIPEDE_FLAG(type, name, default_value, description) // // default_value must be a compile-time constant. // description must be a string literal. #ifndef CENTIPEDE_FLAG #error This file must be used only in Centipede with CENTIPEDE_FLAG defined. #endif // TODO(kcc): document usage of standalone binaries and how to use @@ wildcard. // If the "binary" contains @@, it means the binary can only accept inputs // from the command line, and only one input per process. // @@ will be replaced with a path to file with the input. // @@ is chosen to follow the AFL command line syntax. // TODO(kcc): rename --binary to --command (same for --extra_binaries), // while remaining backward compatible. CENTIPEDE_FLAG(std::string, binary, "", "The target binary.") CENTIPEDE_FLAG( std::string, coverage_binary, "", "The actual binary from which coverage is collected - if different " "from --binary.") CENTIPEDE_FLAG( std::string, binary_hash, "", "If not-empty, this hash string is used instead of the hash of the " "contents of coverage_binary. Use this flag when the coverage_binary " "is not available nor needed, e.g. when using --distill.") CENTIPEDE_FLAG( std::string, clang_coverage_binary, "", "A clang source-based code coverage binary used to produce " "human-readable reports. Do not add this binary to extra_binaries. " "You must have llvm-cov and llvm-profdata in your path to generate " "the reports. --workdir in turn must be local in order for this " "functionality to work. See " "https://clang.llvm.org/docs/SourceBasedCodeCoverage.html") CENTIPEDE_FLAG(std::string, test_name, "", "The name of test to pass to the binary to operate on.") CENTIPEDE_FLAG( std::vector, extra_binaries, {}, "A comma-separated list of extra target binaries. These binaries are " "fed the same inputs as the main binary, but the coverage feedback " "from them is not collected. Use this e.g. to run the target under " "sanitizers.") CENTIPEDE_FLAG(std::string, workdir, "", "The working directory.") CENTIPEDE_FLAG( std::string, merge_from, "", "Another working directory to merge the corpus from. Inputs from " "--merge_from will be added to --workdir if the add new features.") CENTIPEDE_FLAG(size_t, num_runs, std::numeric_limits::max(), "Number of inputs to run per shard (see --total_shards).") CENTIPEDE_FLAG(size_t, total_shards, 1, "Number of shards.") CENTIPEDE_FLAG(size_t, my_shard_index, 0, "Index of the first shard, [0, --total_shards - --num_threads].") CENTIPEDE_FLAG( size_t, num_threads, 1, "Number of threads to execute in one process. i-th thread, where i " "is in [0, --num_threads), will work on shard " "(--first_shard_index + i).") CENTIPEDE_FLAG(size_t, j, 0, "If not 0, --j=N is a shorthand for " "--num_threads=N --total_shards=N --first_shard_index=0. " "Overrides values of these flags if they are also used.") CENTIPEDE_FLAG(size_t, max_len, 4000, "Max length of mutants. Passed to mutator as a hint.") CENTIPEDE_FLAG( size_t, batch_size, 1000, "The number of inputs given to the target at one time. Batches of " "more than 1 input are used to amortize the process start-up cost.") CENTIPEDE_FLAG(size_t, mutate_batch_size, 2, "Mutate this many inputs to produce batch_size mutants") CENTIPEDE_FLAG( bool, use_legacy_default_mutator, false, "When set, use the legacy ByteArrayMutator as the default mutator. " "Otherwise, the FuzzTest domain based mutator will be used.") CENTIPEDE_FLAG( size_t, load_other_shard_frequency, 10, "Load a random other shard after processing this many batches. Use 0 " "to disable loading other shards. For now, choose the value of this " "flag so that shard loads happen at most once in a few minutes. In " "future we may be able to find the suitable value automatically.") // TODO(b/262798184): Remove once the bug is fixed. CENTIPEDE_FLAG( bool, serialize_shard_loads, false, "When this flag is on, shard loading is serialized. " " Useful to avoid excessive RAM consumption when loading more" " that one shard at a time. Currently, loading a single large shard" " may create too many temporary heap allocations. " " This means, if we load many large shards concurrently," " we may run out or RAM.") CENTIPEDE_FLAG( size_t, seed, 0, "A seed for the random number generator. If 0, some other random " "number is used as seed.") CENTIPEDE_FLAG( size_t, prune_frequency, 100, "Prune the corpus every time after this many inputs were added. If " "zero, pruning is disabled. Pruning removes redundant inputs from " "the corpus, e.g. inputs that have only \"frequent\", i.e. " "uninteresting features. When the corpus gets larger than " "--max_corpus_size, some random elements may also be removed.") CENTIPEDE_FLAG( size_t, address_space_limit_mb, #ifdef __APPLE__ // Address space limit is ignored on MacOS. // Reference: // https://bugs.chromium.org/p/chromium/issues/detail?id=853873#c2 0 #else 8192 #endif , "If not zero, instructs the target to set setrlimit(RLIMIT_AS) to " "this number of megabytes. Some targets (e.g. if built with ASAN, " "which can't run with RLIMIT_AS) may choose to ignore this flag. See " "also --rss_limit_mb.") CENTIPEDE_FLAG( size_t, rss_limit_mb, 4096, "If not zero, instructs the target to fail if RSS goes over this " "number of megabytes and report an OOM. See also " "--address_space_limit_mb. These two flags have somewhat different " "meaning. --address_space_limit_mb does not allow the process to " "grow the used address space beyond the limit. --rss_limit_mb runs a " "background thread that monitors max RSS and also checks max RSS " "after executing every input, so it may detect OOM late. However " "--rss_limit_mb allows Centipede to *report* an OOM condition in " "most cases, while --address_space_limit_mb will cause a crash that " "may be hard to attribute to OOM.") CENTIPEDE_FLAG( size_t, stack_limit_kb, 0, "If not zero, instructs the target to fail if stack usage goes over " "this number of KiB.") CENTIPEDE_FLAG( size_t, timeout_per_input, 60, "If not zero, the timeout in seconds for a single input. If an input " "runs longer than this, the runner process will abort. Support may " "vary depending on the runner.") CENTIPEDE_FLAG( size_t, timeout_per_batch, 0, "If not zero, the collective timeout budget in seconds for a single " "batch of inputs. Each input in a batch still has up to " "--timeout_per_input seconds to finish, but the entire batch must " "finish within --timeout_per_batch seconds. The default is computed " "as a function of --timeout_per_input * --batch_size. Support may " "vary depending on the runner.") CENTIPEDE_FLAG(size_t, ignore_timeout_reports, false, "If set, will ignore reporting timeouts as errors.") CENTIPEDE_FLAG( absl::Time, stop_at, absl::InfiniteFuture(), "Stop fuzzing in all shards (--total_shards) at approximately this " "time in ISO-8601/RFC-3339 format, e.g. 2023-04-06T23:35:02Z. " "If a given shard is still running at that time, it will gracefully " "wind down by letting the current batch of inputs to finish and then " "exiting. A special value 'infinite-future' (the default) is " "supported. Tip: `date` is useful for conversion of mostly free " "format human readable date/time strings, e.g. " "--stop_at=$(date --date='next Monday 6pm' --utc --iso-8601=seconds) " ". Also see --stop_after. These two flags are mutually exclusive.") CENTIPEDE_FLAG( bool, fork_server, true, "If true (default) tries to execute the target(s) via the fork " "server, if supported by the target(s). Prepend the binary path with " "'%f' to disable the fork server. --fork_server applies to binaries " "passed via these flags: --binary, --extra_binaries, " "--input_filter.") CENTIPEDE_FLAG( bool, full_sync, false, "Perform a full corpus sync on startup. If true, feature sets and " "corpora are read from all shards before fuzzing. This way fuzzing " "starts with a full knowledge of the current state and will avoid " "adding duplicating inputs. This however is very expensive when the " "number of shards is very large.") CENTIPEDE_FLAG( bool, use_corpus_weights, true, "If true, use weighted distribution when choosing the corpus element " "to mutate. This flag is mostly for Centipede developers.") CENTIPEDE_FLAG( bool, use_coverage_frontier, false, "If true, use coverage frontier when choosing the corpus element to " "mutate. This flag is mostly for Centipede developers.") CENTIPEDE_FLAG( size_t, max_corpus_size, 100000, "Indicates the number of inputs in the in-memory corpus after which" "more aggressive pruning will be applied.") CENTIPEDE_FLAG( size_t, crossover_level, 50, "Defines how much crossover is used during mutations. 0 means no " "crossover, 100 means the most aggressive crossover. See " "https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm).") CENTIPEDE_FLAG(bool, use_pc_features, true, "When available from instrumentation, use features derived from " "PCs.") CENTIPEDE_FLAG( size_t, path_level, 0, // Not ready for wide usage. "When available from instrumentation, use features derived from " "bounded execution paths. Be careful, may cause exponential feature " "explosion. 0 means no path features. Values between 1 and 100 " "define how aggressively to use the paths.") CENTIPEDE_FLAG(bool, use_cmp_features, true, "When available from instrumentation, use features derived from " "instrumentation of CMP instructions.") CENTIPEDE_FLAG( size_t, callstack_level, 0, "When available from instrumentation, use features derived from " "observing the function call stacks. 0 means no callstack features." "Values between 1 and 100 define how aggressively to use the " "callstacks. Level N roughly corresponds to N call frames.") CENTIPEDE_FLAG(bool, use_auto_dictionary, true, "If true, use automatically-generated dictionary derived from " "intercepting comparison instructions, memcmp, and similar.") CENTIPEDE_FLAG(bool, use_dataflow_features, true, "When available from instrumentation, use features derived from " "data flows.") CENTIPEDE_FLAG( bool, use_counter_features, false, "When available from instrumentation, use features derived from " "counting the number of occurrences of a given PC. When enabled, " "supersedes --use_pc_features.") CENTIPEDE_FLAG(bool, use_pcpair_features, false, "If true, PC pairs are used as additional synthetic features. " "Experimental, use with care - it may explode the corpus.") CENTIPEDE_FLAG( uint64_t, user_feature_domain_mask, ~0UL, "A bitmask indicating which user feature domains should be enabled. " "A value of zero will disable all user features.") CENTIPEDE_FLAG( size_t, feature_frequency_threshold, 100, "Internal flag. When a given feature is present in the corpus this " "many times Centipede will stop recording it for future corpus " "elements. Larger values will use more RAM but may improve corpus " "weights. Valid values are 2 - 255.") CENTIPEDE_FLAG(bool, require_pc_table, true, "If true, Centipede will exit if the --pc_table is not found.") CENTIPEDE_FLAG(bool, require_seeds, false, "If true, Centipede will exit if no seed inputs are found.") CENTIPEDE_FLAG( int, telemetry_frequency, 0, "Dumping frequency for intermediate telemetry files, i.e. coverage " "report (workdir/coverage-report-BINARY.*.txt), corpus stats " "(workdir/corpus-stats-*.json), etc. Positive value N means dump " "every N batches. Negative N means start dumping after 2^N processed " "batches with exponential 2x back-off (e.g. for " "--telemetry_frequency=-5, dump on batches 32, 64, 128,...). Zero " "means no telemetry. Note that the before-fuzzing and after-fuzzing " "telemetry are always dumped.") CENTIPEDE_FLAG(bool, print_runner_log, false, "If true, runner logs are printed after every batch. Note that " "crash logs are always printed regardless of this flag's value.") // TODO(kcc): --distill and several others had better be dedicated binaries. CENTIPEDE_FLAG( bool, distill, false, "Distill (minimize) the --total_shards input shards from --workdir " "into --num_threads output shards. The input shards are randomly and " "evenly divided between --num_threads concurrent distillation " "threads to speed up processing. The threads share and update the " "global coverage info as they go, so the output shards will never " "have identical input/feature pairs (some intputs can still be " "identical if a non-deterministic target produced different features " "for identical inputs in the corpus). The features.* files are " "looked up in a --workdir subdirectory that corresponds to " "--coverage_binary and --binary_hash, if --binary_hash is provided; " "if it is not provided, the actual hash of the --coverage_binary " "file on disk is computed and used. Therefore, with an explicit " "--binary_hash, --coverage_binary can be just the basename of the " "actual target binary; without it, it must be the full path. " "Each distillation thread writes a distilled corpus shard to " "to <--workdir>/distilled-<--coverage_binary basename>..") CENTIPEDE_FLAG( size_t, log_features_shards, 0, "The first --log_features_shards shards will log newly observed " "features as symbols. In most cases you don't need this to be >= 2.") CENTIPEDE_FLAG( std::string, knobs_file, "", "If not empty, knobs will be read from this (possibly remote) file." " The feature is experimental, not yet fully functional.") CENTIPEDE_FLAG( std::string, corpus_to_files, "", "Save the remote corpus from working to the given directory, one " "file per corpus.") CENTIPEDE_FLAG( std::string, crashes_to_files, "", "When set to a directory path, save the crashing reproducers and " "metadata from the workdir to the given path: Each crash with `ID`" "will be saved with file `ID.data` for the reproducer, `ID.desc` the " "description, `ID.sig` the signature. If multiple crashes with the same ID " "exist, only one crash will be saved.") CENTIPEDE_FLAG( std::string, corpus_from_files, "", "Export a corpus from a local directory with one file per input into " "the sharded remote corpus in workdir. Not recursive.") CENTIPEDE_FLAG( std::vector, corpus_dir, {}, "Comma-separated list of paths to local corpus dirs, with one file " "per input. At startup, the files are exported into the corpus in " "--workdir. While fuzzing, the new corpus elements are written to " "the first dir if it is not empty. This makes it more convenient to " "interop with libFuzzer corpora.") CENTIPEDE_FLAG( std::string, symbolizer_path, "llvm-symbolizer", "Path to the symbolizer tool. By default, we use llvm-symbolizer " "and assume it is in PATH.") CENTIPEDE_FLAG( std::string, objdump_path, "objdump", "Path to the objdump tool. By default, we use the system objdump " "and assume it is in PATH.") CENTIPEDE_FLAG(std::string, runner_dl_path_suffix, "", "If non-empty, this flag is passed to the Centipede runner. " "It tells the runner that this dynamic library is instrumented " "while the main binary is not. " "The value could be the full path, like '/path/to/my.so' " "or a suffix, like '/my.so' or 'my.so'." "This flag is experimental and may be removed in future") CENTIPEDE_FLAG( std::string, input_filter, "", "Path to a tool that filters bad inputs. The tool is invoked as " "`input_filter INPUT_FILE` and should return 0 if the input is good " "and non-0 otherwise. Ignored if empty. The --input_filter is " "invoked only for inputs that are considered for addition to the " "corpus.") CENTIPEDE_FLAG( std::vector, dictionary, {}, "A comma-separated list of paths to dictionary files. The dictionary " "file is either in AFL/libFuzzer plain text format or in the binary " "Centipede corpus file format. The flag is interpreted by " "CentipedeCallbacks so its meaning may be different in custom " "implementations of CentipedeCallbacks.") CENTIPEDE_FLAG( std::string, function_filter, "", "A comma-separated list of functions that fuzzing needs to focus on. " "If this list is non-empty, the fuzzer will mutate only those inputs " "that trigger code in one of these functions.") CENTIPEDE_FLAG( std::string, for_each_blob, "", "If non-empty, extracts individual blobs from the files given as " "arguments, copies each blob to a temporary file, and applies this " "command to that temporary file. %P is replaced with the temporary " "file's path and %H is replaced with the blob's hash. Example:\n" "$ centipede --for_each_blob='ls -l %P && echo %H' corpus.000000") CENTIPEDE_FLAG( std::string, experiment, "", "A colon-separated list of values, each of which is a flag followed " "by = and a comma-separated list of values. Example: " "'foo=1,2,3:bar=10,20'. When non-empty, this flag is used to run an " "A/B[/C/D...] experiment: different threads will set different " "values of 'foo' and 'bar' and will run independent fuzzing " "sessions. If more than one flag is given, all flag combinations are " "tested. In example above: '--foo=1 --bar=10' ... " "'--foo=3 --bar=20'. The number of threads should be multiple of the " "number of flag combinations.") CENTIPEDE_FLAG( bool, analyze, false, "If set, Centipede will read the corpora from the work dirs provided" " as argv. If two corpora are provided, then analyze differences" " between those corpora. If one corpus is provided, then save the" " coverage report to a file within workdir with prefix" " 'coverage-report-'.") CENTIPEDE_FLAG(bool, exit_on_crash, false, "If true, Centipede will exit on the first crash of the target.") CENTIPEDE_FLAG(size_t, max_num_crash_reports, 5, "report this many crashes per shard.") CENTIPEDE_FLAG( std::string, minimize_crash_file_path, "", "If non-empty, a path to an input file that triggers a crash." " Centipede will run the minimization loop and store smaller crashing" " inputs in workdir/crashes.NNNNNN/, where NNNNNN is " "--first_shard_index padded on the left with zeros. " " --num_runs and --num_threads apply. " " Assumes local workdir.") CENTIPEDE_FLAG( bool, batch_triage_suspect_only, false, "If set, triage the crash on only the suspected input in a crashing " "batch. Otherwise, triage on all the executed inputs") CENTIPEDE_FLAG( size_t, shmem_size_mb, 1024, "Size of the shared memory regions used to communicate between the " "ending and the runner.") CENTIPEDE_FLAG( bool, use_posix_shmem, #ifdef __APPLE__ true #else false #endif , "[INTERNAL] When true, uses shm_open/shm_unlink instead of " "memfd_create to allocate shared memory. You may want this if your " "target doesn't have access to /proc/ subdirs or the " "memfd_create syscall is not supported.") CENTIPEDE_FLAG( bool, dry_run, false, "Initializes as much of Centipede as possible without actually " "running any fuzzing. Useful to validate the rest of the command " "line, verify existence of all the input directories and files, " "etc. Also useful in combination with --save_config or " "--update_config to stop execution immediately after writing the " "(updated) config file.") CENTIPEDE_FLAG(bool, save_binary_info, false, "Save the BinaryInfo from the fuzzing run within the working " "directory.") CENTIPEDE_FLAG( bool, populate_binary_info, true, "Get binary info from a coverage instrumented binary. This should " "only be turned off when coverage is not based on instrumenting some " "binary.") CENTIPEDE_FLAG( bool, riegeli, #ifdef CENTIPEDE_DISABLE_RIEGELI false #else true #endif , "Use Riegeli file format (instead of the legacy bespoke encoding) " "for storage") CENTIPEDE_FLAG(bool, first_corpus_dir_output_only, false, "If set, treat the first entry of `corpus_dir` as output-only. " "For FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG(bool, load_shards_only, false, "If set, load/merge shards without fuzzing new inputs. For " "FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG( bool, fuzztest_single_test_mode, false, "If set, operate on the corpus database for a single test specified by " "FuzzTest instead of all the tests. For FuzzTest framework only, do not " "use from end-users.") CENTIPEDE_FLAG( std::string, fuzztest_configuration, "", "If set, deserializes the FuzzTest configuration from the value as a " "base64url string instead of querying the configuration via runner " "callbacks. For FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG( bool, list_crash_ids, false, "If set, lists the crash IDs of a single test of the binary to the " "`crash_ids_file` with each crash ID in a single line. If there is no " "crash for the test, the empty content will be written to the file. For " "FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG(std::string, list_crash_ids_file, "", "The path to list the crash IDs for `list_crash_ids`. For " "FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG(std::string, crash_id, "", "The crash ID used for `replay_crash` or `export_crash`. For " "FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG(bool, replay_crash, false, "If set, replay `crash_id` in the corpus database. For FuzzTest " "framework only, do not use from end-users.") CENTIPEDE_FLAG( bool, export_crash, false, "If set, export the input contents of `crash_id` from the corpus database. " "For FuzzTest framework only, do not use from end-users.") CENTIPEDE_FLAG( std::string, export_crash_file, "", "The path to export the input contents of `crash_id` for `export_crash`. " "For FuzzTest framework only, do not use from end-users.")