[llvm] r237043 - [lib/Fuzzer] add a trace-based mutatation logic. Same idea as with DFSan-based mutator, but instead of relying on taint tracking, try to find the data directly in the input. More (logic and comments) to go.

Kostya Serebryany kcc at google.com
Mon May 11 13:51:20 PDT 2015


Author: kcc
Date: Mon May 11 15:51:19 2015
New Revision: 237043

URL: http://llvm.org/viewvc/llvm-project?rev=237043&view=rev
Log:
[lib/Fuzzer] add a trace-based mutatation logic. Same idea as with DFSan-based mutator, but instead of relying on taint  tracking, try to find the data directly in the input. More (logic and comments) to go.

Modified:
    llvm/trunk/lib/Fuzzer/FuzzerDFSan.cpp
    llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
    llvm/trunk/lib/Fuzzer/FuzzerFlags.def
    llvm/trunk/lib/Fuzzer/FuzzerInternal.h
    llvm/trunk/lib/Fuzzer/test/fuzzer.test

Modified: llvm/trunk/lib/Fuzzer/FuzzerDFSan.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDFSan.cpp?rev=237043&r1=237042&r2=237043&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDFSan.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDFSan.cpp Mon May 11 15:51:19 2015
@@ -85,7 +85,11 @@ __attribute__((weak))
 dfsan_label dfsan_read_label(const void *addr, size_t size);
 }  // extern "C"
 
-namespace {
+namespace fuzzer {
+
+static bool ReallyHaveDFSan() {
+  return &dfsan_create_label != nullptr;
+}
 
 // These values are copied from include/llvm/IR/InstrTypes.h.
 // We do not include the LLVM headers here to remain independent.
@@ -166,13 +170,17 @@ struct TraceBasedMutation {
 
 class DFSanState {
  public:
-   DFSanState(const fuzzer::Fuzzer::FuzzingOptions &Options)
-       : Options(Options) {}
+   DFSanState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
+       : Options(Options), CurrentUnit(CurrentUnit) {}
 
   LabelRange GetLabelRange(dfsan_label L);
   void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
                         uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
                         dfsan_label L2);
+  void TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1,
+                        uint64_t Arg2);
+  int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
+                           size_t DataSize);
 
   void StartTraceRecording() {
     RecordingTraces = true;
@@ -188,10 +196,16 @@ class DFSanState {
   void ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U);
 
  private:
+  bool IsTwoByteData(uint64_t Data) {
+    int64_t Signed = static_cast<int64_t>(Data);
+    Signed >>= 16;
+    return Signed == 0 || Signed == -1L;
+  }
   bool RecordingTraces = false;
   std::vector<TraceBasedMutation> Mutations;
   LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)] = {};
-  const fuzzer::Fuzzer::FuzzingOptions &Options;
+  const Fuzzer::FuzzingOptions &Options;
+  const Unit &CurrentUnit;
 };
 
 LabelRange DFSanState::GetLabelRange(dfsan_label L) {
@@ -216,6 +230,7 @@ void DFSanState::ApplyTraceBasedMutation
 void DFSanState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
                                   uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
                                   dfsan_label L2) {
+  assert(ReallyHaveDFSan());
   if (!RecordingTraces) return;
   if (L1 == 0 && L2 == 0)
     return;  // Not actionable.
@@ -248,11 +263,42 @@ void DFSanState::DFSanCmpCallback(uintpt
               << "\n";
 }
 
-static DFSanState *DFSan;
+int DFSanState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
+                                    size_t DataSize) {
+  int Res = 0;
+  const uint8_t *Beg = CurrentUnit.data();
+  const uint8_t *End = Beg + CurrentUnit.size();
+  for (const uint8_t *Cur = Beg; Cur < End; Cur += DataSize) {
+    Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize);
+    if (!Cur)
+      break;
+    // std::cerr << "Cur " << (void*)Cur << "\n";
+    size_t Pos = Cur - Beg;
+    assert(Pos < CurrentUnit.size());
+    Mutations.push_back({Pos, DataSize, DesiredData});
+    Mutations.push_back({Pos, DataSize, DesiredData + 1});
+    Mutations.push_back({Pos, DataSize, DesiredData - 1});
+    Cur += DataSize;
+    Res++;
+  }
+  return Res;
+}
 
-}  // namespace
+void DFSanState::TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1,
+                        uint64_t Arg2) {
+  if (!Options.UseTraces) return;
+  int Added = 0;
+  if (Options.Verbosity >= 3)
+    std::cerr << "TraceCmp: " << Arg1 << " " << Arg2 << "\n";
+  Added += TryToAddDesiredData(Arg1, Arg2, CmpSize);
+  Added += TryToAddDesiredData(Arg2, Arg1, CmpSize);
+  if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) {
+    Added += TryToAddDesiredData(Arg1, Arg2, 2);
+    Added += TryToAddDesiredData(Arg2, Arg1, 2);
+  }
+}
 
-namespace fuzzer {
+static DFSanState *DFSan;
 
 void Fuzzer::StartTraceRecording() {
   if (!DFSan) return;
@@ -270,9 +316,11 @@ void Fuzzer::ApplyTraceBasedMutation(siz
 }
 
 void Fuzzer::InitializeDFSan() {
-  if (!&dfsan_create_label || !Options.UseDFSan) return;
-  DFSan = new DFSanState(Options);
+  if (!Options.UseDFSan) return;
+  DFSan = new DFSanState(Options, CurrentUnit);
   CurrentUnit.resize(Options.MaxLen);
+  // The rest really requires DFSan.
+  if (!ReallyHaveDFSan()) return;
   for (size_t i = 0; i < static_cast<size_t>(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.
@@ -283,6 +331,8 @@ void Fuzzer::InitializeDFSan() {
 
 }  // namespace fuzzer
 
+using fuzzer::DFSan;
+
 extern "C" {
 void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
                                       uint64_t Arg2, dfsan_label L0,
@@ -304,13 +354,15 @@ void dfsan_weak_hook_memcmp(void *caller
   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, ICMP_EQ, S1, S2, L1, L2);
+  DFSan->DFSanCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2);
 }
 
 void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
                                uint64_t Arg2) {
-  // This symbol will be present if dfsan is disabled on the given function.
-  // FIXME: implement poor man's taint analysis here (w/o dfsan).
+  if (!DFSan) return;
+  uint64_t CmpSize = (SizeAndType >> 32) / 8;
+  uint64_t Type = (SizeAndType << 32) >> 32;
+  DFSan->TraceCmpCallback(CmpSize, Type, Arg1, Arg2);
 }
 
 }  // extern "C"

Modified: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp?rev=237043&r1=237042&r2=237043&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp Mon May 11 15:51:19 2015
@@ -201,6 +201,7 @@ int FuzzerDriver(int argc, char **argv,
   Options.MutateDepth = Flags.mutate_depth;
   Options.ExitOnFirst = Flags.exit_on_first;
   Options.UseCounters = Flags.use_counters;
+  Options.UseTraces = Flags.use_traces;
   Options.UseFullCoverageSet = Flags.use_full_coverage_set;
   Options.UseCoveragePairs = Flags.use_coverage_pairs;
   Options.UseDFSan = Flags.dfsan;

Modified: llvm/trunk/lib/Fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerFlags.def?rev=237043&r1=237042&r2=237043&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerFlags.def (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def Mon May 11 15:51:19 2015
@@ -33,6 +33,7 @@ FUZZER_FLAG_INT(
     save_minimized_corpus, 0,
     "If 1, the minimized corpus is saved into the first input directory")
 FUZZER_FLAG_INT(use_counters, 0, "Use coverage counters")
+FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces")
 FUZZER_FLAG_INT(use_full_coverage_set, 0,
             "Experimental: Maximize the number of different full"
             " coverage sets as opposed to maximizing the total coverage."

Modified: llvm/trunk/lib/Fuzzer/FuzzerInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerInternal.h?rev=237043&r1=237042&r2=237043&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerInternal.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerInternal.h Mon May 11 15:51:19 2015
@@ -53,6 +53,7 @@ class Fuzzer {
     int  MutateDepth = 5;
     bool ExitOnFirst = false;
     bool UseCounters = false;
+    bool UseTraces = false;
     bool UseFullCoverageSet  = false;
     bool UseCoveragePairs = false;
     bool UseDFSan = false;

Modified: llvm/trunk/lib/Fuzzer/test/fuzzer.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/fuzzer.test?rev=237043&r1=237042&r2=237043&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/fuzzer.test (original)
+++ llvm/trunk/lib/Fuzzer/test/fuzzer.test Mon May 11 15:51:19 2015
@@ -20,6 +20,7 @@ RUN: not ./LLVMFuzzer-FourIndependentBra
 RUN: not ./LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
 
 RUN: not ./LLVMFuzzer-DFSanSimpleCmpTest-DFSan -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s
+RUN: not ./LLVMFuzzer-DFSanSimpleCmpTest -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s
 
 RUN: not ./LLVMFuzzer-DFSanMemcmpTest-DFSan -seed=1 -runs=100 -timeout=5 2>&1 | FileCheck %s
 





More information about the llvm-commits mailing list