[compiler-rt] r318666 - [asan] Use dynamic shadow on 32-bit Android, try 2.

Evgeniy Stepanov via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 20 09:41:57 PST 2017


Author: eugenis
Date: Mon Nov 20 09:41:57 2017
New Revision: 318666

URL: http://llvm.org/viewvc/llvm-project?rev=318666&view=rev
Log:
[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

Added:
    compiler-rt/trunk/lib/asan/asan_premap_shadow.cc
    compiler-rt/trunk/lib/asan/asan_premap_shadow.h
Modified:
    compiler-rt/trunk/lib/asan/CMakeLists.txt
    compiler-rt/trunk/lib/asan/asan_init_version.h
    compiler-rt/trunk/lib/asan/asan_linux.cc
    compiler-rt/trunk/lib/asan/asan_mapping.h
    compiler-rt/trunk/lib/asan/asan_shadow_setup.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_fuchsia.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc

Modified: compiler-rt/trunk/lib/asan/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/CMakeLists.txt?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/asan/CMakeLists.txt Mon Nov 20 09:41:57 2017
@@ -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

Modified: compiler-rt/trunk/lib/asan/asan_init_version.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_init_version.h?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_init_version.h (original)
+++ compiler-rt/trunk/lib/asan/asan_init_version.h Mon Nov 20 09:41:57 2017
@@ -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

Modified: compiler-rt/trunk/lib/asan/asan_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_linux.cc?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_linux.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_linux.cc Mon Nov 20 09:41:57 2017
@@ -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) {

Modified: compiler-rt/trunk/lib/asan/asan_mapping.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_mapping.h?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_mapping.h (original)
+++ compiler-rt/trunk/lib/asan/asan_mapping.h Mon Nov 20 09:41:57 2017
@@ -161,7 +161,7 @@ static const u64 kWindowsShadowOffset32
 #  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
 #  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))
 

Added: compiler-rt/trunk/lib/asan/asan_premap_shadow.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_premap_shadow.cc?rev=318666&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_premap_shadow.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_premap_shadow.cc Mon Nov 20 09:41:57 2017
@@ -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

Added: compiler-rt/trunk/lib/asan/asan_premap_shadow.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_premap_shadow.h?rev=318666&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_premap_shadow.h (added)
+++ compiler-rt/trunk/lib/asan/asan_premap_shadow.h Mon Nov 20 09:41:57 2017
@@ -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

Modified: compiler-rt/trunk/lib/asan/asan_shadow_setup.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_shadow_setup.cc?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_shadow_setup.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_shadow_setup.cc Mon Nov 20 09:41:57 2017
@@ -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

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h Mon Nov 20 09:41:57 2017
@@ -73,6 +73,7 @@ INLINE uptr GetPageSizeCached() {
   return PageSizeCached;
 }
 uptr GetMmapGranularity();
+uptr GetMaxVirtualAddress();
 uptr GetMaxUserVirtualAddress();
 // Threads
 tid_t GetTid();

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_fuchsia.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_fuchsia.cc?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_fuchsia.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_fuchsia.cc Mon Nov 20 09:41:57 2017
@@ -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);

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc Mon Nov 20 09:41:57 2017
@@ -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

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc Mon Nov 20 09:41:57 2017
@@ -864,6 +864,10 @@ uptr GetMaxUserVirtualAddress() {
 #endif  // SANITIZER_WORDSIZE
 }
 
+uptr GetMaxVirtualAddress() {
+  return GetMaxUserVirtualAddress();
+}
+
 uptr FindAvailableMemoryRange(uptr shadow_size,
                               uptr alignment,
                               uptr left_padding,

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc?rev=318666&r1=318665&r2=318666&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc Mon Nov 20 09:41:57 2017
@@ -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;
 }




More information about the llvm-commits mailing list