diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-03-08 10:28:10 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-03-20 13:40:30 +0000 |
commit | e733310db58160074f574c429d48f8308c0afe17 (patch) | |
tree | f8aef4b7e62a69928dbcf880620eece20f98c6df /chromium/third_party/libFuzzer | |
parent | 2f583e4aec1ae3a86fa047829c96b310dc12ecdf (diff) | |
download | qtwebengine-chromium-e733310db58160074f574c429d48f8308c0afe17.tar.gz |
BASELINE: Update Chromium to 56.0.2924.122
Change-Id: I4e04de8f47e47e501c46ed934c76a431c6337ced
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/libFuzzer')
29 files changed, 854 insertions, 997 deletions
diff --git a/chromium/third_party/libFuzzer/src/FuzzerCorpus.h b/chromium/third_party/libFuzzer/src/FuzzerCorpus.h index b9a06655273..355c242e1f4 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerCorpus.h +++ b/chromium/third_party/libFuzzer/src/FuzzerCorpus.h @@ -17,43 +17,71 @@ #include "FuzzerDefs.h" #include "FuzzerRandom.h" +#include "FuzzerTracePC.h" namespace fuzzer { struct InputInfo { Unit U; // The actual input data. uint8_t Sha1[kSHA1NumBytes]; // Checksum. + // Number of features that this input has and no smaller input has. + size_t NumFeatures = 0; + size_t Tmp = 0; // Used by ValidateFeatureSet. // Stats. - uintptr_t NumExecutedMutations = 0; - uintptr_t NumSuccessfullMutations = 0; + size_t NumExecutedMutations = 0; + size_t NumSuccessfullMutations = 0; + bool MayDeleteFile = false; }; class InputCorpus { public: - InputCorpus() { - Inputs.reserve(1 << 14); // Avoid too many resizes. + static const size_t kFeatureSetSize = 1 << 16; + InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) { + memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); + memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); + } + ~InputCorpus() { + for (auto II : Inputs) + delete II; } size_t size() const { return Inputs.size(); } + size_t SizeInBytes() const { + size_t Res = 0; + for (auto II : Inputs) + Res += II->U.size(); + return Res; + } + size_t NumActiveUnits() const { + size_t Res = 0; + for (auto II : Inputs) + Res += !II->U.empty(); + return Res; + } bool empty() const { return Inputs.empty(); } - const Unit &operator[] (size_t Idx) const { return Inputs[Idx].U; } - void AddToCorpus(const Unit &U) { + const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } + void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile = false) { + assert(!U.empty()); uint8_t Hash[kSHA1NumBytes]; + if (FeatureDebug) + Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); ComputeSHA1(U.data(), U.size(), Hash); - if (!Hashes.insert(Sha1ToString(Hash)).second) return; - Inputs.push_back(InputInfo()); - InputInfo &II = Inputs.back(); + Hashes.insert(Sha1ToString(Hash)); + Inputs.push_back(new InputInfo()); + InputInfo &II = *Inputs.back(); II.U = U; + II.NumFeatures = NumFeatures; + II.MayDeleteFile = MayDeleteFile; memcpy(II.Sha1, Hash, kSHA1NumBytes); UpdateCorpusDistribution(); + ValidateFeatureSet(); } - typedef const std::vector<InputInfo>::const_iterator ConstIter; - ConstIter begin() const { return Inputs.begin(); } - ConstIter end() const { return Inputs.end(); } - bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } + bool HasUnit(const std::string &H) { return Hashes.count(H); } InputInfo &ChooseUnitToMutate(Random &Rand) { - return Inputs[ChooseUnitIdxToMutate(Rand)]; + InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)]; + assert(!II.U.empty()); + return II; }; // Returns an index of random unit from the corpus to mutate. @@ -67,30 +95,119 @@ class InputCorpus { void PrintStats() { for (size_t i = 0; i < Inputs.size(); i++) { - const auto &II = Inputs[i]; + const auto &II = *Inputs[i]; Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i, Sha1ToString(II.Sha1).c_str(), II.U.size(), II.NumExecutedMutations, II.NumSuccessfullMutations); } } + void PrintFeatureSet() { + for (size_t i = 0; i < kFeatureSetSize; i++) { + if(size_t Sz = GetFeature(i)) + Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz); + } + Printf("\n\t"); + for (size_t i = 0; i < Inputs.size(); i++) + if (size_t N = Inputs[i]->NumFeatures) + Printf(" %zd=>%zd ", i, N); + Printf("\n"); + } + + void DeleteInput(size_t Idx) { + InputInfo &II = *Inputs[Idx]; + if (!OutputCorpus.empty() && II.MayDeleteFile) + DeleteFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1))); + Unit().swap(II.U); + if (FeatureDebug) + Printf("EVICTED %zd\n", Idx); + } + + bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) { + assert(NewSize); + Idx = Idx % kFeatureSetSize; + uint32_t OldSize = GetFeature(Idx); + if (OldSize == 0 || (Shrink && OldSize > NewSize)) { + if (OldSize > 0) { + size_t OldIdx = SmallestElementPerFeature[Idx]; + InputInfo &II = *Inputs[OldIdx]; + assert(II.NumFeatures > 0); + II.NumFeatures--; + if (II.NumFeatures == 0) + DeleteInput(OldIdx); + } + if (FeatureDebug) + Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize); + SmallestElementPerFeature[Idx] = Inputs.size(); + InputSizesPerFeature[Idx] = NewSize; + CountingFeatures = true; + return true; + } + return false; + } + + size_t NumFeatures() const { + size_t Res = 0; + for (size_t i = 0; i < kFeatureSetSize; i++) + Res += GetFeature(i) != 0; + return Res; + } + + void ResetFeatureSet() { + assert(Inputs.empty()); + memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); + memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); + } + private: + static const bool FeatureDebug = false; + + size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; } + + void ValidateFeatureSet() { + if (!CountingFeatures) return; + if (FeatureDebug) + PrintFeatureSet(); + for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) + if (GetFeature(Idx)) + Inputs[SmallestElementPerFeature[Idx]]->Tmp++; + for (auto II: Inputs) { + if (II->Tmp != II->NumFeatures) + Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures); + assert(II->Tmp == II->NumFeatures); + II->Tmp = 0; + } + } + // 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 N = Inputs.size(); - std::vector<double> Intervals(N + 1); - std::vector<double> Weights(N); + Intervals.resize(N + 1); + Weights.resize(N); std::iota(Intervals.begin(), Intervals.end(), 0); - std::iota(Weights.begin(), Weights.end(), 1); + if (CountingFeatures) + for (size_t i = 0; i < N; i++) + Weights[i] = Inputs[i]->NumFeatures * (i + 1); + else + std::iota(Weights.begin(), Weights.end(), 1); CorpusDistribution = std::piecewise_constant_distribution<double>( Intervals.begin(), Intervals.end(), Weights.begin()); } std::piecewise_constant_distribution<double> CorpusDistribution; + std::vector<double> Intervals; + std::vector<double> Weights; + std::unordered_set<std::string> Hashes; - std::vector<InputInfo> Inputs; + std::vector<InputInfo*> Inputs; + + bool CountingFeatures = false; + uint32_t InputSizesPerFeature[kFeatureSetSize]; + uint32_t SmallestElementPerFeature[kFeatureSetSize]; + + std::string OutputCorpus; }; } // namespace fuzzer diff --git a/chromium/third_party/libFuzzer/src/FuzzerDFSan.h b/chromium/third_party/libFuzzer/src/FuzzerDFSan.h deleted file mode 100644 index eb206ec61ce..00000000000 --- a/chromium/third_party/libFuzzer/src/FuzzerDFSan.h +++ /dev/null @@ -1,61 +0,0 @@ -//===- FuzzerDFSan.h - Internal header for the Fuzzer -----------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// DFSan interface. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_DFSAN_H -#define LLVM_FUZZER_DFSAN_H - -#define LLVM_FUZZER_SUPPORTS_DFSAN 0 -#if defined(__has_include) -# if __has_include(<sanitizer/dfsan_interface.h>) -# if defined (__linux__) -# undef LLVM_FUZZER_SUPPORTS_DFSAN -# define LLVM_FUZZER_SUPPORTS_DFSAN 1 -# include <sanitizer/dfsan_interface.h> -# endif // __linux__ -# endif -#endif // defined(__has_include) - -#if LLVM_FUZZER_SUPPORTS_DFSAN - -extern "C" { -__attribute__((weak)) -dfsan_label dfsan_create_label(const char *desc, void *userdata); -__attribute__((weak)) -void dfsan_set_label(dfsan_label label, void *addr, size_t size); -__attribute__((weak)) -void dfsan_add_label(dfsan_label label, void *addr, size_t size); -__attribute__((weak)) -const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label); -__attribute__((weak)) -dfsan_label dfsan_read_label(const void *addr, size_t size); -} // extern "C" - -namespace fuzzer { -static bool ReallyHaveDFSan() { - return &dfsan_create_label != nullptr; -} -} // namespace fuzzer -#else -// When compiling with a compiler which does not support dfsan, -// this code is still expected to build (but not necessary work). -typedef unsigned short dfsan_label; -struct dfsan_label_info { - dfsan_label l1, l2; - const char *desc; - void *userdata; -}; -namespace fuzzer { -static bool ReallyHaveDFSan() { return false; } -} // namespace fuzzer - -#endif - -#endif // LLVM_FUZZER_DFSAN_H diff --git a/chromium/third_party/libFuzzer/src/FuzzerDefs.h b/chromium/third_party/libFuzzer/src/FuzzerDefs.h index 3fc62da7ae9..287e23c7afd 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerDefs.h +++ b/chromium/third_party/libFuzzer/src/FuzzerDefs.h @@ -60,11 +60,13 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); bool IsFile(const std::string &Path); long GetEpoch(const std::string &Path); std::string FileToString(const std::string &Path); -Unit FileToVector(const std::string &Path, size_t MaxSize = 0); +Unit FileToVector(const std::string &Path, size_t MaxSize = 0, + bool ExitOnError = true); void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, - long *Epoch, size_t MaxSize); + long *Epoch, size_t MaxSize, bool ExitOnError); void WriteToFile(const Unit &U, const std::string &Path); void CopyFileToErr(const std::string &Path); +void DeleteFile(const std::string &Path); // Returns "Dir/FileName" or equivalent for the current OS. std::string DirPlusFile(const std::string &DirPath, const std::string &FileName); @@ -91,6 +93,8 @@ void SetSigIntHandler(); void SetSigTermHandler(); std::string Base64(const Unit &U); int ExecuteCommand(const std::string &Command); +bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out); + size_t GetPeakRSSMb(); // Private copy of SHA1 implementation. @@ -109,5 +113,16 @@ int NumberOfCpuCores(); int GetPid(); void SleepSeconds(int Seconds); + +struct ScopedDoingMyOwnMemmem { + ScopedDoingMyOwnMemmem(); + ~ScopedDoingMyOwnMemmem(); +}; + +inline uint8_t Bswap(uint8_t x) { return x; } +inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } +inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } +inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } + } // namespace fuzzer #endif // LLVM_FUZZER_DEFS_H diff --git a/chromium/third_party/libFuzzer/src/FuzzerDictionary.h b/chromium/third_party/libFuzzer/src/FuzzerDictionary.h index 821cf9bd001..c009838ced6 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerDictionary.h +++ b/chromium/third_party/libFuzzer/src/FuzzerDictionary.h @@ -68,6 +68,13 @@ class DictionaryEntry { size_t GetUseCount() const { return UseCount; } size_t GetSuccessCount() const {return SuccessCount; } + void Print(const char *PrintAfter = "\n") { + PrintASCII(W.data(), W.size()); + if (HasPositionHint()) + Printf("@%zd", GetPositionHint()); + Printf("%s", PrintAfter); + } + private: Word W; size_t PositionHint = std::numeric_limits<size_t>::max(); diff --git a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp index f2452dc95f2..c506361b48f 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp @@ -270,6 +270,7 @@ int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { if (MaxLen && MaxLen < U.size()) U.resize(MaxLen); F->RunOne(U.data(), U.size()); + F->TryDetectingAMemoryLeak(U.data(), U.size(), true); return 0; } @@ -342,10 +343,10 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { Unit U = FileToVector(InputFilePath); assert(U.size() > 2); Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); - Corpus->AddToCorpus(U); + Corpus->AddToCorpus(U, 0); F->SetMaxInputLen(U.size()); F->SetMaxMutationLen(U.size() - 1); - F->Loop(); + F->MinimizeCrashLoop(U); Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); exit(0); return 0; @@ -397,13 +398,16 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.UseIndirCalls = Flags.use_indir_calls; Options.UseMemcmp = Flags.use_memcmp; Options.UseMemmem = Flags.use_memmem; + Options.UseCmp = Flags.use_cmp; Options.UseValueProfile = Flags.use_value_profile; + Options.Shrink = Flags.shrink; Options.ShuffleAtStartUp = Flags.shuffle; Options.PreferSmall = Flags.prefer_small; - Options.Reload = Flags.reload; + Options.ReloadIntervalSec = Flags.reload; Options.OnlyASCII = Flags.only_ascii; Options.OutputCSV = Flags.output_csv; Options.DetectLeaks = Flags.detect_leaks; + Options.TraceMalloc = Flags.trace_malloc; Options.RssLimitMb = Flags.rss_limit_mb; if (Flags.runs >= 0) Options.MaxNumberOfRuns = Flags.runs; @@ -427,9 +431,10 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.PrintFinalStats = Flags.print_final_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; - Options.PruneCorpus = Flags.prune_corpus; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; + if (Flags.exit_on_item) + Options.ExitOnItem = Flags.exit_on_item; unsigned Seed = Flags.seed; // Initialize Seed. @@ -441,7 +446,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Random Rand(Seed); MutationDispatcher MD(Rand, Options); - InputCorpus Corpus; + InputCorpus Corpus(Options.OutputCorpus); Fuzzer F(Callback, Corpus, MD, Options); for (auto &U: Dictionary) @@ -498,7 +503,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { UnitVector InitialCorpus; for (auto &Inp : *Inputs) { Printf("Loading corpus dir: %s\n", Inp.c_str()); - ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, TemporaryMaxLen); + ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, + TemporaryMaxLen, /*ExitOnError=*/false); } if (Options.MaxLen == 0) { @@ -509,11 +515,12 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { } if (InitialCorpus.empty()) { - InitialCorpus.push_back(Unit()); + InitialCorpus.push_back(Unit({0})); if (Options.Verbosity) Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); } F.ShuffleAndMinimize(&InitialCorpus); + InitialCorpus.clear(); // Don't need this memory any more. F.Loop(); if (Flags.verbosity) diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def index e5cb3a7d9bb..b34670f85b4 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def +++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def @@ -29,8 +29,6 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, EXT_FUNC(__lsan_enable, void, (), false); EXT_FUNC(__lsan_disable, void, (), false); EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); -EXT_FUNC(__sanitizer_set_coverage_pc_buffer, void, (uintptr_t*, uintptr_t), false); -EXT_FUNC(__sanitizer_get_coverage_pc_buffer_pos, uintptr_t, (), false); 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), diff --git a/chromium/third_party/libFuzzer/src/FuzzerFlags.def b/chromium/third_party/libFuzzer/src/FuzzerFlags.def index 1d62e429b30..01f733d5226 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerFlags.def +++ b/chromium/third_party/libFuzzer/src/FuzzerFlags.def @@ -49,6 +49,8 @@ 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, 0, "Experimenta. Use CMP traces to guide mutations") +FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.") FUZZER_FLAG_INT(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.") @@ -56,8 +58,8 @@ FUZZER_FLAG_INT(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 periodically to get new units" - " discovered by other processes.") + "Reload the main corpus every <N> 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, @@ -90,13 +92,16 @@ 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(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(prune_corpus, 1, "Prune corpus items without new coverage when " - "loading corpus.") 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_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) diff --git a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp index e956b3eb91e..a70af886c2b 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp @@ -60,9 +60,9 @@ static void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, *Epoch = E; } -Unit FileToVector(const std::string &Path, size_t MaxSize) { +Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { std::ifstream T(Path); - if (!T) { + if (ExitOnError && !T) { Printf("No such directory: %s; exiting\n", Path.c_str()); exit(1); } @@ -78,6 +78,10 @@ Unit FileToVector(const std::string &Path, size_t MaxSize) { return Res; } +void DeleteFile(const std::string &Path) { + unlink(Path.c_str()); +} + std::string FileToString(const std::string &Path) { std::ifstream T(Path); return std::string((std::istreambuf_iterator<char>(T)), @@ -97,7 +101,7 @@ void WriteToFile(const Unit &U, const std::string &Path) { } void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, - long *Epoch, size_t MaxSize) { + long *Epoch, size_t MaxSize, bool ExitOnError) { long E = Epoch ? *Epoch : 0; std::vector<std::string> Files; ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); @@ -108,7 +112,9 @@ void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, NumLoaded++; if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024) Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path); - V->push_back(FileToVector(X, MaxSize)); + auto S = FileToVector(X, MaxSize, ExitOnError); + if (!S.empty()) + V->push_back(S); } } diff --git a/chromium/third_party/libFuzzer/src/FuzzerInternal.h b/chromium/third_party/libFuzzer/src/FuzzerInternal.h index 49f6a6a7cf3..1b491eaafc5 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerInternal.h +++ b/chromium/third_party/libFuzzer/src/FuzzerInternal.h @@ -42,17 +42,13 @@ public: CounterBitmapBits = 0; CounterBitmap.clear(); VPMap.Reset(); - TPCMap.Reset(); } - std::string DebugString() const; - size_t BlockCoverage; size_t CallerCalleeCoverage; // Precalculated number of bits in CounterBitmap. size_t CounterBitmapBits; std::vector<uint8_t> CounterBitmap; - ValueBitMap TPCMap; ValueBitMap VPMap; }; @@ -60,15 +56,22 @@ public: FuzzingOptions Options); ~Fuzzer(); void Loop(); + void MinimizeCrashLoop(const Unit &U); void ShuffleAndMinimize(UnitVector *V); void InitializeTraceState(); - void AssignTaintLabels(uint8_t *Data, size_t Size); void RereadOutputCorpus(size_t MaxSize); size_t secondsSinceProcessStartUp() { return duration_cast<seconds>(system_clock::now() - ProcessStartTime) .count(); } + + bool TimedOut() { + return Options.MaxTotalTimeSec > 0 && + secondsSinceProcessStartUp() > + static_cast<size_t>(Options.MaxTotalTimeSec); + } + size_t execPerSec() { size_t Seconds = secondsSinceProcessStartUp(); return Seconds ? TotalNumberOfRuns / Seconds : 0; @@ -81,7 +84,7 @@ public: static void StaticInterruptCallback(); void ExecuteCallback(const uint8_t *Data, size_t Size); - bool RunOne(const uint8_t *Data, size_t Size); + size_t RunOne(const uint8_t *Data, size_t Size); // Merge Corpora[1:] into Corpora[0]. void Merge(const std::vector<std::string> &Corpora); @@ -98,6 +101,8 @@ public: bool InFuzzingThread() const { return IsMyThread; } size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; + void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, + bool DuringInitialCorpusExecution); private: void AlarmCallback(); @@ -105,20 +110,14 @@ private: void InterruptCallback(); void MutateAndTestOne(); void ReportNewCoverage(InputInfo *II, const Unit &U); - void PrintNewPCs(); - void PrintOneNewPC(uintptr_t PC); - bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); } + size_t RunOne(const Unit &U) { return RunOne(U.data(), U.size()); } void WriteToOutputCorpus(const Unit &U); void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0); void PrintStatusForNewUnit(const Unit &U); void ShuffleCorpus(UnitVector *V); - void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, - bool DuringInitialCorpusExecution); - void AddToCorpusAndMaybeRerun(const Unit &U); - void CheckExitOnSrcPos(); - - bool UpdateMaxCoverage(); + void AddToCorpus(const Unit &U); + void CheckExitOnSrcPosOrItem(); // Trace-based fuzzing: we run a unit with some kind of tracing // enabled and record potentially useful mutations. Then @@ -166,11 +165,6 @@ private: size_t MaxInputLen = 0; size_t MaxMutationLen = 0; - // For -print_pcs - uintptr_t* PcBuffer = nullptr; - size_t PcBufferLen = 0; - size_t PcBufferPos = 0, PrevPcBufferPos = 0; - // Need to know our own thread. static thread_local bool IsMyThread; diff --git a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp index f7d4e4ef362..0d2a38b6a85 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp @@ -17,6 +17,7 @@ #include <algorithm> #include <cstring> +#include <set> #include <memory> #if defined(__has_include) @@ -63,11 +64,8 @@ void Fuzzer::ResetEdgeCoverage() { } void Fuzzer::ResetCounters() { - if (Options.UseCounters) { + if (Options.UseCounters) EF->__sanitizer_update_counter_bitset_and_clear_counters(0); - } - if (EF->__sanitizer_get_coverage_pc_buffer_pos) - PcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos(); } void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) { @@ -82,8 +80,6 @@ void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) { bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) { bool Res = false; - TPC.FinalizeTrace(); - uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage(); if (NewBlockCoverage > C->BlockCoverage) { Res = true; @@ -110,48 +106,52 @@ bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) { } } - if (TPC.UpdateCounterMap(&C->TPCMap)) - Res = true; - - if (TPC.UpdateValueProfileMap(&C->VPMap)) - Res = true; - - if (EF->__sanitizer_get_coverage_pc_buffer_pos) { - uint64_t NewPcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos(); - if (NewPcBufferPos > PcBufferPos) { - Res = true; - PcBufferPos = NewPcBufferPos; - } - - if (PcBufferLen && NewPcBufferPos >= PcBufferLen) { - Printf("ERROR: PC buffer overflow\n"); - _Exit(1); - } - } - 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() { + void Start(int TraceLevel) { + this->TraceLevel = TraceLevel; + if (TraceLevel) + Printf("MallocFreeTracer: START\n"); Mallocs = 0; Frees = 0; } // Returns true if there were more mallocs than frees. - bool Stop() { return Mallocs > Frees; } + bool Stop() { + if (TraceLevel) + Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), + Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); + bool Result = Mallocs > Frees; + Mallocs = 0; + Frees = 0; + TraceLevel = 0; + return Result; + } std::atomic<size_t> Mallocs; std::atomic<size_t> Frees; + int TraceLevel = 0; }; static MallocFreeTracer AllocTracer; void MallocHook(const volatile void *ptr, size_t size) { - AllocTracer.Mallocs++; + size_t N = AllocTracer.Mallocs++; + if (int TraceLevel = AllocTracer.TraceLevel) { + Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); + if (TraceLevel >= 2 && EF) + EF->__sanitizer_print_stack_trace(); + } } void FreeHook(const volatile void *ptr) { - AllocTracer.Frees++; + size_t N = AllocTracer.Frees++; + if (int TraceLevel = AllocTracer.TraceLevel) { + Printf("FREE[%zd] %p\n", N, ptr); + if (TraceLevel >= 2 && EF) + EF->__sanitizer_print_stack_trace(); + } } Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, @@ -161,24 +161,18 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, InitializeTraceState(); assert(!F); F = this; - TPC.ResetTotalPCCoverage(); TPC.ResetMaps(); - TPC.ResetGuards(); ResetCoverage(); IsMyThread = true; if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); TPC.SetUseCounters(Options.UseCounters); TPC.SetUseValueProfile(Options.UseValueProfile); + TPC.SetPrintNewPCs(Options.PrintNewCovPcs); - if (Options.PrintNewCovPcs) { - PcBufferLen = 1 << 24; - PcBuffer = new uintptr_t[PcBufferLen]; - EF->__sanitizer_set_coverage_pc_buffer(PcBuffer, PcBufferLen); - } if (Options.Verbosity) TPC.PrintModuleInfo(); - if (!Options.OutputCorpus.empty() && Options.Reload) + if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); MaxInputLen = MaxMutationLen = Options.MaxLen; AllocateCurrentUnitData(); @@ -303,7 +297,7 @@ void Fuzzer::RssLimitCallback() { 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); + EF->__sanitizer_print_memory_profile(95); DumpCurrentUnit("oom-"); Printf("SUMMARY: libFuzzer: out-of-memory\n"); PrintFinalStats(); @@ -328,21 +322,32 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { Printf("#%zd\t%s", TotalNumberOfRuns, Where); if (MaxCoverage.BlockCoverage) Printf(" cov: %zd", MaxCoverage.BlockCoverage); + if (size_t N = MaxCoverage.VPMap.GetNumBitsSinceLastMerge()) + Printf(" vp: %zd", N); if (size_t N = TPC.GetTotalPCCoverage()) Printf(" cov: %zd", N); - if (MaxCoverage.VPMap.GetNumBitsSinceLastMerge()) - Printf(" vp: %zd", MaxCoverage.VPMap.GetNumBitsSinceLastMerge()); if (auto TB = MaxCoverage.CounterBitmapBits) Printf(" bits: %zd", TB); - if (auto TB = MaxCoverage.TPCMap.GetNumBitsSinceLastMerge()) - Printf(" bits: %zd", MaxCoverage.TPCMap.GetNumBitsSinceLastMerge()); + if (size_t N = Corpus.NumFeatures()) + Printf( " ft: %zd", N); if (MaxCoverage.CallerCalleeCoverage) Printf(" indir: %zd", MaxCoverage.CallerCalleeCoverage); - if (size_t N = Corpus.size()) - Printf(" units: %zd", N); + if (!Corpus.empty()) { + Printf(" corp: %zd", Corpus.NumActiveUnits()); + if (size_t N = Corpus.SizeInBytes()) { + if (N < (1<<14)) + Printf("/%zdb", N); + else if (N < (1 << 24)) + Printf("/%zdKb", N >> 10); + else + Printf("/%zdMb", N >> 20); + } + } if (Units) Printf(" units: %zd", Units); + Printf(" exec/s: %zd", ExecPerSec); + Printf(" rss: %zdMb", GetPeakRSSMb()); Printf("%s", End); } @@ -374,52 +379,52 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { this->MaxMutationLen = MaxMutationLen; } -void Fuzzer::CheckExitOnSrcPos() { +void Fuzzer::CheckExitOnSrcPosOrItem() { if (!Options.ExitOnSrcPos.empty()) { - uintptr_t *PCIDs; - if (size_t NumNewPCIDs = TPC.GetNewPCIDs(&PCIDs)) { - for (size_t i = 0; i < NumNewPCIDs; i++) { - std::string Descr = DescribePC("%L", TPC.GetPCbyPCID(PCIDs[i])); - if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { - Printf("INFO: found line matching '%s', exiting.\n", - Options.ExitOnSrcPos.c_str()); - _Exit(0); - } + static auto *PCsSet = new std::set<uintptr_t>; + for (size_t i = 1, N = TPC.GetNumPCs(); i < N; i++) { + uintptr_t PC = TPC.GetPC(i); + if (!PC) continue; + if (!PCsSet->insert(PC).second) continue; + std::string Descr = DescribePC("%L", PC); + if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { + Printf("INFO: found line matching '%s', exiting.\n", + Options.ExitOnSrcPos.c_str()); + _Exit(0); } } } -} - -void Fuzzer::AddToCorpusAndMaybeRerun(const Unit &U) { - CheckExitOnSrcPos(); - Corpus.AddToCorpus(U); - if (TPC.GetTotalPCCoverage()) { - TPC.ResetMaps(); - TPC.ResetGuards(); - ExecuteCallback(U.data(), U.size()); - TPC.FinalizeTrace(); - TPC.UpdateFeatureSet(Corpus.size() - 1, U.size()); - // TPC.PrintFeatureSet(); + if (!Options.ExitOnItem.empty()) { + if (Corpus.HasUnit(Options.ExitOnItem)) { + Printf("INFO: found item with checksum '%s', exiting.\n", + Options.ExitOnItem.c_str()); + _Exit(0); + } } } void Fuzzer::RereadOutputCorpus(size_t MaxSize) { - if (Options.OutputCorpus.empty() || !Options.Reload) return; + if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; std::vector<Unit> AdditionalCorpus; ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, - &EpochOfLastReadOfOutputCorpus, MaxSize); + &EpochOfLastReadOfOutputCorpus, MaxSize, + /*ExitOnError*/ false); if (Options.Verbosity >= 2) Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); - for (auto &X : AdditionalCorpus) { - if (X.size() > MaxSize) - X.resize(MaxSize); - if (!Corpus.HasUnit(X)) { - if (RunOne(X)) { - AddToCorpusAndMaybeRerun(X); - PrintStats("RELOAD"); + bool Reloaded = false; + for (auto &U : AdditionalCorpus) { + if (U.size() > MaxSize) + U.resize(MaxSize); + if (!Corpus.HasUnit(U)) { + if (size_t NumFeatures = RunOne(U)) { + CheckExitOnSrcPosOrItem(); + Corpus.AddToCorpus(U, NumFeatures); + Reloaded = true; } } } + if (Reloaded) + PrintStats("RELOAD"); } void Fuzzer::ShuffleCorpus(UnitVector *V) { @@ -435,10 +440,14 @@ void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { if (Options.ShuffleAtStartUp) ShuffleCorpus(InitialCorpus); + // Test the callback with empty input and never try it again. + uint8_t dummy; + ExecuteCallback(&dummy, 0); + for (const auto &U : *InitialCorpus) { - bool NewCoverage = RunOne(U); - if (!Options.PruneCorpus || NewCoverage) { - AddToCorpusAndMaybeRerun(U); + if (size_t NumFeatures = RunOne(U)) { + CheckExitOnSrcPosOrItem(); + Corpus.AddToCorpus(U, NumFeatures); if (Options.Verbosity >= 2) Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size()); } @@ -453,18 +462,22 @@ void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { } } -bool Fuzzer::UpdateMaxCoverage() { - PrevPcBufferPos = PcBufferPos; - bool Res = RecordMaxCoverage(&MaxCoverage); - - return Res; -} - -bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) { +size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) { + if (!Size) return 0; TotalNumberOfRuns++; ExecuteCallback(Data, Size); - bool Res = UpdateMaxCoverage(); + + size_t Res = 0; + if (size_t NumFeatures = TPC.FinalizeTrace(&Corpus, Size, Options.Shrink)) + Res = NumFeatures; + + if (!TPC.UsingTracePcGuard()) { + if (TPC.UpdateValueProfileMap(&MaxCoverage.VPMap)) + Res = 1; + if (!Res && RecordMaxCoverage(&MaxCoverage)) + Res = 1; + } auto TimeOfUnit = duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); @@ -494,13 +507,11 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { memcpy(DataCopy, Data, Size); if (CurrentUnitData && CurrentUnitData != Data) memcpy(CurrentUnitData, Data, Size); - AssignTaintLabels(DataCopy, Size); CurrentUnitSize = Size; - AllocTracer.Start(); + AllocTracer.Start(Options.TraceMalloc); UnitStartTime = system_clock::now(); ResetCounters(); // Reset coverage right before the callback. TPC.ResetMaps(); - TPC.ResetGuards(); int Res = CB(DataCopy, Size); UnitStopTime = system_clock::now(); (void)Res; @@ -510,16 +521,6 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { delete[] DataCopy; } -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) + " VPMapBits " + - std::to_string(VPMap.GetNumBitsSinceLastMerge()) + "}"; - return Result; -} - void Fuzzer::WriteToOutputCorpus(const Unit &U) { if (Options.OnlyASCII) assert(IsASCII(U)); @@ -555,34 +556,13 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U) { } } -void Fuzzer::PrintOneNewPC(uintptr_t PC) { - PrintPC("\tNEW_PC: %p %F %L\n", - "\tNEW_PC: %p\n", PC); -} - -void Fuzzer::PrintNewPCs() { - if (!Options.PrintNewCovPcs) return; - if (PrevPcBufferPos != PcBufferPos) { - int NumPrinted = 0; - for (size_t I = PrevPcBufferPos; I < PcBufferPos; ++I) { - if (NumPrinted++ > 30) break; // Don't print too many new PCs. - PrintOneNewPC(PcBuffer[I]); - } - } - uintptr_t *PCIDs; - if (size_t NumNewPCIDs = TPC.GetNewPCIDs(&PCIDs)) - for (size_t i = 0; i < NumNewPCIDs; i++) - PrintOneNewPC(TPC.GetPCbyPCID(PCIDs[i])); -} - void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { II->NumSuccessfullMutations++; MD.RecordSuccessfulMutationSequence(); PrintStatusForNewUnit(U); WriteToOutputCorpus(U); NumberOfNewUnitsAdded++; - PrintNewPCs(); - AddToCorpusAndMaybeRerun(U); + TPC.PrintNewPCs(); } // Finds minimal number of units in 'Extra' that add coverage to 'Initial'. @@ -597,16 +577,20 @@ UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial, for (int Iter = 0; Iter < 10; Iter++) { ShuffleCorpus(&Res); TPC.ResetMaps(); - TPC.ResetGuards(); + Corpus.ResetFeatureSet(); ResetCoverage(); - for (auto &U : Initial) + for (auto &U : Initial) { + TPC.ResetMaps(); RunOne(U); + } Tmp.clear(); - for (auto &U : Res) + for (auto &U : Res) { + TPC.ResetMaps(); if (RunOne(U)) Tmp.push_back(U); + } char Stat[7] = "MIN "; Stat[3] = '0' + Iter; @@ -633,9 +617,9 @@ void Fuzzer::Merge(const std::vector<std::string> &Corpora) { assert(MaxInputLen > 0); UnitVector Initial, Extra; - ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, MaxInputLen); + ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, MaxInputLen, true); for (auto &C : ExtraCorpora) - ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, MaxInputLen); + ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, MaxInputLen, true); if (!Initial.empty()) { Printf("=== Minimizing the initial corpus of %zd units\n", Initial.size()); @@ -663,7 +647,7 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, // Run the target once again, but with lsan disabled so that if there is // a real leak we do not report it twice. EF->__lsan_disable(); - RunOne(Data, Size); + ExecuteCallback(Data, Size); EF->__lsan_enable(); if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. if (NumberOfLeakDetectionAttempts++ > 1000) { @@ -671,6 +655,8 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" " Most likely the target function accumulates allocated\n" " memory in a global state w/o actually leaking it.\n" + " You may try running this binary with -trace_malloc=[12]" + " to get a trace of mallocs and frees.\n" " If LeakSanitizer is enabled in this process it will still\n" " run on the process shutdown.\n"); return; @@ -712,8 +698,12 @@ void Fuzzer::MutateAndTestOne() { if (i == 0) StartTraceRecording(); II.NumExecutedMutations++; - if (RunOne(CurrentUnitData, Size)) + if (size_t NumFeatures = RunOne(CurrentUnitData, Size)) { + Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size}, NumFeatures, + /*MayDeleteFile=*/true); ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); + CheckExitOnSrcPosOrItem(); + } StopTraceRecording(); TryDetectingAMemoryLeak(CurrentUnitData, Size, /*DuringInitialCorpusExecution*/ false); @@ -732,16 +722,14 @@ void Fuzzer::Loop() { MD.SetCorpus(&Corpus); while (true) { auto Now = system_clock::now(); - if (duration_cast<seconds>(Now - LastCorpusReload).count()) { + if (duration_cast<seconds>(Now - LastCorpusReload).count() >= + Options.ReloadIntervalSec) { RereadOutputCorpus(MaxInputLen); - LastCorpusReload = Now; + LastCorpusReload = system_clock::now(); } if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) break; - if (Options.MaxTotalTimeSec > 0 && - secondsSinceProcessStartUp() > - static_cast<size_t>(Options.MaxTotalTimeSec)) - break; + if (TimedOut()) break; // Perform several mutations and runs. MutateAndTestOne(); } @@ -750,6 +738,21 @@ void Fuzzer::Loop() { MD.PrintRecommendedDictionary(); } +void Fuzzer::MinimizeCrashLoop(const Unit &U) { + if (U.size() <= 2) return; + while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { + MD.StartMutationSequence(); + memcpy(CurrentUnitData, U.data(), U.size()); + for (int i = 0; i < Options.MutateDepth; i++) { + size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); + assert(NewSize > 0 && NewSize <= MaxMutationLen); + RunOne(CurrentUnitData, NewSize); + TryDetectingAMemoryLeak(CurrentUnitData, NewSize, + /*DuringInitialCorpusExecution*/ false); + } + } +} + } // namespace fuzzer extern "C" { diff --git a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp index e3b35d4de81..0109f5104fe 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp @@ -43,12 +43,15 @@ MutationDispatcher::MutationDispatcher(Random &Rand, {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, {&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "AddFromManualDict"}, + "ManualDict"}, {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, - "AddFromTempAutoDict"}, + "TempAutoDict"}, {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "AddFromPersAutoDict"}, + "PersAutoDict"}, }); + if(Options.UseCmp) + DefaultMutators.push_back( + {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); if (EF->LLVMFuzzerCustomMutator) Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); @@ -171,19 +174,13 @@ size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary( return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize); } -size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( - uint8_t *Data, size_t Size, size_t MaxSize) { - return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); -} - -size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, - size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; - if (D.empty()) return 0; - DictionaryEntry &DE = D[Rand(D.size())]; +size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size, + size_t MaxSize, + DictionaryEntry &DE) { const Word &W = DE.GetW(); bool UsePositionHint = DE.HasPositionHint() && - DE.GetPositionHint() + W.size() < Size && Rand.RandBool(); + DE.GetPositionHint() + W.size() < Size && + Rand.RandBool(); if (Rand.RandBool()) { // Insert W. if (Size + W.size() > MaxSize) return 0; size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1); @@ -195,6 +192,84 @@ size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size()); memcpy(Data + Idx, W.data(), W.size()); } + return Size; +} + +// Somewhere in the past we have observed a comparison instructions +// with arguments Arg1 Arg2. This function tries to guess a dictionary +// entry that will satisfy that comparison. +// It first tries to find one of the arguments (possibly swapped) in the +// input and if it succeeds it creates a DE with a position hint. +// Otherwise it creates a DE with one of the arguments w/o a position hint. +template <class T> +DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( + T Arg1, T Arg2, const uint8_t *Data, size_t Size) { + ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem; + bool HandleFirst = Rand.RandBool(); + T ExistingBytes, DesiredBytes; + Word W; + const uint8_t *End = Data + Size; + for (int Arg = 0; Arg < 2; Arg++) { + ExistingBytes = HandleFirst ? Arg1 : Arg2; + DesiredBytes = HandleFirst ? Arg2 : Arg1; + DesiredBytes += Rand(-1, 1); + if (Rand.RandBool()) ExistingBytes = Bswap(ExistingBytes); + if (Rand.RandBool()) DesiredBytes = Bswap(DesiredBytes); + HandleFirst = !HandleFirst; + W.Set(reinterpret_cast<uint8_t*>(&DesiredBytes), sizeof(T)); + const size_t kMaxNumPositions = 8; + size_t Positions[kMaxNumPositions]; + size_t NumPositions = 0; + for (const uint8_t *Cur = Data; + Cur < End && NumPositions < kMaxNumPositions; Cur++) { + Cur = (uint8_t *)memmem(Cur, End - Cur, &ExistingBytes, sizeof(T)); + if (!Cur) break; + Positions[NumPositions++] = Cur - Data; + } + if (!NumPositions) break; + return DictionaryEntry(W, Positions[Rand(NumPositions)]); + } + DictionaryEntry DE(W); + return DE; +} + +size_t MutationDispatcher::Mutate_AddWordFromTORC( + uint8_t *Data, size_t Size, size_t MaxSize) { + Word W; + DictionaryEntry DE; + if (Rand.RandBool()) { + auto X = TPC.TORC8.Get(Rand.Rand()); + DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); + } else { + auto X = TPC.TORC4.Get(Rand.Rand()); + if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool()) + DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, + Size); + else + DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); + } + Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); + if (!Size) return 0; + DictionaryEntry &DERef = + CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ % + kCmpDictionaryEntriesDequeSize]; + DERef = DE; + CurrentDictionaryEntrySequence.push_back(&DERef); + return Size; +} + +size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( + uint8_t *Data, size_t Size, size_t MaxSize) { + return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); +} + +size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, + size_t Size, size_t MaxSize) { + if (Size > MaxSize) return 0; + if (D.empty()) return 0; + DictionaryEntry &DE = D[Rand(D.size())]; + Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); + if (!Size) return 0; DE.IncUseCount(); CurrentDictionaryEntrySequence.push_back(&DE); return Size; @@ -284,26 +359,27 @@ size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, return Size; } -uint8_t Bswap(uint8_t x) { return x; } -uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } -uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } -uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } - template<class T> size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { if (Size < sizeof(T)) return 0; size_t Off = Rand(Size - sizeof(T) + 1); assert(Off + sizeof(T) <= Size); T Val; - memcpy(&Val, Data + Off, sizeof(Val)); - T Add = Rand(21); - Add -= 10; - if (Rand.RandBool()) - Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. - else - Val = Val + Add; // Add assuming current endiannes. - if (Add == 0 || Rand.RandBool()) // Maybe negate. - Val = -Val; + if (Off < 64 && !Rand(4)) { + Val = Size; + if (Rand.RandBool()) + Val = Bswap(Val); + } else { + memcpy(&Val, Data + Off, sizeof(Val)); + T Add = Rand(21); + Add -= 10; + if (Rand.RandBool()) + Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. + else + Val = Val + Add; // Add assuming current endiannes. + if (Add == 0 || Rand.RandBool()) // Maybe negate. + Val = -Val; + } memcpy(Data + Off, &Val, sizeof(Val)); return Size; } diff --git a/chromium/third_party/libFuzzer/src/FuzzerMutate.h b/chromium/third_party/libFuzzer/src/FuzzerMutate.h index f8611a77124..d3c0b001246 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerMutate.h +++ b/chromium/third_party/libFuzzer/src/FuzzerMutate.h @@ -55,6 +55,9 @@ public: size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by adding a word from the TORC. + size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by adding a word from the persistent automatic dictionary. size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size, size_t MaxSize); @@ -104,6 +107,12 @@ private: size_t ToSize, size_t MaxToSize); size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, size_t ToSize); + size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize, + DictionaryEntry &DE); + + template <class T> + DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2, + const uint8_t *Data, size_t Size); Random &Rand; const FuzzingOptions &Options; @@ -116,8 +125,14 @@ private: // Persistent dictionary modified by the fuzzer, consists of // entries that led to successfull discoveries in the past mutations. Dictionary PersistentAutoDictionary; + std::vector<Mutator> CurrentMutatorSequence; std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence; + + static const size_t kCmpDictionaryEntriesDequeSize = 16; + DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; + size_t CmpDictionaryEntriesDequeIdx = 0; + const InputCorpus *Corpus = nullptr; std::vector<uint8_t> MutateInPlaceHere; diff --git a/chromium/third_party/libFuzzer/src/FuzzerOptions.h b/chromium/third_party/libFuzzer/src/FuzzerOptions.h index 56c35aa5253..59126a231e3 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerOptions.h +++ b/chromium/third_party/libFuzzer/src/FuzzerOptions.h @@ -30,8 +30,10 @@ struct FuzzingOptions { bool UseIndirCalls = true; bool UseMemcmp = true; bool UseMemmem = true; + bool UseCmp = false; bool UseValueProfile = false; - bool Reload = true; + bool Shrink = false; + int ReloadIntervalSec = 1; bool ShuffleAtStartUp = true; bool PreferSmall = true; size_t MaxNumberOfRuns = -1L; @@ -41,6 +43,7 @@ struct FuzzingOptions { std::string ArtifactPrefix = "./"; std::string ExactArtifactPath; std::string ExitOnSrcPos; + std::string ExitOnItem; bool SaveArtifacts = true; bool PrintNEW = true; // Print a status line when new units are found; bool OutputCSV = false; @@ -49,7 +52,7 @@ struct FuzzingOptions { bool PrintCorpusStats = false; bool PrintCoverage = false; bool DetectLeaks = true; - bool PruneCorpus = true; + int TraceMalloc = 0; }; } // namespace fuzzer diff --git a/chromium/third_party/libFuzzer/src/FuzzerRandom.h b/chromium/third_party/libFuzzer/src/FuzzerRandom.h index c7714181571..b1be0bb935f 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerRandom.h +++ b/chromium/third_party/libFuzzer/src/FuzzerRandom.h @@ -21,6 +21,11 @@ class Random { size_t Rand() { return R(); } size_t RandBool() { return Rand() % 2; } size_t operator()(size_t n) { return n ? Rand() % n : 0; } + intptr_t operator()(intptr_t From, intptr_t To) { + assert(From < To); + intptr_t RangeSize = To - From + 1; + return operator()(RangeSize) + From; + } std::mt19937 &Get_mt19937() { return R; } private: std::mt19937 R; diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp index 9789d5df852..e61d5e0cdb6 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp @@ -12,7 +12,14 @@ // //===----------------------------------------------------------------------===// +#include <map> +#include <set> +#include <sstream> + +#include "FuzzerCorpus.h" #include "FuzzerDefs.h" +#include "FuzzerDictionary.h" +#include "FuzzerExtFunctions.h" #include "FuzzerTracePC.h" #include "FuzzerValueBitMap.h" @@ -20,33 +27,25 @@ namespace fuzzer { TracePC TPC; -void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) { - uintptr_t Idx = *Guard; +void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) { + uint32_t Idx = *Guard; if (!Idx) return; - uint8_t *CounterPtr = &Counters[Idx % kNumCounters]; - uint8_t Counter = *CounterPtr; - if (Counter == 0) { - if (!PCs[Idx]) { - AddNewPCID(Idx); - TotalPCCoverage++; - PCs[Idx] = PC; - } - } - if (UseCounters) { - if (Counter < 128) - *CounterPtr = Counter + 1; - else - *Guard = 0; - } else { - *CounterPtr = 1; - *Guard = 0; - } + PCs[Idx % kNumPCs] = PC; + Counters[Idx % kNumCounters]++; +} + +size_t TracePC::GetTotalPCCoverage() { + size_t Res = 0; + for (size_t i = 1; i < GetNumPCs(); i++) + if (PCs[i]) + Res++; + return Res; } -void TracePC::HandleInit(uintptr_t *Start, uintptr_t *Stop) { +void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { if (Start == Stop || *Start) return; assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); - for (uintptr_t *P = Start; P < Stop; P++) + for (uint32_t *P = Start; P < Stop; P++) *P = ++NumGuards; Modules[NumModules].Start = Start; Modules[NumModules].Stop = Stop; @@ -60,91 +59,227 @@ void TracePC::PrintModuleInfo() { Printf("\n"); } -void TracePC::ResetGuards() { - uintptr_t N = 0; - for (size_t M = 0; M < NumModules; M++) - for (uintptr_t *X = Modules[M].Start; X < Modules[M].Stop; X++) - *X = ++N; - assert(N == NumGuards); -} - -void TracePC::FinalizeTrace() { - if (TotalPCCoverage) { - const size_t Step = 8; - assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0); - size_t N = Min(kNumCounters, NumGuards + 1); - N = (N + Step - 1) & ~(Step - 1); // Round up. - for (size_t Idx = 0; Idx < N; Idx += Step) { - uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]); - if (!Bundle) continue; - for (size_t i = Idx; i < Idx + Step; i++) { - uint8_t Counter = (Bundle >> (i * 8)) & 0xff; - if (!Counter) continue; - Counters[i] = 0; - unsigned Bit = 0; - /**/ if (Counter >= 128) Bit = 7; - else if (Counter >= 32) Bit = 6; - else if (Counter >= 16) Bit = 5; - else if (Counter >= 8) Bit = 4; - else if (Counter >= 4) Bit = 3; - else if (Counter >= 3) Bit = 2; - else if (Counter >= 2) Bit = 1; - CounterMap.AddValue(i * 8 + Bit); - } +size_t TracePC::FinalizeTrace(InputCorpus *C, size_t InputSize, bool Shrink) { + if (!UsingTracePcGuard()) return 0; + size_t Res = 0; + const size_t Step = 8; + assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0); + size_t N = Min(kNumCounters, NumGuards + 1); + N = (N + Step - 1) & ~(Step - 1); // Round up. + for (size_t Idx = 0; Idx < N; Idx += Step) { + uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]); + if (!Bundle) continue; + for (size_t i = Idx; i < Idx + Step; i++) { + uint8_t Counter = (Bundle >> (i * 8)) & 0xff; + if (!Counter) continue; + Counters[i] = 0; + unsigned Bit = 0; + /**/ if (Counter >= 128) Bit = 7; + else if (Counter >= 32) Bit = 6; + else if (Counter >= 16) Bit = 5; + else if (Counter >= 8) Bit = 4; + else if (Counter >= 4) Bit = 3; + else if (Counter >= 3) Bit = 2; + else if (Counter >= 2) Bit = 1; + size_t Feature = (i * 8 + Bit); + if (C->AddFeature(Feature, InputSize, Shrink)) + Res++; } } + if (UseValueProfile) + ValueProfileMap.ForEach([&](size_t Idx) { + if (C->AddFeature(NumGuards + Idx, InputSize, Shrink)) + Res++; + }); + return Res; } void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { const uintptr_t kBits = 12; const uintptr_t kMask = (1 << kBits) - 1; - CounterMap.AddValue((Caller & kMask) | ((Callee & kMask) << kBits)); + uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits); + HandleValueProfile(Idx); } -void TracePC::PrintCoverage() { - Printf("COVERAGE:\n"); - for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) { - if (PCs[i]) - PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]); +static bool IsInterestingCoverageFile(std::string &File) { + if (File.find("compiler-rt/lib/") != std::string::npos) + return false; // sanitizer internal. + if (File.find("/usr/lib/") != std::string::npos) + return false; + if (File.find("/usr/include/") != std::string::npos) + return false; + if (File == "<null>") + return false; + return true; +} + +void TracePC::PrintNewPCs() { + if (DoPrintNewPCs) { + if (!PrintedPCs) + PrintedPCs = new std::set<uintptr_t>; + for (size_t i = 1; i < GetNumPCs(); i++) + if (PCs[i] && PrintedPCs->insert(PCs[i]).second) + PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PCs[i]); } } +void TracePC::PrintCoverage() { + if (!EF->__sanitizer_symbolize_pc) { + Printf("INFO: __sanitizer_symbolize_pc is not available," + " not printing coverage\n"); + return; + } + std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule; + std::map<std::string, uintptr_t> ModuleOffsets; + std::set<std::string> CoveredFiles, CoveredFunctions, CoveredLines; + Printf("COVERAGE:\n"); + for (size_t i = 1; i < GetNumPCs(); i++) { + if (!PCs[i]) continue; + std::string FileStr = DescribePC("%s", PCs[i]); + if (!IsInterestingCoverageFile(FileStr)) continue; + std::string FixedPCStr = DescribePC("%p", PCs[i]); + std::string FunctionStr = DescribePC("%F", PCs[i]); + std::string LineStr = DescribePC("%l", PCs[i]); + // TODO(kcc): get the module using some other way since this + // does not work with ASAN_OPTIONS=strip_path_prefix=something. + std::string Module = DescribePC("%m", PCs[i]); + std::string OffsetStr = DescribePC("%o", PCs[i]); + uintptr_t FixedPC = std::stol(FixedPCStr, 0, 16); + uintptr_t PcOffset = std::stol(OffsetStr, 0, 16); + ModuleOffsets[Module] = FixedPC - PcOffset; + CoveredPCsPerModule[Module].push_back(PcOffset); + CoveredFunctions.insert(FunctionStr); + CoveredFiles.insert(FileStr); + if (!CoveredLines.insert(FileStr + ":" + LineStr).second) + continue; + Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(), + FileStr.c_str(), LineStr.c_str()); + } -void TracePC::UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize) { - if (!CurrentElementSize) return; - for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) { - if (!CounterMap.Get(Idx)) continue; - Feature &Fe = FeatureSet[Idx]; - Fe.Count++; - if (!Fe.SmallestElementSize || Fe.SmallestElementSize > CurrentElementSize) { - Fe.SmallestElementIdx = CurrentElementIdx; - Fe.SmallestElementSize = CurrentElementSize; + for (auto &M : CoveredPCsPerModule) { + std::set<std::string> UncoveredFiles, UncoveredFunctions; + std::map<std::string, std::set<int> > UncoveredLines; // Func+File => lines + auto &ModuleName = M.first; + auto &CoveredOffsets = M.second; + uintptr_t ModuleOffset = ModuleOffsets[ModuleName]; + std::sort(CoveredOffsets.begin(), CoveredOffsets.end()); + Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str()); + // sancov does not yet fully support DSOs. + // std::string Cmd = "sancov -print-coverage-pcs " + ModuleName; + std::string Cmd = "objdump -d " + ModuleName + + " | grep 'call.*__sanitizer_cov_trace_pc_guard' | awk -F: '{print $1}'"; + std::string SanCovOutput; + if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) { + Printf("INFO: Command failed: %s\n", Cmd.c_str()); + continue; } + std::istringstream ISS(SanCovOutput); + std::string S; + while (std::getline(ISS, S, '\n')) { + uintptr_t PcOffset = std::stol(S, 0, 16); + if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(), + PcOffset)) { + uintptr_t PC = ModuleOffset + PcOffset; + auto FileStr = DescribePC("%s", PC); + if (!IsInterestingCoverageFile(FileStr)) continue; + if (CoveredFiles.count(FileStr) == 0) { + UncoveredFiles.insert(FileStr); + continue; + } + auto FunctionStr = DescribePC("%F", PC); + if (CoveredFunctions.count(FunctionStr) == 0) { + UncoveredFunctions.insert(FunctionStr); + continue; + } + std::string LineStr = DescribePC("%l", PC); + uintptr_t Line = std::stoi(LineStr); + std::string FileLineStr = FileStr + ":" + LineStr; + if (CoveredLines.count(FileLineStr) == 0) + UncoveredLines[FunctionStr + " " + FileStr].insert(Line); + } + } + for (auto &FileLine: UncoveredLines) + for (int Line : FileLine.second) + Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line); + for (auto &Func : UncoveredFunctions) + Printf("UNCOVERED_FUNC: %s\n", Func.c_str()); + for (auto &File : UncoveredFiles) + Printf("UNCOVERED_FILE: %s\n", File.c_str()); } } -void TracePC::PrintFeatureSet() { - Printf("[id: cnt idx sz] "); - for (size_t i = 0; i < kFeatureSetSize; i++) { - auto &Fe = FeatureSet[i]; - if (!Fe.Count) continue; - Printf("[%zd: %zd %zd %zd] ", i, Fe.Count, Fe.SmallestElementIdx, - Fe.SmallestElementSize); - } - Printf("\n"); +// Value profile. +// We keep track of various values that affect control flow. +// These values are inserted into a bit-set-based hash map. +// Every new bit in the map is treated as a new coverage. +// +// For memcmp/strcmp/etc the interesting value is the length of the common +// prefix of the parameters. +// For cmp instructions the interesting value is a XOR of the parameters. +// The interesting value is mixed up with the PC and is then added to the map. + +void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, + size_t n) { + if (!n) return; + size_t Len = std::min(n, (size_t)32); + const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1); + const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2); + size_t I = 0; + for (; I < Len; I++) + if (A1[I] != A2[I]) + break; + size_t PC = reinterpret_cast<size_t>(caller_pc); + size_t Idx = I; + // if (I < Len) + // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1; + TPC.HandleValueProfile((PC & 4095) | (Idx << 12)); +} + +void TracePC::AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2, + size_t n) { + if (!n) return; + size_t Len = std::min(n, (size_t)32); + const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1); + const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2); + size_t I = 0; + for (; I < Len; I++) + if (A1[I] != A2[I] || A1[I] == 0) + break; + size_t PC = reinterpret_cast<size_t>(caller_pc); + size_t Idx = I; + // if (I < Len && A1[I]) + // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1; + TPC.HandleValueProfile((PC & 4095) | (Idx << 12)); +} + +template <class T> +ATTRIBUTE_TARGET_POPCNT +#ifdef __clang__ // g++ can't handle this __attribute__ here :( +__attribute__((always_inline)) +#endif // __clang__ +void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) { + uintptr_t PCuint = reinterpret_cast<uintptr_t>(PC); + uint64_t ArgXor = Arg1 ^ Arg2; + uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65] + uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance; + if (sizeof(T) == 4) + TORC4.Insert(ArgXor, Arg1, Arg2); + else if (sizeof(T) == 8) + TORC8.Insert(ArgXor, Arg1, Arg2); + HandleValueProfile(Idx); } } // namespace fuzzer extern "C" { __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard(uintptr_t *Guard) { +void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { uintptr_t PC = (uintptr_t)__builtin_return_address(0); fuzzer::TPC.HandleTrace(Guard, PC); } __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard_init(uintptr_t *Start, uintptr_t *Stop) { +void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { fuzzer::TPC.HandleInit(Start, Stop); } @@ -153,4 +288,45 @@ void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { uintptr_t PC = (uintptr_t)__builtin_return_address(0); fuzzer::TPC.HandleCallerCallee(PC, Callee); } + +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); +} +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); +} +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); +} +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); } + +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { + uint64_t N = Cases[0]; + uint64_t *Vals = Cases + 2; + char *PC = (char*)__builtin_return_address(0); + for (size_t i = 0; i < N; i++) + if (Val != Vals[i]) + fuzzer::TPC.HandleCmp(PC + i, Val, Vals[i]); +} + +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_div4(uint32_t Val) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint32_t)0); +} +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_div8(uint64_t Val) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint64_t)0); +} +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_gep(uintptr_t Idx) { + fuzzer::TPC.HandleCmp(__builtin_return_address(0), Idx, (uintptr_t)0); +} + +} // extern "C" diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.h b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h index 0f2b6a878c4..4cce36354d7 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerTracePC.h +++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h @@ -12,39 +12,56 @@ #ifndef LLVM_FUZZER_TRACE_PC #define LLVM_FUZZER_TRACE_PC +#include <set> + #include "FuzzerDefs.h" #include "FuzzerValueBitMap.h" namespace fuzzer { +// TableOfRecentCompares (TORC) remembers the most recently performed +// comparisons of type T. +// We record the arguments of CMP instructions in this table unconditionally +// because it seems cheaper this way than to compute some expensive +// conditions inside __sanitizer_cov_trace_cmp*. +// After the unit has been executed we may decide to use the contents of +// this table to populate a Dictionary. +template<class T, size_t kSizeT> +struct TableOfRecentCompares { + static const size_t kSize = kSizeT; + struct Pair { + T A, B; + }; + void Insert(size_t Idx, T Arg1, T Arg2) { + Idx = Idx % kSize; + Table[Idx].A = Arg1; + Table[Idx].B = Arg2; + } + + Pair Get(size_t I) { return Table[I % kSize]; } + + Pair Table[kSize]; +}; + class TracePC { public: - void HandleTrace(uintptr_t *guard, uintptr_t PC); - void HandleInit(uintptr_t *start, uintptr_t *stop); + static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems; + + void HandleTrace(uint32_t *guard, uintptr_t PC); + void HandleInit(uint32_t *start, uint32_t *stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); } - size_t GetTotalPCCoverage() { return TotalPCCoverage; } - void ResetTotalPCCoverage() { TotalPCCoverage = 0; } + template <class T> void HandleCmp(void *PC, T Arg1, T Arg2); + size_t GetTotalPCCoverage(); void SetUseCounters(bool UC) { UseCounters = UC; } void SetUseValueProfile(bool VP) { UseValueProfile = VP; } - bool UpdateCounterMap(ValueBitMap *MaxCounterMap) { - return MaxCounterMap->MergeFrom(CounterMap); - } + void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } + size_t FinalizeTrace(InputCorpus *C, size_t InputSize, bool Shrink); bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap) { return UseValueProfile && MaxValueProfileMap->MergeFrom(ValueProfileMap); } - void FinalizeTrace(); - - size_t GetNewPCIDs(uintptr_t **NewPCIDsPtr) { - *NewPCIDsPtr = NewPCIDs; - return Min(kMaxNewPCIDs, NumNewPCIDs); - } - - uintptr_t GetPCbyPCID(uintptr_t PCID) { return PCs[PCID]; } void ResetMaps() { - NumNewPCIDs = 0; - CounterMap.Reset(); ValueProfileMap.Reset(); memset(Counters, 0, sizeof(Counters)); } @@ -52,26 +69,35 @@ class TracePC { void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize); void PrintFeatureSet(); - void ResetGuards(); - void PrintModuleInfo(); void PrintCoverage(); + void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, + size_t n); + void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2, + size_t n); + + bool UsingTracePcGuard() const {return NumModules; } + + static const size_t kTORCSize = 1 << 5; + TableOfRecentCompares<uint32_t, kTORCSize> TORC4; + TableOfRecentCompares<uint64_t, kTORCSize> TORC8; + + void PrintNewPCs(); + size_t GetNumPCs() const { return Min(kNumPCs, NumGuards + 1); } + uintptr_t GetPC(size_t Idx) { + assert(Idx < GetNumPCs()); + return PCs[Idx]; + } + private: bool UseCounters = false; bool UseValueProfile = false; - size_t TotalPCCoverage = 0; - - static const size_t kMaxNewPCIDs = 1024; - uintptr_t NewPCIDs[kMaxNewPCIDs]; - size_t NumNewPCIDs = 0; - void AddNewPCID(uintptr_t PCID) { - NewPCIDs[(NumNewPCIDs++) % kMaxNewPCIDs] = PCID; - } + bool DoPrintNewPCs = false; struct Module { - uintptr_t *Start, *Stop; + uint32_t *Start, *Stop; }; Module Modules[4096]; @@ -81,20 +107,12 @@ private: static const size_t kNumCounters = 1 << 14; alignas(8) uint8_t Counters[kNumCounters]; - static const size_t kNumPCs = 1 << 20; + static const size_t kNumPCs = 1 << 24; uintptr_t PCs[kNumPCs]; - ValueBitMap CounterMap; - ValueBitMap ValueProfileMap; - - struct Feature { - size_t Count; - size_t SmallestElementIdx; - size_t SmallestElementSize; - }; + std::set<uintptr_t> *PrintedPCs; - static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems; - Feature FeatureSet[kFeatureSetSize]; + ValueBitMap ValueProfileMap; }; extern TracePC TPC; diff --git a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp index 97d5935008b..9cccfcbc26f 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp @@ -6,71 +6,9 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// This file implements a mutation algorithm based on instruction traces and -// on taint analysis feedback from DFSan. -// -// Instruction traces are special hooks inserted by the compiler around -// interesting instructions. Currently supported traces: -// * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction, -// receives the type, size and arguments of ICMP. -// -// Every time a traced event is intercepted we analyse the data involved -// in the event and suggest a mutation for future executions. -// For example if 4 bytes of data that derive from input bytes {4,5,6,7} -// are compared with a constant 12345, -// we try to insert 12345, 12344, 12346 into bytes -// {4,5,6,7} of the next fuzzed inputs. -// -// The fuzzer can work only with the traces, or with both traces and DFSan. -// -// DataFlowSanitizer (DFSan) is a tool for -// generalised dynamic data flow (taint) analysis: -// http://clang.llvm.org/docs/DataFlowSanitizer.html . -// -// The approach with DFSan-based fuzzing has some similarity to -// "Taint-based Directed Whitebox Fuzzing" -// by Vijay Ganesh & Tim Leek & Martin Rinard: -// http://dspace.mit.edu/openaccess-disseminate/1721.1/59320, -// but it uses a full blown LLVM IR taint analysis and separate instrumentation -// to analyze all of the "attack points" at once. -// -// Workflow with DFSan: -// * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation. -// * The code under test is compiled with DFSan *and* with instruction traces. -// * Every call to HOOK(a,b) is replaced by DFSan with -// __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK -// gets all the taint labels for the arguments. -// * At the Fuzzer startup we assign a unique DFSan label -// to every byte of the input string (Fuzzer::CurrentUnitData) so that -// for any chunk of data we know which input bytes it has derived from. -// * The __dfsw_* functions (implemented in this file) record the -// parameters (i.e. the application data and the corresponding taint labels) -// in a global state. -// -// Parts of this code will not function when DFSan is not linked in. -// Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer -// we redeclare the dfsan_* interface functions as weak and check if they -// are nullptr before calling. -// If this approach proves to be useful we may add attribute(weak) to the -// dfsan declarations in dfsan_interface.h -// -// This module is in the "proof of concept" stage. -// It is capable of solving only the simplest puzzles -// like test/dfsan/DFSanSimpleCmpTest.cpp. +// Data tracing. //===----------------------------------------------------------------------===// -/* Example of manual usage (-fsanitize=dataflow is optional): -( - cd $LLVM/lib/Fuzzer/ - clang -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp - clang++ -O0 -std=c++11 -fsanitize-coverage=edge,trace-cmp \ - -fsanitize=dataflow \ - test/SimpleCmpTest.cpp Fuzzer*.o - ./a.out -use_traces=1 -) -*/ - -#include "FuzzerDFSan.h" #include "FuzzerInternal.h" #include "FuzzerDictionary.h" #include "FuzzerMutate.h" @@ -83,90 +21,8 @@ #include <map> #include <set> -#if !LLVM_FUZZER_SUPPORTS_DFSAN -// Stubs for dfsan for platforms where dfsan does not exist and weak -// functions don't work. -extern "C" { -dfsan_label dfsan_create_label(const char *desc, void *userdata) { return 0; } -void dfsan_set_label(dfsan_label label, void *addr, size_t size) {} -void dfsan_add_label(dfsan_label label, void *addr, size_t size) {} -const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) { - return nullptr; -} -dfsan_label dfsan_read_label(const void *addr, size_t size) { return 0; } -} // extern "C" -#endif // !LLVM_FUZZER_SUPPORTS_DFSAN - namespace fuzzer { -// These values are copied from include/llvm/IR/InstrTypes.h. -// We do not include the LLVM headers here to remain independent. -// If these values ever change, an assertion in ComputeCmp will fail. -enum Predicate { - ICMP_EQ = 32, ///< equal - ICMP_NE = 33, ///< not equal - ICMP_UGT = 34, ///< unsigned greater than - ICMP_UGE = 35, ///< unsigned greater or equal - ICMP_ULT = 36, ///< unsigned less than - ICMP_ULE = 37, ///< unsigned less or equal - ICMP_SGT = 38, ///< signed greater than - ICMP_SGE = 39, ///< signed greater or equal - ICMP_SLT = 40, ///< signed less than - ICMP_SLE = 41, ///< signed less or equal -}; - -template <class U, class S> -bool ComputeCmp(size_t CmpType, U Arg1, U Arg2) { - switch(CmpType) { - case ICMP_EQ : return Arg1 == Arg2; - case ICMP_NE : return Arg1 != Arg2; - case ICMP_UGT: return Arg1 > Arg2; - case ICMP_UGE: return Arg1 >= Arg2; - case ICMP_ULT: return Arg1 < Arg2; - case ICMP_ULE: return Arg1 <= Arg2; - case ICMP_SGT: return (S)Arg1 > (S)Arg2; - case ICMP_SGE: return (S)Arg1 >= (S)Arg2; - case ICMP_SLT: return (S)Arg1 < (S)Arg2; - case ICMP_SLE: return (S)Arg1 <= (S)Arg2; - default: assert(0 && "unsupported CmpType"); - } - return false; -} - -static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1, - uint64_t Arg2) { - if (CmpSize == 8) return ComputeCmp<uint64_t, int64_t>(CmpType, Arg1, Arg2); - if (CmpSize == 4) return ComputeCmp<uint32_t, int32_t>(CmpType, Arg1, Arg2); - if (CmpSize == 2) return ComputeCmp<uint16_t, int16_t>(CmpType, Arg1, Arg2); - if (CmpSize == 1) return ComputeCmp<uint8_t, int8_t>(CmpType, Arg1, Arg2); - // Other size, == - if (CmpType == ICMP_EQ) return Arg1 == Arg2; - // assert(0 && "unsupported cmp and type size combination"); - return true; -} - -// As a simplification we use the range of input bytes instead of a set of input -// bytes. -struct LabelRange { - uint16_t Beg, End; // Range is [Beg, End), thus Beg==End is an empty range. - - LabelRange(uint16_t Beg = 0, uint16_t End = 0) : Beg(Beg), End(End) {} - - static LabelRange Join(LabelRange LR1, LabelRange LR2) { - if (LR1.Beg == LR1.End) return LR2; - if (LR2.Beg == LR2.End) return LR1; - return {std::min(LR1.Beg, LR2.Beg), std::max(LR1.End, LR2.End)}; - } - LabelRange &Join(LabelRange LR) { - return *this = Join(*this, LR); - } - static LabelRange Singleton(const dfsan_label_info *LI) { - uint16_t Idx = (uint16_t)(uintptr_t)LI->userdata; - assert(Idx > 0); - return {(uint16_t)(Idx - 1), Idx}; - } -}; - // For now, very simple: put Size bytes of Data at position Pos. struct TraceBasedMutation { uint32_t Pos; @@ -178,10 +34,8 @@ static bool RecordingMemcmp = false; static bool RecordingMemmem = false; static bool DoingMyOwnMemmem = false; -struct ScopedDoingMyOwnMemmem { - ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; } - ~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; } -}; +ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; } +ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; } class TraceState { public: @@ -189,17 +43,6 @@ public: 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, - uint64_t Arg1, uint64_t Arg2, dfsan_label L1, - dfsan_label L2); - void DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1, - const uint8_t *Data2, dfsan_label L1, - dfsan_label L2); - void DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val, - size_t NumCases, uint64_t *Cases, dfsan_label L); - void TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, - uint64_t Arg1, uint64_t Arg2); void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, const uint8_t *Data2); @@ -270,17 +113,6 @@ public: InterestingWords.insert(W); } - void EnsureDfsanLabels(size_t Size) { - for (; LastDfsanLabel < Size; LastDfsanLabel++) { - dfsan_label L = dfsan_create_label("input", (void *)(LastDfsanLabel + 1)); - // We assume that no one else has called dfsan_create_label before. - if (L != LastDfsanLabel + 1) { - Printf("DFSan labels are not starting from 1, exiting\n"); - exit(1); - } - } - } - private: bool IsTwoByteData(uint64_t Data) { int64_t Signed = static_cast<int64_t>(Data); @@ -308,8 +140,6 @@ public: TraceBasedMutation Mutations[kMaxMutations]; // TODO: std::set is too inefficient, need to have a custom DS here. std::set<Word> InterestingWords; - LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)]; - size_t LastDfsanLabel = 0; MutationDispatcher &MD; const FuzzingOptions Options; const Fuzzer *F; @@ -317,93 +147,6 @@ public: size_t AutoDictAdds = 0; }; - -LabelRange TraceState::GetLabelRange(dfsan_label L) { - LabelRange &LR = LabelRanges[L]; - if (LR.Beg < LR.End || L == 0) - return LR; - const dfsan_label_info *LI = dfsan_get_label_info(L); - if (LI->l1 || LI->l2) - return LR = LabelRange::Join(GetLabelRange(LI->l1), GetLabelRange(LI->l2)); - return LR = LabelRange::Singleton(LI); -} - -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 (!F->InFuzzingThread()) return; - if (L1 == 0 && L2 == 0) - return; // Not actionable. - if (L1 != 0 && L2 != 0) - return; // Probably still actionable. - bool Res = ComputeCmp(CmpSize, CmpType, Arg1, Arg2); - uint64_t Data = L1 ? Arg2 : Arg1; - LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2); - - for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) { - AddMutation(Pos, CmpSize, Data); - AddMutation(Pos, CmpSize, Data + 1); - AddMutation(Pos, CmpSize, Data - 1); - } - - if (CmpSize > (size_t)(LR.End - LR.Beg)) - AddMutation(LR.Beg, (unsigned)(LR.End - LR.Beg), Data); - - - if (Options.Verbosity >= 3) - Printf("DFSanCmpCallback: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 " - "%d MU %zd\n", - PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, NumMutations); -} - -void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1, - const uint8_t *Data2, dfsan_label L1, - dfsan_label L2) { - - assert(ReallyHaveDFSan()); - if (!RecordingMemcmp || !F->InFuzzingThread()) return; - if (L1 == 0 && L2 == 0) - return; // Not actionable. - if (L1 != 0 && L2 != 0) - return; // Probably still actionable. - - const uint8_t *Data = L1 ? Data2 : Data1; - LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2); - for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) { - AddMutation(Pos, CmpSize, Data); - if (Options.Verbosity >= 3) - Printf("DFSanMemcmpCallback: Pos %d Size %d\n", Pos, CmpSize); - } -} - -void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, - uint64_t Val, size_t NumCases, - uint64_t *Cases, dfsan_label L) { - assert(ReallyHaveDFSan()); - if (!F->InFuzzingThread()) return; - if (!L) return; // Not actionable. - LabelRange LR = GetLabelRange(L); - size_t ValSize = ValSizeInBits / 8; - bool TryShort = IsTwoByteData(Val); - for (size_t i = 0; i < NumCases; i++) - TryShort &= IsTwoByteData(Cases[i]); - - for (size_t Pos = LR.Beg; Pos + ValSize <= LR.End; Pos++) - for (size_t i = 0; i < NumCases; i++) - AddMutation(Pos, ValSize, Cases[i]); - - if (TryShort) - for (size_t Pos = LR.Beg; Pos + 2 <= LR.End; Pos++) - for (size_t i = 0; i < NumCases; i++) - AddMutation(Pos, 2, Cases[i]); - - if (Options.Verbosity >= 3) - Printf("DFSanSwitchCallback: PC %lx Val %zd SZ %zd # %zd L %d: {%d, %d} " - "TryShort %d\n", - PC, Val, ValSize, NumCases, L, LR.Beg, LR.End, TryShort); -} - int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, size_t DataSize) { if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0; @@ -449,22 +192,6 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData, return Res; } -void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, - uint64_t Arg1, uint64_t Arg2) { - if (!F->InFuzzingThread()) return; - if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2) - return; // No reason to mutate. - int Added = 0; - Added += TryToAddDesiredData(Arg1, Arg2, CmpSize); - Added += TryToAddDesiredData(Arg2, Arg1, CmpSize); - if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) { - Added += TryToAddDesiredData(Arg1, Arg2, 2); - Added += TryToAddDesiredData(Arg2, Arg1, 2); - } - if (Options.Verbosity >= 3 && Added) - Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2); -} - void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, const uint8_t *Data2) { if (!RecordingMemcmp || !F->InFuzzingThread()) return; @@ -511,14 +238,6 @@ void Fuzzer::StopTraceRecording() { TS->StopTraceRecording(); } -void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) { - if (!Options.UseMemcmp) return; - if (!ReallyHaveDFSan()) return; - TS->EnsureDfsanLabels(Size); - for (size_t i = 0; i < Size; i++) - dfsan_set_label(i + 1, &Data[i], 1); -} - void Fuzzer::InitializeTraceState() { if (!Options.UseMemcmp) return; TS = new TraceState(MD, Options, this); @@ -530,128 +249,12 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) { return Len; } -// Value profile. -// We keep track of various values that affect control flow. -// These values are inserted into a bit-set-based hash map. -// Every new bit in the map is treated as a new coverage. -// -// For memcmp/strcmp/etc the interesting value is the length of the common -// prefix of the parameters. -// For cmp instructions the interesting value is a XOR of the parameters. -// The interesting value is mixed up with the PC and is then added to the map. - -static void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, - size_t n) { - if (!n) return; - size_t Len = std::min(n, (size_t)32); - const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1); - const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2); - size_t I = 0; - for (; I < Len; I++) - if (A1[I] != A2[I]) - break; - size_t PC = reinterpret_cast<size_t>(caller_pc); - size_t Idx = I; - // if (I < Len) - // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1; - TPC.HandleValueProfile((PC & 4095) | (Idx << 12)); -} - -static void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2, - size_t n) { - if (!n) return; - size_t Len = std::min(n, (size_t)32); - const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1); - const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2); - size_t I = 0; - for (; I < Len; I++) - if (A1[I] != A2[I] || A1[I] == 0) - break; - size_t PC = reinterpret_cast<size_t>(caller_pc); - size_t Idx = I; - // if (I < Len && A1[I]) - // Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1; - TPC.HandleValueProfile((PC & 4095) | (Idx << 12)); -} - -ATTRIBUTE_TARGET_POPCNT -static void AddValueForCmp(void *PCptr, uint64_t Arg1, uint64_t Arg2) { - if (Arg1 == Arg2) - return; - uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr); - uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) - 1; // [0,63] - uintptr_t Idx = (PC & 4095) | (ArgDistance << 12); - TPC.HandleValueProfile(Idx); -} - -static void AddValueForSingleVal(void *PCptr, uintptr_t Val) { - if (!Val) return; - uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr); - uint64_t ArgDistance = __builtin_popcountl(Val) - 1; // [0,63] - uintptr_t Idx = (PC & 4095) | (ArgDistance << 12); - TPC.HandleValueProfile(Idx); -} - } // namespace fuzzer using fuzzer::TS; using fuzzer::RecordingMemcmp; extern "C" { -void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, - uint64_t Arg2, dfsan_label L0, - dfsan_label L1, dfsan_label L2) { -} - -#define DFSAN_CMP_CALLBACK(N) \ - void __dfsw___sanitizer_cov_trace_cmp##N(uint64_t Arg1, uint64_t Arg2, \ - dfsan_label L1, dfsan_label L2) { \ - } - -DFSAN_CMP_CALLBACK(1) -DFSAN_CMP_CALLBACK(2) -DFSAN_CMP_CALLBACK(4) -DFSAN_CMP_CALLBACK(8) -#undef DFSAN_CMP_CALLBACK - -void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases, - dfsan_label L1, dfsan_label L2) { -} - -void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, - size_t n, dfsan_label s1_label, - dfsan_label s2_label, dfsan_label n_label) { - if (!RecordingMemcmp) return; - dfsan_label L1 = dfsan_read_label(s1, n); - dfsan_label L2 = dfsan_read_label(s2, n); - TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1), - reinterpret_cast<const uint8_t *>(s2), L1, L2); -} - -void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, - size_t n, dfsan_label s1_label, - dfsan_label s2_label, dfsan_label n_label) { - if (!RecordingMemcmp) return; - n = std::min(n, fuzzer::InternalStrnlen(s1, n)); - n = std::min(n, fuzzer::InternalStrnlen(s2, n)); - dfsan_label L1 = dfsan_read_label(s1, n); - dfsan_label L2 = dfsan_read_label(s2, n); - TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1), - reinterpret_cast<const uint8_t *>(s2), L1, L2); -} - -void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2, - dfsan_label s1_label, dfsan_label s2_label) { - if (!RecordingMemcmp) return; - size_t Len1 = strlen(s1); - size_t Len2 = strlen(s2); - size_t N = std::min(Len1, Len2); - if (N <= 1) return; // Not interesting. - dfsan_label L1 = dfsan_read_label(s1, Len1); - dfsan_label L2 = dfsan_read_label(s2, Len2); - TS->DFSanMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1), - reinterpret_cast<const uint8_t *>(s2), L1, L2); -} // We may need to avoid defining weak hooks to stay compatible with older clang. #ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS @@ -661,7 +264,7 @@ void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2, #if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, size_t n, int result) { - fuzzer::AddValueForMemcmp(caller_pc, s1, s2, n); + fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n); if (!RecordingMemcmp) return; if (result == 0) return; // No reason to mutate. if (n <= 1) return; // Not interesting. @@ -671,7 +274,7 @@ void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, size_t n, int result) { - fuzzer::AddValueForStrcmp(caller_pc, s1, s2, n); + fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, n); if (!RecordingMemcmp) return; if (result == 0) return; // No reason to mutate. size_t Len1 = fuzzer::InternalStrnlen(s1, n); @@ -685,7 +288,7 @@ void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2, int result) { - fuzzer::AddValueForStrcmp(caller_pc, s1, s2, 64); + fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, 64); if (!RecordingMemcmp) return; if (result == 0) return; // No reason to mutate. size_t Len1 = strlen(s1); @@ -719,47 +322,4 @@ void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, } #endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS - -// TODO: this one will not be used with the newest clang. Remove it. -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, - uint64_t Arg2) { - fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2); -} - -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_cmp8(uint64_t Arg1, int64_t Arg2) { - fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2); -} -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_cmp4(uint32_t Arg1, int32_t Arg2) { - fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2); -} -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_cmp2(uint16_t Arg1, int16_t Arg2) { - fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2); -} -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_cmp1(uint8_t Arg1, int8_t Arg2) { - fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2); -} - -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { - // TODO(kcc): support value profile here. -} - -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_div4(uint32_t Val) { - fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val); -} -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_div8(uint64_t Val) { - fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val); -} -__attribute__((visibility("default"))) -void __sanitizer_cov_trace_gep(uintptr_t Idx) { - fuzzer::AddValueForSingleVal(__builtin_return_address(0), Idx); -} - } // extern "C" diff --git a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp index 254d9c826df..d845333a169 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp +++ b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp @@ -19,6 +19,7 @@ #include <cassert> #include <chrono> #include <cstring> +#include <stdio.h> #include <signal.h> #include <sstream> #include <unistd.h> @@ -306,4 +307,14 @@ void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { Printf(FallbackFMT, PC); } +bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) { + FILE *Pipe = popen(Command.c_str(), "r"); + if (!Pipe) return false; + char Buff[1024]; + size_t N; + while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0) + Out->append(Buff, N); + return true; +} + } // namespace fuzzer diff --git a/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h b/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h index 97f4c5e51b9..0692acd13ee 100644 --- a/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h +++ b/chromium/third_party/libFuzzer/src/FuzzerValueBitMap.h @@ -68,6 +68,15 @@ struct ValueBitMap { return OldNumBits < NumBits; } + template <class Callback> + void ForEach(Callback CB) { + for (size_t i = 0; i < kMapSizeInWords; i++) + if (uintptr_t M = Map[i]) + for (size_t j = 0; j < sizeof(M) * 8; j++) + if (M & ((uintptr_t)1 << j)) + CB(i * sizeof(M) * 8 + j); + } + private: size_t NumBits = 0; uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512))); diff --git a/chromium/third_party/libFuzzer/src/build.sh b/chromium/third_party/libFuzzer/src/build.sh index 92d7b8cdbf7..27c148ad43d 100755 --- a/chromium/third_party/libFuzzer/src/build.sh +++ b/chromium/third_party/libFuzzer/src/build.sh @@ -1,7 +1,7 @@ #!/bin/bash LIBFUZZER_SRC_DIR=$(dirname $0) for f in $LIBFUZZER_SRC_DIR/*.cpp; do - clang -O2 -std=c++11 $f -c & + clang -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c & done wait rm -f libFuzzer.a diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh deleted file mode 100755 index 69fa7241b86..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/build.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -[ -e $(basename $0) ] && echo "PLEASE USE THIS SCRIPT FROM ANOTHER DIR" && exit 1 -SCRIPT_DIR=$(dirname $0) -EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR) -LIBFUZZER_SRC=$(dirname $(dirname $SCRIPT_DIR)) -JOBS=20 - -# FUZZ_CXXFLAGS=" -g -fsanitize=address -fsanitize-coverage=edge" -FUZZ_CXXFLAGS=" -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,trace-gep" - -get() { - [ ! -e SRC ] && git clone https://github.com/openssl/openssl.git SRC && (cd SRC && git checkout OpenSSL_1_0_1f) -# [ ! -e SRC ] && wget https://www.openssl.org/source/openssl-1.0.1f.tar.gz && tar xf openssl-1.0.1f.tar.gz && mv openssl-1.0.1f SRC -} -build_lib() { - rm -rf BUILD - cp -rf SRC BUILD - (cd BUILD && ./config && make clean && make CC="clang $FUZZ_CXXFLAGS" -j $JOBS) -} - -get -build_lib -$LIBFUZZER_SRC/build.sh -clang++ -g $SCRIPT_DIR/target.cc -DCERT_PATH=\"$SCRIPT_DIR/\" $FUZZ_CXXFLAGS BUILD/libssl.a BUILD/libcrypto.a libFuzzer.a -o $EXECUTABLE_NAME_BASE diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key deleted file mode 100644 index 4e887edb0e1..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.key +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA1AdZNDVOA9cXm97f -erp1bukz2kohjToJS6Ma8fOb36VV9lQGmDNsJanXFiqafOgV+kh1HXqZ3l1I0JmZ -71b+QQIDAQABAkAHGfPn5r0lLcgRpWZQwvv56f+dmQwEoeP7z4uwfNtEo0JcRD66 -1WRCvx3LE0VbNeaEdNmSPiRXhlwIggjfrBi9AiEA9UusPBcEp/QcPGs96nQQdQzE -fw4x0HL/eSV3qHimT6MCIQDdSAiX4Ouxoiwn/9KhDMcZXRYX/OPzj6w8u1YIH7BI -ywIgSozbJdAhHCJ2ym4VfUIVFl3xAmSAA0hQGLOocE1qzl0CIQDRicOxZmhqBiKA -IgznOn1StEYWov+MhRFZVSBLgw5gbwIgJzOlSlu0Y22hEUsLCKyHBrCAZZHcZ020 -20pfogmQYn0= ------END PRIVATE KEY----- diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem deleted file mode 100644 index a7962debc37..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/server.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBYTCCAQugAwIBAgIJAMPQQtUHkx+KMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV -BAMMAWEwHhcNMTYwOTI0MjIyMDUyWhcNNDQwMjA5MjIyMDUyWjAMMQowCAYDVQQD -DAFhMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANQHWTQ1TgPXF5ve33q6dW7pM9pK -IY06CUujGvHzm9+lVfZUBpgzbCWp1xYqmnzoFfpIdR16md5dSNCZme9W/kECAwEA -AaNQME4wHQYDVR0OBBYEFCXtEo9rkLuKGSlm0mFE4Yk/HDJVMB8GA1UdIwQYMBaA -FCXtEo9rkLuKGSlm0mFE4Yk/HDJVMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADQQCnldOnbdNJZxBO/J+979Urg8qDp8MnlN0979AmK1P5/YzPnAF4BU7QTOTE -imS5qZ0MvziBa81nVlnnFRkIezcD ------END CERTIFICATE----- diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc deleted file mode 100644 index 9dc2d5dc21b..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/target.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <assert.h> -#include <stdint.h> -#include <stddef.h> - -#ifndef CERT_PATH -# define CERT_PATH -#endif - -SSL_CTX *Init() { - SSL_library_init(); - SSL_load_error_strings(); - ERR_load_BIO_strings(); - OpenSSL_add_all_algorithms(); - SSL_CTX *sctx; - assert (sctx = SSL_CTX_new(TLSv1_method())); - /* These two file were created with this command: - openssl req -x509 -newkey rsa:512 -keyout server.key \ - -out server.pem -days 9999 -nodes -subj /CN=a/ - */ - assert(SSL_CTX_use_certificate_file(sctx, CERT_PATH "server.pem", - SSL_FILETYPE_PEM)); - assert(SSL_CTX_use_PrivateKey_file(sctx, CERT_PATH "server.key", - SSL_FILETYPE_PEM)); - return sctx; -} -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - static SSL_CTX *sctx = Init(); - SSL *server = SSL_new(sctx); - BIO *sinbio = BIO_new(BIO_s_mem()); - BIO *soutbio = BIO_new(BIO_s_mem()); - SSL_set_bio(server, sinbio, soutbio); - SSL_set_accept_state(server); - BIO_write(sinbio, Data, Size); - SSL_do_handshake(server); - SSL_free(server); - return 0; -} diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh deleted file mode 100755 index 34132e5b300..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/openssl-1.0.1f/test.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Find heartbleed. -set -x -[ -e openssl-1.0.1f ] && ./openssl-1.0.1f -max_total_time=300 2>&1 | tee log -grep -Pzo "(?s)ERROR: AddressSanitizer: heap-buffer-overflow.*READ of size.*#1 0x.* in tls1_process_heartbeat .*ssl/t1_lib.c:2586" log diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh deleted file mode 100755 index c2533bb0dc3..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/build.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -[ -e $(basename $0) ] && echo "PLEASE USE THIS SCRIPT FROM ANOTHER DIR" && exit 1 -SCRIPT_DIR=$(dirname $0) -EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR) -LIBFUZZER_SRC=$(dirname $(dirname $SCRIPT_DIR)) - -FUZZ_CXXFLAGS="-O2 -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div" - -get() { - [ ! -e SRC ] && git clone https://github.com/google/re2.git SRC && (cd SRC && git reset --hard 499ef7eff7455ce9c9fae86111d4a77b6ac335de) -} -build_lib() { - rm -rf BUILD - cp -rf SRC BUILD - (cd BUILD && make clean && CXX=clang++ CXXFLAGS="$FUZZ_CXXFLAGS" make -j) -} - -get -build_lib -$LIBFUZZER_SRC/build.sh -clang++ -g $SCRIPT_DIR/target.cc -I BUILD BUILD/obj/libre2.a libFuzzer.a $FUZZ_CXXFLAGS -o $EXECUTABLE_NAME_BASE diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc deleted file mode 100644 index 834db4e0ff2..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/target.cc +++ /dev/null @@ -1,27 +0,0 @@ -#include <string> -#include "re2/re2.h" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size < 3) return 0; - uint16_t f = (data[0] << 16) + data[1]; - RE2::Options opt; - opt.set_log_errors(false); - if (f & 1) opt.set_encoding(RE2::Options::EncodingLatin1); - opt.set_posix_syntax(f & 2); - opt.set_longest_match(f & 4); - opt.set_literal(f & 8); - opt.set_never_nl(f & 16); - opt.set_dot_nl(f & 32); - opt.set_never_capture(f & 64); - opt.set_case_sensitive(f & 128); - opt.set_perl_classes(f & 256); - opt.set_word_boundary(f & 512); - opt.set_one_line(f & 1024); - const char *b = reinterpret_cast<const char*>(data) + 2; - const char *e = reinterpret_cast<const char*>(data) + size; - std::string s1(b, e); - RE2 re(s1, opt); - if (re.ok()) - RE2::FullMatch(s1, re); - return 0; -} diff --git a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh b/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh deleted file mode 100755 index 3e07a956234..00000000000 --- a/chromium/third_party/libFuzzer/src/fuzzer-test-suite/re2-2014-12-09/test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -x -SCRIPT_DIR=$(dirname $0) -EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR) -CORPUS=CORPUS-$EXECUTABLE_NAME_BASE -JOBS=8 -rm -rf $CORPUS -mkdir $CORPUS -[ -e $EXECUTABLE_NAME_BASE ] && ./$EXECUTABLE_NAME_BASE -exit_on_src_pos=re2/dfa.cc:474 -exit_on_src_pos=re2/dfa.cc:474 -runs=1000000 -jobs=$JOBS -workers=$JOBS $CORPUS -grep "INFO: found line matching 're2/dfa.cc:474', exiting." fuzz-0.log diff --git a/chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c b/chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c new file mode 100644 index 00000000000..0d76ea49e79 --- /dev/null +++ b/chromium/third_party/libFuzzer/src/standalone/StandaloneFuzzTargetMain.c @@ -0,0 +1,41 @@ +/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This main() function can be linked to a fuzz target (i.e. a library +// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize()) +// instead of libFuzzer. This main() function will not perform any fuzzing +// but will simply feed all input files one by one to the fuzz target. +// +// Use this file to provide reproducers for bugs when linking against libFuzzer +// or other fuzzing engine is undesirable. +//===----------------------------------------------------------------------===*/ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); +__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); +int main(int argc, char **argv) { + fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + for (int i = 1; i < argc; i++) { + fprintf(stderr, "Running: %s\n", argv[i]); + FILE *f = fopen(argv[i], "r"); + assert(f); + fseek(f, 0, SEEK_END); + size_t len = ftell(f); + fseek(f, 0, SEEK_SET); + unsigned char *buf = (unsigned char*)malloc(len); + size_t n_read = fread(buf, 1, len, f); + assert(n_read == len); + LLVMFuzzerTestOneInput(buf, len); + free(buf); + fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); + } +} |