From 380051868a7531830d94d312f0f11b0e19e3284f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 10 Sep 2020 15:26:46 +0200 Subject: add libfuzzer custom mutator, minor enhancements and fixes --- custom_mutators/libfuzzer/FuzzerFlags.def | 197 ++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 custom_mutators/libfuzzer/FuzzerFlags.def (limited to 'custom_mutators/libfuzzer/FuzzerFlags.def') diff --git a/custom_mutators/libfuzzer/FuzzerFlags.def b/custom_mutators/libfuzzer/FuzzerFlags.def new file mode 100644 index 00000000..c9a787e0 --- /dev/null +++ b/custom_mutators/libfuzzer/FuzzerFlags.def @@ -0,0 +1,197 @@ +//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the +// point of inclusion. We are not using any flag parsing library for better +// portability and independence. +//===----------------------------------------------------------------------===// +FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.") +FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") +FUZZER_FLAG_INT(runs, -1, + "Number of individual test runs (-1 for infinite runs).") +FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " + "If 0, libFuzzer tries to guess a good value based on the corpus " + "and reports it. ") +FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, " + "then try larger inputs over time. Specifies the rate at which the length " + "limit is increased (smaller == faster). If 0, immediately try inputs with " + "size up to max_len. Default value is 0, if LLVMFuzzerCustomMutator is used.") +FUZZER_FLAG_STRING(seed_inputs, "A comma-separated list of input files " + "to use as an additional seed corpus. Alternatively, an \"@\" followed by " + "the name of a file containing the comma-separated list.") +FUZZER_FLAG_INT(keep_seed, 0, "If 1, keep seed inputs in the corpus even if " + "they do not produce new coverage. When used with |reduce_inputs==1|, the " + "seed inputs will never be reduced. This option can be useful when seeds are" + "not properly formed for the fuzz target but still have useful snippets.") +FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") +FUZZER_FLAG_INT(cross_over_uniform_dist, 0, "Experimental. If 1, use a " + "uniform probability distribution when choosing inputs to cross over with. " + "Some of the inputs in the corpus may never get chosen for mutation " + "depending on the input mutation scheduling policy. With this flag, all " + "inputs, regardless of the input mutation scheduling policy, can be chosen " + "as an input to cross over with. This can be particularly useful with " + "|keep_seed==1|; all the initial seed inputs, even though they do not " + "increase coverage because they are not properly formed, will still be " + "chosen as an input to cross over with.") + +FUZZER_FLAG_INT(mutate_depth, 5, + "Apply this number of consecutive mutations to each input.") +FUZZER_FLAG_INT(reduce_depth, 0, "Experimental/internal. " + "Reduce depth if mutations lose unique features") +FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup") +FUZZER_FLAG_INT(prefer_small, 1, + "If 1, always prefer smaller inputs during the corpus shuffle.") +FUZZER_FLAG_INT( + timeout, 1200, + "Timeout in seconds (if positive). " + "If one unit runs more than this number of seconds the process will abort.") +FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug " + "this exit code will be used.") +FUZZER_FLAG_INT(timeout_exitcode, 70, "When libFuzzer reports a timeout " + "this exit code will be used.") +FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " + "time in seconds to run the fuzzer.") +FUZZER_FLAG_INT(help, 0, "Print help.") +FUZZER_FLAG_INT(fork, 0, "Experimental mode where fuzzing happens " + "in a subprocess") +FUZZER_FLAG_INT(ignore_timeouts, 1, "Ignore timeouts in fork mode") +FUZZER_FLAG_INT(ignore_ooms, 1, "Ignore OOMs in fork mode") +FUZZER_FLAG_INT(ignore_crashes, 0, "Ignore crashes in fork mode") +FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " + "merged into the 1-st corpus. Only interesting units will be taken. " + "This flag can be used to minimize a corpus.") +FUZZER_FLAG_STRING(stop_file, "Stop fuzzing ASAP if this file exists") +FUZZER_FLAG_STRING(merge_inner, "internal flag") +FUZZER_FLAG_STRING(merge_control_file, + "Specify a control file used for the merge process. " + "If a merge process gets killed it tries to leave this file " + "in a state suitable for resuming the merge. " + "By default a temporary file will be used." + "The same file can be used for multistep merge process.") +FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided" + " crash input. Use with -runs=N or -max_total_time=N to limit " + "the number attempts." + " Use with -exact_artifact_path to specify the output." + " Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that" + " the minimized input triggers the same crash." + ) +FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided" + " crash input to make it contain fewer original bytes." + " Use with -exact_artifact_path to specify the output." + ) +FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag") +FUZZER_FLAG_STRING(features_dir, "internal flag. Used to dump feature sets on disk." + "Every time a new input is added to the corpus, a corresponding file in the features_dir" + " is created containing the unique features of that input." + " Features are stored in binary format.") +FUZZER_FLAG_STRING(mutation_graph_file, "Saves a graph (in DOT format) to" + " mutation_graph_file. The graph contains a vertex for each input that has" + " unique coverage; directed edges are provided between parents and children" + " where the child has unique coverage, and are recorded with the type of" + " mutation that caused the child.") +FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") +FUZZER_FLAG_INT(use_memmem, 1, + "Use hints from intercepting memmem, strstr, etc") +FUZZER_FLAG_INT(use_value_profile, 0, + "Experimental. Use value profile to guide fuzzing.") +FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations") +FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.") +FUZZER_FLAG_INT(reduce_inputs, 1, + "Try to reduce the size of inputs while preserving their full feature sets") +FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" + " this number of jobs in separate worker processes" + " with stdout/stderr redirected to fuzz-JOB.log.") +FUZZER_FLAG_UNSIGNED(workers, 0, + "Number of simultaneous worker processes to run the jobs." + " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.") +FUZZER_FLAG_INT(reload, 1, + "Reload the main corpus every seconds to get new units" + " discovered by other processes. If 0, disabled") +FUZZER_FLAG_INT(report_slow_units, 10, + "Report slowest units if they run for more than this number of seconds.") +FUZZER_FLAG_INT(only_ascii, 0, + "If 1, generate only ASCII (isprint+isspace) inputs.") +FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.") +FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, " + "timeout, or slow inputs) as " + "$(artifact_prefix)file") +FUZZER_FLAG_STRING(exact_artifact_path, + "Write the single artifact on failure (crash, timeout) " + "as $(exact_artifact_path). This overrides -artifact_prefix " + "and will not use checksum in the file name. Do not " + "use the same path for several parallel processes.") +FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") +FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of " + "newly covered functions.") +FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") +FUZZER_FLAG_INT(print_corpus_stats, 0, + "If 1, print statistics on corpus elements at exit.") +FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" + " at exit.") +FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated.") +FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") +FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.") +FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") +FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.") +FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.") +FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.") +FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.") +FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.") +FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.") +FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.") +FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " + "if 2, close stderr; if 3, close both. " + "Be careful, this will also close e.g. stderr of asan.") +FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled " + "try to detect memory leaks during fuzzing (i.e. not only at shut down).") +FUZZER_FLAG_INT(purge_allocator_interval, 1, "Purge allocator caches and " + "quarantines every seconds. When rss_limit_mb is specified (>0), " + "purging starts when RSS exceeds 50% of rss_limit_mb. Pass " + "purge_allocator_interval=-1 to disable this functionality.") +FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. " + "If >= 2 will also print stack traces.") +FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" + "reaching this limit of RSS memory usage.") +FUZZER_FLAG_INT(malloc_limit_mb, 0, "If non-zero, the fuzzer will exit " + "if the target tries to allocate this number of Mb with one malloc call. " + "If zero (default) same limit as rss_limit_mb is applied.") +FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates" + " from the given source location. Example: -exit_on_src_pos=foo.cc:123. " + "Used primarily for testing libFuzzer itself.") +FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum" + " was added to the corpus. " + "Used primarily for testing libFuzzer itself.") +FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed " + "after this one. Useful for fuzzers that need to do their own " + "argument parsing.") +FUZZER_FLAG_STRING(focus_function, "Experimental. " + "Fuzzing will focus on inputs that trigger calls to this function. " + "If -focus_function=auto and -data_flow_trace is used, libFuzzer " + "will choose the focus functions automatically.") +FUZZER_FLAG_INT(entropic, 0, "Experimental. Enables entropic power schedule.") +FUZZER_FLAG_INT(entropic_feature_frequency_threshold, 0xFF, "Experimental. If " + "entropic is enabled, all features which are observed less often than " + "the specified value are considered as rare.") +FUZZER_FLAG_INT(entropic_number_of_rarest_features, 100, "Experimental. If " + "entropic is enabled, we keep track of the frequencies only for the " + "Top-X least abundant features (union features that are considered as " + "rare).") +FUZZER_FLAG_INT(entropic_scale_per_exec_time, 0, "Experimental. If 1, " + "the Entropic power schedule gets scaled based on the input execution " + "time. Inputs with lower execution time get scheduled more (up to 30x). " + "Note that, if 1, fuzzer stops from being deterministic even if a " + "non-zero random seed is given.") + +FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") +FUZZER_DEPRECATED_FLAG(use_clang_coverage) +FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace") +FUZZER_FLAG_STRING(collect_data_flow, + "Experimental: collect the data flow trace") + +FUZZER_FLAG_INT(create_missing_dirs, 0, "Automatically attempt to create " + "directories for arguments that would normally expect them to already " + "exist (i.e. artifact_prefix, exact_artifact_path, features_dir, corpus)") -- cgit 1.4.1 From 207cbd5cf7c1956969f42e89bfcb9a0ab451e351 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 21 Sep 2020 15:47:10 +0200 Subject: fix and update libfuzzer custom mutator --- custom_mutators/libfuzzer/FuzzerDriver.cpp | 19 +- .../libfuzzer/FuzzerExtFunctionsDlsym.cpp | 4 +- .../libfuzzer/FuzzerExtFunctionsWeak.cpp | 7 +- .../libfuzzer/FuzzerExtFunctionsWindows.cpp | 23 +- custom_mutators/libfuzzer/FuzzerFlags.def | 5 +- custom_mutators/libfuzzer/FuzzerInterceptors.cpp | 290 +++++++++++++++++++++ custom_mutators/libfuzzer/FuzzerLoop.cpp | 2 +- custom_mutators/libfuzzer/FuzzerMain.cpp | 26 ++ custom_mutators/libfuzzer/FuzzerMutate.cpp | 19 +- custom_mutators/libfuzzer/FuzzerMutate.h | 5 +- custom_mutators/libfuzzer/FuzzerOptions.h | 2 +- custom_mutators/libfuzzer/Makefile | 54 ++-- custom_mutators/libfuzzer/README.md | 2 +- custom_mutators/libfuzzer/libfuzzer.cpp | 2 +- 14 files changed, 387 insertions(+), 73 deletions(-) create mode 100644 custom_mutators/libfuzzer/FuzzerInterceptors.cpp create mode 100644 custom_mutators/libfuzzer/FuzzerMain.cpp (limited to 'custom_mutators/libfuzzer/FuzzerFlags.def') diff --git a/custom_mutators/libfuzzer/FuzzerDriver.cpp b/custom_mutators/libfuzzer/FuzzerDriver.cpp index 6468a02e..c79278bd 100644 --- a/custom_mutators/libfuzzer/FuzzerDriver.cpp +++ b/custom_mutators/libfuzzer/FuzzerDriver.cpp @@ -77,7 +77,7 @@ struct { } Flags; static const FlagDescription FlagDescriptions[]{ - +\ #define FUZZER_DEPRECATED_FLAG(Name) \ {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, #define FUZZER_FLAG_INT(Name, Default, Description) \ @@ -941,23 +941,12 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.EntropicNumberOfRarestFeatures = (size_t)Flags.entropic_number_of_rarest_features; Options.EntropicScalePerExecTime = Flags.entropic_scale_per_exec_time; - if (Options.Entropic) { - - if (!Options.FocusFunction.empty()) { - - Printf( - "ERROR: The parameters `--entropic` and `--focus_function` cannot " - "be used together.\n"); - exit(1); - - } - + if (!Options.FocusFunction.empty()) + Options.Entropic = false; // FocusFunction overrides entropic scheduling. + if (Options.Entropic) Printf("INFO: Running with entropic power schedule (0x%X, %d).\n", Options.EntropicFeatureFrequencyThreshold, Options.EntropicNumberOfRarestFeatures); - - } - struct EntropicOptions Entropic; Entropic.Enabled = Options.Entropic; Entropic.FeatureFrequencyThreshold = diff --git a/custom_mutators/libfuzzer/FuzzerExtFunctionsDlsym.cpp b/custom_mutators/libfuzzer/FuzzerExtFunctionsDlsym.cpp index 4a4d58fc..8009b237 100644 --- a/custom_mutators/libfuzzer/FuzzerExtFunctionsDlsym.cpp +++ b/custom_mutators/libfuzzer/FuzzerExtFunctionsDlsym.cpp @@ -45,8 +45,8 @@ namespace fuzzer { ExternalFunctions::ExternalFunctions() { \ - #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) this->NAME = - GetFnPtr < decltype(ExternalFunctions::NAME)>(#NAME, WARN) + #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr(#NAME, WARN) #include "FuzzerExtFunctions.def" diff --git a/custom_mutators/libfuzzer/FuzzerExtFunctionsWeak.cpp b/custom_mutators/libfuzzer/FuzzerExtFunctionsWeak.cpp index caf1a7ef..c7a1d05e 100644 --- a/custom_mutators/libfuzzer/FuzzerExtFunctionsWeak.cpp +++ b/custom_mutators/libfuzzer/FuzzerExtFunctionsWeak.cpp @@ -46,9 +46,10 @@ namespace fuzzer { ExternalFunctions::ExternalFunctions() { \ - #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) this->NAME = ::NAME; - CheckFnPtr(reinterpret_cast(reinterpret_cast(::NAME)), - #NAME, WARN); + #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = ::NAME; \ + CheckFnPtr(reinterpret_cast(reinterpret_cast(::NAME)), \ + #NAME, WARN); #include "FuzzerExtFunctions.def" diff --git a/custom_mutators/libfuzzer/FuzzerExtFunctionsWindows.cpp b/custom_mutators/libfuzzer/FuzzerExtFunctionsWindows.cpp index 630f352d..a727220a 100644 --- a/custom_mutators/libfuzzer/FuzzerExtFunctionsWindows.cpp +++ b/custom_mutators/libfuzzer/FuzzerExtFunctionsWindows.cpp @@ -45,16 +45,15 @@ using namespace fuzzer; #endif // LIBFUZZER_MSVC extern "C" { - - #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) -RETURN_TYPE NAME##Def FUNC_SIG { - - Printf("ERROR: Function \"%s\" not defined.\n", #NAME); - exit(1); - -} - -EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG +\ + #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE NAME##Def FUNC_SIG { \ + \ + Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ + exit(1); \ + \ + } \ + EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG #include "FuzzerExtFunctions.def" @@ -81,8 +80,8 @@ namespace fuzzer { ExternalFunctions::ExternalFunctions() { \ - #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) this->NAME = - GetFnPtr < decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN); + #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr(::NAME, ::NAME##Def, #NAME, WARN); #include "FuzzerExtFunctions.def" diff --git a/custom_mutators/libfuzzer/FuzzerFlags.def b/custom_mutators/libfuzzer/FuzzerFlags.def index c9a787e0..4d4841b1 100644 --- a/custom_mutators/libfuzzer/FuzzerFlags.def +++ b/custom_mutators/libfuzzer/FuzzerFlags.def @@ -171,8 +171,9 @@ FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed " FUZZER_FLAG_STRING(focus_function, "Experimental. " "Fuzzing will focus on inputs that trigger calls to this function. " "If -focus_function=auto and -data_flow_trace is used, libFuzzer " - "will choose the focus functions automatically.") -FUZZER_FLAG_INT(entropic, 0, "Experimental. Enables entropic power schedule.") + "will choose the focus functions automatically. Disables -entropic when " + "specified.") +FUZZER_FLAG_INT(entropic, 1, "Enables entropic power schedule.") FUZZER_FLAG_INT(entropic_feature_frequency_threshold, 0xFF, "Experimental. If " "entropic is enabled, all features which are observed less often than " "the specified value are considered as rare.") diff --git a/custom_mutators/libfuzzer/FuzzerInterceptors.cpp b/custom_mutators/libfuzzer/FuzzerInterceptors.cpp new file mode 100644 index 00000000..442ab79a --- /dev/null +++ b/custom_mutators/libfuzzer/FuzzerInterceptors.cpp @@ -0,0 +1,290 @@ +//===-- FuzzerInterceptors.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Intercept certain libc functions to aid fuzzing. +// Linked only when other RTs that define their own interceptors are not linked. +//===----------------------------------------------------------------------===// + +#include "FuzzerPlatform.h" + +#if LIBFUZZER_LINUX + + #define GET_CALLER_PC() __builtin_return_address(0) + + #define PTR_TO_REAL(x) real_##x + #define REAL(x) __interception::PTR_TO_REAL(x) + #define FUNC_TYPE(x) x##_type + #define DEFINE_REAL(ret_type, func, ...) \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __interception { \ + \ + FUNC_TYPE(func) PTR_TO_REAL(func); \ + \ + } + + #include + #include + #include // for dlsym() + +static void *getFuncAddr(const char *name, uintptr_t wrapper_addr) { + + void *addr = dlsym(RTLD_NEXT, name); + if (!addr) { + + // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is + // later in the library search order than the DSO that we are trying to + // intercept, which means that we cannot intercept this function. We still + // want the address of the real definition, though, so look it up using + // RTLD_DEFAULT. + addr = dlsym(RTLD_DEFAULT, name); + + // In case `name' is not loaded, dlsym ends up finding the actual wrapper. + // We don't want to intercept the wrapper and have it point to itself. + if (reinterpret_cast(addr) == wrapper_addr) addr = nullptr; + + } + + return addr; + +} + +static int FuzzerInited = 0; +static bool FuzzerInitIsRunning; + +static void fuzzerInit(); + +static void ensureFuzzerInited() { + + assert(!FuzzerInitIsRunning); + if (!FuzzerInited) { fuzzerInit(); } + +} + +static int internal_strcmp_strncmp(const char *s1, const char *s2, bool strncmp, + size_t n) { + + size_t i = 0; + while (true) { + + if (strncmp) { + + if (i == n) break; + i++; + + } + + unsigned c1 = *s1; + unsigned c2 = *s2; + if (c1 != c2) return (c1 < c2) ? -1 : 1; + if (c1 == 0) break; + s1++; + s2++; + + } + + return 0; + +} + +static int internal_strncmp(const char *s1, const char *s2, size_t n) { + + return internal_strcmp_strncmp(s1, s2, true, n); + +} + +static int internal_strcmp(const char *s1, const char *s2) { + + return internal_strcmp_strncmp(s1, s2, false, 0); + +} + +static int internal_memcmp(const void *s1, const void *s2, size_t n) { + + const uint8_t *t1 = static_cast(s1); + const uint8_t *t2 = static_cast(s2); + for (size_t i = 0; i < n; ++i, ++t1, ++t2) + if (*t1 != *t2) return *t1 < *t2 ? -1 : 1; + return 0; + +} + +static size_t internal_strlen(const char *s) { + + size_t i = 0; + while (s[i]) + i++; + return i; + +} + +static char *internal_strstr(const char *haystack, const char *needle) { + + // This is O(N^2), but we are not using it in hot places. + size_t len1 = internal_strlen(haystack); + size_t len2 = internal_strlen(needle); + if (len1 < len2) return nullptr; + for (size_t pos = 0; pos <= len1 - len2; pos++) { + + if (internal_memcmp(haystack + pos, needle, len2) == 0) + return const_cast(haystack) + pos; + + } + + return nullptr; + +} + +extern "C" { + +// Weak hooks forward-declared to avoid dependency on +// . +void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1, + const void *s2, size_t n, int result); +void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result); +void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result); +void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1, + const char *s2, int result); +void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, + const char *s2, int result); +void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, + const char *s2, char *result); +void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, + const char *s2, char *result); +void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, + const void *s2, size_t len2, void *result); + +DEFINE_REAL(int, bcmp, const void *, const void *, size_t) +DEFINE_REAL(int, memcmp, const void *, const void *, size_t) +DEFINE_REAL(int, strncmp, const char *, const char *, size_t) +DEFINE_REAL(int, strcmp, const char *, const char *) +DEFINE_REAL(int, strncasecmp, const char *, const char *, size_t) +DEFINE_REAL(int, strcasecmp, const char *, const char *) +DEFINE_REAL(char *, strstr, const char *, const char *) +DEFINE_REAL(char *, strcasestr, const char *, const char *) +DEFINE_REAL(void *, memmem, const void *, size_t, const void *, size_t) + +ATTRIBUTE_INTERFACE int bcmp(const char *s1, const char *s2, size_t n) { + + if (!FuzzerInited) return internal_memcmp(s1, s2, n); + int result = REAL(bcmp)(s1, s2, n); + __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result); + return result; + +} + +ATTRIBUTE_INTERFACE int memcmp(const void *s1, const void *s2, size_t n) { + + if (!FuzzerInited) return internal_memcmp(s1, s2, n); + int result = REAL(memcmp)(s1, s2, n); + __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result); + return result; + +} + +ATTRIBUTE_INTERFACE int strncmp(const char *s1, const char *s2, size_t n) { + + if (!FuzzerInited) return internal_strncmp(s1, s2, n); + int result = REAL(strncmp)(s1, s2, n); + __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1, s2, n, result); + return result; + +} + +ATTRIBUTE_INTERFACE int strcmp(const char *s1, const char *s2) { + + if (!FuzzerInited) return internal_strcmp(s1, s2); + int result = REAL(strcmp)(s1, s2); + __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1, s2, result); + return result; + +} + +ATTRIBUTE_INTERFACE int strncasecmp(const char *s1, const char *s2, size_t n) { + + ensureFuzzerInited(); + int result = REAL(strncasecmp)(s1, s2, n); + __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1, s2, n, result); + return result; + +} + +ATTRIBUTE_INTERFACE int strcasecmp(const char *s1, const char *s2) { + + ensureFuzzerInited(); + int result = REAL(strcasecmp)(s1, s2); + __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1, s2, result); + return result; + +} + +ATTRIBUTE_INTERFACE char *strstr(const char *s1, const char *s2) { + + if (!FuzzerInited) return internal_strstr(s1, s2); + char *result = REAL(strstr)(s1, s2); + __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1, s2, result); + return result; + +} + +ATTRIBUTE_INTERFACE char *strcasestr(const char *s1, const char *s2) { + + ensureFuzzerInited(); + char *result = REAL(strcasestr)(s1, s2); + __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1, s2, result); + return result; + +} + +ATTRIBUTE_INTERFACE +void *memmem(const void *s1, size_t len1, const void *s2, size_t len2) { + + ensureFuzzerInited(); + void *result = REAL(memmem)(s1, len1, s2, len2); + __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1, len1, s2, len2, result); + return result; + +} + +__attribute__((section(".preinit_array"), + used)) static void (*__local_fuzzer_preinit)(void) = fuzzerInit; + +} // extern "C" + +static void fuzzerInit() { + + assert(!FuzzerInitIsRunning); + if (FuzzerInited) return; + FuzzerInitIsRunning = true; + + REAL(bcmp) = reinterpret_cast( + getFuncAddr("bcmp", reinterpret_cast(&bcmp))); + REAL(memcmp) = reinterpret_cast( + getFuncAddr("memcmp", reinterpret_cast(&memcmp))); + REAL(strncmp) = reinterpret_cast( + getFuncAddr("strncmp", reinterpret_cast(&strncmp))); + REAL(strcmp) = reinterpret_cast( + getFuncAddr("strcmp", reinterpret_cast(&strcmp))); + REAL(strncasecmp) = reinterpret_cast( + getFuncAddr("strncasecmp", reinterpret_cast(&strncasecmp))); + REAL(strcasecmp) = reinterpret_cast( + getFuncAddr("strcasecmp", reinterpret_cast(&strcasecmp))); + REAL(strstr) = reinterpret_cast( + getFuncAddr("strstr", reinterpret_cast(&strstr))); + REAL(strcasestr) = reinterpret_cast( + getFuncAddr("strcasestr", reinterpret_cast(&strcasestr))); + REAL(memmem) = reinterpret_cast( + getFuncAddr("memmem", reinterpret_cast(&memmem))); + + FuzzerInitIsRunning = false; + FuzzerInited = 1; + +} + +#endif + diff --git a/custom_mutators/libfuzzer/FuzzerLoop.cpp b/custom_mutators/libfuzzer/FuzzerLoop.cpp index 49187b30..201883f0 100644 --- a/custom_mutators/libfuzzer/FuzzerLoop.cpp +++ b/custom_mutators/libfuzzer/FuzzerLoop.cpp @@ -752,7 +752,7 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { if (Options.Verbosity) { Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); - MD.PrintMutationSequence(); + MD.PrintMutationSequence(Options.Verbosity >= 2); Printf("\n"); } diff --git a/custom_mutators/libfuzzer/FuzzerMain.cpp b/custom_mutators/libfuzzer/FuzzerMain.cpp new file mode 100644 index 00000000..b02c88e9 --- /dev/null +++ b/custom_mutators/libfuzzer/FuzzerMain.cpp @@ -0,0 +1,26 @@ +//===- FuzzerMain.cpp - main() function and flags -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// main() and flags. +//===----------------------------------------------------------------------===// + +#include "FuzzerDefs.h" +#include "FuzzerPlatform.h" + +extern "C" { + +// This function should be defined by the user. +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +} // extern "C" + +ATTRIBUTE_INTERFACE int main(int argc, char **argv) { + + return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); + +} + diff --git a/custom_mutators/libfuzzer/FuzzerMutate.cpp b/custom_mutators/libfuzzer/FuzzerMutate.cpp index 8faf6918..eebae39b 100644 --- a/custom_mutators/libfuzzer/FuzzerMutate.cpp +++ b/custom_mutators/libfuzzer/FuzzerMutate.cpp @@ -17,7 +17,8 @@ namespace fuzzer { -const size_t Dictionary::kMaxDictSize; +const size_t Dictionary::kMaxDictSize; +static const size_t kMaxMutationsToPrint = 10; static void PrintASCII(const Word &W, const char *PrintAfter) { @@ -608,18 +609,24 @@ void MutationDispatcher::PrintRecommendedDictionary() { } -void MutationDispatcher::PrintMutationSequence() { +void MutationDispatcher::PrintMutationSequence(bool Verbose) { Printf("MS: %zd ", CurrentMutatorSequence.size()); - for (auto M : CurrentMutatorSequence) - Printf("%s-", M.Name); + size_t EntriesToPrint = + Verbose ? CurrentMutatorSequence.size() + : std::min(kMaxMutationsToPrint, CurrentMutatorSequence.size()); + for (size_t i = 0; i < EntriesToPrint; i++) + Printf("%s-", CurrentMutatorSequence[i].Name); if (!CurrentDictionaryEntrySequence.empty()) { Printf(" DE: "); - for (auto DE : CurrentDictionaryEntrySequence) { + EntriesToPrint = Verbose ? CurrentDictionaryEntrySequence.size() + : std::min(kMaxMutationsToPrint, + CurrentDictionaryEntrySequence.size()); + for (size_t i = 0; i < EntriesToPrint; i++) { Printf("\""); - PrintASCII(DE->GetW(), "\"-"); + PrintASCII(CurrentDictionaryEntrySequence[i]->GetW(), "\"-"); } diff --git a/custom_mutators/libfuzzer/FuzzerMutate.h b/custom_mutators/libfuzzer/FuzzerMutate.h index 3ce3159f..37fd6100 100644 --- a/custom_mutators/libfuzzer/FuzzerMutate.h +++ b/custom_mutators/libfuzzer/FuzzerMutate.h @@ -24,8 +24,9 @@ public: ~MutationDispatcher() {} /// Indicate that we are about to start a new sequence of mutations. void StartMutationSequence(); - /// Print the current sequence of mutations. - void PrintMutationSequence(); + /// Print the current sequence of mutations. Only prints the full sequence + /// when Verbose is true. + void PrintMutationSequence(bool Verbose = true); /// Return the current sequence of mutations. std::string MutationSequence(); /// Indicate that the current sequence of mutations was successful. diff --git a/custom_mutators/libfuzzer/FuzzerOptions.h b/custom_mutators/libfuzzer/FuzzerOptions.h index 706e1c64..20b810b2 100644 --- a/custom_mutators/libfuzzer/FuzzerOptions.h +++ b/custom_mutators/libfuzzer/FuzzerOptions.h @@ -46,7 +46,7 @@ struct FuzzingOptions { size_t MaxNumberOfRuns = -1L; int ReportSlowUnits = 10; bool OnlyASCII = false; - bool Entropic = false; + bool Entropic = true; size_t EntropicFeatureFrequencyThreshold = 0xFF; size_t EntropicNumberOfRarestFeatures = 100; bool EntropicScalePerExecTime = false; diff --git a/custom_mutators/libfuzzer/Makefile b/custom_mutators/libfuzzer/Makefile index 34a358ac..95402f6c 100644 --- a/custom_mutators/libfuzzer/Makefile +++ b/custom_mutators/libfuzzer/Makefile @@ -1,81 +1,81 @@ -#CFLAGS = -O3 -funroll-loops -fPIC -fpermissive -std=c++11 -CFLAGS = -g -O0 -fPIC -fpermissive -std=c++11 -CC ?= clang++ +CFLAGS = -g -O3 -funroll-loops -fPIC -fpermissive -std=c++11 +#CFLAGS = -g -O0 -fPIC -fpermissive -std=c++11 +CXX ?= clang++ all: libfuzzer-mutator.so FuzzerCrossOver.o: FuzzerCrossOver.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerDataFlowTrace.o: FuzzerDataFlowTrace.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerDriver.o: FuzzerDriver.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerExtFunctionsDlsym.o: FuzzerExtFunctionsDlsym.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerExtFunctionsWeak.o: FuzzerExtFunctionsWeak.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerExtFunctionsWindows.o: FuzzerExtFunctionsWindows.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerExtraCounters.o: FuzzerExtraCounters.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerFork.o: FuzzerFork.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerIO.o: FuzzerIO.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerIOPosix.o: FuzzerIOPosix.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerIOWindows.o: FuzzerIOWindows.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerLoop.o: FuzzerLoop.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerMerge.o: FuzzerMerge.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerMutate.o: FuzzerMutate.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerSHA1.o: FuzzerSHA1.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerTracePC.o: FuzzerTracePC.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerUtil.o: FuzzerUtil.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerUtilDarwin.o: FuzzerUtilDarwin.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerUtilFuchsia.o: FuzzerUtilFuchsia.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerUtilLinux.o: FuzzerUtilLinux.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerUtilPosix.o: FuzzerUtilPosix.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ FuzzerUtilWindows.o: FuzzerUtilWindows.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ libfuzzer.o: libfuzzer.cpp - $(CC) $(CFLAGS) -I../../include -I. -c $^ + $(CXX) $(CFLAGS) -I../../include -I. -c $^ libfuzzer-mutator.so: FuzzerCrossOver.o FuzzerDataFlowTrace.o FuzzerDriver.o FuzzerExtFunctionsDlsym.o FuzzerExtFunctionsWeak.o FuzzerExtFunctionsWindows.o FuzzerExtraCounters.o FuzzerFork.o FuzzerIO.o FuzzerIOPosix.o FuzzerIOWindows.o FuzzerLoop.o FuzzerMerge.o FuzzerMutate.o FuzzerSHA1.o FuzzerTracePC.o FuzzerUtil.o FuzzerUtilDarwin.o FuzzerUtilFuchsia.o FuzzerUtilLinux.o FuzzerUtilPosix.o FuzzerUtilWindows.o libfuzzer.o - $(CC) $(CFLAGS) -I../../include -I. -shared -o libfuzzer-mutator.so *.o + $(CXX) $(CFLAGS) -I../../include -I. -shared -o libfuzzer-mutator.so *.o clean: rm -f *.o *~ *.so core diff --git a/custom_mutators/libfuzzer/README.md b/custom_mutators/libfuzzer/README.md index a773da02..4783f2ca 100644 --- a/custom_mutators/libfuzzer/README.md +++ b/custom_mutators/libfuzzer/README.md @@ -21,4 +21,4 @@ are done. > Original repository: https://github.com/llvm/llvm-project > Path: compiler-rt/lib/fuzzer/*.{h|cpp} -> Source commit: d4b88ac1658d681e143482336cac27c6a74b8b24 +> Source commit: df3e903655e2499968fc7af64fb5fa52b2ee79bb diff --git a/custom_mutators/libfuzzer/libfuzzer.cpp b/custom_mutators/libfuzzer/libfuzzer.cpp index cf41af2d..5e37df66 100644 --- a/custom_mutators/libfuzzer/libfuzzer.cpp +++ b/custom_mutators/libfuzzer/libfuzzer.cpp @@ -72,7 +72,7 @@ extern "C" my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { /* When a new queue entry is added we check if there are new dictionary entries to add to honggfuzz structure */ -#if ß +#if 0 extern "C" void afl_custom_queue_new_entry(my_mutator_t * data, const uint8_t *filename_new_queue, const uint8_t *filename_orig_queue) { -- cgit 1.4.1