diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-08-01 12:59:39 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-08-04 12:40:43 +0000 |
commit | 28b1110370900897ab652cb420c371fab8857ad4 (patch) | |
tree | 41b32127d23b0df4f2add2a27e12dc87bddb260e /chromium/third_party/libFuzzer | |
parent | 399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (diff) | |
download | qtwebengine-chromium-28b1110370900897ab652cb420c371fab8857ad4.tar.gz |
BASELINE: Update Chromium to 53.0.2785.41
Also adds a few extra files for extensions.
Change-Id: Iccdd55d98660903331cf8b7b29188da781830af4
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/libFuzzer')
21 files changed, 963 insertions, 381 deletions
diff --git a/chromium/third_party/libFuzzer/BUILD.gn b/chromium/third_party/libFuzzer/BUILD.gn index 449114f922b..208a02042a6 100644 --- a/chromium/third_party/libFuzzer/BUILD.gn +++ b/chromium/third_party/libFuzzer/BUILD.gn @@ -5,12 +5,14 @@ source_set("libfuzzer") { # libfuzzer should be compiled without coverage (infinite loop in trace_cmp). configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ] - configs += [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ] + configs += + [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ] sources = [ "src/FuzzerCrossOver.cpp", "src/FuzzerDriver.cpp", + "src/FuzzerExtFunctionsDlsym.cpp", + "src/FuzzerExtFunctionsWeak.cpp", "src/FuzzerIO.cpp", - "src/FuzzerInterface.cpp", "src/FuzzerLoop.cpp", "src/FuzzerMain.cpp", "src/FuzzerMutate.cpp", @@ -20,3 +22,14 @@ source_set("libfuzzer") { "src/FuzzerUtil.cpp", ] } + +source_set("afl_driver") { + # AFL should be compiled without coverage (infinite loop in trace_cmp). + configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ] + configs += + [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ] + + sources = [ + "src/afl/afl_driver.cpp", + ] +} diff --git a/chromium/third_party/libFuzzer/src/CMakeLists.txt b/chromium/third_party/libFuzzer/src/CMakeLists.txt index 16620b06e71..16a769fafb9 100644 --- a/chromium/third_party/libFuzzer/src/CMakeLists.txt +++ b/chromium/third_party/libFuzzer/src/CMakeLists.txt @@ -1,12 +1,19 @@ -set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}") +set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS}") # Disable the coverage and sanitizer instrumentation for the fuzzer itself. -set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror") +set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror") if( LLVM_USE_SANITIZE_COVERAGE ) + if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address") + message(FATAL_ERROR + "LibFuzzer and its tests require LLVM_USE_SANITIZER=Address and " + "LLVM_USE_SANITIZE_COVERAGE=YES to be set." + ) + endif() add_library(LLVMFuzzerNoMainObjects OBJECT FuzzerCrossOver.cpp - FuzzerInterface.cpp FuzzerTraceState.cpp FuzzerDriver.cpp + FuzzerExtFunctionsDlsym.cpp + FuzzerExtFunctionsWeak.cpp FuzzerIO.cpp FuzzerLoop.cpp FuzzerMutate.cpp diff --git a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp index db520790823..08a5e19ce75 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp @@ -163,8 +163,9 @@ static bool ParseOneFlag(const char *Param) { } } } - PrintHelp(); - exit(1); + Printf("\n\nWARNING: unrecognized flag '%s'; " + "use -help=1 to list all flags\n\n", Param); + return true; } // We don't use any library to minimize dependencies. @@ -189,7 +190,7 @@ static std::mutex Mu; static void PulseThread() { while (true) { - std::this_thread::sleep_for(std::chrono::seconds(600)); + SleepSeconds(600); std::lock_guard<std::mutex> Lock(Mu); Printf("pulse...\n"); } @@ -234,6 +235,21 @@ static int RunInMultipleProcesses(const std::vector<std::string> &Args, return HasErrors ? 1 : 0; } +static void RssThread(Fuzzer *F, size_t RssLimitMb) { + while (true) { + SleepSeconds(1); + size_t Peak = GetPeakRSSMb(); + if (Peak > RssLimitMb) + F->RssLimitCallback(); + } +} + +static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { + if (!RssLimitMb) return; + std::thread T(RssThread, F, RssLimitMb); + T.detach(); +} + int RunOneTest(Fuzzer *F, const char *InputFilePath) { Unit U = FileToVector(InputFilePath); Unit PreciseSizedU(U); @@ -250,9 +266,13 @@ static bool AllInputsAreFiles() { return true; } -static int FuzzerDriver(const std::vector<std::string> &Args, - UserCallback Callback) { +int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { using namespace fuzzer; + assert(argc && argv && "Argument pointers cannot be nullptr"); + EF = new ExternalFunctions(); + if (EF->LLVMFuzzerInitialize) + EF->LLVMFuzzerInitialize(argc, argv); + const std::vector<std::string> Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); ParseFlags(Args); @@ -295,6 +315,7 @@ static int FuzzerDriver(const std::vector<std::string> &Args, Options.OnlyASCII = Flags.only_ascii; Options.OutputCSV = Flags.output_csv; Options.DetectLeaks = Flags.detect_leaks; + Options.RssLimitMb = Flags.rss_limit_mb; if (Flags.runs >= 0) Options.MaxNumberOfRuns = Flags.runs; if (!Inputs->empty()) @@ -314,6 +335,8 @@ static int FuzzerDriver(const std::vector<std::string> &Args, Options.SaveArtifacts = !DoPlainRun; Options.PrintNewCovPcs = Flags.print_new_cov_pcs; Options.PrintFinalStats = Flags.print_final_stats; + Options.TruncateUnits = Flags.truncate_units; + Options.PruneCorpus = Flags.prune_corpus; unsigned Seed = Flags.seed; // Initialize Seed. @@ -331,6 +354,8 @@ static int FuzzerDriver(const std::vector<std::string> &Args, if (U.size() <= Word::GetMaxSize()) MD.AddWordToManualDictionary(Word(U.data(), U.size())); + StartRssThread(&F, Flags.rss_limit_mb); + // Timer if (Flags.timeout > 0) SetTimer(Flags.timeout / 2 + 1); @@ -349,11 +374,12 @@ static int FuzzerDriver(const std::vector<std::string> &Args, Inputs->size(), Runs); for (auto &Path : *Inputs) { auto StartTime = system_clock::now(); + Printf("Running: %s\n", Path.c_str()); for (int Iter = 0; Iter < Runs; Iter++) RunOneTest(&F, Path.c_str()); auto StopTime = system_clock::now(); auto MS = duration_cast<milliseconds>(StopTime - StartTime).count(); - Printf("%s: %zd ms\n", Path.c_str(), (long)MS); + Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); } F.PrintFinalStats(); exit(0); @@ -397,9 +423,7 @@ static int FuzzerDriver(const std::vector<std::string> &Args, exit(0); // Don't let F destroy itself. } -int FuzzerDriver(int argc, char **argv, UserCallback Callback) { - std::vector<std::string> Args(argv, argv + argc); - return FuzzerDriver(Args, Callback); -} +// Storage for global ExternalFunctions object. +ExternalFunctions *EF = nullptr; } // namespace fuzzer diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def new file mode 100644 index 00000000000..f7dcf9b54fb --- /dev/null +++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def @@ -0,0 +1,46 @@ +//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This defines the external function pointers that +// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The +// EXT_FUNC macro must be defined at the point of inclusion. The signature of +// the macro is: +// +// EXT_FUNC(<name>, <return_type>, <function_signature>, <warn_if_missing>) +//===----------------------------------------------------------------------===// + +// Optional user functions +EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false); +EXT_FUNC(LLVMFuzzerCustomMutator, size_t, + (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed), + false); +EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, + (const uint8_t * Data1, size_t Size1, + const uint8_t * Data2, size_t Size2, + uint8_t * Out, size_t MaxOutSize, unsigned int Seed), + false); + +// Sanitizer functions +EXT_FUNC(__lsan_enable, void, (), false); +EXT_FUNC(__lsan_disable, void, (), false); +EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); +EXT_FUNC(__sanitizer_get_coverage_pc_buffer, uintptr_t, (uintptr_t**), true); +EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false); +EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int, + (void (*malloc_hook)(const volatile void *, size_t), + void (*free_hook)(const volatile void *)), + false); +EXT_FUNC(__sanitizer_get_total_unique_caller_callee_pairs, size_t, (), false); +EXT_FUNC(__sanitizer_get_total_unique_coverage, size_t, (), true); +EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t), false); +EXT_FUNC(__sanitizer_print_stack_trace, void, (), true); +EXT_FUNC(__sanitizer_reset_coverage, void, (), true); +EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true); +EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); +EXT_FUNC(__sanitizer_update_counter_bitset_and_clear_counters, uintptr_t, + (uint8_t*), false); diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h new file mode 100644 index 00000000000..2ec86cb9231 --- /dev/null +++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h @@ -0,0 +1,33 @@ +//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Defines an interface to (possibly optional) functions. +//===----------------------------------------------------------------------===// +#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H +#define LLVM_FUZZER_EXT_FUNCTIONS_H + +#include <stddef.h> +#include <stdint.h> + +namespace fuzzer { + +struct ExternalFunctions { + // Initialize function pointers. Functions that are not available will be set + // to nullptr. Do not call this constructor before ``main()`` has been + // entered. + ExternalFunctions(); + +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE(*NAME) FUNC_SIG = nullptr + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +}; +} // namespace fuzzer +#endif diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp new file mode 100644 index 00000000000..7b9681a6193 --- /dev/null +++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp @@ -0,0 +1,49 @@ +//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation for operating systems that support dlsym(). We only use it on +// Apple platforms for now. We don't use this approach on Linux because it +// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker. +// That is a complication we don't wish to expose to clients right now. +//===----------------------------------------------------------------------===// +#include "FuzzerInternal.h" +#if LIBFUZZER_APPLE + +#include "FuzzerExtFunctions.h" +#include <dlfcn.h> + +using namespace fuzzer; + +template <typename T> +static T GetFnPtr(const char *FnName, bool WarnIfMissing) { + dlerror(); // Clear any previous errors. + void *Fn = dlsym(RTLD_DEFAULT, FnName); + if (Fn == nullptr) { + if (WarnIfMissing) { + const char *ErrorMsg = dlerror(); + Printf("WARNING: Failed to find function \"%s\".", FnName); + if (ErrorMsg) + Printf(" Reason %s.", ErrorMsg); + Printf("\n"); + } + } + return reinterpret_cast<T>(Fn); +} + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr<decltype(ExternalFunctions::NAME)>(#NAME, WARN) + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} +} // namespace fuzzer +#endif // LIBFUZZER_APPLE diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp new file mode 100644 index 00000000000..75c0ed9f830 --- /dev/null +++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp @@ -0,0 +1,50 @@ +//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Implementation for Linux. This relies on the linker's support for weak +// symbols. We don't use this approach on Apple platforms because it requires +// clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow +// weak symbols to be undefined. That is a complication we don't want to expose +// to clients right now. +//===----------------------------------------------------------------------===// +#include "FuzzerInternal.h" +#if LIBFUZZER_LINUX + +#include "FuzzerExtFunctions.h" + +extern "C" { +// Declare these symbols as weak to allow them to be optionally defined. +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} + +using namespace fuzzer; + +static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) { + if (FnPtr == nullptr && WarnIfMissing) { + Printf("WARNING: Failed to find function \"%s\".\n", FnName); + } +} + +namespace fuzzer { + +ExternalFunctions::ExternalFunctions() { +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = ::NAME; \ + CheckFnPtr((void *)::NAME, #NAME, WARN); + +#include "FuzzerExtFunctions.def" + +#undef EXT_FUNC +} +} // namespace fuzzer +#endif // LIBFUZZER_LINUX diff --git a/chromium/third_party/libFuzzer/src/FuzzerFlags.def b/chromium/third_party/libFuzzer/src/FuzzerFlags.def index 86b203ce0ce..2945152ae70 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerFlags.def +++ b/chromium/third_party/libFuzzer/src/FuzzerFlags.def @@ -35,7 +35,8 @@ 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(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.") + "merged into the 1-st corpus. Only interesting units will be taken. " + "This flag can be used to minimize a corpus.") FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces") @@ -81,6 +82,11 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " "Be careful, this will also close e.g. asan's stderr/stdout.") 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(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" + "reaching this limit of RSS memory usage.") +FUZZER_FLAG_INT(truncate_units, 0, "Try truncated units when loading corpus.") +FUZZER_FLAG_INT(prune_corpus, 1, "Prune corpus items without new coverage when " + "loading corpus.") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) diff --git a/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h b/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h index ae121d238dc..eb2c219b870 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h +++ b/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <algorithm> +#include <string> #include <tuple> #include <vector> diff --git a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp index ac35d736bbf..0e0c4e989cc 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// // IO functions. //===----------------------------------------------------------------------===// +#include "FuzzerExtFunctions.h" #include "FuzzerInternal.h" #include <iterator> #include <fstream> @@ -122,6 +123,8 @@ void DupAndCloseStderr() { FILE *NewOutputFile = fdopen(OutputFd, "w"); if (NewOutputFile) { OutputFile = NewOutputFile; + if (EF->__sanitizer_set_report_fd) + EF->__sanitizer_set_report_fd(reinterpret_cast<void *>(OutputFd)); close(2); } } diff --git a/chromium/third_party/libFuzzer/src/FuzzerInterface.cpp b/chromium/third_party/libFuzzer/src/FuzzerInterface.cpp deleted file mode 100644 index 5de7d614429..00000000000 --- a/chromium/third_party/libFuzzer/src/FuzzerInterface.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===- FuzzerInterface.cpp - Mutate a test input --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Parts of public interface for libFuzzer. -//===----------------------------------------------------------------------===// - - -#include "FuzzerInterface.h" -#include "FuzzerInternal.h" -#include <random> - -namespace fuzzer { - - -} // namespace fuzzer. diff --git a/chromium/third_party/libFuzzer/src/FuzzerInterface.h b/chromium/third_party/libFuzzer/src/FuzzerInterface.h index 30620e51396..d47e20e3a2b 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerInterface.h +++ b/chromium/third_party/libFuzzer/src/FuzzerInterface.h @@ -6,75 +6,62 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// Define the interface between the Fuzzer and the library being tested. +// Define the interface between libFuzzer and the library being tested. //===----------------------------------------------------------------------===// -// WARNING: keep the interface free of STL or any other header-based C++ lib, -// to avoid bad interactions between the code used in the fuzzer and -// the code used in the target function. +// NOTE: the libFuzzer interface is thin and in the majority of cases +// you should not include this file into your target. In 95% of cases +// all you need is to define the following function in your file: +// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +// WARNING: keep the interface in C. #ifndef LLVM_FUZZER_INTERFACE_H #define LLVM_FUZZER_INTERFACE_H -#include <cstddef> -#include <cstdint> +#include <stddef.h> +#include <stdint.h> -// Plain C interface. Should be sufficient for most uses. +#ifdef __cplusplus extern "C" { -// The target function, mandatory. +#endif // __cplusplus + +// Mandatory user-provided target function. +// Executes the code under test with [Data, Data+Size) as the input. +// libFuzzer will invoke this function *many* times with different inputs. // Must return 0. int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -// The initialization function, optional. + +// Optional user-provided initialization function. +// If provided, this function will be called by libFuzzer once at startup. +// It may read and modify argc/argv. +// Must return 0. int LLVMFuzzerInitialize(int *argc, char ***argv); -// Custom mutator, optional. -// Mutates raw data in [Data, Data+Size] inplace. + +// Optional user-provided custom mutator. +// Mutates raw data in [Data, Data+Size) inplace. // Returns the new size, which is not greater than MaxSize. // Given the same Seed produces the same mutation. size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed); -} // extern "C" - -namespace fuzzer { - -/// Returns an int 0. Values other than zero are reserved for future. -typedef int (*UserCallback)(const uint8_t *Data, size_t Size); -/** Simple C-like interface with a single user-supplied callback. +// Optional user-provided custom cross-over function. +// Combines pieces of Data1 & Data2 together into Out. +// Returns the new size, which is not greater than MaxOutSize. +// Should produce the same mutation given the same Seed. +size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, + unsigned int Seed); -Usage: - -#\code -#include "FuzzerInterface.h" - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - DoStuffWithData(Data, Size); - return 0; -} - -// Optional. -// Define this only if you need to read/modify argc/argv at startup -// and you are using libFuzzer's main(). -// Must return 0. -int LLVMFuzzerInitialize(int *argc, char ***argv) { - ReadAndMaybeModify(argc, argv); - return 0; -} - -// Implement your own main() or use the one from FuzzerMain.cpp. -// *NOT* recommended for most cases. -int main(int argc, char **argv) { - InitializeMeIfNeeded(); - return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput); -} -#\endcode -*/ -int FuzzerDriver(int argc, char **argv, UserCallback Callback); - -// Mutates raw data in [Data, Data+Size] inplace. +// Experimental, may go away in future. +// libFuzzer-provided function to be used inside LLVMFuzzerTestOneInput. +// Mutates raw data in [Data, Data+Size) inplace. // Returns the new size, which is not greater than MaxSize. -// Can be used inside the user-supplied LLVMFuzzerTestOneInput. -size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); -} // namespace fuzzer +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus #endif // LLVM_FUZZER_INTERFACE_H diff --git a/chromium/third_party/libFuzzer/src/FuzzerInternal.h b/chromium/third_party/libFuzzer/src/FuzzerInternal.h index a34bfec57c1..6fb429e705e 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerInternal.h +++ b/chromium/third_party/libFuzzer/src/FuzzerInternal.h @@ -13,6 +13,7 @@ #define LLVM_FUZZER_INTERNAL_H #include <algorithm> +#include <atomic> #include <cassert> #include <chrono> #include <climits> @@ -24,9 +25,26 @@ #include <unordered_set> #include <vector> +#include "FuzzerExtFunctions.h" #include "FuzzerInterface.h" +#include "FuzzerTracePC.h" + +// Platform detection. +#ifdef __linux__ +#define LIBFUZZER_LINUX 1 +#define LIBFUZZER_APPLE 0 +#elif __APPLE__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 1 +#else +#error "Support for your platform has not been implemented" +#endif namespace fuzzer { + +typedef int (*UserCallback)(const uint8_t *Data, size_t Size); +int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); + using namespace std::chrono; typedef std::vector<uint8_t> Unit; typedef std::vector<Unit> UnitVector; @@ -106,16 +124,11 @@ void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); // Returns true iff U has been changed. bool ToASCII(uint8_t *Data, size_t Size); bool IsASCII(const Unit &U); +bool IsASCII(const uint8_t *Data, size_t Size); int NumberOfCpuCores(); int GetPid(); - -// Clears the current PC Map. -void PcMapResetCurrent(); -// Merges the current PC Map into the combined one, and clears the former. -void PcMapMergeCurrentToCombined(); -// Returns the size of the combined PC Map. -size_t PcMapCombinedSize(); +void SleepSeconds(int Seconds); class Random { public: @@ -192,7 +205,7 @@ private: class MutationDispatcher { public: - MutationDispatcher(Random &Rand) : Rand(Rand) {} + MutationDispatcher(Random &Rand); ~MutationDispatcher() {} /// Indicate that we are about to start a new sequence of mutations. void StartMutationSequence(); @@ -200,6 +213,10 @@ public: void PrintMutationSequence(); /// Indicate that the current sequence of mutations was successfull. void RecordSuccessfulMutationSequence(); + /// Mutates data by invoking user-provided mutator. + size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by invoking user-provided crossover. + size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by shuffling bytes. size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by erasing a byte. @@ -229,9 +246,12 @@ public: /// CrossOver Data with some other element of the corpus. size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); - /// Applies one of the above mutations. + /// Applies one of the configured mutations. /// Returns the new size of data which could be up to MaxSize. size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + /// Applies one of the default mutations. Provided as a service + /// to mutation authors. + size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); /// Creates a cross-over of two pieces of Data, returns its size. size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, @@ -256,6 +276,8 @@ private: size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, size_t MaxSize); + size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, + const std::vector<Mutator> &Mutators); Random &Rand; // Dictionary provided by the user via -dict=DICT_FILE. @@ -271,7 +293,8 @@ private: const std::vector<Unit> *Corpus = nullptr; std::vector<uint8_t> MutateInPlaceHere; - static Mutator Mutators[]; + std::vector<Mutator> Mutators; + std::vector<Mutator> DefaultMutators; }; class Fuzzer { @@ -283,6 +306,7 @@ public: int TimeoutExitCode = 77; int ErrorExitCode = 77; int MaxTotalTimeSec = 0; + int RssLimitMb = 0; bool DoCrossOver = true; int MutateDepth = 5; bool UseCounters = false; @@ -305,7 +329,38 @@ public: bool PrintNewCovPcs = false; bool PrintFinalStats = false; bool DetectLeaks = true; + bool TruncateUnits = false; + bool PruneCorpus = true; + }; + + // Aggregates all available coverage measurements. + struct Coverage { + Coverage() { Reset(); } + + void Reset() { + BlockCoverage = 0; + CallerCalleeCoverage = 0; + PcMapBits = 0; + CounterBitmapBits = 0; + PcBufferLen = 0; + CounterBitmap.clear(); + PCMap.Reset(); + } + + std::string DebugString() const; + + size_t BlockCoverage; + size_t CallerCalleeCoverage; + + size_t PcBufferLen; + // Precalculated number of bits in CounterBitmap. + size_t CounterBitmapBits; + std::vector<uint8_t> CounterBitmap; + // Precalculated number of bits in PCMap. + size_t PcMapBits; + PcCoverageMap PCMap; }; + Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options); void AddToCorpus(const Unit &U) { Corpus.push_back(U); @@ -313,6 +368,7 @@ public: } size_t ChooseUnitIdxToMutate(); const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; }; + void TruncateUnits(std::vector<Unit> *NewCorpus); void Loop(); void Drill(); void ShuffleAndMinimize(); @@ -353,6 +409,13 @@ public: MutationDispatcher &GetMD() { return MD; } void PrintFinalStats(); void SetMaxLen(size_t MaxLen); + void RssLimitCallback(); + + // Public for tests. + void ResetCoverage(); + + bool InFuzzingThread() const { return IsMyThread; } + size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; private: void AlarmCallback(); @@ -361,24 +424,20 @@ private: void MutateAndTestOne(); void ReportNewCoverage(const Unit &U); bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); } - void RunOneAndUpdateCorpus(uint8_t *Data, size_t Size); + void RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size); void WriteToOutputCorpus(const Unit &U); void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); void PrintStats(const char *Where, const char *End = "\n"); void PrintStatusForNewUnit(const Unit &U); void ShuffleCorpus(UnitVector *V); - void TryDetectingAMemoryLeak(uint8_t *Data, size_t Size); - void CheckForMemoryLeaks(); + void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, + bool DuringInitialCorpusExecution); // Updates the probability distribution for the units in the corpus. // Must be called whenever the corpus or unit weights are changed. void UpdateCorpusDistribution(); - size_t RecordBlockCoverage(); - size_t RecordCallerCalleeCoverage(); - void PrepareCoverageBeforeRun(); - bool CheckCoverageAfterRun(); - void ResetCoverage(); + bool UpdateMaxCoverage(); // Trace-based fuzzing: we run a unit with some kind of tracing // enabled and record potentially useful mutations. Then @@ -394,8 +453,9 @@ private: void DumpCurrentUnit(const char *Prefix); void DeathCallback(); + void LazyAllocateCurrentUnitData(); uint8_t *CurrentUnitData = nullptr; - size_t CurrentUnitSize = 0; + std::atomic<size_t> CurrentUnitSize; size_t TotalNumberOfRuns = 0; size_t NumberOfNewUnitsAdded = 0; @@ -406,17 +466,6 @@ private: std::vector<Unit> Corpus; std::unordered_set<std::string> UnitHashesAddedToCorpus; - // For UseCounters - std::vector<uint8_t> CounterBitmap; - size_t TotalBits() { // Slow. Call it only for printing stats. - size_t Res = 0; - for (auto x : CounterBitmap) - Res += __builtin_popcount(x); - return Res; - } - - std::vector<uint8_t> MutateInPlaceHere; - std::piecewise_constant_distribution<double> CorpusDistribution; UserCallback CB; MutationDispatcher &MD; @@ -425,12 +474,17 @@ private: system_clock::time_point UnitStartTime; long TimeOfLongestUnitInSeconds = 0; long EpochOfLastReadOfOutputCorpus = 0; - size_t LastRecordedBlockCoverage = 0; - size_t LastRecordedPcMapSize = 0; - size_t LastRecordedCallerCalleeCoverage = 0; - size_t LastCoveragePcBufferLen = 0; + + // Maximum recorded coverage. + Coverage MaxCoverage; + + // Need to know our own thread. + static thread_local bool IsMyThread; }; +// Global interface to functions that may or may not be available. +extern ExternalFunctions *EF; + }; // namespace fuzzer #endif // LLVM_FUZZER_INTERNAL_H diff --git a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp index 3b0b339bf9c..51cb8703c26 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp @@ -31,54 +31,119 @@ #endif #endif -extern "C" { -// Re-declare some of the sanitizer functions as "weak" so that -// libFuzzer can be linked w/o the sanitizers and sanitizer-coverage -// (in which case it will complain at start-up time). -__attribute__((weak)) void __sanitizer_print_stack_trace(); -__attribute__((weak)) void __sanitizer_reset_coverage(); -__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs(); -__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage(); -__attribute__((weak)) void -__sanitizer_set_death_callback(void (*callback)(void)); -__attribute__((weak)) size_t __sanitizer_get_number_of_counters(); -__attribute__((weak)) uintptr_t -__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); -__attribute__((weak)) uintptr_t -__sanitizer_get_coverage_pc_buffer(uintptr_t **data); - -__attribute__((weak)) size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, - size_t MaxSize, - unsigned int Seed); -__attribute__((weak)) void __sanitizer_malloc_hook(void *ptr, size_t size); -__attribute__((weak)) void __sanitizer_free_hook(void *ptr); -__attribute__((weak)) void __lsan_enable(); -__attribute__((weak)) void __lsan_disable(); -__attribute__((weak)) int __lsan_do_recoverable_leak_check(); -} - namespace fuzzer { static const size_t kMaxUnitSizeToPrint = 256; +static const size_t TruncateMaxRuns = 1000; + +thread_local bool Fuzzer::IsMyThread; -static void MissingWeakApiFunction(const char *FnName) { +static void MissingExternalApiFunction(const char *FnName) { Printf("ERROR: %s is not defined. Exiting.\n" "Did you use -fsanitize-coverage=... to build your code?\n", FnName); exit(1); } -#define CHECK_WEAK_API_FUNCTION(fn) \ +#define CHECK_EXTERNAL_FUNCTION(fn) \ do { \ - if (!fn) \ - MissingWeakApiFunction(#fn); \ + if (!(EF->fn)) \ + MissingExternalApiFunction(#fn); \ } while (false) // Only one Fuzzer per process. static Fuzzer *F; -size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { - assert(F); - return F->GetMD().Mutate(Data, Size, MaxSize); +struct CoverageController { + static void Reset() { + CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage); + EF->__sanitizer_reset_coverage(); + PcMapResetCurrent(); + } + + static void ResetCounters(const Fuzzer::FuzzingOptions &Options) { + if (Options.UseCounters) { + EF->__sanitizer_update_counter_bitset_and_clear_counters(0); + } + } + + static void Prepare(const Fuzzer::FuzzingOptions &Options, + Fuzzer::Coverage *C) { + if (Options.UseCounters) { + size_t NumCounters = EF->__sanitizer_get_number_of_counters(); + C->CounterBitmap.resize(NumCounters); + } + } + + // Records data to a maximum coverage tracker. Returns true if additional + // coverage was discovered. + static bool RecordMax(const Fuzzer::FuzzingOptions &Options, + Fuzzer::Coverage *C) { + bool Res = false; + + uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage(); + if (NewBlockCoverage > C->BlockCoverage) { + Res = true; + C->BlockCoverage = NewBlockCoverage; + } + + if (Options.UseIndirCalls && + EF->__sanitizer_get_total_unique_caller_callee_pairs) { + uint64_t NewCallerCalleeCoverage = + EF->__sanitizer_get_total_unique_caller_callee_pairs(); + if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) { + Res = true; + C->CallerCalleeCoverage = NewCallerCalleeCoverage; + } + } + + if (Options.UseCounters) { + uint64_t CounterDelta = + EF->__sanitizer_update_counter_bitset_and_clear_counters( + C->CounterBitmap.data()); + if (CounterDelta > 0) { + Res = true; + C->CounterBitmapBits += CounterDelta; + } + } + + uint64_t NewPcMapBits = PcMapMergeInto(&C->PCMap); + if (NewPcMapBits > C->PcMapBits) { + Res = true; + C->PcMapBits = NewPcMapBits; + } + + uintptr_t *CoverageBuf; + uint64_t NewPcBufferLen = + EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf); + if (NewPcBufferLen > C->PcBufferLen) { + Res = true; + C->PcBufferLen = NewPcBufferLen; + } + + return Res; + } +}; + +// Leak detection is expensive, so we first check if there were more mallocs +// than frees (using the sanitizer malloc hooks) and only then try to call lsan. +struct MallocFreeTracer { + void Start() { + Mallocs = 0; + Frees = 0; + } + // Returns true if there were more mallocs than frees. + bool Stop() { return Mallocs > Frees; } + std::atomic<size_t> Mallocs; + std::atomic<size_t> Frees; +}; + +static MallocFreeTracer AllocTracer; + +void MallocHook(const volatile void *ptr, size_t size) { + AllocTracer.Mallocs++; +} +void FreeHook(const volatile void *ptr) { + AllocTracer.Frees++; } Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options) @@ -87,11 +152,20 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options) InitializeTraceState(); assert(!F); F = this; + ResetCoverage(); + IsMyThread = true; + if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) + EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); +} + +void Fuzzer::LazyAllocateCurrentUnitData() { + if (CurrentUnitData || Options.MaxLen == 0) return; + CurrentUnitData = new uint8_t[Options.MaxLen]; } void Fuzzer::SetDeathCallback() { - CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback); - __sanitizer_set_death_callback(StaticDeathCallback); + CHECK_EXTERNAL_FUNCTION(__sanitizer_set_death_callback); + EF->__sanitizer_set_death_callback(StaticDeathCallback); } void Fuzzer::StaticDeathCallback() { @@ -100,18 +174,18 @@ void Fuzzer::StaticDeathCallback() { } void Fuzzer::DumpCurrentUnit(const char *Prefix) { - if (CurrentUnitSize <= kMaxUnitSizeToPrint) { - PrintHexArray(CurrentUnitData, CurrentUnitSize, "\n"); - PrintASCII(CurrentUnitData, CurrentUnitSize, "\n"); + if (!CurrentUnitData) return; // Happens when running individual inputs. + size_t UnitSize = CurrentUnitSize; + if (UnitSize <= kMaxUnitSizeToPrint) { + PrintHexArray(CurrentUnitData, UnitSize, "\n"); + PrintASCII(CurrentUnitData, UnitSize, "\n"); } - WriteUnitToFileWithPrefix( - {CurrentUnitData, CurrentUnitData + CurrentUnitSize}, Prefix); + WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, + Prefix); } NO_SANITIZE_MEMORY void Fuzzer::DeathCallback() { - if (!CurrentUnitSize) return; - Printf("DEATH:\n"); DumpCurrentUnit("crash-"); PrintFinalStats(); } @@ -133,8 +207,8 @@ void Fuzzer::StaticInterruptCallback() { void Fuzzer::CrashCallback() { Printf("==%d== ERROR: libFuzzer: deadly signal\n", GetPid()); - if (__sanitizer_print_stack_trace) - __sanitizer_print_stack_trace(); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" " Combine libFuzzer with AddressSanitizer or similar for better " "crash reports.\n"); @@ -153,6 +227,7 @@ void Fuzzer::InterruptCallback() { NO_SANITIZE_MEMORY void Fuzzer::AlarmCallback() { assert(Options.UnitTimeoutSec > 0); + if (!InFuzzingThread()) return; if (!CurrentUnitSize) return; // We have not started running units yet. size_t Seconds = @@ -168,14 +243,27 @@ void Fuzzer::AlarmCallback() { DumpCurrentUnit("timeout-"); Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), Seconds); - if (__sanitizer_print_stack_trace) - __sanitizer_print_stack_trace(); + if (EF->__sanitizer_print_stack_trace) + EF->__sanitizer_print_stack_trace(); Printf("SUMMARY: libFuzzer: timeout\n"); PrintFinalStats(); _Exit(Options.TimeoutExitCode); // Stop right now. } } +void Fuzzer::RssLimitCallback() { + Printf( + "==%d== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", + GetPid(), GetPeakRSSMb(), Options.RssLimitMb); + Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); + if (EF->__sanitizer_print_memory_profile) + EF->__sanitizer_print_memory_profile(50); + DumpCurrentUnit("oom-"); + Printf("SUMMARY: libFuzzer: out-of-memory\n"); + PrintFinalStats(); + _Exit(Options.ErrorExitCode); // Stop right now. +} + void Fuzzer::PrintStats(const char *Where, const char *End) { size_t ExecPerSec = execPerSec(); if (Options.OutputCSV) { @@ -185,22 +273,21 @@ void Fuzzer::PrintStats(const char *Where, const char *End) { Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n"); } Printf("%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns, - LastRecordedBlockCoverage, TotalBits(), - LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec, - Where); + MaxCoverage.BlockCoverage, MaxCoverage.CounterBitmapBits, + MaxCoverage.CallerCalleeCoverage, Corpus.size(), ExecPerSec, Where); } if (!Options.Verbosity) return; Printf("#%zd\t%s", TotalNumberOfRuns, Where); - if (LastRecordedBlockCoverage) - Printf(" cov: %zd", LastRecordedBlockCoverage); - if (LastRecordedPcMapSize) - Printf(" path: %zd", LastRecordedPcMapSize); - if (auto TB = TotalBits()) + if (MaxCoverage.BlockCoverage) + Printf(" cov: %zd", MaxCoverage.BlockCoverage); + if (MaxCoverage.PcMapBits) + Printf(" path: %zd", MaxCoverage.PcMapBits); + if (auto TB = MaxCoverage.CounterBitmapBits) Printf(" bits: %zd", TB); - if (LastRecordedCallerCalleeCoverage) - Printf(" indir: %zd", LastRecordedCallerCalleeCoverage); + if (MaxCoverage.CallerCalleeCoverage) + Printf(" indir: %zd", MaxCoverage.CallerCalleeCoverage); Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec); Printf("%s", End); } @@ -265,33 +352,99 @@ void Fuzzer::ShuffleCorpus(UnitVector *V) { }); } +// Tries random prefixes of corpus items. +// Prefix length is chosen according to exponential distribution +// to sample short lengths much more heavily. +void Fuzzer::TruncateUnits(std::vector<Unit> *NewCorpus) { + size_t MaxCorpusLen = 0; + for (const auto &U : Corpus) + MaxCorpusLen = std::max(MaxCorpusLen, U.size()); + + if (MaxCorpusLen <= 1) + return; + + // 50% of exponential distribution is Log[2]/lambda. + // Choose lambda so that median is MaxCorpusLen / 2. + double Lambda = 2.0 * log(2.0) / static_cast<double>(MaxCorpusLen); + std::exponential_distribution<> Dist(Lambda); + std::vector<double> Sizes; + size_t TruncatePoints = std::max(1ul, TruncateMaxRuns / Corpus.size()); + Sizes.reserve(TruncatePoints); + for (size_t I = 0; I < TruncatePoints; ++I) { + Sizes.push_back(Dist(MD.GetRand().Get_mt19937()) + 1); + } + std::sort(Sizes.begin(), Sizes.end()); + + for (size_t S : Sizes) { + for (const auto &U : Corpus) { + if (S < U.size() && RunOne(U.data(), S)) { + Unit U1(U.begin(), U.begin() + S); + NewCorpus->push_back(U1); + WriteToOutputCorpus(U1); + PrintStatusForNewUnit(U1); + } + } + } + PrintStats("TRUNC "); +} + void Fuzzer::ShuffleAndMinimize() { PrintStats("READ "); std::vector<Unit> NewCorpus; if (Options.ShuffleAtStartUp) ShuffleCorpus(&Corpus); + if (Options.TruncateUnits) { + ResetCoverage(); + TruncateUnits(&NewCorpus); + ResetCoverage(); + } + for (const auto &U : Corpus) { - if (RunOne(U)) { + bool NewCoverage = RunOne(U); + if (!Options.PruneCorpus || NewCoverage) { NewCorpus.push_back(U); if (Options.Verbosity >= 2) - Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size()); + Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size()); } + TryDetectingAMemoryLeak(U.data(), U.size(), + /*DuringInitialCorpusExecution*/ true); } Corpus = NewCorpus; UpdateCorpusDistribution(); for (auto &X : Corpus) UnitHashesAddedToCorpus.insert(Hash(X)); PrintStats("INITED"); - CheckForMemoryLeaks(); + if (Corpus.empty()) { + Printf("ERROR: no interesting inputs were found. " + "Is the code instrumented for coverage? Exiting.\n"); + exit(1); + } +} + +bool Fuzzer::UpdateMaxCoverage() { + uintptr_t PrevBufferLen = MaxCoverage.PcBufferLen; + bool Res = CoverageController::RecordMax(Options, &MaxCoverage); + + if (Options.PrintNewCovPcs && PrevBufferLen != MaxCoverage.PcBufferLen) { + uintptr_t *CoverageBuf; + EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf); + assert(CoverageBuf); + for (size_t I = PrevBufferLen; I < MaxCoverage.PcBufferLen; ++I) { + Printf("%p\n", CoverageBuf[I]); + } + } + + return Res; } bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) { TotalNumberOfRuns++; - PrepareCoverageBeforeRun(); + // TODO(aizatsky): this Reset call seems to be not needed. + CoverageController::ResetCounters(Options); ExecuteCallback(Data, Size); - bool Res = CheckCoverageAfterRun(); + bool Res = UpdateMaxCoverage(); auto UnitStopTime = system_clock::now(); auto TimeOfUnit = @@ -308,118 +461,58 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) { return Res; } -void Fuzzer::RunOneAndUpdateCorpus(uint8_t *Data, size_t Size) { +void Fuzzer::RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size) { if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) return; - if (Options.OnlyASCII) - ToASCII(Data, Size); if (RunOne(Data, Size)) ReportNewCoverage({Data, Data + Size}); } -// Leak detection is expensive, so we first check if there were more mallocs -// than frees (using the sanitizer malloc hooks) and only then try to call lsan. -struct MallocFreeTracer { - void Start() { - Mallocs = 0; - Frees = 0; - } - // Returns true if there were more mallocs than frees. - bool Stop() { return Mallocs > Frees; } - size_t Mallocs; - size_t Frees; -}; - -static thread_local MallocFreeTracer AllocTracer; - -extern "C" { -void __sanitizer_malloc_hook(void *ptr, size_t size) { AllocTracer.Mallocs++; } -void __sanitizer_free_hook(void *ptr) { AllocTracer.Frees++; } -} // extern "C" +size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { + assert(InFuzzingThread()); + *Data = CurrentUnitData; + return CurrentUnitSize; +} void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { + assert(InFuzzingThread()); + LazyAllocateCurrentUnitData(); UnitStartTime = system_clock::now(); // We copy the contents of Unit into a separate heap buffer // so that we reliably find buffer overflows in it. std::unique_ptr<uint8_t[]> DataCopy(new uint8_t[Size]); memcpy(DataCopy.get(), Data, Size); + if (CurrentUnitData && CurrentUnitData != Data) + memcpy(CurrentUnitData, Data, Size); AssignTaintLabels(DataCopy.get(), Size); - CurrentUnitData = DataCopy.get(); CurrentUnitSize = Size; AllocTracer.Start(); int Res = CB(DataCopy.get(), Size); (void)Res; HasMoreMallocsThanFrees = AllocTracer.Stop(); CurrentUnitSize = 0; - CurrentUnitData = nullptr; assert(Res == 0); } -size_t Fuzzer::RecordBlockCoverage() { - CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage); - uintptr_t PrevCoverage = LastRecordedBlockCoverage; - LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); - - if (PrevCoverage == LastRecordedBlockCoverage || !Options.PrintNewCovPcs) - return LastRecordedBlockCoverage; - - uintptr_t PrevBufferLen = LastCoveragePcBufferLen; - uintptr_t *CoverageBuf; - LastCoveragePcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf); - assert(CoverageBuf); - for (size_t i = PrevBufferLen; i < LastCoveragePcBufferLen; ++i) { - Printf("%p\n", CoverageBuf[i]); - } - - return LastRecordedBlockCoverage; -} - -size_t Fuzzer::RecordCallerCalleeCoverage() { - if (!Options.UseIndirCalls) - return 0; - if (!__sanitizer_get_total_unique_caller_callee_pairs) - return 0; - return LastRecordedCallerCalleeCoverage = - __sanitizer_get_total_unique_caller_callee_pairs(); -} - -void Fuzzer::PrepareCoverageBeforeRun() { - if (Options.UseCounters) { - size_t NumCounters = __sanitizer_get_number_of_counters(); - CounterBitmap.resize(NumCounters); - __sanitizer_update_counter_bitset_and_clear_counters(0); - } - RecordBlockCoverage(); - RecordCallerCalleeCoverage(); -} - -bool Fuzzer::CheckCoverageAfterRun() { - size_t OldCoverage = LastRecordedBlockCoverage; - size_t NewCoverage = RecordBlockCoverage(); - size_t OldCallerCalleeCoverage = LastRecordedCallerCalleeCoverage; - size_t NewCallerCalleeCoverage = RecordCallerCalleeCoverage(); - size_t NumNewBits = 0; - size_t OldPcMapSize = LastRecordedPcMapSize; - PcMapMergeCurrentToCombined(); - size_t NewPcMapSize = PcMapCombinedSize(); - LastRecordedPcMapSize = NewPcMapSize; - if (NewPcMapSize > OldPcMapSize) - return true; - if (Options.UseCounters) - NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters( - CounterBitmap.data()); - return NewCoverage > OldCoverage || - NewCallerCalleeCoverage > OldCallerCalleeCoverage || NumNewBits; +std::string Fuzzer::Coverage::DebugString() const { + std::string Result = + std::string("Coverage{") + "BlockCoverage=" + + std::to_string(BlockCoverage) + " CallerCalleeCoverage=" + + std::to_string(CallerCalleeCoverage) + " CounterBitmapBits=" + + std::to_string(CounterBitmapBits) + " PcMapBits=" + + std::to_string(PcMapBits) + "}"; + return Result; } void Fuzzer::WriteToOutputCorpus(const Unit &U) { + if (Options.OnlyASCII) + assert(IsASCII(U)); if (Options.OutputCorpus.empty()) return; std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); WriteToFile(U, Path); if (Options.Verbosity >= 2) Printf("Written to %s\n", Path.c_str()); - assert(!Options.OnlyASCII || IsASCII(U)); } void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { @@ -491,9 +584,10 @@ UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial, PrintStats(Stat); size_t NewSize = Corpus.size(); + assert(NewSize <= OldSize); Res.swap(Corpus); - if (NewSize == OldSize) + if (NewSize + 5 >= OldSize) break; OldSize = NewSize; } @@ -527,35 +621,20 @@ void Fuzzer::Merge(const std::vector<std::string> &Corpora) { Printf("=== Merge: written %zd units\n", Res.size()); } -// Tries to call lsan, and if there are leaks exits. We call this right after -// the initial corpus was read because if there are leaky inputs in the corpus -// further fuzzing will likely hit OOMs. -void Fuzzer::CheckForMemoryLeaks() { - if (!Options.DetectLeaks) return; - if (!__lsan_do_recoverable_leak_check) - return; - if (__lsan_do_recoverable_leak_check()) { - Printf("==%d== ERROR: libFuzzer: initial corpus triggers memory leaks.\n" - "Exiting now. Use -detect_leaks=0 to disable leak detection here.\n" - "LeakSanitizer will still check for leaks at the process exit.\n", - GetPid()); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); - } -} - // Tries detecting a memory leak on the particular input that we have just // executed before calling this function. -void Fuzzer::TryDetectingAMemoryLeak(uint8_t *Data, size_t Size) { +void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, + bool DuringInitialCorpusExecution) { if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. if (!Options.DetectLeaks) return; - if (!&__lsan_enable || !&__lsan_disable || !__lsan_do_recoverable_leak_check) + if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || + !(EF->__lsan_do_recoverable_leak_check)) return; // No lsan. // Run the target once again, but with lsan disabled so that if there is // a real leak we do not report it twice. - __lsan_disable(); - RunOneAndUpdateCorpus(Data, Size); - __lsan_enable(); + EF->__lsan_disable(); + RunOne(Data, Size); + EF->__lsan_enable(); if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. if (NumberOfLeakDetectionAttempts++ > 1000) { Options.DetectLeaks = false; @@ -568,8 +647,10 @@ void Fuzzer::TryDetectingAMemoryLeak(uint8_t *Data, size_t Size) { } // Now perform the actual lsan pass. This is expensive and we must ensure // we don't call it too often. - if (__lsan_do_recoverable_leak_check()) { // Leak is found, report it. - CurrentUnitData = Data; + if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. + if (DuringInitialCorpusExecution) + Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); + Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); CurrentUnitSize = Size; DumpCurrentUnit("leak-"); PrintFinalStats(); @@ -578,30 +659,30 @@ void Fuzzer::TryDetectingAMemoryLeak(uint8_t *Data, size_t Size) { } void Fuzzer::MutateAndTestOne() { + LazyAllocateCurrentUnitData(); MD.StartMutationSequence(); auto &U = ChooseUnitToMutate(); - MutateInPlaceHere.resize(Options.MaxLen); + assert(CurrentUnitData); size_t Size = U.size(); assert(Size <= Options.MaxLen && "Oversized Unit"); - memcpy(MutateInPlaceHere.data(), U.data(), Size); + memcpy(CurrentUnitData, U.data(), Size); for (int i = 0; i < Options.MutateDepth; i++) { size_t NewSize = 0; - if (LLVMFuzzerCustomMutator) - NewSize = LLVMFuzzerCustomMutator(MutateInPlaceHere.data(), Size, - Options.MaxLen, MD.GetRand().Rand()); - else - NewSize = MD.Mutate(MutateInPlaceHere.data(), Size, Options.MaxLen); + NewSize = MD.Mutate(CurrentUnitData, Size, Options.MaxLen); assert(NewSize > 0 && "Mutator returned empty unit"); assert(NewSize <= Options.MaxLen && "Mutator return overisized unit"); Size = NewSize; + if (Options.OnlyASCII) + ToASCII(CurrentUnitData, Size); if (i == 0) StartTraceRecording(); - RunOneAndUpdateCorpus(MutateInPlaceHere.data(), Size); + RunOneAndUpdateCorpus(CurrentUnitData, Size); StopTraceRecording(); - TryDetectingAMemoryLeak(MutateInPlaceHere.data(), Size); + TryDetectingAMemoryLeak(CurrentUnitData, Size, + /*DuringInitialCorpusExecution*/ false); } } @@ -616,9 +697,9 @@ size_t Fuzzer::ChooseUnitIdxToMutate() { } void Fuzzer::ResetCoverage() { - CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage); - __sanitizer_reset_coverage(); - CounterBitmap.clear(); + CoverageController::Reset(); + MaxCoverage.Reset(); + CoverageController::Prepare(Options, &MaxCoverage); } // Experimental search heuristic: drilling. @@ -704,3 +785,11 @@ void Fuzzer::UpdateCorpusDistribution() { } } // namespace fuzzer + +extern "C" { + +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { + assert(fuzzer::F); + return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); +} +} // extern "C" diff --git a/chromium/third_party/libFuzzer/src/FuzzerMain.cpp b/chromium/third_party/libFuzzer/src/FuzzerMain.cpp index 0d5c1132ea5..55f1687b5f0 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerMain.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerMain.cpp @@ -15,12 +15,8 @@ extern "C" { // This function should be defined by the user. int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -// This function may optionally be defined by the user. -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); } // extern "C" int main(int argc, char **argv) { - if (LLVMFuzzerInitialize) - LLVMFuzzerInitialize(&argc, &argv); - return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput); + return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); } diff --git a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp index bc10f1af49f..bd82c0dee59 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp @@ -18,21 +18,34 @@ namespace fuzzer { const size_t Dictionary::kMaxDictSize; -MutationDispatcher::Mutator MutationDispatcher::Mutators[] = { - {&MutationDispatcher::Mutate_EraseByte, "EraseByte"}, - {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, - {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, - {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, - {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, - {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, - {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, - {&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "AddFromManualDict"}, - {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, - "AddFromTempAutoDict"}, - {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "AddFromPersAutoDict"}, -}; +MutationDispatcher::MutationDispatcher(Random &Rand) : Rand(Rand) { + DefaultMutators.insert( + DefaultMutators.begin(), + { + {&MutationDispatcher::Mutate_EraseByte, "EraseByte"}, + {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, + {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, + {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, + {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, + {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, + {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, + {&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "AddFromManualDict"}, + {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, + "AddFromTempAutoDict"}, + {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, + "AddFromPersAutoDict"}, + }); + + if (EF->LLVMFuzzerCustomMutator) + Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); + else + Mutators = DefaultMutators; + + if (EF->LLVMFuzzerCustomCrossOver) + Mutators.push_back( + {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); +} static char FlipRandomBit(char X, Random &Rand) { int Bit = Rand(8); @@ -52,6 +65,30 @@ static char RandCh(Random &Rand) { return Special[Rand(sizeof(Special) - 1)]; } +size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, + size_t MaxSize) { + return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); +} + +size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (!Corpus || Corpus->size() < 2 || Size == 0) + return 0; + size_t Idx = Rand(Corpus->size()); + const Unit &Other = (*Corpus)[Idx]; + if (Other.empty()) + return 0; + MutateInPlaceHere.resize(MaxSize); + auto &U = MutateInPlaceHere; + size_t NewSize = EF->LLVMFuzzerCustomCrossOver( + Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); + if (!NewSize) + return 0; + assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); + memcpy(Data, U.data(), NewSize); + return NewSize; +} + size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize) { assert(Size); @@ -230,8 +267,19 @@ void MutationDispatcher::PrintMutationSequence() { } } -// Mutates Data in place, returns new size. size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + return MutateImpl(Data, Size, MaxSize, Mutators); +} + +size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, + size_t MaxSize) { + return MutateImpl(Data, Size, MaxSize, DefaultMutators); +} + +// Mutates Data in place, returns new size. +size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, + size_t MaxSize, + const std::vector<Mutator> &Mutators) { assert(MaxSize > 0); assert(Size <= MaxSize); if (Size == 0) { @@ -244,9 +292,7 @@ size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 10; Iter++) { - size_t NumMutators = sizeof(Mutators) / sizeof(Mutators[0]); - size_t MutatorIdx = Rand(NumMutators); - auto M = Mutators[MutatorIdx]; + auto M = Mutators[Rand(Mutators.size())]; size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); if (NewSize) { CurrentMutatorSequence.push_back(M); diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp index 1afd6e392fd..46c43d0c17f 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp @@ -15,45 +15,57 @@ #include "FuzzerInternal.h" namespace fuzzer { -static const size_t kMapSizeInBits = 65371; // Prime. -static const size_t kMapSizeInBitsAligned = 65536; // 2^16 -static const size_t kBitsInWord =(sizeof(uintptr_t) * 8); -static const size_t kMapSizeInWords = kMapSizeInBitsAligned / kBitsInWord; -static uintptr_t CurrentMap[kMapSizeInWords] __attribute__((aligned(512))); -static uintptr_t CombinedMap[kMapSizeInWords] __attribute__((aligned(512))); -static size_t CombinedMapSize; + +void PcCoverageMap::Reset() { memset(Map, 0, sizeof(Map)); } + +void PcCoverageMap::Update(uintptr_t Addr) { + uintptr_t Idx = Addr % kMapSizeInBits; + uintptr_t WordIdx = Idx / kBitsInWord; + uintptr_t BitIdx = Idx % kBitsInWord; + Map[WordIdx] |= 1UL << BitIdx; +} + +size_t PcCoverageMap::MergeFrom(const PcCoverageMap &Other) { + uintptr_t Res = 0; + for (size_t i = 0; i < kMapSizeInWords; i++) + Res += __builtin_popcountl(Map[i] |= Other.Map[i]); + return Res; +} + +static PcCoverageMap CurrentMap; static thread_local uintptr_t Prev; void PcMapResetCurrent() { if (Prev) { Prev = 0; - memset(CurrentMap, 0, sizeof(CurrentMap)); + CurrentMap.Reset(); } } -void PcMapMergeCurrentToCombined() { - if (!Prev) return; - uintptr_t Res = 0; - for (size_t i = 0; i < kMapSizeInWords; i++) - Res += __builtin_popcountl(CombinedMap[i] |= CurrentMap[i]); - CombinedMapSize = Res; +size_t PcMapMergeInto(PcCoverageMap *Map) { + if (!Prev) + return 0; + return Map->MergeFrom(CurrentMap); } -size_t PcMapCombinedSize() { return CombinedMapSize; } - static void HandlePC(uint32_t PC) { // We take 12 bits of PC and mix it with the previous PCs. uintptr_t Next = (Prev << 5) ^ (PC & 4095); - uintptr_t Idx = Next % kMapSizeInBits; - uintptr_t WordIdx = Idx / kBitsInWord; - uintptr_t BitIdx = Idx % kBitsInWord; - CurrentMap[WordIdx] |= 1UL << BitIdx; + CurrentMap.Update(Next); Prev = Next; } } // namespace fuzzer -extern "C" void __sanitizer_cov_trace_pc() { +extern "C" { +void __sanitizer_cov_trace_pc() { fuzzer::HandlePC(static_cast<uint32_t>( reinterpret_cast<uintptr_t>(__builtin_return_address(0)))); } + +void __sanitizer_cov_trace_pc_indir(int *) { + // Stub to allow linking with code built with + // -fsanitize=indirect-calls,trace-pc. + // This isn't used currently. +} +} diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.h b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h new file mode 100644 index 00000000000..47280ba7faa --- /dev/null +++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h @@ -0,0 +1,37 @@ +//===- FuzzerTracePC.h - INTERNAL - Path tracer. --------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Trace PCs. +// This module implements __sanitizer_cov_trace_pc, a callback required +// for -fsanitize-coverage=trace-pc instrumentation. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_TRACE_PC_H +#define LLVM_FUZZER_TRACE_PC_H + +namespace fuzzer { +struct PcCoverageMap { + static const size_t kMapSizeInBits = 65371; // Prime. + static const size_t kMapSizeInBitsAligned = 65536; // 2^16 + static const size_t kBitsInWord = (sizeof(uintptr_t) * 8); + static const size_t kMapSizeInWords = kMapSizeInBitsAligned / kBitsInWord; + + void Reset(); + inline void Update(uintptr_t Addr); + size_t MergeFrom(const PcCoverageMap &Other); + + uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512))); +}; + +// Clears the current PC Map. +void PcMapResetCurrent(); +// Merges the current PC Map into the combined one, and clears the former. +size_t PcMapMergeInto(PcCoverageMap *Map); +} + +#endif diff --git a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp index 8123407e98c..3ee69e43aba 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp @@ -174,15 +174,9 @@ static bool RecordingMemcmp = false; class TraceState { public: - TraceState(MutationDispatcher &MD, const Fuzzer::FuzzingOptions &Options, - uint8_t **CurrentUnitData, size_t *CurrentUnitSize) - : MD(MD), Options(Options), CurrentUnitData(CurrentUnitData), - CurrentUnitSize(CurrentUnitSize) { - // Current trace collection is not thread-friendly and it probably - // does not have to be such, but at least we should not crash in presence - // of threads. So, just ignore all traces coming from all threads but one. - IsMyThread = true; - } + TraceState(MutationDispatcher &MD, const Fuzzer::FuzzingOptions &Options, + const Fuzzer *F) + : MD(MD), Options(Options), F(F) {} LabelRange GetLabelRange(dfsan_label L); void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, @@ -201,12 +195,13 @@ class TraceState { void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases); int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, - size_t DataSize); + size_t DataSize); int TryToAddDesiredData(const uint8_t *PresentData, const uint8_t *DesiredData, size_t DataSize); void StartTraceRecording() { - if (!Options.UseTraces && !Options.UseMemcmp) return; + if (!Options.UseTraces && !Options.UseMemcmp) + return; RecordingTraces = Options.UseTraces; RecordingMemcmp = Options.UseMemcmp; NumMutations = 0; @@ -293,14 +288,11 @@ class TraceState { size_t LastDfsanLabel = 0; MutationDispatcher &MD; const Fuzzer::FuzzingOptions &Options; - uint8_t **CurrentUnitData; - size_t *CurrentUnitSize; + const Fuzzer *F; std::map<Word, size_t> AutoDictUnitCounts; size_t AutoDictAdds = 0; - static thread_local bool IsMyThread; }; -thread_local bool TraceState::IsMyThread; LabelRange TraceState::GetLabelRange(dfsan_label L) { LabelRange &LR = LabelRanges[L]; @@ -316,7 +308,7 @@ void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2, dfsan_label L1, dfsan_label L2) { assert(ReallyHaveDFSan()); - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; if (L1 == 0 && L2 == 0) return; // Not actionable. if (L1 != 0 && L2 != 0) @@ -346,7 +338,7 @@ void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1, dfsan_label L2) { assert(ReallyHaveDFSan()); - if (!RecordingMemcmp || !IsMyThread) return; + if (!RecordingMemcmp || !F->InFuzzingThread()) return; if (L1 == 0 && L2 == 0) return; // Not actionable. if (L1 != 0 && L2 != 0) @@ -365,7 +357,7 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases, dfsan_label L) { assert(ReallyHaveDFSan()); - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; if (!L) return; // Not actionable. LabelRange LR = GetLabelRange(L); size_t ValSize = ValSizeInBits / 8; @@ -391,15 +383,17 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, size_t DataSize) { if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0; + const uint8_t *UnitData; + auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData); int Res = 0; - const uint8_t *Beg = *CurrentUnitData; - const uint8_t *End = Beg + *CurrentUnitSize; + const uint8_t *Beg = UnitData; + const uint8_t *End = Beg + UnitSize; for (const uint8_t *Cur = Beg; Cur < End; Cur++) { Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize); if (!Cur) break; size_t Pos = Cur - Beg; - assert(Pos < *CurrentUnitSize); + assert(Pos < UnitSize); AddMutation(Pos, DataSize, DesiredData); AddMutation(Pos, DataSize, DesiredData + 1); AddMutation(Pos, DataSize, DesiredData - 1); @@ -412,15 +406,17 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData, const uint8_t *DesiredData, size_t DataSize) { if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0; + const uint8_t *UnitData; + auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData); int Res = 0; - const uint8_t *Beg = *CurrentUnitData; - const uint8_t *End = Beg + *CurrentUnitSize; + const uint8_t *Beg = UnitData; + const uint8_t *End = Beg + UnitSize; for (const uint8_t *Cur = Beg; Cur < End; Cur++) { Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize); if (!Cur) break; size_t Pos = Cur - Beg; - assert(Pos < *CurrentUnitSize); + assert(Pos < UnitSize); AddMutation(Pos, DataSize, DesiredData); Res++; } @@ -429,7 +425,7 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData, void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2) { - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2) return; // No reason to mutate. int Added = 0; @@ -445,7 +441,7 @@ void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, const uint8_t *Data2) { - if (!RecordingMemcmp || !IsMyThread) return; + if (!RecordingMemcmp || !F->InFuzzingThread()) return; CmpSize = std::min(CmpSize, Word::GetMaxSize()); int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize); int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize); @@ -460,7 +456,7 @@ void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases) { - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; size_t ValSize = ValSizeInBits / 8; bool TryShort = IsTwoByteData(Val); for (size_t i = 0; i < NumCases; i++) @@ -499,7 +495,7 @@ void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) { void Fuzzer::InitializeTraceState() { if (!Options.UseTraces && !Options.UseMemcmp) return; - TS = new TraceState(MD, Options, &CurrentUnitData, &CurrentUnitSize); + TS = new TraceState(MD, Options, this); } static size_t InternalStrnlen(const char *S, size_t MaxLen) { diff --git a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp index d5335616a83..c2ae94c4d3d 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp @@ -14,12 +14,16 @@ #include <iomanip> #include <sys/resource.h> #include <sys/time.h> +#include <sys/types.h> +#include <sys/syscall.h> #include <cassert> +#include <chrono> #include <cstring> #include <signal.h> #include <sstream> #include <unistd.h> #include <errno.h> +#include <thread> namespace fuzzer { @@ -109,11 +113,36 @@ void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); } void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); } int NumberOfCpuCores() { - FILE *F = popen("nproc", "r"); - int N = 0; - if (fscanf(F, "%d", &N) != 1) + const char *CmdLine = nullptr; + if (LIBFUZZER_LINUX) { + CmdLine = "nproc"; + } else if (LIBFUZZER_APPLE) { + CmdLine = "sysctl -n hw.ncpu"; + } else { + assert(0 && "NumberOfCpuCores() is not implemented for your platform"); + } + + FILE *F = popen(CmdLine, "r"); + int N = 1; + if (!F || fscanf(F, "%d", &N) != 1) { + Printf("WARNING: Failed to parse output of command \"%s\" in %s(). " + "Assuming CPU count of 1.\n", + CmdLine, __func__); + N = 1; + } + + if (pclose(F)) { + Printf("WARNING: Executing command \"%s\" failed in %s(). " + "Assuming CPU count of 1.\n", + CmdLine, __func__); + N = 1; + } + if (N < 1) { + Printf("WARNING: Reported CPU count (%d) from command \"%s\" was invalid " + "in %s(). Assuming CPU count of 1.\n", + N, CmdLine, __func__); N = 1; - fclose(F); + } return N; } @@ -135,9 +164,11 @@ bool ToASCII(uint8_t *Data, size_t Size) { return Changed; } -bool IsASCII(const Unit &U) { - for (auto X : U) - if (!(isprint(X) || isspace(X))) return false; +bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); } + +bool IsASCII(const uint8_t *Data, size_t Size) { + for (size_t i = 0; i < Size; i++) + if (!(isprint(Data[i]) || isspace(Data[i]))) return false; return true; } @@ -214,8 +245,11 @@ bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) { return true; } -int GetPid() { return getpid(); } +void SleepSeconds(int Seconds) { + std::this_thread::sleep_for(std::chrono::seconds(Seconds)); +} +int GetPid() { return getpid(); } std::string Base64(const Unit &U) { static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -249,7 +283,15 @@ size_t GetPeakRSSMb() { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage)) return 0; - return usage.ru_maxrss >> 10; + if (LIBFUZZER_LINUX) { + // ru_maxrss is in KiB + return usage.ru_maxrss >> 10; + } else if (LIBFUZZER_APPLE) { + // ru_maxrss is in bytes + return usage.ru_maxrss >> 20; + } + assert(0 && "GetPeakRSSMb() is not implemented for your platform"); + return 0; } } // namespace fuzzer diff --git a/chromium/third_party/libFuzzer/src/afl/afl_driver.cpp b/chromium/third_party/libFuzzer/src/afl/afl_driver.cpp new file mode 100644 index 00000000000..228317ca9e3 --- /dev/null +++ b/chromium/third_party/libFuzzer/src/afl/afl_driver.cpp @@ -0,0 +1,111 @@ +//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===// + +/* This file allows to fuzz libFuzzer-style target functions + (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. + +Usage: +################################################################################ +cat << EOF > test_fuzzer.cc +#include <stdint.h> +#include <stddef.h> +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size > 0 && data[0] == 'H') + if (size > 1 && data[1] == 'I') + if (size > 2 && data[2] == '!') + __builtin_trap(); + return 0; +} +EOF +# Build your target with -fsanitize-coverage=trace-pc using fresh clang. +clang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c +# Build afl-llvm-rt.o.c from the AFL distribution. +clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c +# Build this file, link it with afl-llvm-rt.o.o and the target code. +clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o +# Run AFL: +rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; +$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out +################################################################################ +*/ +#include <assert.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +// libFuzzer interface is thin, so we don't include any libFuzzer headers. +extern "C" { +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); +} + +// Notify AFL about persistent mode. +static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; +extern "C" int __afl_persistent_loop(unsigned int); +static volatile char suppress_warning2 = AFL_PERSISTENT[0]; + +// Notify AFL about deferred forkserver. +static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; +extern "C" void __afl_manual_init(); +static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; + +// Input buffer. +static const size_t kMaxAflInputSize = 1 << 20; +static uint8_t AflInputBuf[kMaxAflInputSize]; + +// If the user asks us to duplicate stderr, then do it. +static void maybe_duplicate_stderr() { + char* stderr_duplicate_filename = + getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + + if (!stderr_duplicate_filename) + return; + + FILE* stderr_duplicate_stream = + freopen(stderr_duplicate_filename, "a+", stderr); + + if (!stderr_duplicate_stream) { + fprintf(stderr, + "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME" + ); + abort(); + } +} + +int main(int argc, char **argv) { + fprintf(stderr, "Running in AFl-fuzz mode\nUsage:\n" + "afl-fuzz [afl-flags] %s [N] " + "-- run N fuzzing iterations before " + "re-spawning the process (default: 1000)\n", + argv[0]); + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + // Do any other expensive one-time initialization here. + + maybe_duplicate_stderr(); + + __afl_manual_init(); + + int N = 1000; + if (argc >= 2) + N = atoi(argv[1]); + assert(N > 0); + while (__afl_persistent_loop(N)) { + ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); + if (n_read > 0) { + // Copy AflInputBuf into a separate buffer to let asan find buffer + // overflows. Don't use unique_ptr/etc to avoid extra dependencies. + uint8_t *copy = new uint8_t[n_read]; + memcpy(copy, AflInputBuf, n_read); + LLVMFuzzerTestOneInput(copy, n_read); + delete[] copy; + } + } +} |