diff options
| author | Kostya Serebryany <kcc@google.com> | 2016-01-13 23:02:30 +0000 |
|---|---|---|
| committer | Kostya Serebryany <kcc@google.com> | 2016-01-13 23:02:30 +0000 |
| commit | d50a3eedb4df2298de19e94189559b85af0f5094 (patch) | |
| tree | ff45de1ce4a0dfce6dd9a211888d0413b86fb472 /llvm/lib | |
| parent | 9913322327833d25ad52528167208e282155e439 (diff) | |
| download | bcm5719-llvm-d50a3eedb4df2298de19e94189559b85af0f5094.tar.gz bcm5719-llvm-d50a3eedb4df2298de19e94189559b85af0f5094.zip | |
[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
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Fuzzer/FuzzerInternal.h | 1 | ||||
| -rw-r--r-- | llvm/lib/Fuzzer/FuzzerLoop.cpp | 13 | ||||
| -rw-r--r-- | llvm/lib/Fuzzer/FuzzerTraceState.cpp | 27 | ||||
| -rw-r--r-- | llvm/lib/Fuzzer/test/BufferOverflowOnInput.cpp | 20 | ||||
| -rw-r--r-- | llvm/lib/Fuzzer/test/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | llvm/lib/Fuzzer/test/fuzzer.test | 3 |
6 files changed, 48 insertions, 17 deletions
diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index c1e9daac980..3ab43d2928b 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -106,6 +106,7 @@ class Fuzzer { 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 5237682ff24..ccc05c8b128 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::RunOneAndUpdateCorpus(Unit &U) { } 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 b2006fa3aa4..10eab0183c3 100644 --- a/llvm/lib/Fuzzer/FuzzerTraceState.cpp +++ b/llvm/lib/Fuzzer/FuzzerTraceState.cpp @@ -451,9 +451,6 @@ static TraceState *TS; 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 @@ void Fuzzer::StopTraceRecording() { 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 00000000000..9bebd84a56f --- /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 cd0b167eb38..2d526bdaa0b 100644 --- a/llvm/lib/Fuzzer/test/CMakeLists.txt +++ b/llvm/lib/Fuzzer/test/CMakeLists.txt @@ -13,6 +13,7 @@ set(DFSanTests ) set(Tests + BufferOverflowOnInput CallerCalleeTest CounterTest FourIndependentBranchesTest diff --git a/llvm/lib/Fuzzer/test/fuzzer.test b/llvm/lib/Fuzzer/test/fuzzer.test index c63014f59d6..5b98fde6815 100644 --- a/llvm/lib/Fuzzer/test/fuzzer.test +++ b/llvm/lib/Fuzzer/test/fuzzer.test @@ -34,3 +34,6 @@ PCS:{{^0x[a-f0-9]+}} 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 |

