[libFuzzer] add hooks for strstr, strcasestr, strcasecmp, strncasecmp
authorKostya Serebryany <kcc@google.com>
Fri, 15 Jul 2016 23:27:19 +0000 (23:27 +0000)
committerKostya Serebryany <kcc@google.com>
Fri, 15 Jul 2016 23:27:19 +0000 (23:27 +0000)
llvm-svn: 275648

llvm/lib/Fuzzer/FuzzerDriver.cpp
llvm/lib/Fuzzer/FuzzerFlags.def
llvm/lib/Fuzzer/FuzzerInternal.h
llvm/lib/Fuzzer/FuzzerMutate.cpp
llvm/lib/Fuzzer/FuzzerTraceState.cpp
llvm/lib/Fuzzer/test/CMakeLists.txt
llvm/lib/Fuzzer/test/FuzzerUnittest.cpp
llvm/lib/Fuzzer/test/StrstrTest.cpp [new file with mode: 0644]
llvm/lib/Fuzzer/test/fuzzer-traces-hooks.test

index ba6edb3..f520a5c 100644 (file)
@@ -309,6 +309,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
   Options.UseIndirCalls = Flags.use_indir_calls;
   Options.UseTraces = Flags.use_traces;
   Options.UseMemcmp = Flags.use_memcmp;
+  Options.UseMemmem = Flags.use_memmem;
   Options.ShuffleAtStartUp = Flags.shuffle;
   Options.PreferSmall = Flags.prefer_small;
   Options.Reload = Flags.reload;
index 2945152..599ac36 100644 (file)
@@ -42,6 +42,8 @@ FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters")
 FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces")
 FUZZER_FLAG_INT(use_memcmp, 1,
                 "Use hints from intercepting memcmp, strcmp, etc")
+FUZZER_FLAG_INT(use_memmem, 1,
+                "Use hints from intercepting memmem, strstr, etc")
 FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
                           " this number of jobs in separate worker processes"
                           " with stdout/stderr redirected to fuzz-JOB.log.")
index d27ac86..08f8801 100644 (file)
@@ -217,6 +217,7 @@ struct FuzzingOptions {
   bool UseIndirCalls = true;
   bool UseTraces = false;
   bool UseMemcmp = true;
+  bool UseMemmem = true;
   bool UseFullCoverageSet = false;
   bool Reload = true;
   bool ShuffleAtStartUp = true;
@@ -293,7 +294,7 @@ public:
 
   void AddWordToManualDictionary(const Word &W);
 
-  void AddWordToAutoDictionary(const Word &W, size_t PositionHint);
+  void AddWordToAutoDictionary(DictionaryEntry DE);
   void ClearAutoDictionary();
   void PrintRecommendedDictionary();
 
index 72b095d..65e1650 100644 (file)
@@ -313,11 +313,10 @@ void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
       {W, std::numeric_limits<size_t>::max()});
 }
 
-void MutationDispatcher::AddWordToAutoDictionary(const Word &W,
-                                                 size_t PositionHint) {
+void MutationDispatcher::AddWordToAutoDictionary(DictionaryEntry DE) {
   static const size_t kMaxAutoDictSize = 1 << 14;
   if (TempAutoDictionary.size() >= kMaxAutoDictSize) return;
-  TempAutoDictionary.push_back({W, PositionHint});
+  TempAutoDictionary.push_back(DE);
 }
 
 void MutationDispatcher::ClearAutoDictionary() {
index cbfa87d..d6e1f79 100644 (file)
@@ -77,6 +77,7 @@
 #include <cstring>
 #include <thread>
 #include <map>
+#include <set>
 
 #if !LLVM_FUZZER_SUPPORTS_DFSAN
 // Stubs for dfsan for platforms where dfsan does not exist and weak
@@ -171,6 +172,7 @@ struct TraceBasedMutation {
 // Declared as static globals for faster checks inside the hooks.
 static bool RecordingTraces = false;
 static bool RecordingMemcmp = false;
+static bool RecordingMemmem = false;
 
 class TraceState {
 public:
@@ -204,7 +206,9 @@ public:
       return;
     RecordingTraces = Options.UseTraces;
     RecordingMemcmp = Options.UseMemcmp;
+    RecordingMemmem = Options.UseMemmem;
     NumMutations = 0;
+    InterestingWords.clear();
     MD.ClearAutoDictionary();
   }
 
@@ -233,8 +237,10 @@ public:
           }
         }
       }
-      MD.AddWordToAutoDictionary(M.W, M.Pos);
+      MD.AddWordToAutoDictionary({M.W, M.Pos});
     }
+    for (auto &W : InterestingWords)
+      MD.AddWordToAutoDictionary({W});
   }
 
   void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) {
@@ -249,6 +255,14 @@ public:
     AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data));
   }
 
+  void AddInterestingWord(const uint8_t *Data, size_t Size) {
+    if (!RecordingMemmem || !F->InFuzzingThread()) return;
+    if (Size <= 1) return;
+    Size = std::min(Size, Word::GetMaxSize());
+    Word W(Data, Size);
+    InterestingWords.insert(W);
+  }
+
   void EnsureDfsanLabels(size_t Size) {
     for (; LastDfsanLabel < Size; LastDfsanLabel++) {
       dfsan_label L = dfsan_create_label("input", (void *)(LastDfsanLabel + 1));
@@ -285,6 +299,8 @@ public:
   static const size_t kMaxMutations = 1 << 16;
   size_t NumMutations;
   TraceBasedMutation Mutations[kMaxMutations];
+  // TODO: std::set is too inefficient, need to have a custom DS here.
+  std::set<Word> InterestingWords;
   LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)];
   size_t LastDfsanLabel = 0;
   MutationDispatcher &MD;
@@ -605,6 +621,27 @@ void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
                           reinterpret_cast<const uint8_t *>(s2));
 }
 
+void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+                                       const char *s2, size_t n, int result) {
+  return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
+}
+void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+                                      const char *s2, int result) {
+  return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
+}
+void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
+                                  const char *s2, char *result) {
+  TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
+                                      const char *s2, char *result) {
+  TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
+                                  const void *s2, size_t len2, void *result) {
+  // TODO: can't hook memmem since memmem is used by libFuzzer.
+}
+
 #endif  // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
 
 __attribute__((visibility("default")))
index e079650..cbc983e 100644 (file)
@@ -90,6 +90,7 @@ set(Tests
   SpamyTest
   StrcmpTest
   StrncmpTest
+  StrstrTest
   SwitchTest
   ThreadedLeakTest
   ThreadedTest
index 3630e39..3fd87e5 100644 (file)
@@ -311,7 +311,7 @@ void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) {
   MutationDispatcher MD(Rand, {});
   uint8_t W[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF};
   size_t PosHint = 7777;
-  MD.AddWordToAutoDictionary(Word(W, sizeof(W)), PosHint);
+  MD.AddWordToAutoDictionary({Word(W, sizeof(W)), PosHint});
   int FoundMask = 0;
   for (int i = 0; i < NumIter; i++) {
     uint8_t T[10000];
diff --git a/llvm/lib/Fuzzer/test/StrstrTest.cpp b/llvm/lib/Fuzzer/test/StrstrTest.cpp
new file mode 100644 (file)
index 0000000..90d539b
--- /dev/null
@@ -0,0 +1,18 @@
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// Test strstr and strcasestr hooks.
+#include <string>
+#include <string.h>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  std::string s(reinterpret_cast<const char*>(Data), Size);
+  if (strstr(s.c_str(), "FUZZ") && strcasestr(s.c_str(), "aBcD")) {
+    fprintf(stderr, "BINGO\n");
+    exit(1);
+  }
+  return 0;
+}
index b98972d..71fe6f2 100644 (file)
@@ -14,6 +14,8 @@ RUN:     LLVMFuzzer-StrncmpTest -use_memcmp=0 -seed=3 -runs=1000000  2>&1 | File
 RUN: not LLVMFuzzer-StrcmpTest               -seed=4 -runs=200000   2>&1 | FileCheck %s
 RUN:     LLVMFuzzer-StrcmpTest -use_memcmp=0 -seed=5 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
+RUN: not LLVMFuzzer-StrstrTest               -seed=6 -runs=200000   2>&1 | FileCheck %s
+RUN:     LLVMFuzzer-StrstrTest -use_memmem=0 -seed=7 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
 RUN: LLVMFuzzer-RepeatedMemcmp -seed=10 -runs=100000 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT
 RECOMMENDED_DICT:###### Recommended dictionary. ######