[llvm] r292646 - [libFuzzer] experimental support for 'equivalance fuzzing'

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 20 12:57:08 PST 2017


Author: kcc
Date: Fri Jan 20 14:57:07 2017
New Revision: 292646

URL: http://llvm.org/viewvc/llvm-project?rev=292646&view=rev
Log:
[libFuzzer] experimental support for 'equivalance fuzzing'

Added:
    llvm/trunk/lib/Fuzzer/FuzzerShmem.h
    llvm/trunk/lib/Fuzzer/FuzzerShmemPosix.cpp
    llvm/trunk/lib/Fuzzer/test/equivalence.test
Modified:
    llvm/trunk/lib/Fuzzer/CMakeLists.txt
    llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
    llvm/trunk/lib/Fuzzer/FuzzerFlags.def
    llvm/trunk/lib/Fuzzer/FuzzerInternal.h
    llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
    llvm/trunk/lib/Fuzzer/test/EquivalenceATest.cpp
    llvm/trunk/lib/Fuzzer/test/EquivalenceBTest.cpp

Modified: llvm/trunk/lib/Fuzzer/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/CMakeLists.txt?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/CMakeLists.txt (original)
+++ llvm/trunk/lib/Fuzzer/CMakeLists.txt Fri Jan 20 14:57:07 2017
@@ -21,6 +21,7 @@ if( LLVM_USE_SANITIZE_COVERAGE )
     FuzzerMerge.cpp
     FuzzerMutate.cpp
     FuzzerSHA1.cpp
+    FuzzerShmemPosix.cpp
     FuzzerTracePC.cpp
     FuzzerTraceState.cpp
     FuzzerUtil.cpp

Modified: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp Fri Jan 20 14:57:07 2017
@@ -15,6 +15,7 @@
 #include "FuzzerIO.h"
 #include "FuzzerMutate.h"
 #include "FuzzerRandom.h"
+#include "FuzzerShmem.h"
 #include "FuzzerTracePC.h"
 #include <algorithm>
 #include <atomic>
@@ -474,6 +475,31 @@ int FuzzerDriver(int *argc, char ***argv
   if (Flags.minimize_crash_internal_step)
     return MinimizeCrashInputInternalStep(F, Corpus);
 
+  if (auto Name = Flags.run_equivalence_server) {
+    SMR.Destroy(Name);
+    if (!SMR.Create(Name, 1 << 12)) {
+      Printf("ERROR: can't create shared memory region\n");
+      return 1;
+    }
+    Printf("INFO: EQUIVALENCE SERVER UP\n");
+    while (true) {
+      SMR.WaitClient();
+      size_t Size = SMR.ReadByteArraySize();
+      SMR.WriteByteArray(nullptr, 0);
+      F->RunOne(SMR.GetByteArray(), Size);
+      SMR.PostServer();
+    }
+    return 0;
+  }
+
+  if (auto Name = Flags.use_equivalence_server) {
+    if (!SMR.Open(Name)) {
+      Printf("ERROR: can't open shared memory region\n");
+      return 1;
+    }
+    Printf("INFO: EQUIVALENCE CLIENT UP\n");
+  }
+
   if (DoPlainRun) {
     Options.SaveArtifacts = false;
     int Runs = std::max(1, Flags.runs);

Modified: llvm/trunk/lib/Fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerFlags.def?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerFlags.def (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def Fri Jan 20 14:57:07 2017
@@ -106,6 +106,9 @@ FUZZER_FLAG_STRING(exit_on_item, "Exit i
     " was added to the corpus. "
     "Used primarily for testing libFuzzer itself.")
 
+FUZZER_FLAG_STRING(run_equivalence_server, "Experimental")
+FUZZER_FLAG_STRING(use_equivalence_server, "Experimental")
+
 FUZZER_DEPRECATED_FLAG(exit_on_first)
 FUZZER_DEPRECATED_FLAG(save_minimized_corpus)
 FUZZER_DEPRECATED_FLAG(sync_command)

Modified: llvm/trunk/lib/Fuzzer/FuzzerInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerInternal.h?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerInternal.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerInternal.h Fri Jan 20 14:57:07 2017
@@ -109,6 +109,7 @@ public:
                                bool DuringInitialCorpusExecution);
 
   void HandleMalloc(size_t Size);
+  void AnnounceOutput(const uint8_t *Data, size_t Size);
 
 private:
   void AlarmCallback();

Modified: llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp Fri Jan 20 14:57:07 2017
@@ -14,6 +14,7 @@
 #include "FuzzerIO.h"
 #include "FuzzerMutate.h"
 #include "FuzzerRandom.h"
+#include "FuzzerShmem.h"
 #include "FuzzerTracePC.h"
 #include <algorithm>
 #include <cstring>
@@ -42,6 +43,8 @@ static const size_t kMaxUnitSizeToPrint
 
 thread_local bool Fuzzer::IsMyThread;
 
+SharedMemoryRegion SMR;
+
 static void MissingExternalApiFunction(const char *FnName) {
   Printf("ERROR: %s is not defined. Exiting.\n"
          "Did you use -fsanitize-coverage=... to build your code?\n",
@@ -531,6 +534,8 @@ size_t Fuzzer::GetCurrentUnitInFuzzingTh
 
 void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
   assert(InFuzzingThread());
+  if (SMR.IsClient())
+    SMR.WriteByteArray(Data, Size);
   // We copy the contents of Unit into a separate heap buffer
   // so that we reliably find buffer overflows in it.
   uint8_t *DataCopy = new uint8_t[Size];
@@ -806,6 +811,29 @@ void Fuzzer::MinimizeCrashLoop(const Uni
   }
 }
 
+void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {
+  if (SMR.IsServer()) {
+    SMR.WriteByteArray(Data, Size);
+  } else if (SMR.IsClient()) {
+    SMR.PostClient();
+    SMR.WaitServer();
+    size_t OtherSize = SMR.ReadByteArraySize();
+    uint8_t *OtherData = SMR.GetByteArray();
+    if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) {
+      size_t i = 0;
+      for (i = 0; i < Min(Size, OtherSize); i++)
+        if (Data[i] != OtherData[i])
+          break;
+      Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; "
+             "offset %zd\n", GetPid(), Size, OtherSize, i);
+      DumpCurrentUnit("mismatch-");
+      Printf("SUMMARY: libFuzzer: equivalence-mismatch\n");
+      PrintFinalStats();
+      _Exit(Options.ErrorExitCode);
+    }
+  }
+}
+
 } // namespace fuzzer
 
 extern "C" {
@@ -816,5 +844,8 @@ size_t LLVMFuzzerMutate(uint8_t *Data, s
 }
 
 // Experimental
-void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {}
+void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
+  assert(fuzzer::F);
+  fuzzer::F->AnnounceOutput(Data, Size);
+}
 }  // extern "C"

Added: llvm/trunk/lib/Fuzzer/FuzzerShmem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerShmem.h?rev=292646&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerShmem.h (added)
+++ llvm/trunk/lib/Fuzzer/FuzzerShmem.h Fri Jan 20 14:57:07 2017
@@ -0,0 +1,69 @@
+//===- FuzzerShmem.h - shared memory interface ------------------*- C++ -* ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_SHMEM_H
+#define LLVM_FUZZER_SHMEM_H
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+class SharedMemoryRegion {
+ public:
+  bool Create(const char *Name, size_t Size);
+  bool Open(const char *Name);
+  bool Destroy(const char *Name);
+  size_t GetSize() const { return Size; }
+  uint8_t *GetData() { return Data; }
+  void PostServer() {Post(0);}
+  void WaitServer() {Wait(0);}
+  void PostClient() {Post(1);}
+  void WaitClient() {Wait(1);}
+
+  size_t WriteByteArray(const uint8_t *Bytes, size_t N) {
+    N = std::min(N, GetSize() - sizeof(N));
+    memcpy(GetData(), &N, sizeof(N));
+    memcpy(GetData() + sizeof(N), Bytes, N);
+    assert(N == ReadByteArraySize());
+    return N;
+  }
+  size_t ReadByteArraySize() {
+    size_t Res;
+    memcpy(&Res, GetData(), sizeof(Res));
+    return Res;
+  }
+  uint8_t *GetByteArray() { return GetData() + sizeof(size_t); }
+
+  bool IsServer() const { return Data && IAmServer; }
+  bool IsClient() const { return Data && !IAmServer; }
+
+private:
+  bool IAmServer;
+  std::string Path(const char *Name);
+  std::string SemName(const char *Name, int Idx);
+  void Post(int Idx);
+  void Wait(int Idx);
+
+  bool Map(int fd);
+  size_t Size = 0;
+  uint8_t *Data = nullptr;
+  void *Semaphore[2];
+};
+
+extern SharedMemoryRegion SMR;
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_SHMEM_H

Added: llvm/trunk/lib/Fuzzer/FuzzerShmemPosix.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerShmemPosix.cpp?rev=292646&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerShmemPosix.cpp (added)
+++ llvm/trunk/lib/Fuzzer/FuzzerShmemPosix.cpp Fri Jan 20 14:57:07 2017
@@ -0,0 +1,97 @@
+//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#ifdef LIBFUZZER_POSIX
+
+#include "FuzzerIO.h"
+#include "FuzzerShmem.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+namespace fuzzer {
+
+std::string SharedMemoryRegion::Path(const char *Name) {
+  return DirPlusFile(TmpDir(), Name);
+}
+
+std::string SharedMemoryRegion::SemName(const char *Name, int Idx) {
+  std::string Res(Name);
+  return Res + (char)('0' + Idx);
+}
+
+bool SharedMemoryRegion::Map(int fd) {
+  Data = (uint8_t *)mmap(0, Size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
+  if (Data == (uint8_t*)-1)
+    return false;
+  return true;
+}
+
+bool SharedMemoryRegion::Create(const char *Name, size_t Size) {
+  int fd = open(Path(Name).c_str(), O_CREAT | O_RDWR, 0777);
+  if (fd < 0) return false;
+  if (ftruncate(fd, Size) < 0) return false;
+  this->Size = Size;
+  if (!Map(fd))
+    return false;
+  for (int i = 0; i < 2; i++) {
+    sem_unlink(SemName(Name, i).c_str());
+    Semaphore[i] = sem_open(SemName(Name, i).c_str(), O_CREAT, 0644, 0);
+    if (Semaphore[i] == (void *)-1)
+      return false;
+  }
+  IAmServer = true;
+  return true;
+}
+
+bool SharedMemoryRegion::Open(const char *Name) {
+  int fd = open(Path(Name).c_str(), O_RDWR);
+  if (fd < 0) return false;
+  struct stat stat_res;
+  if (0 != fstat(fd, &stat_res))
+    return false;
+  Size = stat_res.st_size;
+  if (!Map(fd))
+    return false;
+  for (int i = 0; i < 2; i++) {
+    Semaphore[i] = sem_open(SemName(Name, i).c_str(), 0);
+    if (Semaphore[i] == (void *)-1)
+      return false;
+  }
+  IAmServer = false;
+  return true;
+}
+
+bool SharedMemoryRegion::Destroy(const char *Name) {
+  return 0 == unlink(Path(Name).c_str());
+}
+
+void SharedMemoryRegion::Post(int Idx) {
+  assert(Idx == 0 || Idx == 1);
+  sem_post((sem_t*)Semaphore[Idx]);
+}
+
+void SharedMemoryRegion::Wait(int Idx) {
+  assert(Idx == 0 || Idx == 1);
+  if (sem_wait((sem_t*)Semaphore[Idx])) {
+    Printf("ERROR: sem_wait failed\n");
+    exit(1);
+  }
+}
+
+}  // namespace fuzzer
+
+#endif  // LIBFUZZER_POSIX

Modified: llvm/trunk/lib/Fuzzer/test/EquivalenceATest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/EquivalenceATest.cpp?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/EquivalenceATest.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/EquivalenceATest.cpp Fri Jan 20 14:57:07 2017
@@ -2,12 +2,14 @@
 // License. See LICENSE.TXT for details.
 #include <stddef.h>
 #include <stdint.h>
+#include <stdio.h>
 
 // Test for libFuzzer's "equivalence" fuzzing, part A.
 extern "C" void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size);
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-  if (Size > 100) return 0;
-  uint8_t Result[100];
+  // fprintf(stderr, "A %zd\n", Size);
+  uint8_t Result[50];
+  if (Size > 50) Size = 50;
   for (size_t i = 0; i < Size; i++)
     Result[Size - i - 1] = Data[i];
   LLVMFuzzerAnnounceOutput(Result, Size);

Modified: llvm/trunk/lib/Fuzzer/test/EquivalenceBTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/EquivalenceBTest.cpp?rev=292646&r1=292645&r2=292646&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/EquivalenceBTest.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/EquivalenceBTest.cpp Fri Jan 20 14:57:07 2017
@@ -7,18 +7,19 @@
 // Test for libFuzzer's "equivalence" fuzzing, part B.
 extern "C" void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size);
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-  if (Size > 100) return 0;
-  uint8_t Result[100];
+  // fprintf(stderr, "B %zd\n", Size);
+  uint8_t Result[50];
+  if (Size > 50) Size = 50;
   for (size_t i = 0; i < Size; i++)
     Result[Size - i - 1] = Data[i];
 
   // Be a bit different from EquivalenceATest
-  if (Size > 42 && Data[10] == 'B') {
+  if (Size > 10 && Data[5] == 'B' && Data[6] == 'C' && Data[7] == 'D') {
     static int c;
     if (!c)
       fprintf(stderr, "ZZZZZZZ\n");
     c = 1;
-    Result[42]++;
+    Result[2]++;
   }
 
   LLVMFuzzerAnnounceOutput(Result, Size);

Added: llvm/trunk/lib/Fuzzer/test/equivalence.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/equivalence.test?rev=292646&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/equivalence.test (added)
+++ llvm/trunk/lib/Fuzzer/test/equivalence.test Fri Jan 20 14:57:07 2017
@@ -0,0 +1,5 @@
+RUN: LLVMFuzzer-EquivalenceATest -run_equivalence_server=EQUIV_TEST & export APID=$!
+RUN: not LLVMFuzzer-EquivalenceBTest -use_equivalence_server=EQUIV_TEST 2>&1 | FileCheck %s
+CHECK: ERROR: libFuzzer: equivalence-mismatch. Sizes: {{.*}}; offset 2
+CHECK: SUMMARY: libFuzzer: equivalence-mismatch
+RUN: kill -9 $APID




More information about the llvm-commits mailing list