From ab240104f0315bc109a6973395b69d4c377bf422 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 7 Jan 2016 01:49:35 +0000 Subject: [PATCH] [libFuzzer] add a position hint to the dictionary-based mutator git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257013 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerDriver.cpp | 2 +- lib/Fuzzer/FuzzerInterface.h | 14 ++++-- lib/Fuzzer/FuzzerMutate.cpp | 70 +++++++++++++++++++++--------- lib/Fuzzer/test/FuzzerUnittest.cpp | 35 +++++++++++++-- lib/Fuzzer/test/fuzzer-dict.test | 6 +++ lib/Fuzzer/test/fuzzer.test | 6 +-- 6 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 lib/Fuzzer/test/fuzzer-dict.test diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index e8c117ef608..595e39759c9 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -286,7 +286,7 @@ int FuzzerDriver(const std::vector &Args, Fuzzer F(USF, Options); for (auto &U: Dictionary) - USF.GetMD().AddWordToDictionary(U.data(), U.size()); + USF.GetMD().AddWordToManualDictionary(U); // Timer if (Flags.timeout > 0) diff --git a/lib/Fuzzer/FuzzerInterface.h b/lib/Fuzzer/FuzzerInterface.h index 65f1707ba92..0950a1a6610 100644 --- a/lib/Fuzzer/FuzzerInterface.h +++ b/lib/Fuzzer/FuzzerInterface.h @@ -16,6 +16,7 @@ #ifndef LLVM_FUZZER_INTERFACE_H #define LLVM_FUZZER_INTERFACE_H +#include #include #include #include @@ -86,9 +87,13 @@ class MutationDispatcher { /// Mutates data by chanding one bit. size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by adding a word from the dictionary. - size_t Mutate_AddWordFromDictionary(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 automatic dictionary. + size_t Mutate_AddWordFromAutoDictionary(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); @@ -104,7 +109,8 @@ class MutationDispatcher { size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize); - void AddWordToDictionary(const uint8_t *Word, size_t Size); + void AddWordToManualDictionary(const Unit &Word); + void AddWordToAutoDictionary(const Unit &Word, size_t PositionHint); void SetCorpus(const std::vector *Corpus); private: diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp index 84ee18e69fb..11d320b7bc3 100644 --- a/lib/Fuzzer/FuzzerMutate.cpp +++ b/lib/Fuzzer/FuzzerMutate.cpp @@ -22,14 +22,21 @@ struct Mutator { const char *Name; }; +struct DictionaryEntry { + Unit Word; + size_t PositionHint; +}; + struct MutationDispatcher::Impl { - std::vector Dictionary; + std::vector ManualDictionary; + std::vector AutoDictionary; std::vector Mutators; std::vector CurrentMutatorSequence; const std::vector *Corpus = nullptr; + FuzzerRandomBase &Rand; void Add(Mutator M) { Mutators.push_back(M); } - Impl() { + Impl(FuzzerRandomBase &Rand) : Rand(Rand) { Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"}); Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"}); Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}); @@ -37,14 +44,14 @@ struct MutationDispatcher::Impl { Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}); Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}); Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"}); - } - void AddWordToDictionary(const uint8_t *Word, size_t Size) { - if (Dictionary.empty()) { - Add({&MutationDispatcher::Mutate_AddWordFromDictionary, "AddFromDict"}); - } - Dictionary.push_back(Unit(Word, Word + Size)); + Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "AddFromManualDict"}); + Add({&MutationDispatcher::Mutate_AddWordFromAutoDictionary, + "AddFromAutoDict"}); } void SetCorpus(const std::vector *Corpus) { this->Corpus = Corpus; } + size_t AddWordFromDictionary(const std::vector &D, + uint8_t *Data, size_t Size, size_t MaxSize); }; static char FlipRandomBit(char X, FuzzerRandomBase &Rand) { @@ -68,7 +75,8 @@ static char RandCh(FuzzerRandomBase &Rand) { size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize) { assert(Size); - size_t ShuffleAmount = Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. + size_t ShuffleAmount = + Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. size_t ShuffleStart = Rand(Size - ShuffleAmount); assert(ShuffleStart + ShuffleAmount <= Size); std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, @@ -110,22 +118,38 @@ size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, return Size; } -size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data, - size_t Size, - size_t MaxSize) { - auto &D = MDImpl->Dictionary; - assert(!D.empty()); +size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, + size_t Size, + size_t MaxSize) { + return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size, + MaxSize); +} + +size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data, + size_t Size, + size_t MaxSize) { + return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size, + MaxSize); +} + +size_t MutationDispatcher::Impl::AddWordFromDictionary( + const std::vector &D, uint8_t *Data, size_t Size, + size_t MaxSize) { if (D.empty()) return 0; - const Unit &Word = D[Rand(D.size())]; + const DictionaryEntry &DE = D[Rand(D.size())]; + const Unit &Word = DE.Word; + size_t PositionHint = DE.PositionHint; + bool UsePositionHint = PositionHint != std::numeric_limits::max() && + PositionHint + Word.size() < Size && Rand.RandBool(); if (Rand.RandBool()) { // Insert Word. if (Size + Word.size() > MaxSize) return 0; - size_t Idx = Rand(Size + 1); + size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1); memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx); memcpy(Data + Idx, Word.data(), Word.size()); return Size + Word.size(); } else { // Overwrite some bytes with Word. if (Word.size() > Size) return 0; - size_t Idx = Rand(Size - Word.size()); + size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size()); memcpy(Data + Idx, Word.data(), Word.size()); return Size; } @@ -219,12 +243,18 @@ void MutationDispatcher::SetCorpus(const std::vector *Corpus) { MDImpl->SetCorpus(Corpus); } -void MutationDispatcher::AddWordToDictionary(const uint8_t *Word, size_t Size) { - MDImpl->AddWordToDictionary(Word, Size); +void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) { + MDImpl->ManualDictionary.push_back( + {Word, std::numeric_limits::max()}); +} + +void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word, + size_t PositionHint) { + MDImpl->AutoDictionary.push_back({Word, PositionHint}); } MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) { - MDImpl = new Impl; + MDImpl = new Impl(Rand); } MutationDispatcher::~MutationDispatcher() { delete MDImpl; } diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp index 8c0012708af..b33e0c96145 100644 --- a/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -247,8 +247,8 @@ void TestAddWordFromDictionary(Mutator M, int NumIter) { MutationDispatcher MD(Rand); uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD}; uint8_t Word2[3] = {0xFF, 0xEE, 0xEF}; - MD.AddWordToDictionary(Word1, sizeof(Word1)); - MD.AddWordToDictionary(Word2, sizeof(Word2)); + MD.AddWordToManualDictionary(Unit(Word1, Word1 + sizeof(Word1))); + MD.AddWordToManualDictionary(Unit(Word2, Word2 + sizeof(Word2))); int FoundMask = 0; uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD}; uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22}; @@ -274,14 +274,41 @@ void TestAddWordFromDictionary(Mutator M, int NumIter) { } TEST(FuzzerMutate, AddWordFromDictionary1) { - TestAddWordFromDictionary(&MutationDispatcher::Mutate_AddWordFromDictionary, - 1 << 15); + TestAddWordFromDictionary( + &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15); } TEST(FuzzerMutate, AddWordFromDictionary2) { TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15); } +void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + uint8_t Word[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF}; + size_t PosHint = 7777; + MD.AddWordToAutoDictionary(Unit(Word, Word + sizeof(Word)), PosHint); + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[10000]; + memset(T, 0, sizeof(T)); + size_t NewSize = (MD.*M)(T, 9000, 10000); + if (NewSize >= PosHint + sizeof(Word) && + !memcmp(Word, T + PosHint, sizeof(Word))) + FoundMask = 1; + } + EXPECT_EQ(FoundMask, 1); +} + +TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) { + TestAddWordFromDictionaryWithHint( + &MutationDispatcher::Mutate_AddWordFromAutoDictionary, 1 << 5); +} + +TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) { + TestAddWordFromDictionaryWithHint(&MutationDispatcher::Mutate, 1 << 10); +} + void TestChangeASCIIInteger(Mutator M, int NumIter) { FuzzerRandomLibc Rand(0); MutationDispatcher MD(Rand); diff --git a/lib/Fuzzer/test/fuzzer-dict.test b/lib/Fuzzer/test/fuzzer-dict.test new file mode 100644 index 00000000000..dec002f6a37 --- /dev/null +++ b/lib/Fuzzer/test/fuzzer-dict.test @@ -0,0 +1,6 @@ +CHECK: BINGO +Done1000000: Done 1000000 runs in + +RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s +RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + diff --git a/lib/Fuzzer/test/fuzzer.test b/lib/Fuzzer/test/fuzzer.test index 150fc7202b0..c63014f59d6 100644 --- a/lib/Fuzzer/test/fuzzer.test +++ b/lib/Fuzzer/test/fuzzer.test @@ -20,14 +20,12 @@ NullDerefTestExactPath: Test unit written to FOOBAR RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s RUN: not LLVMFuzzer-CallerCalleeTest -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s -RUN: LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 +# This one is flaky, may actually find the goal even w/o use_indir_calls. +# LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 RUN: not LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s -RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s -RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 - RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. -- 2.34.1