diff options
Diffstat (limited to 'compiler-rt/lib/asan')
| -rw-r--r-- | compiler-rt/lib/asan/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_init_version.h | 7 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_linux.cc | 32 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_mapping.h | 8 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_premap_shadow.cc | 69 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_premap_shadow.h | 28 |
6 files changed, 142 insertions, 3 deletions
diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 334235746a0..9291e71099f 100644 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/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/compiler-rt/lib/asan/asan_init_version.h b/compiler-rt/lib/asan/asan_init_version.h index f48cc19cc51..c49fcd74024 100644 --- a/compiler-rt/lib/asan/asan_init_version.h +++ b/compiler-rt/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/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index a949a9888e2..902c64cc4e0 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/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,10 +82,37 @@ void *AsanDoesNotSupportStaticLinkage() { return &_DYNAMIC; // defined in link.h } +#if ASAN_PREMAP_SHADOW uptr FindDynamicShadowStart() { - UNREACHABLE("FindDynamicShadowStart is not available"); - return 0; + uptr granularity = GetMmapGranularity(); + uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); + uptr shadow_size = PremapShadowSize(); + UnmapOrDie((void *)(shadow_start - granularity), shadow_size + granularity); + // MmapNoAccess does not touch TotalMmap, but UnmapOrDie decreases it. + // Compensate. + IncreaseTotalMmap(shadow_size + granularity); + return shadow_start; } +#else +uptr FindDynamicShadowStart() { + uptr granularity = GetMmapGranularity(); + uptr alignment = granularity * 8; + uptr left_padding = granularity; + uptr shadow_size = kHighShadowEnd + left_padding; + uptr map_size = shadow_size + alignment; + + uptr map_start = (uptr)MmapNoAccess(map_size); + CHECK_NE(map_start, ~(uptr)0); + + uptr shadow_start = RoundUpTo(map_start, alignment); + UnmapOrDie((void *)map_start, map_size); + // MmapNoAccess does not touch TotalMmap, but UnmapOrDie decreases it. + // Compensate. + IncreaseTotalMmap(map_size); + + return shadow_start; +} +#endif void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index fcd95114e1c..febe090e2ea 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -156,7 +156,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 @@ -200,6 +200,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/compiler-rt/lib/asan/asan_premap_shadow.cc b/compiler-rt/lib/asan/asan_premap_shadow.cc new file mode 100644 index 00000000000..0e66eeef126 --- /dev/null +++ b/compiler-rt/lib/asan/asan_premap_shadow.cc @@ -0,0 +1,69 @@ +//===-- 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() { + return GetMaxVirtualAddress() >> SHADOW_SCALE; +} + +// 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; +} + +} // 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/compiler-rt/lib/asan/asan_premap_shadow.h b/compiler-rt/lib/asan/asan_premap_shadow.h new file mode 100644 index 00000000000..6349e04ae44 --- /dev/null +++ b/compiler-rt/lib/asan/asan_premap_shadow.h @@ -0,0 +1,28 @@ +//===-- 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(); +} +#endif + +extern "C" INTERFACE_ATTRIBUTE void __asan_shadow(); + +#endif // ASAN_PREMAP_SHADOW_H |

