[libFuzzer] make sure we find buffer overflow in the input buffer. Previously, re-using the same vector object was hiding buffer overflows (unless we used annotated vector)
llvm-svn: 257701
diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h
index c1e9daa..3ab43d2 100644
--- a/llvm/lib/Fuzzer/FuzzerInternal.h
+++ b/llvm/lib/Fuzzer/FuzzerInternal.h
@@ -106,6 +106,7 @@
void Drill();
void ShuffleAndMinimize();
void InitializeTraceState();
+ void AssignTaintLabels(uint8_t *Data, size_t Size);
size_t CorpusSize() const { return Corpus.size(); }
void ReadDir(const std::string &Path, long *Epoch) {
Printf("Loading corpus: %s\n", Path.c_str());
diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp
index 5237682..ccc05c8 100644
--- a/llvm/lib/Fuzzer/FuzzerLoop.cpp
+++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp
@@ -11,6 +11,8 @@
#include "FuzzerInternal.h"
#include <algorithm>
+#include <cstring>
+#include <memory>
#if defined(__has_include)
# if __has_include(<sanitizer/coverage_interface.h>)
@@ -240,11 +242,12 @@
}
void Fuzzer::ExecuteCallback(const Unit &U) {
- const uint8_t *Data = U.data();
- uint8_t EmptyData;
- if (!Data)
- Data = &EmptyData;
- int Res = USF.TargetFunction(Data, U.size());
+ // We copy the contents of Unit into a separate heap buffer
+ // so that we reliably find buffer overflows in it.
+ std::unique_ptr<uint8_t[]> Data(new uint8_t[U.size()]);
+ memcpy(Data.get(), U.data(), U.size());
+ AssignTaintLabels(Data.get(), U.size());
+ int Res = USF.TargetFunction(Data.get(), U.size());
(void)Res;
assert(Res == 0);
}
diff --git a/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/llvm/lib/Fuzzer/FuzzerTraceState.cpp
index b2006fa..10eab01 100644
--- a/llvm/lib/Fuzzer/FuzzerTraceState.cpp
+++ b/llvm/lib/Fuzzer/FuzzerTraceState.cpp
@@ -451,9 +451,6 @@
void Fuzzer::StartTraceRecording() {
if (!TS) return;
- if (ReallyHaveDFSan())
- for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++)
- dfsan_set_label(i + 1, &CurrentUnit[i], 1);
TS->StartTraceRecording();
}
@@ -462,18 +459,24 @@
TS->StopTraceRecording();
}
+void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) {
+ if (!Options.UseTraces) return;
+ if (!ReallyHaveDFSan()) return;
+ for (size_t i = 0; i < Size; i++)
+ dfsan_set_label(i + 1, &Data[i], 1);
+}
+
void Fuzzer::InitializeTraceState() {
if (!Options.UseTraces) return;
TS = new TraceState(USF, 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.
- if (L != i + 1) {
- Printf("DFSan labels are not starting from 1, exiting\n");
- exit(1);
+ if (ReallyHaveDFSan()) {
+ 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.
+ if (L != i + 1) {
+ Printf("DFSan labels are not starting from 1, exiting\n");
+ exit(1);
+ }
}
}
}
diff --git a/llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp b/llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp
new file mode 100644
index 0000000..9bebd84
--- /dev/null
+++ b/llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp
@@ -0,0 +1,20 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <assert.h>
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile bool SeedLargeBuffer;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ assert(Data);
+ if (Size >= 4)
+ SeedLargeBuffer = true;
+ if (Size == 3 && SeedLargeBuffer && Data[3]) {
+ std::cout << "Woops, reading Data[3] w/o crashing\n";
+ exit(1);
+ }
+ return 0;
+}
+
diff --git a/llvm/lib/Fuzzer/test/CMakeLists.txt b/llvm/lib/Fuzzer/test/CMakeLists.txt
index cd0b167..2d526bd 100644
--- a/llvm/lib/Fuzzer/test/CMakeLists.txt
+++ b/llvm/lib/Fuzzer/test/CMakeLists.txt
@@ -13,6 +13,7 @@
)
set(Tests
+ BufferOverflowOnInput
CallerCalleeTest
CounterTest
FourIndependentBranchesTest
diff --git a/llvm/lib/Fuzzer/test/fuzzer.test b/llvm/lib/Fuzzer/test/fuzzer.test
index c63014f..5b98fde 100644
--- a/llvm/lib/Fuzzer/test/fuzzer.test
+++ b/llvm/lib/Fuzzer/test/fuzzer.test
@@ -34,3 +34,6 @@
PCS:NEW
PCS:BINGO
+RUN: not LLVMFuzzer-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB
+OOB: AddressSanitizer: heap-buffer-overflow
+OOB: is located 0 bytes to the right of 3-byte region