1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +01:00

[libFuzzer] experimental support for 'equivalance fuzzing'

llvm-svn: 292646
This commit is contained in:
Kostya Serebryany 2017-01-20 20:57:07 +00:00
parent 097611dedc
commit ed0ebff1b3
10 changed files with 243 additions and 7 deletions

View File

@ -21,6 +21,7 @@ if( LLVM_USE_SANITIZE_COVERAGE )
FuzzerMerge.cpp
FuzzerMutate.cpp
FuzzerSHA1.cpp
FuzzerShmemPosix.cpp
FuzzerTracePC.cpp
FuzzerTraceState.cpp
FuzzerUtil.cpp

View File

@ -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, UserCallback Callback) {
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);

View File

@ -106,6 +106,9 @@ FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
" 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)

View File

@ -109,6 +109,7 @@ public:
bool DuringInitialCorpusExecution);
void HandleMalloc(size_t Size);
void AnnounceOutput(const uint8_t *Data, size_t Size);
private:
void AlarmCallback();

View File

@ -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 = 256;
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::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
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 Unit &U) {
}
}
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, size_t Size, size_t MaxSize) {
}
// 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"

69
lib/Fuzzer/FuzzerShmem.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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