From f46303af7914bb2d4fe0a51687c6d446048b182a Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 1 Oct 2016 01:04:29 +0000 Subject: [PATCH] [libFuzzer] implement the -shrink=1 option that tires to make elements of the corpus smaller, off by default git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282995 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerCorpus.h | 3 ++- lib/Fuzzer/FuzzerDriver.cpp | 3 +++ lib/Fuzzer/FuzzerFlags.def | 4 ++++ lib/Fuzzer/FuzzerInternal.h | 1 + lib/Fuzzer/FuzzerLoop.cpp | 36 +++++++++++++++++++++++++++--------- lib/Fuzzer/FuzzerOptions.h | 2 ++ lib/Fuzzer/FuzzerTracePC.cpp | 12 ++++++++++-- lib/Fuzzer/FuzzerTracePC.h | 3 ++- 8 files changed, 51 insertions(+), 13 deletions(-) diff --git a/lib/Fuzzer/FuzzerCorpus.h b/lib/Fuzzer/FuzzerCorpus.h index 6438a6035f1..802f700f5c9 100644 --- a/lib/Fuzzer/FuzzerCorpus.h +++ b/lib/Fuzzer/FuzzerCorpus.h @@ -58,6 +58,7 @@ class InputCorpus { 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)]; }; @@ -81,7 +82,7 @@ class InputCorpus { } void PrintFeatureSet() { - Printf("Features [id: cnt idx sz] "); + Printf("Features [id: idx sz] "); for (size_t i = 0; i < kFeatureSetSize; i++) { auto &Fe = FeatureSet[i]; if (!Fe.Count) continue; diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index 484d8901525..8f7820d521d 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -398,6 +398,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.UseMemcmp = Flags.use_memcmp; Options.UseMemmem = Flags.use_memmem; Options.UseValueProfile = Flags.use_value_profile; + Options.Shrink = Flags.shrink; Options.ShuffleAtStartUp = Flags.shuffle; Options.PreferSmall = Flags.prefer_small; Options.Reload = Flags.reload; @@ -429,6 +430,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.PrintCoverage = Flags.print_coverage; 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. diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def index 230ad579955..ea998bb9a9e 100644 --- a/lib/Fuzzer/FuzzerFlags.def +++ b/lib/Fuzzer/FuzzerFlags.def @@ -49,6 +49,7 @@ 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(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.") @@ -95,6 +96,9 @@ FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" 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/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index e85bd8aa17e..ba538b89826 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -117,6 +117,7 @@ private: bool DuringInitialCorpusExecution); void AddToCorpus(const Unit &U); void CheckExitOnSrcPos(); + void CheckExitOnItem(); // Trace-based fuzzing: we run a unit with some kind of tracing // enabled and record potentially useful mutations. Then diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index ab4a25da8ee..f2e0f243a1a 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -79,8 +79,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; @@ -107,12 +105,6 @@ bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) { } } - if (TPC.UpdateCounterMap(&C->TPCMap)) - Res = true; - - if (TPC.UpdateValueProfileMap(&C->VPMap)) - Res = true; - return Res; } @@ -353,6 +345,16 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { this->MaxMutationLen = MaxMutationLen; } +void Fuzzer::CheckExitOnItem() { + 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::CheckExitOnSrcPos() { if (!Options.ExitOnSrcPos.empty()) { uintptr_t *PCIDs; @@ -422,7 +424,22 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) { TotalNumberOfRuns++; ExecuteCallback(Data, Size); - bool Res = RecordMaxCoverage(&MaxCoverage); + bool Res = false; + + if (TPC.FinalizeTrace(Size)) + if (Options.Shrink) + Res = true; + + if (!Res) { + if (TPC.UpdateCounterMap(&MaxCoverage.TPCMap)) + Res = true; + + if (TPC.UpdateValueProfileMap(&MaxCoverage.VPMap)) + Res = true; + } + + if (RecordMaxCoverage(&MaxCoverage)) + Res = true; CheckExitOnSrcPos(); auto TimeOfUnit = @@ -667,6 +684,7 @@ void Fuzzer::MutateAndTestOne() { if (RunOne(CurrentUnitData, Size)) { Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size}); ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); + CheckExitOnItem(); } StopTraceRecording(); TryDetectingAMemoryLeak(CurrentUnitData, Size, diff --git a/lib/Fuzzer/FuzzerOptions.h b/lib/Fuzzer/FuzzerOptions.h index 09b2cdec945..04a44d8c9ff 100644 --- a/lib/Fuzzer/FuzzerOptions.h +++ b/lib/Fuzzer/FuzzerOptions.h @@ -31,6 +31,7 @@ struct FuzzingOptions { bool UseMemcmp = true; bool UseMemmem = true; bool UseValueProfile = false; + bool Shrink = false; bool Reload = true; bool ShuffleAtStartUp = true; bool PreferSmall = true; @@ -41,6 +42,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; diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index f97da96589d..f02b71dc9de 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -68,7 +68,8 @@ void TracePC::ResetGuards() { assert(N == NumGuards); } -void TracePC::FinalizeTrace() { +bool TracePC::FinalizeTrace(size_t InputSize) { + bool Res = false; if (TotalPCCoverage) { const size_t Step = 8; assert(reinterpret_cast(Counters) % Step == 0); @@ -89,10 +90,17 @@ void TracePC::FinalizeTrace() { 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 Feature = i * 8 + Bit; + CounterMap.AddValue(Feature); + uint32_t *SizePtr = &InputSizesPerFeature[Feature]; + if (!*SizePtr || *SizePtr > InputSize) { + *SizePtr = InputSize; + Res = true; + } } } } + return Res; } void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { diff --git a/lib/Fuzzer/FuzzerTracePC.h b/lib/Fuzzer/FuzzerTracePC.h index 1eb4a303ef0..79ec7fb70c5 100644 --- a/lib/Fuzzer/FuzzerTracePC.h +++ b/lib/Fuzzer/FuzzerTracePC.h @@ -35,7 +35,7 @@ class TracePC { bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap) { return UseValueProfile && MaxValueProfileMap->MergeFrom(ValueProfileMap); } - void FinalizeTrace(); + bool FinalizeTrace(size_t InputSize); size_t GetNewPCIDs(uintptr_t **NewPCIDsPtr) { *NewPCIDsPtr = NewPCIDs; @@ -90,6 +90,7 @@ private: ValueBitMap CounterMap; ValueBitMap ValueProfileMap; + uint32_t InputSizesPerFeature[kFeatureSetSize]; }; extern TracePC TPC; -- 2.11.0