[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
This commit is contained in:
Kostya Serebryany 2016-01-13 23:02:30 +00:00
parent 9913322327
commit d50a3eedb4
6 changed files with 48 additions and 17 deletions

View File

@ -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());

View File

@ -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);
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}

View File

@ -13,6 +13,7 @@ set(DFSanTests
)
set(Tests
BufferOverflowOnInput
CallerCalleeTest
CounterTest
FourIndependentBranchesTest

View File

@ -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