From 404c69f2c8c7f7d4993f80fb1f7390571ffe56b6 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 24 Jul 2015 01:06:40 +0000 Subject: [PATCH] [libFuzzer] allow users to supply their own implementation of rand llvm-svn: 243078 --- llvm/lib/Fuzzer/FuzzerCrossOver.cpp | 6 ++--- llvm/lib/Fuzzer/FuzzerDriver.cpp | 5 +++-- llvm/lib/Fuzzer/FuzzerInterface.cpp | 20 +++++++++++++++-- llvm/lib/Fuzzer/FuzzerInterface.h | 30 ++++++++++++++++++++++++- llvm/lib/Fuzzer/FuzzerInternal.h | 9 +++++--- llvm/lib/Fuzzer/FuzzerLoop.cpp | 8 +++---- llvm/lib/Fuzzer/FuzzerMutate.cpp | 25 +++++++++++---------- llvm/lib/Fuzzer/FuzzerTraceState.cpp | 6 ++--- llvm/lib/Fuzzer/test/FuzzerUnittest.cpp | 3 ++- llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp | 5 ++++- 10 files changed, 85 insertions(+), 32 deletions(-) diff --git a/llvm/lib/Fuzzer/FuzzerCrossOver.cpp b/llvm/lib/Fuzzer/FuzzerCrossOver.cpp index d93ce5c..8b13698 100644 --- a/llvm/lib/Fuzzer/FuzzerCrossOver.cpp +++ b/llvm/lib/Fuzzer/FuzzerCrossOver.cpp @@ -18,9 +18,9 @@ namespace fuzzer { // Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize) { + uint8_t *Out, size_t MaxOutSize, FuzzerRandomBase &Rand) { assert(Size1 || Size2); - MaxOutSize = rand() % MaxOutSize + 1; + MaxOutSize = Rand(MaxOutSize) + 1; size_t OutPos = 0; size_t Pos1 = 0; size_t Pos2 = 0; @@ -34,7 +34,7 @@ size_t CrossOver(const uint8_t *Data1, size_t Size1, if (*InPos < InSize) { size_t InSizeLeft = InSize - *InPos; size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft); - size_t ExtraSize = rand() % MaxExtraSize + 1; + size_t ExtraSize = Rand(MaxExtraSize) + 1; memcpy(Out + OutPos, Data + *InPos, ExtraSize); OutPos += ExtraSize; (*InPos) += ExtraSize; diff --git a/llvm/lib/Fuzzer/FuzzerDriver.cpp b/llvm/lib/Fuzzer/FuzzerDriver.cpp index 0ee08e1..c0f8220 100644 --- a/llvm/lib/Fuzzer/FuzzerDriver.cpp +++ b/llvm/lib/Fuzzer/FuzzerDriver.cpp @@ -202,7 +202,8 @@ int ApplyTokens(const Fuzzer &F, const char *InputFilePath) { } int FuzzerDriver(int argc, char **argv, UserCallback Callback) { - SimpleUserSuppliedFuzzer SUSF(Callback); + FuzzerRandomLibc Rand(0); + SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); return FuzzerDriver(argc, argv, SUSF); } @@ -257,7 +258,7 @@ int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) { Seed = time(0) * 10000 + getpid(); if (Flags.verbosity) Printf("Seed: %u\n", Seed); - srand(Seed); + USF.GetRand().ResetSeed(Seed); // Timer if (Flags.timeout > 0) diff --git a/llvm/lib/Fuzzer/FuzzerInterface.cpp b/llvm/lib/Fuzzer/FuzzerInterface.cpp index dcd4e74..c7553f4 100644 --- a/llvm/lib/Fuzzer/FuzzerInterface.cpp +++ b/llvm/lib/Fuzzer/FuzzerInterface.cpp @@ -14,14 +14,30 @@ #include "FuzzerInternal.h" namespace fuzzer { + +void FuzzerRandomLibc::ResetSeed(int seed) { srand(seed); } + +size_t FuzzerRandomLibc::Rand() { return rand(); } + +UserSuppliedFuzzer::UserSuppliedFuzzer() + : OwnRand(true), Rand(new FuzzerRandomLibc(0)) {} + +UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand) : Rand(Rand) {} + +UserSuppliedFuzzer::~UserSuppliedFuzzer() { + if (OwnRand) + delete Rand; +} + size_t UserSuppliedFuzzer::BasicMutate(uint8_t *Data, size_t Size, size_t MaxSize) { - return ::fuzzer::Mutate(Data, Size, MaxSize); + return ::fuzzer::Mutate(Data, Size, MaxSize, *Rand); } size_t UserSuppliedFuzzer::BasicCrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize) { - return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize); + return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize, + *Rand); } } // namespace fuzzer. diff --git a/llvm/lib/Fuzzer/FuzzerInterface.h b/llvm/lib/Fuzzer/FuzzerInterface.h index 3fd807a..3be4b05 100644 --- a/llvm/lib/Fuzzer/FuzzerInterface.h +++ b/llvm/lib/Fuzzer/FuzzerInterface.h @@ -42,6 +42,26 @@ int main(int argc, char **argv) { */ int FuzzerDriver(int argc, char **argv, UserCallback Callback); +class FuzzerRandomBase { + public: + FuzzerRandomBase(){} + virtual ~FuzzerRandomBase(){}; + virtual void ResetSeed(int seed) = 0; + // Return a random number. + virtual size_t Rand() = 0; + // Return a random number in range [0,n). + size_t operator()(size_t n) { return Rand() % n; } + bool RandBool() { return Rand() % 2; } +}; + +class FuzzerRandomLibc : public FuzzerRandomBase { + public: + FuzzerRandomLibc(int seed) { ResetSeed(seed); } + void ResetSeed(int seed) override; + ~FuzzerRandomLibc() override {} + size_t Rand() override; +}; + /** An abstract class that allows to use user-supplied mutators with libFuzzer. Usage: @@ -50,6 +70,7 @@ Usage: #include "FuzzerInterface.h" class MyFuzzer : public fuzzer::UserSuppliedFuzzer { public: + MyFuzzer(fuzzer::FuzzerRandomBase *Rand); // Must define the target function. void TargetFunction(...) { ... } // Optionally define the mutator. @@ -66,6 +87,8 @@ int main(int argc, char **argv) { */ class UserSuppliedFuzzer { public: + UserSuppliedFuzzer(); // Deprecated, don't use. + UserSuppliedFuzzer(FuzzerRandomBase *Rand); /// Executes the target function on 'Size' bytes of 'Data'. virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0; /// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes, @@ -80,7 +103,9 @@ class UserSuppliedFuzzer { uint8_t *Out, size_t MaxOutSize) { return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize); } - virtual ~UserSuppliedFuzzer() {} + virtual ~UserSuppliedFuzzer(); + + FuzzerRandomBase &GetRand() { return *Rand; } protected: /// These can be called internally by Mutate and CrossOver. @@ -88,6 +113,9 @@ class UserSuppliedFuzzer { size_t BasicCrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize); + private: + bool OwnRand = false; + FuzzerRandomBase *Rand; }; /// Runs the fuzzing with the UserSuppliedFuzzer. diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index af3d011..fe78698 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -33,10 +33,12 @@ void CopyFileToErr(const std::string &Path); std::string DirPlusFile(const std::string &DirPath, const std::string &FileName); -size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); +size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand); size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, - size_t Size2, uint8_t *Out, size_t MaxOutSize); + size_t Size2, uint8_t *Out, size_t MaxOutSize, + FuzzerRandomBase &Rand); void Printf(const char *Fmt, ...); void Print(const Unit &U, const char *PrintAfter = ""); @@ -155,7 +157,8 @@ class Fuzzer { class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer { public: - SimpleUserSuppliedFuzzer(UserCallback Callback) : Callback(Callback) {} + SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback) + : UserSuppliedFuzzer(Rand), Callback(Callback) {} virtual void TargetFunction(const uint8_t *Data, size_t Size) { return Callback(Data, Size); } diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp index d653391..e659223 100644 --- a/llvm/lib/Fuzzer/FuzzerLoop.cpp +++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -113,14 +113,14 @@ void Fuzzer::RereadOutputCorpus() { void Fuzzer::ShuffleAndMinimize() { size_t MaxCov = 0; - bool PreferSmall = - (Options.PreferSmallDuringInitialShuffle == 1 || - (Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2)); + bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 || + (Options.PreferSmallDuringInitialShuffle == -1 && + USF.GetRand().RandBool())); if (Options.Verbosity) Printf("PreferSmall: %d\n", PreferSmall); PrintStats("READ ", 0); std::vector NewCorpus; - std::random_shuffle(Corpus.begin(), Corpus.end()); + std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand()); if (PreferSmall) std::stable_sort( Corpus.begin(), Corpus.end(), diff --git a/llvm/lib/Fuzzer/FuzzerMutate.cpp b/llvm/lib/Fuzzer/FuzzerMutate.cpp index f537fa9..66df98a 100644 --- a/llvm/lib/Fuzzer/FuzzerMutate.cpp +++ b/llvm/lib/Fuzzer/FuzzerMutate.cpp @@ -15,8 +15,8 @@ namespace fuzzer { -static char FlipRandomBit(char X) { - int Bit = rand() % 8; +static char FlipRandomBit(char X, FuzzerRandomBase &Rand) { + int Bit = Rand(8); char Mask = 1 << Bit; char R; if (X & (1 << Bit)) @@ -27,24 +27,25 @@ static char FlipRandomBit(char X) { return R; } -static char RandCh() { - if (rand() % 2) return rand(); +static char RandCh(FuzzerRandomBase &Rand) { + if (Rand.RandBool()) return Rand(256); const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~."; - return Special[rand() % (sizeof(Special) - 1)]; + return Special[Rand(sizeof(Special) - 1)]; } // Mutates Data in place, returns new size. -size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { +size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand) { assert(MaxSize > 0); assert(Size <= MaxSize); if (Size == 0) { for (size_t i = 0; i < MaxSize; i++) - Data[i] = RandCh(); + Data[i] = RandCh(Rand); return MaxSize; } assert(Size > 0); - size_t Idx = rand() % Size; - switch (rand() % 3) { + size_t Idx = Rand(Size); + switch (Rand(3)) { case 0: if (Size > 1) { // Erase Data[Idx]. @@ -56,12 +57,12 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { if (Size < MaxSize) { // Insert new value at Data[Idx]. memmove(Data + Idx + 1, Data + Idx, Size - Idx); - Data[Idx] = RandCh(); + Data[Idx] = RandCh(Rand); } - Data[Idx] = RandCh(); + Data[Idx] = RandCh(Rand); break; case 2: - Data[Idx] = FlipRandomBit(Data[Idx]); + Data[Idx] = FlipRandomBit(Data[Idx], Rand); break; } assert(Size > 0); diff --git a/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/llvm/lib/Fuzzer/FuzzerTraceState.cpp index b2e1e95..75b77ca 100644 --- a/llvm/lib/Fuzzer/FuzzerTraceState.cpp +++ b/llvm/lib/Fuzzer/FuzzerTraceState.cpp @@ -191,9 +191,9 @@ class TraceState { Mutations.clear(); } - size_t StopTraceRecording() { + size_t StopTraceRecording(FuzzerRandomBase &Rand) { RecordingTraces = false; - std::random_shuffle(Mutations.begin(), Mutations.end()); + std::random_shuffle(Mutations.begin(), Mutations.end(), Rand); return Mutations.size(); } @@ -302,7 +302,7 @@ void Fuzzer::StartTraceRecording() { size_t Fuzzer::StopTraceRecording() { if (!TS) return 0; - return TS->StopTraceRecording(); + return TS->StopTraceRecording(USF.GetRand()); } void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) { diff --git a/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp b/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp index 50f2f99..ed52a55 100644 --- a/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -10,6 +10,7 @@ extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { TEST(Fuzzer, CrossOver) { using namespace fuzzer; + FuzzerRandomLibc Rand(0); Unit A({0, 1, 2}), B({5, 6, 7}); Unit C; Unit Expected[] = { @@ -53,7 +54,7 @@ TEST(Fuzzer, CrossOver) { for (int Iter = 0; Iter < 3000; Iter++) { C.resize(Len); size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(), - C.data(), C.size()); + C.data(), C.size(), Rand); C.resize(NewSize); FoundUnits.insert(C); } diff --git a/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp b/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp index b46313d..8ebe157 100644 --- a/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp +++ b/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp @@ -14,6 +14,8 @@ static const uint64_t kMagic = 8860221463604ULL; class MyFuzzer : public fuzzer::UserSuppliedFuzzer { public: + MyFuzzer(fuzzer::FuzzerRandomBase *Rand) + : fuzzer::UserSuppliedFuzzer(Rand) {} void TargetFunction(const uint8_t *Data, size_t Size) { if (Size <= 10) return; if (memcmp(Data, &kMagic, sizeof(kMagic))) return; @@ -42,6 +44,7 @@ class MyFuzzer : public fuzzer::UserSuppliedFuzzer { }; int main(int argc, char **argv) { - MyFuzzer F; + fuzzer::FuzzerRandomLibc Rand(0); + MyFuzzer F(&Rand); fuzzer::FuzzerDriver(argc, argv, F); } -- 2.7.4