From 4deda57106f7c9b982a49cb907c33e3966c8de7f Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Wed, 19 Aug 2020 15:07:17 -0700 Subject: [PATCH] [DFSan] Handle mmap() calls before interceptors are installed. InitializeInterceptors() calls dlsym(), which calls calloc(). Depending on the allocator implementation, calloc() may invoke mmap(), which results in a segfault since REAL(mmap) is still being resolved. We fix this by doing a direct syscall if interceptors haven't been fully resolved yet. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D86168 --- compiler-rt/lib/dfsan/dfsan_interceptors.cpp | 25 ++++++++++++++++------ compiler-rt/test/dfsan/interceptors.c | 32 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 compiler-rt/test/dfsan/interceptors.c diff --git a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp index 673171c..12b74df 100644 --- a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp +++ b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp @@ -11,16 +11,29 @@ // Interceptors for standard library functions. //===----------------------------------------------------------------------===// +#include +#include + #include "dfsan/dfsan.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" using namespace __sanitizer; +static bool interceptors_initialized; + INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { - void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); - if (res != (void*)-1) + void *res; + + // interceptors_initialized is set to true during preinit_array, when we're + // single-threaded. So we don't need to worry about accessing it atomically. + if (!interceptors_initialized) + res = (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset); + else + res = REAL(mmap)(addr, length, prot, flags, fd, offset); + + if (res != (void *)-1) dfsan_set_label(0, res, RoundUpTo(length, GetPageSize())); return res; } @@ -28,18 +41,18 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); - if (res != (void*)-1) + if (res != (void *)-1) dfsan_set_label(0, res, RoundUpTo(length, GetPageSize())); return res; } namespace __dfsan { void InitializeInterceptors() { - static int inited = 0; - CHECK_EQ(inited, 0); + CHECK(!interceptors_initialized); INTERCEPT_FUNCTION(mmap); INTERCEPT_FUNCTION(mmap64); - inited = 1; + + interceptors_initialized = true; } } // namespace __dfsan diff --git a/compiler-rt/test/dfsan/interceptors.c b/compiler-rt/test/dfsan/interceptors.c new file mode 100644 index 0000000..77aec20 --- /dev/null +++ b/compiler-rt/test/dfsan/interceptors.c @@ -0,0 +1,32 @@ +// RUN: %clang_dfsan -fno-sanitize=dataflow -DCALLOC -c %s -o %t-calloc.o +// RUN: %clang_dfsan %s %t-calloc.o -o %t +// RUN: %run %t +// +// Tests that calling mmap() during during dfsan initialization works. + +#include +#include +#include +#include +#include + +#ifdef CALLOC + +// dfsan_init() installs interceptors via dlysm(), which calls calloc(). +// Calling mmap() from here should work even if interceptors haven't been fully +// set up yet. +void *calloc(size_t Num, size_t Size) { + size_t PageSize = getpagesize(); + Size = Size * Num; + Size = (Size + PageSize - 1) & ~(PageSize - 1); // Round up to PageSize. + void *Ret = mmap(NULL, Size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(Ret != MAP_FAILED); + return Ret; +} + +#else + +int main() { return 0; } + +#endif // CALLOC -- 2.7.4