From 130a190bf08a3d955d9db24dac936159dc049e12 Mon Sep 17 00:00:00 2001 From: Etienne Bergeron Date: Mon, 19 Sep 2016 15:59:01 +0000 Subject: [PATCH] [compiler-rt] Add support for the dynamic shadow allocation Summary: This patch is adding the needed code to compiler-rt to support dynamic shadow. This is to support this patch: https://reviews.llvm.org/D23354 It's adding support for using a shadow placed at a dynamic address determined at runtime. The dynamic shadow is required to work on windows 64-bits. Reviewers: rnk, kcc, vitalybuka Subscribers: kubabrecka, dberris, llvm-commits, chrisha Differential Revision: https://reviews.llvm.org/D23363 llvm-svn: 281909 --- compiler-rt/lib/asan/asan_interface_internal.h | 7 ++++++ compiler-rt/lib/asan/asan_mapping.h | 3 +-- compiler-rt/lib/asan/asan_rtl.cc | 28 +++++++++++++++++----- compiler-rt/lib/asan/asan_win_dll_thunk.cc | 12 ++++------ .../lib/asan/asan_win_dynamic_runtime_thunk.cc | 17 ------------- .../lib/sanitizer_common/sanitizer_common.h | 3 +++ .../lib/sanitizer_common/sanitizer_posix.cc | 5 ++++ compiler-rt/lib/sanitizer_common/sanitizer_win.cc | 20 ++++++++++++++++ 8 files changed, 63 insertions(+), 32 deletions(-) diff --git a/compiler-rt/lib/asan/asan_interface_internal.h b/compiler-rt/lib/asan/asan_interface_internal.h index f9a1eb5..da45cef 100644 --- a/compiler-rt/lib/asan/asan_interface_internal.h +++ b/compiler-rt/lib/asan/asan_interface_internal.h @@ -31,6 +31,10 @@ extern "C" { // before any instrumented code is executed and before any call to malloc. SANITIZER_INTERFACE_ATTRIBUTE void __asan_init(); + // This function should be called by a loaded instrumented module. + SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_from_dll( + int *detect_stack_use_after_return, uptr *shadow_memory_dynamic_address); + // This function exists purely to get a linker/loader error when using // incompatible versions of instrumentation and runtime library. Please note // that __asan_version_mismatch_check is a macro that is replaced with @@ -172,6 +176,9 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ const char* __asan_default_options(); + SANITIZER_INTERFACE_ATTRIBUTE + extern uptr __asan_shadow_memory_dynamic_address; + // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return SANITIZER_INTERFACE_ATTRIBUTE extern int __asan_option_detect_stack_use_after_return; diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index 52c4f67..40ff54f 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -140,7 +140,6 @@ static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 -static const u64 kWindowsShadowOffset64 = 1ULL << 45; // 32TB #define SHADOW_SCALE kDefaultShadowScale @@ -183,7 +182,7 @@ static const u64 kWindowsShadowOffset64 = 1ULL << 45; // 32TB # elif defined(__mips64) # define SHADOW_OFFSET kMIPS64_ShadowOffset64 # elif SANITIZER_WINDOWS64 -# define SHADOW_OFFSET kWindowsShadowOffset64 +# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address # else # define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index 5a1128d..1d676bd 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -32,6 +32,7 @@ #include "ubsan/ubsan_init.h" #include "ubsan/ubsan_platform.h" +uptr __asan_shadow_memory_dynamic_address; // Global interface symbol. int __asan_option_detect_stack_use_after_return; // Global interface symbol. uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. @@ -460,7 +461,20 @@ static void AsanInitInternal() { ReplaceSystemMalloc(); + __asan_shadow_memory_dynamic_address = 0; uptr shadow_start = kLowShadowBeg; + if (shadow_start == 0) { + uptr granularity = GetMmapGranularity(); + uptr alignment = 8 * granularity; + uptr left_padding = granularity; + uptr space_size = kHighShadowEnd + left_padding; + + shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity); + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + } + __asan_shadow_memory_dynamic_address = shadow_start; + if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); bool full_shadow_is_available = @@ -472,12 +486,6 @@ static void AsanInitInternal() { kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; } -#elif SANITIZER_WINDOWS64 - // Disable the "mid mem" shadow layout. - if (!full_shadow_is_available) { - kMidMemBeg = 0; - kMidMemEnd = 0; - } #endif if (Verbosity()) PrintAddressSpaceLayout(); @@ -650,6 +658,14 @@ void __asan_init() { AsanInitInternal(); } +// Called by a loaded DLL to initialize itself. +void __asan_init_from_dll(int *detect_stack_use_after_return, + uptr *shadow_memory_dynamic_address) { + __asan_init(); + *detect_stack_use_after_return = __asan_option_detect_stack_use_after_return; + *shadow_memory_dynamic_address = __asan_shadow_memory_dynamic_address; +} + void __asan_version_mismatch_check() { // Do nothing. } diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc index 4b8a08c..870286d 100644 --- a/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -199,23 +199,21 @@ static void InterceptHooks(); // ----------------- ASan own interface functions -------------------- // Don't use the INTERFACE_FUNCTION machinery for this function as we actually // want to call it in the __asan_init interceptor. -WRAP_W_V(__asan_should_detect_stack_use_after_return) - extern "C" { int __asan_option_detect_stack_use_after_return; + uptr __asan_shadow_memory_dynamic_address; // Manually wrap __asan_init as we need to initialize // __asan_option_detect_stack_use_after_return afterwards. void __asan_init() { - typedef void (*fntype)(); + typedef void (*fntype)(int*, uptr*); static fntype fn = 0; // __asan_init is expected to be called by only one thread. if (fn) return; - fn = (fntype)getRealProcAddressOrDie("__asan_init"); - fn(); - __asan_option_detect_stack_use_after_return = - (__asan_should_detect_stack_use_after_return() != 0); + fn = (fntype)getRealProcAddressOrDie("__asan_init_from_dll"); + fn(&__asan_option_detect_stack_use_after_return, + &__asan_shadow_memory_dynamic_address); InterceptHooks(); } diff --git a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc index c6e2a65..4dcd47e 100644 --- a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -34,23 +34,6 @@ #pragma section(".CRT$XTY", long, read) // NOLINT //////////////////////////////////////////////////////////////////////////////// -// Define a copy of __asan_option_detect_stack_use_after_return that should be -// used when linking an MD runtime with a set of object files on Windows. -// -// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', -// so normally we would just dllimport it. Unfortunately, the dllimport -// attribute adds __imp_ prefix to the symbol name of a variable. -// Since in general we don't know if a given TU is going to be used -// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows -// just to work around this issue, let's clone the variable that is constant -// after initialization anyways. -extern "C" { -__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); -int __asan_option_detect_stack_use_after_return = - __asan_should_detect_stack_use_after_return(); -} - -//////////////////////////////////////////////////////////////////////////////// // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL // unload or on exit. ASan relies on LLVM global_dtors to call // __asan_unregister_globals on these events, which unfortunately doesn't work diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index d0b983c..0dabfb0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -98,6 +98,9 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); bool MprotectNoAccess(uptr addr, uptr size); bool MprotectReadOnly(uptr addr, uptr size); +// Find an available address space. +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding); + // Used to check if we can map shadow memory to a fixed location. bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); void ReleaseMemoryToOS(uptr addr, uptr size); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index c70d5a4..e00f2a9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -358,6 +358,11 @@ SignalContext SignalContext::Create(void *siginfo, void *context) { return SignalContext(context, addr, pc, sp, bp, is_memory_access, write_flag); } +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { + CHECK("FindAvailableMemoryRange is not available" && 0); + return 0; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index 7555360..1fd7923 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -249,6 +249,26 @@ void DontDumpShadowMemory(uptr addr, uptr length) { // FIXME: add madvise-analog when we move to 64-bits. } +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { + uptr address = 0; + while (true) { + MEMORY_BASIC_INFORMATION info; + if (!::VirtualQuery((void*)address, &info, sizeof(info))) + return 0; + + if (info.State == MEM_FREE) { + uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, + alignment); + if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) + return shadow_address; + } + + // Move to the next region. + address = (uptr)info.BaseAddress + info.RegionSize; + } + return 0; +} + bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { MEMORY_BASIC_INFORMATION mbi; CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); -- 2.7.4