[libFuzzer] simplify the code for use_cmp, also use the position hint when available, add a test

llvm-svn: 285049
This commit is contained in:
Kostya Serebryany 2016-10-25 02:04:43 +00:00
parent 7695cb6da8
commit 3364f90783
9 changed files with 130 additions and 102 deletions

View File

@ -68,6 +68,13 @@ class DictionaryEntry {
size_t GetUseCount() const { return UseCount; }
size_t GetSuccessCount() const {return SuccessCount; }
void Print(const char *PrintAfter = "\n") {
PrintASCII(W.data(), W.size());
if (HasPositionHint())
Printf("@%zd", GetPositionHint());
Printf("%s", PrintAfter);
}
private:
Word W;
size_t PositionHint = std::numeric_limits<size_t>::max();

View File

@ -478,9 +478,6 @@ size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
Res = 1;
}
if (Res && Options.UseCmp)
TPC.ProcessTORC(MD.GetTraceCmpDictionary(), CurrentUnitData, Size);
auto TimeOfUnit =
duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
@ -514,8 +511,6 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
UnitStartTime = system_clock::now();
ResetCounters(); // Reset coverage right before the callback.
TPC.ResetMaps();
if (Options.UseCmp)
TPC.ResetTORC();
if (Options.UseCounters)
TPC.ResetGuards();
int Res = CB(DataCopy, Size);

View File

@ -51,8 +51,7 @@ MutationDispatcher::MutationDispatcher(Random &Rand,
});
if(Options.UseCmp)
DefaultMutators.push_back(
{&MutationDispatcher::Mutate_AddWordFromTraceCmpDictionary,
"TraceCmpDict"});
{&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
if (EF->LLVMFuzzerCustomMutator)
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
@ -175,9 +174,96 @@ size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
}
size_t MutationDispatcher::Mutate_AddWordFromTraceCmpDictionary(
size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
size_t MaxSize,
DictionaryEntry &DE) {
const Word &W = DE.GetW();
bool UsePositionHint = DE.HasPositionHint() &&
DE.GetPositionHint() + W.size() < Size &&
Rand.RandBool();
if (Rand.RandBool()) { // Insert W.
if (Size + W.size() > MaxSize) return 0;
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
memcpy(Data + Idx, W.data(), W.size());
Size += W.size();
} else { // Overwrite some bytes with W.
if (W.size() > Size) return 0;
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
memcpy(Data + Idx, W.data(), W.size());
}
return Size;
}
// Somewhere in the past we have observed a comparison instructions
// with arguments Arg1 Arg2. This function tries to guess a dictionary
// entry that will satisfy that comparison.
// It first tries to find one of the arguments (possibly swapped) in the
// input and if it succeeds it creates a DE with a position hint.
// Otherwise it creates a DE with one of the arguments w/o a position hint.
template <class T>
DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
if (Rand.RandBool()) Arg1 = Bswap(Arg1);
if (Rand.RandBool()) Arg2 = Bswap(Arg2);
bool HandleFirst = Rand.RandBool();
T ExistingBytes, DesiredBytes;
Word W;
const uint8_t *End = Data + Size;
for (int Arg = 0; Arg < 2; Arg++) {
ExistingBytes = HandleFirst ? Arg1 : Arg2;
DesiredBytes = HandleFirst ? Arg2 : Arg1;
HandleFirst = !HandleFirst;
W.Set(reinterpret_cast<uint8_t*>(&DesiredBytes), sizeof(T));
const size_t kMaxNumPositions = 8;
size_t Positions[kMaxNumPositions];
size_t NumPositions = 0;
for (const uint8_t *Cur = Data;
Cur < End && NumPositions < kMaxNumPositions; Cur++) {
Cur = (uint8_t *)memmem(Cur, End - Cur, &ExistingBytes, sizeof(T));
if (!Cur) break;
Positions[NumPositions++] = Cur - Data;
}
if (!NumPositions) break;
return DictionaryEntry(W, Positions[Rand(NumPositions)]);
}
DictionaryEntry DE(W);
return DE;
}
size_t MutationDispatcher::Mutate_AddWordFromTORC(
uint8_t *Data, size_t Size, size_t MaxSize) {
return AddWordFromDictionary(TraceCmpDictionary, Data, Size, MaxSize);
Word W;
DictionaryEntry DE;
bool Debug = false;
if (Rand.RandBool()) {
auto X = TPC.TORC8.Get(Rand.Rand());
DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
if (X.A > 10000 &&X.B > 10000) Debug = false;
if (Debug) {
Printf("ZZZ %zx %zx\n", X.A, X.B);
DE.Print();
}
} else {
auto X = TPC.TORC4.Get(Rand.Rand());
if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data,
Size);
else
DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
}
Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
if (!Size) return 0;
if (Debug) {
Printf("DONE\n");
}
DictionaryEntry &DERef =
CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
kCmpDictionaryEntriesDequeSize];
DERef = DE;
CurrentDictionaryEntrySequence.push_back(&DERef);
return Size;
}
size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
@ -190,20 +276,8 @@ size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
if (Size > MaxSize) return 0;
if (D.empty()) return 0;
DictionaryEntry &DE = D[Rand(D.size())];
const Word &W = DE.GetW();
bool UsePositionHint = DE.HasPositionHint() &&
DE.GetPositionHint() + W.size() < Size && Rand.RandBool();
if (Rand.RandBool()) { // Insert W.
if (Size + W.size() > MaxSize) return 0;
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
memcpy(Data + Idx, W.data(), W.size());
Size += W.size();
} else { // Overwrite some bytes with W.
if (W.size() > Size) return 0;
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
memcpy(Data + Idx, W.data(), W.size());
}
Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
if (!Size) return 0;
DE.IncUseCount();
CurrentDictionaryEntrySequence.push_back(&DE);
return Size;

View File

@ -55,9 +55,8 @@ public:
size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
/// Mutates data by adding a word from the trace-cmp dictionary.
size_t Mutate_AddWordFromTraceCmpDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
/// Mutates data by adding a word from the TORC.
size_t Mutate_AddWordFromTORC(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,
@ -92,8 +91,6 @@ public:
Random &GetRand() { return Rand; }
Dictionary *GetTraceCmpDictionary() { return &TraceCmpDictionary; }
private:
struct Mutator {
@ -110,6 +107,12 @@ private:
size_t ToSize, size_t MaxToSize);
size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
size_t ToSize);
size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
DictionaryEntry &DE);
template <class T>
DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
const uint8_t *Data, size_t Size);
Random &Rand;
const FuzzingOptions &Options;
@ -123,11 +126,13 @@ private:
// entries that led to successfull discoveries in the past mutations.
Dictionary PersistentAutoDictionary;
// Dictionary from tracing CMP instructions.
Dictionary TraceCmpDictionary;
std::vector<Mutator> CurrentMutatorSequence;
std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
static const size_t kCmpDictionaryEntriesDequeSize = 16;
DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
size_t CmpDictionaryEntriesDequeIdx = 0;
const InputCorpus *Corpus = nullptr;
std::vector<uint8_t> MutateInPlaceHere;

View File

@ -272,55 +272,6 @@ void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) {
HandleValueProfile(Idx);
}
void TracePC::ProcessTORC(Dictionary *Dict, const uint8_t *Data, size_t Size) {
TORCToDict(TORC8, Dict, Data, Size);
TORCToDict(TORC4, Dict, Data, Size);
}
template <class T>
void TracePC::TORCToDict(const TableOfRecentCompares<T, kTORCSize> &TORC,
Dictionary *Dict, const uint8_t *Data, size_t Size) {
ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
for (size_t i = 0; i < TORC.kSize; i++) {
T A[2] = {TORC.Table[i][0], TORC.Table[i][1]};
if (!A[0] && !A[1]) continue;
for (int j = 0; j < 2; j++)
TORCToDict(Dict, A[j], A[!j], Data, Size);
}
}
template <class T>
void TracePC::TORCToDict(Dictionary *Dict, T FindInData, T Substitute,
const uint8_t *Data, size_t Size) {
if (FindInData == Substitute) return;
if (sizeof(T) == 4) {
uint16_t HigherBytes = Substitute >> sizeof(T) * 4;
if (HigherBytes == 0 || HigherBytes == 0xffff)
TORCToDict(Dict, static_cast<uint16_t>(FindInData),
static_cast<uint16_t>(Substitute), Data, Size);
}
const size_t DataSize = sizeof(T);
const uint8_t *End = Data + Size;
int Attempts = 3;
for (int DoSwap = 0; DoSwap <= 1; DoSwap++) {
for (const uint8_t *Cur = Data; Cur < End && Attempts--; Cur++) {
Cur = (uint8_t *)memmem(Cur, End - Cur, &FindInData, DataSize);
if (!Cur)
break;
size_t Pos = Cur - Data;
Word W(reinterpret_cast<uint8_t *>(&Substitute), sizeof(Substitute));
DictionaryEntry DE(W, Pos);
// TODO: evict all entries from Dic if it's full.
Dict->push_back(DE);
// Printf("Dict[%zd] TORC%zd %llx => %llx pos %zd\n", Dict->size(),
// sizeof(T),
// (uint64_t)FindInData, (uint64_t)Substitute, Pos);
}
FindInData = Bswap(FindInData);
Substitute = Bswap(Substitute);
}
}
} // namespace fuzzer
extern "C" {

View File

@ -27,13 +27,18 @@ namespace fuzzer {
template<class T, size_t kSizeT>
struct TableOfRecentCompares {
static const size_t kSize = kSizeT;
struct Pair {
T A, B;
};
void Insert(size_t Idx, T Arg1, T Arg2) {
Idx = Idx % kSize;
Table[Idx][0] = Arg1;
Table[Idx][1] = Arg2;
Table[Idx].A = Arg1;
Table[Idx].B = Arg2;
}
void Clear() { memset(Table, 0, sizeof(Table)); }
T Table[kSize][2];
Pair Get(size_t I) { return Table[I % kSize]; }
Pair Table[kSize];
};
class TracePC {
@ -67,11 +72,6 @@ class TracePC {
memset(Counters, 0, sizeof(Counters));
}
void ResetTORC() {
TORC4.Clear();
TORC8.Clear();
}
void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
void PrintFeatureSet();
@ -88,7 +88,9 @@ class TracePC {
bool UsingTracePcGuard() const {return NumModules; }
void ProcessTORC(Dictionary *Dict, const uint8_t *Data, size_t Size);
static const size_t kTORCSize = 1 << 5;
TableOfRecentCompares<uint32_t, kTORCSize> TORC4;
TableOfRecentCompares<uint64_t, kTORCSize> TORC8;
private:
bool UseCounters = false;
@ -113,9 +115,6 @@ private:
static const size_t kNumCounters = 1 << 14;
alignas(8) uint8_t Counters[kNumCounters];
static const size_t kTORCSize = 1 << 12;
TableOfRecentCompares<uint32_t, kTORCSize> TORC4;
TableOfRecentCompares<uint64_t, kTORCSize> TORC8;
void TORCInsert(size_t Idx, uint8_t Arg1, uint8_t Arg2) {
// Do nothing, too small to be interesting.
}
@ -129,13 +128,6 @@ private:
TORC8.Insert(Idx, Arg1, Arg2);
}
template <class T>
void TORCToDict(const TableOfRecentCompares<T, kTORCSize> &TORC,
Dictionary *Dict, const uint8_t *Data, size_t Size);
template <class T>
void TORCToDict(Dictionary *Dict, T FindInData, T Substitute,
const uint8_t *Data, size_t Size);
static const size_t kNumPCs = 1 << 24;
uintptr_t PCs[kNumPCs];

View File

@ -25,7 +25,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
z < -10000 &&
z >= -10005 &&
z != -10003 &&
a == 4242) {
a == 4242 &&
true) {
fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n",
Size, x, y, z, a);
exit(1);

View File

@ -21,8 +21,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
z = __builtin_bswap16(z);
if (x == 0x46555A5A5A5A5546ULL &&
z == 0x4F4B &&
y == 0x66757A7A &&
z == 0x4F4B
true
) {
if (Data[Size - 3] == 'z') {
fprintf(stderr, "BINGO; Found the target\n");

View File

@ -0,0 +1,2 @@
CHECK: BINGO
RUN: not LLVMFuzzer-SwapCmpTest -seed=1 -use_cmp=1 -runs=10000000 2>&1 | FileCheck %s