From 6f5a804cdb6563293d4dc93bd9abf44950bc1076 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 21 Sep 2016 01:50:50 +0000 Subject: [PATCH] [libFuzzer] refactoring: split the large header into many; NFC llvm-svn: 282044 --- llvm/lib/Fuzzer/FuzzerCorpus.h | 56 +++++ llvm/lib/Fuzzer/FuzzerCrossOver.cpp | 2 + llvm/lib/Fuzzer/FuzzerDefs.h | 100 ++++++++ llvm/lib/Fuzzer/FuzzerDictionary.h | 114 ++++++++++ llvm/lib/Fuzzer/FuzzerDriver.cpp | 2 + llvm/lib/Fuzzer/FuzzerInternal.h | 391 +------------------------------- llvm/lib/Fuzzer/FuzzerLoop.cpp | 4 + llvm/lib/Fuzzer/FuzzerMain.cpp | 3 +- llvm/lib/Fuzzer/FuzzerMutate.cpp | 6 +- llvm/lib/Fuzzer/FuzzerMutate.h | 130 +++++++++++ llvm/lib/Fuzzer/FuzzerRandom.h | 31 +++ llvm/lib/Fuzzer/FuzzerTracePC.cpp | 1 + llvm/lib/Fuzzer/FuzzerTracePC.h | 84 +++++++ llvm/lib/Fuzzer/FuzzerTraceState.cpp | 5 +- llvm/lib/Fuzzer/FuzzerUtil.cpp | 4 - llvm/lib/Fuzzer/test/FuzzerUnittest.cpp | 3 + 16 files changed, 539 insertions(+), 397 deletions(-) create mode 100644 llvm/lib/Fuzzer/FuzzerCorpus.h create mode 100644 llvm/lib/Fuzzer/FuzzerDefs.h create mode 100644 llvm/lib/Fuzzer/FuzzerDictionary.h create mode 100644 llvm/lib/Fuzzer/FuzzerMutate.h create mode 100644 llvm/lib/Fuzzer/FuzzerRandom.h create mode 100644 llvm/lib/Fuzzer/FuzzerTracePC.h diff --git a/llvm/lib/Fuzzer/FuzzerCorpus.h b/llvm/lib/Fuzzer/FuzzerCorpus.h new file mode 100644 index 0000000..877a483 --- /dev/null +++ b/llvm/lib/Fuzzer/FuzzerCorpus.h @@ -0,0 +1,56 @@ +//===- FuzzerCorpus.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. +// +//===----------------------------------------------------------------------===// +// fuzzer::InputCorpus +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_CORPUS +#define LLVM_FUZZER_CORPUS + +#include "FuzzerDefs.h" + +namespace fuzzer { + +struct InputInfo { + Unit U; // The actual input data. +}; + +class InputCorpus { + public: + InputCorpus() { + Corpus.reserve(1 << 14); // Avoid too many resizes. + } + size_t size() const { return Corpus.size(); } + bool empty() const { return Corpus.empty(); } + const Unit &operator[] (size_t Idx) const { return Corpus[Idx].U; } + void Append(const std::vector &V) { + for (auto &U : V) + push_back(U); + } + void push_back(const Unit &U) { + auto H = Hash(U); + if (!Hashes.insert(H).second) return; + InputInfo II; + II.U = U; + Corpus.push_back(II); + } + + typedef const std::vector::const_iterator ConstIter; + ConstIter begin() const { return Corpus.begin(); } + ConstIter end() const { return Corpus.end(); } + + bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } + + private: + std::unordered_set Hashes; + std::vector Corpus; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_CORPUS diff --git a/llvm/lib/Fuzzer/FuzzerCrossOver.cpp b/llvm/lib/Fuzzer/FuzzerCrossOver.cpp index 5203dea..8f2b8f4 100644 --- a/llvm/lib/Fuzzer/FuzzerCrossOver.cpp +++ b/llvm/lib/Fuzzer/FuzzerCrossOver.cpp @@ -12,6 +12,8 @@ #include #include "FuzzerInternal.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" namespace fuzzer { diff --git a/llvm/lib/Fuzzer/FuzzerDefs.h b/llvm/lib/Fuzzer/FuzzerDefs.h new file mode 100644 index 0000000..9f47ece --- /dev/null +++ b/llvm/lib/Fuzzer/FuzzerDefs.h @@ -0,0 +1,100 @@ +//===- FuzzerDefs.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. +// +//===----------------------------------------------------------------------===// +// Basic definitions. +//===----------------------------------------------------------------------===// +#ifndef LLVM_FUZZER_DEFS_H +#define LLVM_FUZZER_DEFS_H + +#include +#include +#include +#include + +// Platform detection. +#ifdef __linux__ +#define LIBFUZZER_LINUX 1 +#define LIBFUZZER_APPLE 0 +#elif __APPLE__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 1 +#else +#error "Support for your platform has not been implemented" +#endif + +#ifdef __x86_64 +#define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt"))) +#else +#define ATTRIBUTE_TARGET_POPCNT +#endif + +namespace fuzzer { + +class Random; +class Dictionary; +class DictionaryEntry; +class MutationDispatcher; + +typedef std::vector Unit; +typedef std::vector UnitVector; +typedef int (*UserCallback)(const uint8_t *Data, size_t Size); +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); +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, + long *Epoch, size_t MaxSize); +void WriteToFile(const Unit &U, const std::string &Path); +void CopyFileToErr(const std::string &Path); +// Returns "Dir/FileName" or equivalent for the current OS. +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName); + +void DupAndCloseStderr(); +void CloseStdout(); +void Printf(const char *Fmt, ...); +void PrintHexArray(const Unit &U, const char *PrintAfter = ""); +void PrintHexArray(const uint8_t *Data, size_t Size, + const char *PrintAfter = ""); +void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); +void PrintASCII(const Unit &U, const char *PrintAfter = ""); + +void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC); +std::string Hash(const Unit &U); +void SetTimer(int Seconds); +void SetSigSegvHandler(); +void SetSigBusHandler(); +void SetSigAbrtHandler(); +void SetSigIllHandler(); +void SetSigFpeHandler(); +void SetSigIntHandler(); +void SetSigTermHandler(); +std::string Base64(const Unit &U); +int ExecuteCommand(const std::string &Command); +size_t GetPeakRSSMb(); + +// Private copy of SHA1 implementation. +static const int kSHA1NumBytes = 20; +// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. +void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); +std::string Sha1ToString(uint8_t Sha1[kSHA1NumBytes]); + +// Changes U to contain only ASCII (isprint+isspace) characters. +// Returns true iff U has been changed. +bool ToASCII(uint8_t *Data, size_t Size); +bool IsASCII(const Unit &U); +bool IsASCII(const uint8_t *Data, size_t Size); + +int NumberOfCpuCores(); +int GetPid(); +void SleepSeconds(int Seconds); + +} // namespace fuzzer +#endif // LLVM_FUZZER_DEFS_H diff --git a/llvm/lib/Fuzzer/FuzzerDictionary.h b/llvm/lib/Fuzzer/FuzzerDictionary.h new file mode 100644 index 0000000..3b5457b --- /dev/null +++ b/llvm/lib/Fuzzer/FuzzerDictionary.h @@ -0,0 +1,114 @@ +//===- FuzzerDictionary.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. +// +//===----------------------------------------------------------------------===// +// fuzzer::Dictionary +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_DICTIONARY_H +#define LLVM_FUZZER_DICTIONARY_H + +#include "FuzzerDefs.h" + +namespace fuzzer { +// A simple POD sized array of bytes. +template class FixedWord { +public: + FixedWord() {} + FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); } + + void Set(const uint8_t *B, uint8_t S) { + assert(S <= kMaxSize); + memcpy(Data, B, S); + Size = S; + } + + bool operator==(const FixedWord &w) const { + return Size == w.Size && 0 == memcmp(Data, w.Data, Size); + } + + bool operator<(const FixedWord &w) const { + if (Size != w.Size) + return Size < w.Size; + return memcmp(Data, w.Data, Size) < 0; + } + + static size_t GetMaxSize() { return kMaxSize; } + const uint8_t *data() const { return Data; } + uint8_t size() const { return Size; } + +private: + uint8_t Size = 0; + uint8_t Data[kMaxSize]; +}; + +typedef FixedWord<27> Word; // 28 bytes. + +class DictionaryEntry { + public: + DictionaryEntry() {} + DictionaryEntry(Word W) : W(W) {} + DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} + const Word &GetW() const { return W; } + + bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } + size_t GetPositionHint() const { + assert(HasPositionHint()); + return PositionHint; + } + void IncUseCount() { UseCount++; } + void IncSuccessCount() { SuccessCount++; } + size_t GetUseCount() const { return UseCount; } + size_t GetSuccessCount() const {return SuccessCount; } + +private: + Word W; + size_t PositionHint = std::numeric_limits::max(); + size_t UseCount = 0; + size_t SuccessCount = 0; +}; + +class Dictionary { + public: + static const size_t kMaxDictSize = 1 << 14; + + bool ContainsWord(const Word &W) const { + return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { + return DE.GetW() == W; + }); + } + const DictionaryEntry *begin() const { return &DE[0]; } + const DictionaryEntry *end() const { return begin() + Size; } + DictionaryEntry & operator[] (size_t Idx) { + assert(Idx < Size); + return DE[Idx]; + } + void push_back(DictionaryEntry DE) { + if (Size < kMaxDictSize) + this->DE[Size++] = DE; + } + void clear() { Size = 0; } + bool empty() const { return Size == 0; } + size_t size() const { return Size; } + +private: + DictionaryEntry DE[kMaxDictSize]; + size_t Size = 0; +}; + +// Parses one dictionary entry. +// If successfull, write the enty to Unit and returns true, +// otherwise returns false. +bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); +// Parses the dictionary file, fills Units, returns true iff all lines +// were parsed succesfully. +bool ParseDictionaryFile(const std::string &Text, std::vector *Units); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_DICTIONARY_H + diff --git a/llvm/lib/Fuzzer/FuzzerDriver.cpp b/llvm/lib/Fuzzer/FuzzerDriver.cpp index 054d4c5..253aa8e 100644 --- a/llvm/lib/Fuzzer/FuzzerDriver.cpp +++ b/llvm/lib/Fuzzer/FuzzerDriver.cpp @@ -11,6 +11,8 @@ #include "FuzzerInterface.h" #include "FuzzerInternal.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" #include #include diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index 1035c04..7b774d3 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -17,205 +17,24 @@ #include #include #include -#include #include -#include #include -#include #include -#include - -// Platform detection. -#ifdef __linux__ -#define LIBFUZZER_LINUX 1 -#define LIBFUZZER_APPLE 0 -#elif __APPLE__ -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_APPLE 1 -#else -#error "Support for your platform has not been implemented" -#endif - -#ifdef __x86_64 -#define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt"))) -#else -#define ATTRIBUTE_TARGET_POPCNT -#endif +#include "FuzzerDefs.h" #include "FuzzerExtFunctions.h" #include "FuzzerInterface.h" #include "FuzzerValueBitMap.h" +#include "FuzzerCorpus.h" // TODO(kcc): remove this from here. namespace fuzzer { -typedef int (*UserCallback)(const uint8_t *Data, size_t Size); -int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); - using namespace std::chrono; -typedef std::vector Unit; -typedef std::vector UnitVector; - -// A simple POD sized array of bytes. -template class FixedWord { -public: - FixedWord() {} - FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); } - - void Set(const uint8_t *B, uint8_t S) { - assert(S <= kMaxSize); - memcpy(Data, B, S); - Size = S; - } - - bool operator==(const FixedWord &w) const { - return Size == w.Size && 0 == memcmp(Data, w.Data, Size); - } - - bool operator<(const FixedWord &w) const { - if (Size != w.Size) - return Size < w.Size; - return memcmp(Data, w.Data, Size) < 0; - } - - static size_t GetMaxSize() { return kMaxSize; } - const uint8_t *data() const { return Data; } - uint8_t size() const { return Size; } - -private: - uint8_t Size = 0; - uint8_t Data[kMaxSize]; -}; - -typedef FixedWord<27> Word; // 28 bytes. - -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); -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, - long *Epoch, size_t MaxSize); -void WriteToFile(const Unit &U, const std::string &Path); -void CopyFileToErr(const std::string &Path); -// Returns "Dir/FileName" or equivalent for the current OS. -std::string DirPlusFile(const std::string &DirPath, - const std::string &FileName); - -void DupAndCloseStderr(); -void CloseStdout(); -void Printf(const char *Fmt, ...); -void PrintHexArray(const Unit &U, const char *PrintAfter = ""); -void PrintHexArray(const uint8_t *Data, size_t Size, - const char *PrintAfter = ""); -void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); -void PrintASCII(const Unit &U, const char *PrintAfter = ""); -void PrintASCII(const Word &W, const char *PrintAfter = ""); -void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC); -std::string Hash(const Unit &U); -void SetTimer(int Seconds); -void SetSigSegvHandler(); -void SetSigBusHandler(); -void SetSigAbrtHandler(); -void SetSigIllHandler(); -void SetSigFpeHandler(); -void SetSigIntHandler(); -void SetSigTermHandler(); -std::string Base64(const Unit &U); -int ExecuteCommand(const std::string &Command); -size_t GetPeakRSSMb(); - -// Private copy of SHA1 implementation. -static const int kSHA1NumBytes = 20; -// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. -void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); -std::string Sha1ToString(uint8_t Sha1[kSHA1NumBytes]); - -// Changes U to contain only ASCII (isprint+isspace) characters. -// Returns true iff U has been changed. -bool ToASCII(uint8_t *Data, size_t Size); -bool IsASCII(const Unit &U); -bool IsASCII(const uint8_t *Data, size_t Size); - -int NumberOfCpuCores(); -int GetPid(); -void SleepSeconds(int Seconds); // See FuzzerTraceState.cpp void EnableValueProfile(); size_t VPMapMergeFromCurrent(ValueBitMap &M); -class Random { - public: - Random(unsigned int seed) : R(seed) {} - size_t Rand() { return R(); } - size_t RandBool() { return Rand() % 2; } - size_t operator()(size_t n) { return n ? Rand() % n : 0; } - std::mt19937 &Get_mt19937() { return R; } - private: - std::mt19937 R; -}; - -// Dictionary. - -// Parses one dictionary entry. -// If successfull, write the enty to Unit and returns true, -// otherwise returns false. -bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); -// Parses the dictionary file, fills Units, returns true iff all lines -// were parsed succesfully. -bool ParseDictionaryFile(const std::string &Text, std::vector *Units); - -class DictionaryEntry { - public: - DictionaryEntry() {} - DictionaryEntry(Word W) : W(W) {} - DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} - const Word &GetW() const { return W; } - - bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } - size_t GetPositionHint() const { - assert(HasPositionHint()); - return PositionHint; - } - void IncUseCount() { UseCount++; } - void IncSuccessCount() { SuccessCount++; } - size_t GetUseCount() const { return UseCount; } - size_t GetSuccessCount() const {return SuccessCount; } - -private: - Word W; - size_t PositionHint = std::numeric_limits::max(); - size_t UseCount = 0; - size_t SuccessCount = 0; -}; - -class Dictionary { - public: - static const size_t kMaxDictSize = 1 << 14; - - bool ContainsWord(const Word &W) const { - return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { - return DE.GetW() == W; - }); - } - const DictionaryEntry *begin() const { return &DE[0]; } - const DictionaryEntry *end() const { return begin() + Size; } - DictionaryEntry & operator[] (size_t Idx) { - assert(Idx < Size); - return DE[Idx]; - } - void push_back(DictionaryEntry DE) { - if (Size < kMaxDictSize) - this->DE[Size++] = DE; - } - void clear() { Size = 0; } - bool empty() const { return Size == 0; } - size_t size() const { return Size; } - -private: - DictionaryEntry DE[kMaxDictSize]; - size_t Size = 0; -}; - struct FuzzingOptions { int Verbosity = 1; size_t MaxLen = 0; @@ -250,212 +69,6 @@ struct FuzzingOptions { bool PruneCorpus = true; }; -struct InputInfo { - Unit U; // The actual input data. -}; - -class InputCorpus { - public: - InputCorpus() { - Corpus.reserve(1 << 14); // Avoid too many resizes. - } - size_t size() const { return Corpus.size(); } - bool empty() const { return Corpus.empty(); } - const Unit &operator[] (size_t Idx) const { return Corpus[Idx].U; } - void Append(const std::vector &V) { - for (auto &U : V) - push_back(U); - } - void push_back(const Unit &U) { - auto H = Hash(U); - if (!Hashes.insert(H).second) return; - InputInfo II; - II.U = U; - Corpus.push_back(II); - } - - typedef const std::vector::const_iterator ConstIter; - ConstIter begin() const { return Corpus.begin(); } - ConstIter end() const { return Corpus.end(); } - - bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } - - private: - std::unordered_set Hashes; - std::vector Corpus; -}; - -class MutationDispatcher { -public: - MutationDispatcher(Random &Rand, const FuzzingOptions &Options); - ~MutationDispatcher() {} - /// Indicate that we are about to start a new sequence of mutations. - void StartMutationSequence(); - /// Print the current sequence of mutations. - void PrintMutationSequence(); - /// Indicate that the current sequence of mutations was successfull. - void RecordSuccessfulMutationSequence(); - /// Mutates data by invoking user-provided mutator. - size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by invoking user-provided crossover. - size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by shuffling bytes. - size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by erasing bytes. - size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by inserting a byte. - size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by inserting several repeated bytes. - size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by chanding one byte. - size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by chanding one bit. - size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by copying/inserting a part of data into a different place. - size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Mutates data by adding a word from the manual dictionary. - size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, - size_t MaxSize); - - /// Mutates data by adding a word from the temporary automatic dictionary. - size_t Mutate_AddWordFromTemporaryAutoDictionary(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); - - /// Tries to find an ASCII integer in Data, changes it to another ASCII int. - size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); - /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways. - size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize); - - /// CrossOver Data with some other element of the corpus. - size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Applies one of the configured mutations. - /// Returns the new size of data which could be up to MaxSize. - size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); - /// Applies one of the default mutations. Provided as a service - /// to mutation authors. - size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Creates a cross-over of two pieces of Data, returns its size. - size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, - size_t Size2, uint8_t *Out, size_t MaxOutSize); - - void AddWordToManualDictionary(const Word &W); - - void AddWordToAutoDictionary(DictionaryEntry DE); - void ClearAutoDictionary(); - void PrintRecommendedDictionary(); - - void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; } - - Random &GetRand() { return Rand; } - -private: - - struct Mutator { - size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); - const char *Name; - }; - - size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, - size_t MaxSize); - size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const std::vector &Mutators); - - size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, - size_t ToSize, size_t MaxToSize); - size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, - size_t ToSize); - - Random &Rand; - const FuzzingOptions Options; - - // Dictionary provided by the user via -dict=DICT_FILE. - Dictionary ManualDictionary; - // Temporary dictionary modified by the fuzzer itself, - // recreated periodically. - Dictionary TempAutoDictionary; - // Persistent dictionary modified by the fuzzer, consists of - // entries that led to successfull discoveries in the past mutations. - Dictionary PersistentAutoDictionary; - std::vector CurrentMutatorSequence; - std::vector CurrentDictionaryEntrySequence; - const InputCorpus *Corpus = nullptr; - std::vector MutateInPlaceHere; - - std::vector Mutators; - std::vector DefaultMutators; -}; - -// See TracePC.cpp -class TracePC { - public: - void HandleTrace(uintptr_t *guard, uintptr_t PC); - void HandleInit(uintptr_t *start, uintptr_t *stop); - void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); - size_t GetTotalCoverage() { return TotalCoverage; } - void SetUseCounters(bool UC) { UseCounters = UC; } - size_t UpdateCounterMap(ValueBitMap *Map); - void FinalizeTrace(); - - size_t GetNewPCsAndFlush(uintptr_t **NewPCsPtr = nullptr) { - if (NewPCsPtr) - *NewPCsPtr = NewPCs; - size_t Res = NumNewPCs; - NumNewPCs = 0; - return Res; - } - - void Reset() { - TotalCoverage = 0; - TotalCounterBits = 0; - NumNewPCs = 0; - CounterMap.Reset(); - TotalCoverageMap.Reset(); - ResetGuards(); - } - - void PrintModuleInfo(); - - void PrintCoverage(); - -private: - bool UseCounters = false; - size_t TotalCoverage = 0; - size_t TotalCounterBits = 0; - - static const size_t kMaxNewPCs = 64; - uintptr_t NewPCs[kMaxNewPCs]; - size_t NumNewPCs = 0; - void AddNewPC(uintptr_t PC) { NewPCs[(NumNewPCs++) % kMaxNewPCs] = PC; } - - void ResetGuards(); - - struct Module { - uintptr_t *Start, *Stop; - }; - - Module Modules[4096]; - size_t NumModules = 0; - size_t NumGuards = 0; - - static const size_t kNumCounters = 1 << 14; - uint8_t Counters[kNumCounters]; - - static const size_t kNumPCs = 1 << 20; - uintptr_t PCs[kNumPCs]; - - ValueBitMap CounterMap; - ValueBitMap TotalCoverageMap; -}; - -extern TracePC TPC; - class Fuzzer { public: diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp index 2dcf11e..b68185b 100644 --- a/llvm/lib/Fuzzer/FuzzerLoop.cpp +++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -10,6 +10,10 @@ //===----------------------------------------------------------------------===// #include "FuzzerInternal.h" +#include "FuzzerMutate.h" +#include "FuzzerTracePC.h" +#include "FuzzerRandom.h" + #include #include #include diff --git a/llvm/lib/Fuzzer/FuzzerMain.cpp b/llvm/lib/Fuzzer/FuzzerMain.cpp index 55f1687..af86572 100644 --- a/llvm/lib/Fuzzer/FuzzerMain.cpp +++ b/llvm/lib/Fuzzer/FuzzerMain.cpp @@ -9,8 +9,7 @@ // main() and flags. //===----------------------------------------------------------------------===// -#include "FuzzerInterface.h" -#include "FuzzerInternal.h" +#include "FuzzerDefs.h" extern "C" { // This function should be defined by the user. diff --git a/llvm/lib/Fuzzer/FuzzerMutate.cpp b/llvm/lib/Fuzzer/FuzzerMutate.cpp index ac48dc3..2a356df 100644 --- a/llvm/lib/Fuzzer/FuzzerMutate.cpp +++ b/llvm/lib/Fuzzer/FuzzerMutate.cpp @@ -12,12 +12,16 @@ #include #include "FuzzerInternal.h" - +#include "FuzzerMutate.h" namespace fuzzer { const size_t Dictionary::kMaxDictSize; +static void PrintASCII(const Word &W, const char *PrintAfter) { + PrintASCII(W.data(), W.size(), PrintAfter); +} + MutationDispatcher::MutationDispatcher(Random &Rand, const FuzzingOptions &Options) : Rand(Rand), Options(Options) { diff --git a/llvm/lib/Fuzzer/FuzzerMutate.h b/llvm/lib/Fuzzer/FuzzerMutate.h new file mode 100644 index 0000000..dcb2b19 --- /dev/null +++ b/llvm/lib/Fuzzer/FuzzerMutate.h @@ -0,0 +1,130 @@ +//===- FuzzerMutate.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. +// +//===----------------------------------------------------------------------===// +// fuzzer::MutationDispatcher +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_MUTATE_H +#define LLVM_FUZZER_MUTATE_H + +#include "FuzzerDefs.h" +#include "FuzzerDictionary.h" +#include "FuzzerRandom.h" + +namespace fuzzer { + +class MutationDispatcher { +public: + MutationDispatcher(Random &Rand, const FuzzingOptions &Options); + ~MutationDispatcher() {} + /// Indicate that we are about to start a new sequence of mutations. + void StartMutationSequence(); + /// Print the current sequence of mutations. + void PrintMutationSequence(); + /// Indicate that the current sequence of mutations was successfull. + void RecordSuccessfulMutationSequence(); + /// Mutates data by invoking user-provided mutator. + size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by invoking user-provided crossover. + size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by shuffling bytes. + size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by erasing bytes. + size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting a byte. + size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting several repeated bytes. + size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one byte. + size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one bit. + size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by copying/inserting a part of data into a different place. + size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Mutates data by adding a word from the manual dictionary. + size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Mutates data by adding a word from the temporary automatic dictionary. + size_t Mutate_AddWordFromTemporaryAutoDictionary(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); + + /// Tries to find an ASCII integer in Data, changes it to another ASCII int. + size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); + /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways. + size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize); + + /// CrossOver Data with some other element of the corpus. + size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Applies one of the configured mutations. + /// Returns the new size of data which could be up to MaxSize. + size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + /// Applies one of the default mutations. Provided as a service + /// to mutation authors. + size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Creates a cross-over of two pieces of Data, returns its size. + size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, + size_t Size2, uint8_t *Out, size_t MaxOutSize); + + void AddWordToManualDictionary(const Word &W); + + void AddWordToAutoDictionary(DictionaryEntry DE); + void ClearAutoDictionary(); + void PrintRecommendedDictionary(); + + void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; } + + Random &GetRand() { return Rand; } + +private: + + struct Mutator { + size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); + const char *Name; + }; + + size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, + size_t MaxSize); + size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, + const std::vector &Mutators); + + size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, + size_t ToSize, size_t MaxToSize); + size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, + size_t ToSize); + + Random &Rand; + const FuzzingOptions Options; + + // Dictionary provided by the user via -dict=DICT_FILE. + Dictionary ManualDictionary; + // Temporary dictionary modified by the fuzzer itself, + // recreated periodically. + Dictionary TempAutoDictionary; + // Persistent dictionary modified by the fuzzer, consists of + // entries that led to successfull discoveries in the past mutations. + Dictionary PersistentAutoDictionary; + std::vector CurrentMutatorSequence; + std::vector CurrentDictionaryEntrySequence; + const InputCorpus *Corpus = nullptr; + std::vector MutateInPlaceHere; + + std::vector Mutators; + std::vector DefaultMutators; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_MUTATE_H diff --git a/llvm/lib/Fuzzer/FuzzerRandom.h b/llvm/lib/Fuzzer/FuzzerRandom.h new file mode 100644 index 0000000..c771418 --- /dev/null +++ b/llvm/lib/Fuzzer/FuzzerRandom.h @@ -0,0 +1,31 @@ +//===- FuzzerRandom.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. +// +//===----------------------------------------------------------------------===// +// fuzzer::Random +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_RANDOM_H +#define LLVM_FUZZER_RANDOM_H + +#include + +namespace fuzzer { +class Random { + public: + Random(unsigned int seed) : R(seed) {} + size_t Rand() { return R(); } + size_t RandBool() { return Rand() % 2; } + size_t operator()(size_t n) { return n ? Rand() % n : 0; } + std::mt19937 &Get_mt19937() { return R; } + private: + std::mt19937 R; +}; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_RANDOM_H diff --git a/llvm/lib/Fuzzer/FuzzerTracePC.cpp b/llvm/lib/Fuzzer/FuzzerTracePC.cpp index db62345..9daa721 100644 --- a/llvm/lib/Fuzzer/FuzzerTracePC.cpp +++ b/llvm/lib/Fuzzer/FuzzerTracePC.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "FuzzerInternal.h" +#include "FuzzerTracePC.h" namespace fuzzer { diff --git a/llvm/lib/Fuzzer/FuzzerTracePC.h b/llvm/lib/Fuzzer/FuzzerTracePC.h new file mode 100644 index 0000000..2ba0808 --- /dev/null +++ b/llvm/lib/Fuzzer/FuzzerTracePC.h @@ -0,0 +1,84 @@ +//===- FuzzerTracePC.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. +// +//===----------------------------------------------------------------------===// +// fuzzer::TracePC +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_TRACE_PC +#define LLVM_FUZZER_TRACE_PC + +#include "FuzzerDefs.h" + +namespace fuzzer { + +class TracePC { + public: + void HandleTrace(uintptr_t *guard, uintptr_t PC); + void HandleInit(uintptr_t *start, uintptr_t *stop); + void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); + size_t GetTotalCoverage() { return TotalCoverage; } + void SetUseCounters(bool UC) { UseCounters = UC; } + size_t UpdateCounterMap(ValueBitMap *Map); + void FinalizeTrace(); + + size_t GetNewPCsAndFlush(uintptr_t **NewPCsPtr = nullptr) { + if (NewPCsPtr) + *NewPCsPtr = NewPCs; + size_t Res = NumNewPCs; + NumNewPCs = 0; + return Res; + } + + void Reset() { + TotalCoverage = 0; + TotalCounterBits = 0; + NumNewPCs = 0; + CounterMap.Reset(); + TotalCoverageMap.Reset(); + ResetGuards(); + } + + void PrintModuleInfo(); + + void PrintCoverage(); + +private: + bool UseCounters = false; + size_t TotalCoverage = 0; + size_t TotalCounterBits = 0; + + static const size_t kMaxNewPCs = 64; + uintptr_t NewPCs[kMaxNewPCs]; + size_t NumNewPCs = 0; + void AddNewPC(uintptr_t PC) { NewPCs[(NumNewPCs++) % kMaxNewPCs] = PC; } + + void ResetGuards(); + + struct Module { + uintptr_t *Start, *Stop; + }; + + Module Modules[4096]; + size_t NumModules = 0; + size_t NumGuards = 0; + + static const size_t kNumCounters = 1 << 14; + uint8_t Counters[kNumCounters]; + + static const size_t kNumPCs = 1 << 20; + uintptr_t PCs[kNumPCs]; + + ValueBitMap CounterMap; + ValueBitMap TotalCoverageMap; +}; + +extern TracePC TPC; + +} // namespace fuzzer + +#endif // LLVM_FUZZER_TRACE_PC diff --git a/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/llvm/lib/Fuzzer/FuzzerTraceState.cpp index 77946ef..7280e3f 100644 --- a/llvm/lib/Fuzzer/FuzzerTraceState.cpp +++ b/llvm/lib/Fuzzer/FuzzerTraceState.cpp @@ -72,6 +72,9 @@ #include "FuzzerDFSan.h" #include "FuzzerInternal.h" +#include "FuzzerDictionary.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" #include #include @@ -236,7 +239,7 @@ public: Printf("AutoDict:\n"); for (auto &I : CountedUnits) { Printf(" %zd ", I.first); - PrintASCII(I.second); + PrintASCII(I.second.data(), I.second.size()); Printf("\n"); } } diff --git a/llvm/lib/Fuzzer/FuzzerUtil.cpp b/llvm/lib/Fuzzer/FuzzerUtil.cpp index f06060b..e4d8352 100644 --- a/llvm/lib/Fuzzer/FuzzerUtil.cpp +++ b/llvm/lib/Fuzzer/FuzzerUtil.cpp @@ -55,10 +55,6 @@ void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { Printf("%s", PrintAfter); } -void PrintASCII(const Word &W, const char *PrintAfter) { - PrintASCII(W.data(), W.size(), PrintAfter); -} - void PrintASCII(const Unit &U, const char *PrintAfter) { PrintASCII(U.data(), U.size(), PrintAfter); } diff --git a/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp b/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp index 97d4959..383849e 100644 --- a/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -6,6 +6,9 @@ #define _LIBCPP_HAS_NO_ASAN #include "FuzzerInternal.h" +#include "FuzzerDictionary.h" +#include "FuzzerMutate.h" +#include "FuzzerRandom.h" #include "gtest/gtest.h" #include #include -- 2.7.4