[libFuzzer] Make -fsanitize=memory,fuzzer work.

This patch allows libFuzzer to fuzz applications instrumented with MSan
without recompiling libFuzzer with MSan instrumentation.

Fixes https://github.com/google/sanitizers/issues/958.

Differential Revision: https://reviews.llvm.org/D48891

llvm-svn: 336619
This commit is contained in:
Matt Morehouse 2018-07-09 23:51:08 +00:00
parent 6cd35e8194
commit a34c65e845
8 changed files with 116 additions and 12 deletions

View File

@ -537,6 +537,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
EF = new ExternalFunctions();
if (EF->LLVMFuzzerInitialize)
EF->LLVMFuzzerInitialize(argc, argv);
if (EF->__msan_scoped_disable_interceptor_checks)
EF->__msan_scoped_disable_interceptor_checks();
const Vector<std::string> Args(*argv, *argv + *argc);
assert(!Args.empty());
ProgName = new std::string(Args[0]);

View File

@ -46,3 +46,6 @@ EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
EXT_FUNC(__sanitizer_dump_coverage, void, (const uintptr_t *, uintptr_t),
false);
EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false);
EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false);
EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false);

View File

@ -152,6 +152,28 @@ private:
static thread_local bool IsMyThread;
};
struct ScopedEnableMsanInterceptorChecks {
ScopedEnableMsanInterceptorChecks() {
if (EF->__msan_scoped_enable_interceptor_checks)
EF->__msan_scoped_enable_interceptor_checks();
}
~ScopedEnableMsanInterceptorChecks() {
if (EF->__msan_scoped_disable_interceptor_checks)
EF->__msan_scoped_disable_interceptor_checks();
}
};
struct ScopedDisableMsanInterceptorChecks {
ScopedDisableMsanInterceptorChecks() {
if (EF->__msan_scoped_disable_interceptor_checks)
EF->__msan_scoped_disable_interceptor_checks();
}
~ScopedDisableMsanInterceptorChecks() {
if (EF->__msan_scoped_enable_interceptor_checks)
EF->__msan_scoped_enable_interceptor_checks();
}
};
} // namespace fuzzer
#endif // LLVM_FUZZER_INTERNAL_H

View File

@ -179,6 +179,7 @@ void Fuzzer::StaticDeathCallback() {
void Fuzzer::DumpCurrentUnit(const char *Prefix) {
if (!CurrentUnitData)
return; // Happens when running individual inputs.
ScopedDisableMsanInterceptorChecks S;
MD.PrintMutationSequence();
Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
size_t UnitSize = CurrentUnitSize;
@ -516,19 +517,24 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
// so that we reliably find buffer overflows in it.
uint8_t *DataCopy = new uint8_t[Size];
memcpy(DataCopy, Data, Size);
if (EF->__msan_unpoison)
EF->__msan_unpoison(DataCopy, Size);
if (CurrentUnitData && CurrentUnitData != Data)
memcpy(CurrentUnitData, Data, Size);
CurrentUnitSize = Size;
AllocTracer.Start(Options.TraceMalloc);
UnitStartTime = system_clock::now();
TPC.ResetMaps();
RunningCB = true;
int Res = CB(DataCopy, Size);
RunningCB = false;
UnitStopTime = system_clock::now();
(void)Res;
assert(Res == 0);
HasMoreMallocsThanFrees = AllocTracer.Stop();
{
ScopedEnableMsanInterceptorChecks S;
AllocTracer.Start(Options.TraceMalloc);
UnitStartTime = system_clock::now();
TPC.ResetMaps();
RunningCB = true;
int Res = CB(DataCopy, Size);
RunningCB = false;
UnitStopTime = system_clock::now();
(void)Res;
assert(Res == 0);
HasMoreMallocsThanFrees = AllocTracer.Stop();
}
if (!LooseMemeq(DataCopy, Data, Size))
CrashOnOverwrittenData();
CurrentUnitSize = 0;

View File

@ -0,0 +1,14 @@
#include <cstdint>
#include <cstring>
volatile size_t Sink;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size < 4) return 0;
if (Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') {
char uninit[7];
Sink = strlen(uninit);
}
return 0;
}

View File

@ -0,0 +1,27 @@
#include <cstdint>
#include <cstdio>
struct Simple {
int x_;
Simple() {
x_ = 5;
}
~Simple() {
x_ += 1;
}
};
Simple *volatile SimpleSink;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size < 4) return 0;
if (Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') {
{
Simple S;
SimpleSink = &S;
}
if (SimpleSink->x_) fprintf(stderr, "Failed to catch use-after-dtor\n");
}
return 0;
}

View File

@ -49,7 +49,7 @@ config.substitutions.append(('%build_dir', config.cmake_binary_dir))
libfuzzer_src_root = os.path.join(config.compiler_rt_src_root, "lib", "fuzzer")
config.substitutions.append(('%libfuzzer_src', libfuzzer_src_root))
def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True):
def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False):
compiler_cmd = config.clang
extra_cmd = config.target_flags
if config.clang and config.stdlib == 'libc++':
@ -63,7 +63,10 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True):
link_cmd = '-lstdc++'
std_cmd = '--driver-mode=g++ -std=c++11' if is_cpp else ''
sanitizers = ['address']
if msan_enabled:
sanitizers = ['memory']
else:
sanitizers = ['address']
if fuzzer_enabled:
sanitizers.append('fuzzer')
sanitizers_cmd = ('-fsanitize=%s' % ','.join(sanitizers))
@ -93,6 +96,10 @@ config.substitutions.append(('%no_fuzzer_c_compiler',
generate_compiler_cmd(is_cpp=False, fuzzer_enabled=False)
))
config.substitutions.append(('%msan_compiler',
generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=True)
))
if config.host_os == 'Darwin':
if config.target_arch in ["x86_64", "x86_64h"]:
config.parallelism_group = "darwin-64bit-sanitizer"

View File

@ -0,0 +1,23 @@
RUN: %msan_compiler %S/SimpleTest.cpp -o %t
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
RUN: %msan_compiler %S/SimpleCmpTest.cpp -o %t
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
RUN: %msan_compiler %S/MemcmpTest.cpp -o %t
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
RUN: %msan_compiler %S/StrcmpTest.cpp -o %t
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
NO-REPORT-NOT: MemorySanitizer
NO-REPORT: BINGO
RUN: %msan_compiler %S/UseAfterDtor.cpp -o %t
RUN: MSAN_OPTIONS=poison_in_dtor=1 not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=REPORT
RUN: %msan_compiler %S/UninitializedStrlen.cpp -o %t
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=REPORT
REPORT: MemorySanitizer: use-of-uninitialized-value