[libFuzzer] allow users to supply their own implementation of rand

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243078 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Kostya Serebryany
2015-07-24 01:06:40 +00:00
parent a8f6ce415b
commit 33a9a09cd7
10 changed files with 85 additions and 32 deletions

View File

@@ -18,9 +18,9 @@ namespace fuzzer {
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. // Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
size_t CrossOver(const uint8_t *Data1, size_t Size1, size_t CrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2, const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize) { uint8_t *Out, size_t MaxOutSize, FuzzerRandomBase &Rand) {
assert(Size1 || Size2); assert(Size1 || Size2);
MaxOutSize = rand() % MaxOutSize + 1; MaxOutSize = Rand(MaxOutSize) + 1;
size_t OutPos = 0; size_t OutPos = 0;
size_t Pos1 = 0; size_t Pos1 = 0;
size_t Pos2 = 0; size_t Pos2 = 0;
@@ -34,7 +34,7 @@ size_t CrossOver(const uint8_t *Data1, size_t Size1,
if (*InPos < InSize) { if (*InPos < InSize) {
size_t InSizeLeft = InSize - *InPos; size_t InSizeLeft = InSize - *InPos;
size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft); 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); memcpy(Out + OutPos, Data + *InPos, ExtraSize);
OutPos += ExtraSize; OutPos += ExtraSize;
(*InPos) += ExtraSize; (*InPos) += ExtraSize;

View File

@@ -202,7 +202,8 @@ int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
} }
int FuzzerDriver(int argc, char **argv, UserCallback Callback) { int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
SimpleUserSuppliedFuzzer SUSF(Callback); FuzzerRandomLibc Rand(0);
SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
return FuzzerDriver(argc, argv, SUSF); return FuzzerDriver(argc, argv, SUSF);
} }
@@ -257,7 +258,7 @@ int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) {
Seed = time(0) * 10000 + getpid(); Seed = time(0) * 10000 + getpid();
if (Flags.verbosity) if (Flags.verbosity)
Printf("Seed: %u\n", Seed); Printf("Seed: %u\n", Seed);
srand(Seed); USF.GetRand().ResetSeed(Seed);
// Timer // Timer
if (Flags.timeout > 0) if (Flags.timeout > 0)

View File

@@ -14,14 +14,30 @@
#include "FuzzerInternal.h" #include "FuzzerInternal.h"
namespace fuzzer { 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 UserSuppliedFuzzer::BasicMutate(uint8_t *Data, size_t Size,
size_t MaxSize) { 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, size_t UserSuppliedFuzzer::BasicCrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2, const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize) { 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. } // namespace fuzzer.

View File

@@ -42,6 +42,26 @@ int main(int argc, char **argv) {
*/ */
int FuzzerDriver(int argc, char **argv, UserCallback Callback); 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. /** An abstract class that allows to use user-supplied mutators with libFuzzer.
Usage: Usage:
@@ -50,6 +70,7 @@ Usage:
#include "FuzzerInterface.h" #include "FuzzerInterface.h"
class MyFuzzer : public fuzzer::UserSuppliedFuzzer { class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
public: public:
MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
// Must define the target function. // Must define the target function.
void TargetFunction(...) { ... } void TargetFunction(...) { ... }
// Optionally define the mutator. // Optionally define the mutator.
@@ -66,6 +87,8 @@ int main(int argc, char **argv) {
*/ */
class UserSuppliedFuzzer { class UserSuppliedFuzzer {
public: public:
UserSuppliedFuzzer(); // Deprecated, don't use.
UserSuppliedFuzzer(FuzzerRandomBase *Rand);
/// Executes the target function on 'Size' bytes of 'Data'. /// Executes the target function on 'Size' bytes of 'Data'.
virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0; virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0;
/// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes, /// 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) { uint8_t *Out, size_t MaxOutSize) {
return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize); return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
} }
virtual ~UserSuppliedFuzzer() {} virtual ~UserSuppliedFuzzer();
FuzzerRandomBase &GetRand() { return *Rand; }
protected: protected:
/// These can be called internally by Mutate and CrossOver. /// 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, size_t BasicCrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2, const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize); uint8_t *Out, size_t MaxOutSize);
private:
bool OwnRand = false;
FuzzerRandomBase *Rand;
}; };
/// Runs the fuzzing with the UserSuppliedFuzzer. /// Runs the fuzzing with the UserSuppliedFuzzer.

View File

@@ -33,10 +33,12 @@ void CopyFileToErr(const std::string &Path);
std::string DirPlusFile(const std::string &DirPath, std::string DirPlusFile(const std::string &DirPath,
const std::string &FileName); 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 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 Printf(const char *Fmt, ...);
void Print(const Unit &U, const char *PrintAfter = ""); void Print(const Unit &U, const char *PrintAfter = "");
@@ -155,7 +157,8 @@ class Fuzzer {
class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer { class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
public: 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) { virtual void TargetFunction(const uint8_t *Data, size_t Size) {
return Callback(Data, Size); return Callback(Data, Size);
} }

View File

@@ -113,14 +113,14 @@ void Fuzzer::RereadOutputCorpus() {
void Fuzzer::ShuffleAndMinimize() { void Fuzzer::ShuffleAndMinimize() {
size_t MaxCov = 0; size_t MaxCov = 0;
bool PreferSmall = bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
(Options.PreferSmallDuringInitialShuffle == 1 || (Options.PreferSmallDuringInitialShuffle == -1 &&
(Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2)); USF.GetRand().RandBool()));
if (Options.Verbosity) if (Options.Verbosity)
Printf("PreferSmall: %d\n", PreferSmall); Printf("PreferSmall: %d\n", PreferSmall);
PrintStats("READ ", 0); PrintStats("READ ", 0);
std::vector<Unit> NewCorpus; std::vector<Unit> NewCorpus;
std::random_shuffle(Corpus.begin(), Corpus.end()); std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand());
if (PreferSmall) if (PreferSmall)
std::stable_sort( std::stable_sort(
Corpus.begin(), Corpus.end(), Corpus.begin(), Corpus.end(),

View File

@@ -15,8 +15,8 @@
namespace fuzzer { namespace fuzzer {
static char FlipRandomBit(char X) { static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
int Bit = rand() % 8; int Bit = Rand(8);
char Mask = 1 << Bit; char Mask = 1 << Bit;
char R; char R;
if (X & (1 << Bit)) if (X & (1 << Bit))
@@ -27,24 +27,25 @@ static char FlipRandomBit(char X) {
return R; return R;
} }
static char RandCh() { static char RandCh(FuzzerRandomBase &Rand) {
if (rand() % 2) return rand(); if (Rand.RandBool()) return Rand(256);
const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~."; const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
return Special[rand() % (sizeof(Special) - 1)]; return Special[Rand(sizeof(Special) - 1)];
} }
// Mutates Data in place, returns new size. // 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(MaxSize > 0);
assert(Size <= MaxSize); assert(Size <= MaxSize);
if (Size == 0) { if (Size == 0) {
for (size_t i = 0; i < MaxSize; i++) for (size_t i = 0; i < MaxSize; i++)
Data[i] = RandCh(); Data[i] = RandCh(Rand);
return MaxSize; return MaxSize;
} }
assert(Size > 0); assert(Size > 0);
size_t Idx = rand() % Size; size_t Idx = Rand(Size);
switch (rand() % 3) { switch (Rand(3)) {
case 0: case 0:
if (Size > 1) { if (Size > 1) {
// Erase Data[Idx]. // Erase Data[Idx].
@@ -56,12 +57,12 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
if (Size < MaxSize) { if (Size < MaxSize) {
// Insert new value at Data[Idx]. // Insert new value at Data[Idx].
memmove(Data + Idx + 1, Data + Idx, Size - Idx); memmove(Data + Idx + 1, Data + Idx, Size - Idx);
Data[Idx] = RandCh(); Data[Idx] = RandCh(Rand);
} }
Data[Idx] = RandCh(); Data[Idx] = RandCh(Rand);
break; break;
case 2: case 2:
Data[Idx] = FlipRandomBit(Data[Idx]); Data[Idx] = FlipRandomBit(Data[Idx], Rand);
break; break;
} }
assert(Size > 0); assert(Size > 0);

View File

@@ -191,9 +191,9 @@ class TraceState {
Mutations.clear(); Mutations.clear();
} }
size_t StopTraceRecording() { size_t StopTraceRecording(FuzzerRandomBase &Rand) {
RecordingTraces = false; RecordingTraces = false;
std::random_shuffle(Mutations.begin(), Mutations.end()); std::random_shuffle(Mutations.begin(), Mutations.end(), Rand);
return Mutations.size(); return Mutations.size();
} }
@@ -302,7 +302,7 @@ void Fuzzer::StartTraceRecording() {
size_t Fuzzer::StopTraceRecording() { size_t Fuzzer::StopTraceRecording() {
if (!TS) return 0; if (!TS) return 0;
return TS->StopTraceRecording(); return TS->StopTraceRecording(USF.GetRand());
} }
void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) { void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) {

View File

@@ -10,6 +10,7 @@ extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
TEST(Fuzzer, CrossOver) { TEST(Fuzzer, CrossOver) {
using namespace fuzzer; using namespace fuzzer;
FuzzerRandomLibc Rand(0);
Unit A({0, 1, 2}), B({5, 6, 7}); Unit A({0, 1, 2}), B({5, 6, 7});
Unit C; Unit C;
Unit Expected[] = { Unit Expected[] = {
@@ -53,7 +54,7 @@ TEST(Fuzzer, CrossOver) {
for (int Iter = 0; Iter < 3000; Iter++) { for (int Iter = 0; Iter < 3000; Iter++) {
C.resize(Len); C.resize(Len);
size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(), size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(),
C.data(), C.size()); C.data(), C.size(), Rand);
C.resize(NewSize); C.resize(NewSize);
FoundUnits.insert(C); FoundUnits.insert(C);
} }

View File

@@ -14,6 +14,8 @@ static const uint64_t kMagic = 8860221463604ULL;
class MyFuzzer : public fuzzer::UserSuppliedFuzzer { class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
public: public:
MyFuzzer(fuzzer::FuzzerRandomBase *Rand)
: fuzzer::UserSuppliedFuzzer(Rand) {}
void TargetFunction(const uint8_t *Data, size_t Size) { void TargetFunction(const uint8_t *Data, size_t Size) {
if (Size <= 10) return; if (Size <= 10) return;
if (memcmp(Data, &kMagic, sizeof(kMagic))) return; if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
@@ -42,6 +44,7 @@ class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
}; };
int main(int argc, char **argv) { int main(int argc, char **argv) {
MyFuzzer F; fuzzer::FuzzerRandomLibc Rand(0);
MyFuzzer F(&Rand);
fuzzer::FuzzerDriver(argc, argv, F); fuzzer::FuzzerDriver(argc, argv, F);
} }