131 lines
4.6 KiB
Diff
131 lines
4.6 KiB
Diff
# HG changeset patch
|
|
# User Christian Holler <choller@mozilla.com>
|
|
# Date 1596126448 -7200
|
|
# Thu Jul 30 18:27:28 2020 +0200
|
|
# Node ID ea198a0331a6db043cb5978512226977514104db
|
|
# Parent 8a2a26b33d516c43c366b2f24d731d27d9843349
|
|
[libFuzzer] Change libFuzzer callback contract to allow positive return values
|
|
|
|
diff --git a/FuzzerInternal.h b/FuzzerInternal.h
|
|
--- a/FuzzerInternal.h
|
|
+++ b/FuzzerInternal.h
|
|
@@ -60,17 +60,17 @@ public:
|
|
|
|
static void StaticAlarmCallback();
|
|
static void StaticCrashSignalCallback();
|
|
static void StaticExitCallback();
|
|
static void StaticInterruptCallback();
|
|
static void StaticFileSizeExceedCallback();
|
|
static void StaticGracefulExitCallback();
|
|
|
|
- void ExecuteCallback(const uint8_t *Data, size_t Size);
|
|
+ int ExecuteCallback(const uint8_t *Data, size_t Size);
|
|
bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
|
|
InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
|
|
|
|
// Merge Corpora[1:] into Corpora[0].
|
|
void Merge(const Vector<std::string> &Corpora);
|
|
void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
|
|
MutationDispatcher &GetMD() { return MD; }
|
|
void PrintFinalStats();
|
|
diff --git a/FuzzerLoop.cpp b/FuzzerLoop.cpp
|
|
--- a/FuzzerLoop.cpp
|
|
+++ b/FuzzerLoop.cpp
|
|
@@ -463,17 +463,19 @@ static void RenameFeatureSetFile(const s
|
|
DirPlusFile(FeaturesDir, NewFile));
|
|
}
|
|
|
|
bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
|
|
InputInfo *II, bool *FoundUniqFeatures) {
|
|
if (!Size)
|
|
return false;
|
|
|
|
- ExecuteCallback(Data, Size);
|
|
+ if (ExecuteCallback(Data, Size)) {
|
|
+ return false;
|
|
+ }
|
|
|
|
UniqFeatureSetTmp.clear();
|
|
size_t FoundUniqFeaturesOfII = 0;
|
|
size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
|
|
TPC.CollectFeatures([&](size_t Feature) {
|
|
if (Corpus.AddFeature(Feature, Size, Options.Shrink))
|
|
UniqFeatureSetTmp.push_back(Feature);
|
|
if (Options.Entropic)
|
|
@@ -530,48 +532,49 @@ static bool LooseMemeq(const uint8_t *A,
|
|
const size_t Limit = 64;
|
|
if (Size <= 64)
|
|
return !memcmp(A, B, Size);
|
|
// Compare first and last Limit/2 bytes.
|
|
return !memcmp(A, B, Limit / 2) &&
|
|
!memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
|
|
}
|
|
|
|
-void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
|
|
+int Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
|
|
TPC.RecordInitialStack();
|
|
TotalNumberOfRuns++;
|
|
assert(InFuzzingThread());
|
|
// We copy the contents of Unit into a separate heap buffer
|
|
// so that we reliably find buffer overflows in it.
|
|
uint8_t *DataCopy = new uint8_t[Size];
|
|
memcpy(DataCopy, Data, Size);
|
|
if (EF->__msan_unpoison)
|
|
EF->__msan_unpoison(DataCopy, Size);
|
|
if (EF->__msan_unpoison_param)
|
|
EF->__msan_unpoison_param(2);
|
|
if (CurrentUnitData && CurrentUnitData != Data)
|
|
memcpy(CurrentUnitData, Data, Size);
|
|
CurrentUnitSize = Size;
|
|
+ int Res = 0;
|
|
{
|
|
ScopedEnableMsanInterceptorChecks S;
|
|
AllocTracer.Start(Options.TraceMalloc);
|
|
UnitStartTime = system_clock::now();
|
|
TPC.ResetMaps();
|
|
RunningUserCallback = true;
|
|
- int Res = CB(DataCopy, Size);
|
|
+ Res = CB(DataCopy, Size);
|
|
RunningUserCallback = false;
|
|
UnitStopTime = system_clock::now();
|
|
- (void)Res;
|
|
- assert(Res == 0);
|
|
HasMoreMallocsThanFrees = AllocTracer.Stop();
|
|
}
|
|
if (!LooseMemeq(DataCopy, Data, Size))
|
|
CrashOnOverwrittenData();
|
|
CurrentUnitSize = 0;
|
|
delete[] DataCopy;
|
|
+ return Res;
|
|
}
|
|
|
|
std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
|
|
if (Options.OnlyASCII)
|
|
assert(IsASCII(U));
|
|
if (Options.OutputCorpus.empty())
|
|
return "";
|
|
std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
|
|
diff --git a/FuzzerMerge.cpp b/FuzzerMerge.cpp
|
|
--- a/FuzzerMerge.cpp
|
|
+++ b/FuzzerMerge.cpp
|
|
@@ -223,17 +223,19 @@ void Fuzzer::CrashResistantMergeInternal
|
|
U.shrink_to_fit();
|
|
}
|
|
|
|
// Write the pre-run marker.
|
|
OF << "STARTED " << i << " " << U.size() << "\n";
|
|
OF.flush(); // Flush is important since Command::Execute may crash.
|
|
// Run.
|
|
TPC.ResetMaps();
|
|
- ExecuteCallback(U.data(), U.size());
|
|
+ if (ExecuteCallback(U.data(), U.size())) {
|
|
+ continue;
|
|
+ }
|
|
// Collect coverage. We are iterating over the files in this order:
|
|
// * First, files in the initial corpus ordered by size, smallest first.
|
|
// * Then, all other files, smallest first.
|
|
// So it makes no sense to record all features for all files, instead we
|
|
// only record features that were not seen before.
|
|
Set<size_t> UniqFeatures;
|
|
TPC.CollectFeatures([&](size_t Feature) {
|
|
if (AllFeatures.insert(Feature).second)
|