From 051ef86497b5c292465101af684d5d0708cc37bc Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Mon, 11 May 2015 21:16:27 +0000 Subject: [PATCH] [lib/Fuzzer] rename FuzzerDFSan.cpp to FuzzerTraceState.cpp; update comments. NFC expected git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237050 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/CMakeLists.txt | 2 +- lib/Fuzzer/FuzzerInternal.h | 2 +- lib/Fuzzer/FuzzerLoop.cpp | 2 +- .../{FuzzerDFSan.cpp => FuzzerTraceState.cpp} | 92 ++++++++++--------- 4 files changed, 54 insertions(+), 44 deletions(-) rename lib/Fuzzer/{FuzzerDFSan.cpp => FuzzerTraceState.cpp} (82%) diff --git a/lib/Fuzzer/CMakeLists.txt b/lib/Fuzzer/CMakeLists.txt index bfd87ecc8ec..736950dd396 100644 --- a/lib/Fuzzer/CMakeLists.txt +++ b/lib/Fuzzer/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all") if( LLVM_USE_SANITIZE_COVERAGE ) add_library(LLVMFuzzerNoMain OBJECT FuzzerCrossOver.cpp - FuzzerDFSan.cpp + FuzzerTraceState.cpp FuzzerDriver.cpp FuzzerIO.cpp FuzzerLoop.cpp diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index f085f94d612..f83ea96fe0f 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -67,7 +67,7 @@ class Fuzzer { void AddToCorpus(const Unit &U) { Corpus.push_back(U); } void Loop(size_t NumIterations); void ShuffleAndMinimize(); - void InitializeDFSan(); + void InitializeTraceState(); size_t CorpusSize() const { return Corpus.size(); } void ReadDir(const std::string &Path, long *Epoch) { ReadDirToVectorOfUnits(Path.c_str(), &Corpus, Epoch); diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index 9f9d92e2c0c..a8ea46b4b4d 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -22,7 +22,7 @@ static Fuzzer *F; Fuzzer::Fuzzer(UserCallback Callback, FuzzingOptions Options) : Callback(Callback), Options(Options) { SetDeathCallback(); - InitializeDFSan(); + InitializeTraceState(); assert(!F); F = this; } diff --git a/lib/Fuzzer/FuzzerDFSan.cpp b/lib/Fuzzer/FuzzerTraceState.cpp similarity index 82% rename from lib/Fuzzer/FuzzerDFSan.cpp rename to lib/Fuzzer/FuzzerTraceState.cpp index 217124d2110..c0408490380 100644 --- a/lib/Fuzzer/FuzzerDFSan.cpp +++ b/lib/Fuzzer/FuzzerTraceState.cpp @@ -1,4 +1,4 @@ -//===- FuzzerDFSan.cpp - DFSan-based fuzzer mutator -----------------------===// +//===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===// // // The LLVM Compiler Infrastructure // @@ -6,25 +6,37 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// This file implements a mutation algorithm based on instruction traces and +// on taint analysis feedback from DFSan. +// +// Instruction traces are special hooks inserted by the compiler around +// interesting instructions. Currently supported traces: +// * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction, +// receives the type, size and arguments of ICMP. +// +// Every time a traced event is intercepted we analyse the data involved +// in the event and suggest a mutation for future executions. +// For example if 4 bytes of data that derive from input bytes {4,5,6,7} +// are compared with a constant 12345, +// we try to insert 12345, 12344, 12346 into bytes +// {4,5,6,7} of the next fuzzed inputs. +// +// The fuzzer can work only with the traces, or with both traces and DFSan. +// // DataFlowSanitizer (DFSan) is a tool for // generalised dynamic data flow (taint) analysis: // http://clang.llvm.org/docs/DataFlowSanitizer.html . // -// This file implements a mutation algorithm based on taint -// analysis feedback from DFSan. -// -// The approach has some similarity to "Taint-based Directed Whitebox Fuzzing" +// The approach with DFSan-based fuzzing has some similarity to +// "Taint-based Directed Whitebox Fuzzing" // by Vijay Ganesh & Tim Leek & Martin Rinard: // http://dspace.mit.edu/openaccess-disseminate/1721.1/59320, // but it uses a full blown LLVM IR taint analysis and separate instrumentation // to analyze all of the "attack points" at once. // -// Workflow: +// Workflow with DFSan: // * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation. -// * The code under test is compiled with DFSan *and* with special extra hooks -// that are inserted before dfsan. Currently supported hooks: -// - __sanitizer_cov_trace_cmp: inserted before every ICMP instruction, -// receives the type, size and arguments of ICMP. +// * The code under test is compiled with DFSan *and* with instruction traces. // * Every call to HOOK(a,b) is replaced by DFSan with // __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK // gets all the taint labels for the arguments. @@ -34,14 +46,10 @@ // * The __dfsw_* functions (implemented in this file) record the // parameters (i.e. the application data and the corresponding taint labels) // in a global state. -// * Fuzzer::MutateWithDFSan() tries to use the data recorded by __dfsw_* -// hooks to guide the fuzzing towards new application states. -// For example if 4 bytes of data that derive from input bytes {4,5,6,7} -// are compared with a constant 12345 and the comparison always yields -// the same result, we try to insert 12345, 12344, 12346 into bytes -// {4,5,6,7} of the next fuzzed inputs. +// * Fuzzer::ApplyTraceBasedMutation() tries to use the data recorded +// by __dfsw_* hooks to guide the fuzzing towards new application states. // -// This code does not function when DFSan is not linked in. +// Parts of this code will not function when DFSan is not linked in. // Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer // we redeclare the dfsan_* interface functions as weak and check if they // are nullptr before calling. @@ -53,7 +61,7 @@ // like test/dfsan/DFSanSimpleCmpTest.cpp. //===----------------------------------------------------------------------===// -/* Example of manual usage: +/* Example of manual usage (-fsanitize=dataflow is optional): ( cd $LLVM/lib/Fuzzer/ clang -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp @@ -168,9 +176,9 @@ struct TraceBasedMutation { uint64_t Data; }; -class DFSanState { +class TraceState { public: - DFSanState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit) + TraceState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit) : Options(Options), CurrentUnit(CurrentUnit) {} LabelRange GetLabelRange(dfsan_label L); @@ -208,7 +216,7 @@ class DFSanState { const Unit &CurrentUnit; }; -LabelRange DFSanState::GetLabelRange(dfsan_label L) { +LabelRange TraceState::GetLabelRange(dfsan_label L) { LabelRange &LR = LabelRanges[L]; if (LR.Beg < LR.End || L == 0) return LR; @@ -218,7 +226,7 @@ LabelRange DFSanState::GetLabelRange(dfsan_label L) { return LR = LabelRange::Singleton(LI); } -void DFSanState::ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U) { +void TraceState::ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U) { assert(Idx < Mutations.size()); auto &M = Mutations[Idx]; if (Options.Verbosity >= 3) @@ -227,7 +235,7 @@ void DFSanState::ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U) { memcpy(U->data() + M.Pos, &M.Data, M.Size); } -void DFSanState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, +void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2, dfsan_label L1, dfsan_label L2) { assert(ReallyHaveDFSan()); @@ -263,7 +271,7 @@ void DFSanState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, << "\n"; } -int DFSanState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, +int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, size_t DataSize) { int Res = 0; const uint8_t *Beg = CurrentUnit.data(); @@ -284,7 +292,7 @@ int DFSanState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, return Res; } -void DFSanState::TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1, +void TraceState::TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2) { if (!Options.UseTraces) return; int Added = 0; @@ -298,29 +306,29 @@ void DFSanState::TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1, } } -static DFSanState *DFSan; +static TraceState *TS; void Fuzzer::StartTraceRecording() { - if (!DFSan) return; - DFSan->StartTraceRecording(); + if (!TS) return; + TS->StartTraceRecording(); } size_t Fuzzer::StopTraceRecording() { - if (!DFSan) return 0; - return DFSan->StopTraceRecording(); + if (!TS) return 0; + return TS->StopTraceRecording(); } void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) { - assert(DFSan); - DFSan->ApplyTraceBasedMutation(Idx, U); + assert(TS); + TS->ApplyTraceBasedMutation(Idx, U); } -void Fuzzer::InitializeDFSan() { - if (!Options.UseDFSan) return; - DFSan = new DFSanState(Options, CurrentUnit); +void Fuzzer::InitializeTraceState() { + if (!Options.UseTraces && !Options.UseDFSan) return; + TS = new TraceState(Options, CurrentUnit); CurrentUnit.resize(Options.MaxLen); // The rest really requires DFSan. - if (!ReallyHaveDFSan()) return; + if (!ReallyHaveDFSan() || !Options.UseDFSan) return; for (size_t i = 0; i < static_cast(Options.MaxLen); i++) { dfsan_label L = dfsan_create_label("input", (void*)(i + 1)); // We assume that no one else has called dfsan_create_label before. @@ -331,22 +339,24 @@ void Fuzzer::InitializeDFSan() { } // namespace fuzzer -using fuzzer::DFSan; +using fuzzer::TS; extern "C" { void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2, dfsan_label L0, dfsan_label L1, dfsan_label L2) { + assert(TS); assert(L0 == 0); uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); uint64_t CmpSize = (SizeAndType >> 32) / 8; uint64_t Type = (SizeAndType << 32) >> 32; - DFSan->DFSanCmpCallback(PC, CmpSize, Type, Arg1, Arg2, L1, L2); + TS->DFSanCmpCallback(PC, CmpSize, Type, Arg1, Arg2, L1, L2); } void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label) { + assert(TS); uintptr_t PC = reinterpret_cast(caller_pc); uint64_t S1 = 0, S2 = 0; // Simplification: handle only first 8 bytes. @@ -354,15 +364,15 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, memcpy(&S2, s2, std::min(n, sizeof(S2))); dfsan_label L1 = dfsan_read_label(s1, n); dfsan_label L2 = dfsan_read_label(s2, n); - DFSan->DFSanCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2); + TS->DFSanCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2); } void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2) { - if (!DFSan) return; + if (!TS) return; uint64_t CmpSize = (SizeAndType >> 32) / 8; uint64_t Type = (SizeAndType << 32) >> 32; - DFSan->TraceCmpCallback(CmpSize, Type, Arg1, Arg2); + TS->TraceCmpCallback(CmpSize, Type, Arg1, Arg2); } } // extern "C"