diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2017-11-20 17:41:57 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2017-11-20 17:41:57 +0000 |
commit | 44a36ad2ca0f205deb6eccd3f0e228e3c3bce96d (patch) | |
tree | 50cd4e488ed76e6ed758154637e2f50f82f2723e /lib | |
parent | 7a9c646ba3f2dbf09bc4c0ec073a0530e1fc01a3 (diff) |
[asan] Use dynamic shadow on 32-bit Android, try 2.
Summary:
This change reverts r318575 and changes FindDynamicShadowStart() to
keep the memory range it found mapped PROT_NONE to make sure it is
not reused. We also skip MemoryRangeIsAvailable() check, because it
is (a) unnecessary, and (b) would fail anyway.
Reviewers: pcc, vitalybuka, kcc
Subscribers: srhines, kubamracek, mgorny, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D40203
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@318666 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/asan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/asan/asan_init_version.h | 7 | ||||
-rw-r--r-- | lib/asan/asan_linux.cc | 47 | ||||
-rw-r--r-- | lib/asan/asan_mapping.h | 8 | ||||
-rw-r--r-- | lib/asan/asan_premap_shadow.cc | 79 | ||||
-rw-r--r-- | lib/asan/asan_premap_shadow.h | 30 | ||||
-rw-r--r-- | lib/asan/asan_shadow_setup.cc | 8 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_fuchsia.cc | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.cc | 18 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_mac.cc | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 4 |
12 files changed, 200 insertions, 11 deletions
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 78872cd9f..da82e485b 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -21,6 +21,7 @@ set(ASAN_SOURCES asan_memory_profile.cc asan_poisoning.cc asan_posix.cc + asan_premap_shadow.cc asan_report.cc asan_rtl.cc asan_shadow_setup.cc diff --git a/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h index f48cc19cc..c49fcd740 100644 --- a/lib/asan/asan_init_version.h +++ b/lib/asan/asan_init_version.h @@ -15,6 +15,8 @@ #ifndef ASAN_INIT_VERSION_H #define ASAN_INIT_VERSION_H +#include "sanitizer_common/sanitizer_platform.h" + extern "C" { // Every time the ASan ABI changes we also change the version number in the // __asan_init function name. Objects built with incompatible ASan ABI @@ -32,7 +34,12 @@ extern "C" { // v6=>v7: added 'odr_indicator' to __asan_global // v7=>v8: added '__asan_(un)register_image_globals' functions for dead // stripping support on Mach-O platforms +#if SANITIZER_WORDSIZE == 32 && SANITIZER_ANDROID + // v8=>v9: 32-bit Android switched to dynamic shadow + #define __asan_version_mismatch_check __asan_version_mismatch_check_v9 +#else #define __asan_version_mismatch_check __asan_version_mismatch_check_v8 +#endif } #endif // ASAN_INIT_VERSION_H diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index a949a9888..5cf466661 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -17,6 +17,7 @@ #include "asan_interceptors.h" #include "asan_internal.h" +#include "asan_premap_shadow.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_freebsd.h" @@ -81,9 +82,51 @@ void *AsanDoesNotSupportStaticLinkage() { return &_DYNAMIC; // defined in link.h } +static void UnmapFromTo(uptr from, uptr to) { + CHECK(to >= from); + if (to == from) return; + uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from); + if (UNLIKELY(internal_iserror(res))) { + Report( + "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address " + "%p\n", + to - from, to - from, from); + CHECK("unable to unmap" && 0); + } +} + +#if ASAN_PREMAP_SHADOW +uptr FindPremappedShadowStart() { + uptr granularity = GetMmapGranularity(); + uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); + uptr premap_shadow_size = PremapShadowSize(); + uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); + // We may have mapped too much. Release extra memory. + UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); + return shadow_start; +} +#endif + uptr FindDynamicShadowStart() { - UNREACHABLE("FindDynamicShadowStart is not available"); - return 0; +#if ASAN_PREMAP_SHADOW + if (!PremapShadowFailed()) + return FindPremappedShadowStart(); +#endif + + uptr granularity = GetMmapGranularity(); + uptr alignment = granularity * 8; + uptr left_padding = granularity; + uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); + uptr map_size = shadow_size + left_padding + alignment; + + uptr map_start = (uptr)MmapNoAccess(map_size); + CHECK_NE(map_start, ~(uptr)0); + + uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); + UnmapFromTo(map_start, shadow_start - left_padding); + UnmapFromTo(shadow_start + shadow_size, map_start + map_size); + + return shadow_start; } void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index acdaa60b9..c51c960c5 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -161,7 +161,7 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # define SHADOW_OFFSET (0) #elif SANITIZER_WORDSIZE == 32 # if SANITIZER_ANDROID -# define SHADOW_OFFSET (0) +# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address # elif defined(__mips__) # define SHADOW_OFFSET kMIPS32_ShadowOffset32 # elif SANITIZER_FREEBSD @@ -205,6 +205,12 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # endif #endif +#if SANITIZER_ANDROID && defined(__arm__) +# define ASAN_PREMAP_SHADOW 1 +#else +# define ASAN_PREMAP_SHADOW 0 +#endif + #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) diff --git a/lib/asan/asan_premap_shadow.cc b/lib/asan/asan_premap_shadow.cc new file mode 100644 index 000000000..229eba99f --- /dev/null +++ b/lib/asan/asan_premap_shadow.cc @@ -0,0 +1,79 @@ +//===-- asan_premap_shadow.cc ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Reserve shadow memory with an ifunc resolver. +//===----------------------------------------------------------------------===// + +#include "asan_mapping.h" + +#if ASAN_PREMAP_SHADOW + +#include "asan_premap_shadow.h" +#include "sanitizer_common/sanitizer_posix.h" + +namespace __asan { + +// The code in this file needs to run in an unrelocated binary. It may not +// access any external symbol, including its own non-hidden globals. + +// Conservative upper limit. +uptr PremapShadowSize() { + uptr granularity = GetMmapGranularity(); + return RoundUpTo(GetMaxVirtualAddress() >> SHADOW_SCALE, granularity); +} + +// Returns an address aligned to 8 pages, such that one page on the left and +// PremapShadowSize() bytes on the right of it are mapped r/o. +uptr PremapShadow() { + uptr granularity = GetMmapGranularity(); + uptr alignment = granularity * 8; + uptr left_padding = granularity; + uptr shadow_size = PremapShadowSize(); + uptr map_size = shadow_size + left_padding + alignment; + + uptr map_start = (uptr)MmapNoAccess(map_size); + CHECK_NE(map_start, ~(uptr)0); + + uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); + uptr shadow_end = shadow_start + shadow_size; + internal_munmap(reinterpret_cast<void *>(map_start), + shadow_start - left_padding - map_start); + internal_munmap(reinterpret_cast<void *>(shadow_end), + map_start + map_size - shadow_end); + return shadow_start; +} + +bool PremapShadowFailed() { + uptr shadow = reinterpret_cast<uptr>(&__asan_shadow); + uptr resolver = reinterpret_cast<uptr>(&__asan_premap_shadow); + // shadow == resolver is how Android KitKat and older handles ifunc. + // shadow == 0 just in case. + if (shadow == 0 || shadow == resolver) + return true; + return false; +} +} // namespace __asan + +extern "C" { +decltype(__asan_shadow)* __asan_premap_shadow() { + // The resolver may be called multiple times. Map the shadow just once. + static uptr premapped_shadow = 0; + if (!premapped_shadow) premapped_shadow = __asan::PremapShadow(); + return reinterpret_cast<decltype(__asan_shadow)*>(premapped_shadow); +} + +// __asan_shadow is a "function" that has the same address as the first byte of +// the shadow mapping. +INTERFACE_ATTRIBUTE __attribute__((ifunc("__asan_premap_shadow"))) void +__asan_shadow(); +} + +#endif // ASAN_PREMAP_SHADOW diff --git a/lib/asan/asan_premap_shadow.h b/lib/asan/asan_premap_shadow.h new file mode 100644 index 000000000..41acbdbbb --- /dev/null +++ b/lib/asan/asan_premap_shadow.h @@ -0,0 +1,30 @@ +//===-- asan_mapping.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Premap shadow range with an ifunc resolver. +//===----------------------------------------------------------------------===// + + +#ifndef ASAN_PREMAP_SHADOW_H +#define ASAN_PREMAP_SHADOW_H + +#if ASAN_PREMAP_SHADOW +namespace __asan { +// Conservative upper limit. +uptr PremapShadowSize(); +bool PremapShadowFailed(); +} +#endif + +extern "C" INTERFACE_ATTRIBUTE void __asan_shadow(); +extern "C" decltype(__asan_shadow)* __asan_premap_shadow(); + +#endif // ASAN_PREMAP_SHADOW_H diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc index 08c009184..b3cf0b5c1 100644 --- a/lib/asan/asan_shadow_setup.cc +++ b/lib/asan/asan_shadow_setup.cc @@ -99,17 +99,21 @@ void InitializeShadowMemory() { // when necessary. When dynamic address is used, the macro |kLowShadowBeg| // expands to |__asan_shadow_memory_dynamic_address| which is // |kDefaultShadowSentinel|. + bool full_shadow_is_available = false; if (shadow_start == kDefaultShadowSentinel) { __asan_shadow_memory_dynamic_address = 0; CHECK_EQ(0, kLowShadowBeg); shadow_start = FindDynamicShadowStart(); + if (SANITIZER_LINUX) full_shadow_is_available = true; } // Update the shadow memory address (potentially) used by instrumentation. __asan_shadow_memory_dynamic_address = shadow_start; if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); - bool full_shadow_is_available = - MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); + + if (!full_shadow_is_available) + full_shadow_is_available = + MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ !ASAN_FIXED_MAPPING diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9fb615f96..746ba226c 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -73,6 +73,7 @@ INLINE uptr GetPageSizeCached() { return PageSizeCached; } uptr GetMmapGranularity(); +uptr GetMaxVirtualAddress(); uptr GetMaxUserVirtualAddress(); // Threads tid_t GetTid(); diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc index 554bc458c..c130c10c2 100644 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -191,6 +191,10 @@ uptr GetMaxUserVirtualAddress() { return ShadowBounds.memory_limit - 1; } +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, bool raw_report, bool die_for_nomem) { size = RoundUpTo(size, PAGE_SIZE); diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index ea1e79556..6274b248e 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -954,7 +954,7 @@ static uptr GetKernelAreaSize() { } #endif // SANITIZER_WORDSIZE == 32 -uptr GetMaxUserVirtualAddress() { +uptr GetMaxVirtualAddress() { #if SANITIZER_NETBSD && defined(__x86_64__) return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) #elif SANITIZER_WORDSIZE == 64 @@ -978,15 +978,21 @@ uptr GetMaxUserVirtualAddress() { # if defined(__s390__) return (1ULL << 31) - 1; // 0x7fffffff; # else - uptr res = (1ULL << 32) - 1; // 0xffffffff; - if (!common_flags()->full_address_space) - res -= GetKernelAreaSize(); - CHECK_LT(reinterpret_cast<uptr>(&res), res); - return res; + return (1ULL << 32) - 1; // 0xffffffff; # endif #endif // SANITIZER_WORDSIZE } +uptr GetMaxUserVirtualAddress() { + uptr addr = GetMaxVirtualAddress(); +#if SANITIZER_WORDSIZE == 32 && !defined(__s390__) + if (!common_flags()->full_address_space) + addr -= GetKernelAreaSize(); + CHECK_LT(reinterpret_cast<uptr>(&addr), addr); +#endif + return addr; +} + uptr GetPageSize() { // Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. #if SANITIZER_ANDROID diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 284b6cfc7..195a52c47 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -864,6 +864,10 @@ uptr GetMaxUserVirtualAddress() { #endif // SANITIZER_WORDSIZE } +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + uptr FindAvailableMemoryRange(uptr shadow_size, uptr alignment, uptr left_padding, diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index ef69ad45e..0d72b494d 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -70,6 +70,10 @@ uptr GetMaxUserVirtualAddress() { return (uptr)si.lpMaximumApplicationAddress; } +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + bool FileExists(const char *filename) { return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; } |