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:
parent
097611dedc
commit
ed0ebff1b3
@ -21,6 +21,7 @@ if( LLVM_USE_SANITIZE_COVERAGE )
|
||||
FuzzerMerge.cpp
|
||||
FuzzerMutate.cpp
|
||||
FuzzerSHA1.cpp
|
||||
FuzzerShmemPosix.cpp
|
||||
FuzzerTracePC.cpp
|
||||
FuzzerTraceState.cpp
|
||||
FuzzerUtil.cpp
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -109,6 +109,7 @@ public:
|
||||
bool DuringInitialCorpusExecution);
|
||||
|
||||
void HandleMalloc(size_t Size);
|
||||
void AnnounceOutput(const uint8_t *Data, size_t Size);
|
||||
|
||||
private:
|
||||
void AlarmCallback();
|
||||
|
@ -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
69
lib/Fuzzer/FuzzerShmem.h
Normal 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
|
97
lib/Fuzzer/FuzzerShmemPosix.cpp
Normal file
97
lib/Fuzzer/FuzzerShmemPosix.cpp
Normal 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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
5
lib/Fuzzer/test/equivalence.test
Normal file
5
lib/Fuzzer/test/equivalence.test
Normal 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
|
Loading…
Reference in New Issue
Block a user