forked from OSchip/llvm-project
[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:
parent
9913322327
commit
d50a3eedb4
|
@ -106,6 +106,7 @@ class Fuzzer {
|
||||||
void Drill();
|
void Drill();
|
||||||
void ShuffleAndMinimize();
|
void ShuffleAndMinimize();
|
||||||
void InitializeTraceState();
|
void InitializeTraceState();
|
||||||
|
void AssignTaintLabels(uint8_t *Data, size_t Size);
|
||||||
size_t CorpusSize() const { return Corpus.size(); }
|
size_t CorpusSize() const { return Corpus.size(); }
|
||||||
void ReadDir(const std::string &Path, long *Epoch) {
|
void ReadDir(const std::string &Path, long *Epoch) {
|
||||||
Printf("Loading corpus: %s\n", Path.c_str());
|
Printf("Loading corpus: %s\n", Path.c_str());
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "FuzzerInternal.h"
|
#include "FuzzerInternal.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#if defined(__has_include)
|
#if defined(__has_include)
|
||||||
# if __has_include(<sanitizer/coverage_interface.h>)
|
# if __has_include(<sanitizer/coverage_interface.h>)
|
||||||
|
@ -240,11 +242,12 @@ void Fuzzer::RunOneAndUpdateCorpus(Unit &U) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fuzzer::ExecuteCallback(const Unit &U) {
|
void Fuzzer::ExecuteCallback(const Unit &U) {
|
||||||
const uint8_t *Data = U.data();
|
// We copy the contents of Unit into a separate heap buffer
|
||||||
uint8_t EmptyData;
|
// so that we reliably find buffer overflows in it.
|
||||||
if (!Data)
|
std::unique_ptr<uint8_t[]> Data(new uint8_t[U.size()]);
|
||||||
Data = &EmptyData;
|
memcpy(Data.get(), U.data(), U.size());
|
||||||
int Res = USF.TargetFunction(Data, U.size());
|
AssignTaintLabels(Data.get(), U.size());
|
||||||
|
int Res = USF.TargetFunction(Data.get(), U.size());
|
||||||
(void)Res;
|
(void)Res;
|
||||||
assert(Res == 0);
|
assert(Res == 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -451,9 +451,6 @@ static TraceState *TS;
|
||||||
|
|
||||||
void Fuzzer::StartTraceRecording() {
|
void Fuzzer::StartTraceRecording() {
|
||||||
if (!TS) return;
|
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();
|
TS->StartTraceRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,12 +459,17 @@ void Fuzzer::StopTraceRecording() {
|
||||||
TS->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() {
|
void Fuzzer::InitializeTraceState() {
|
||||||
if (!Options.UseTraces) return;
|
if (!Options.UseTraces) return;
|
||||||
TS = new TraceState(USF, Options, CurrentUnit);
|
TS = new TraceState(USF, Options, CurrentUnit);
|
||||||
CurrentUnit.resize(Options.MaxLen);
|
if (ReallyHaveDFSan()) {
|
||||||
// The rest really requires DFSan.
|
|
||||||
if (!ReallyHaveDFSan()) return;
|
|
||||||
for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
|
for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
|
||||||
dfsan_label L = dfsan_create_label("input", (void *)(i + 1));
|
dfsan_label L = dfsan_create_label("input", (void *)(i + 1));
|
||||||
// We assume that no one else has called dfsan_create_label before.
|
// We assume that no one else has called dfsan_create_label before.
|
||||||
|
@ -477,6 +479,7 @@ void Fuzzer::InitializeTraceState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
|
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
|
||||||
size_t Len = 0;
|
size_t Len = 0;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ set(DFSanTests
|
||||||
)
|
)
|
||||||
|
|
||||||
set(Tests
|
set(Tests
|
||||||
|
BufferOverflowOnInput
|
||||||
CallerCalleeTest
|
CallerCalleeTest
|
||||||
CounterTest
|
CounterTest
|
||||||
FourIndependentBranchesTest
|
FourIndependentBranchesTest
|
||||||
|
|
|
@ -34,3 +34,6 @@ PCS:{{^0x[a-f0-9]+}}
|
||||||
PCS:NEW
|
PCS:NEW
|
||||||
PCS:BINGO
|
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
|
||||||
|
|
Loading…
Reference in New Issue