summaryrefslogtreecommitdiff
path: root/lib/asan/asan_premap_shadow.cc
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2017-11-20 17:41:57 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2017-11-20 17:41:57 +0000
commit44a36ad2ca0f205deb6eccd3f0e228e3c3bce96d (patch)
tree50cd4e488ed76e6ed758154637e2f50f82f2723e /lib/asan/asan_premap_shadow.cc
parent7a9c646ba3f2dbf09bc4c0ec073a0530e1fc01a3 (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/asan/asan_premap_shadow.cc')
-rw-r--r--lib/asan/asan_premap_shadow.cc79
1 files changed, 79 insertions, 0 deletions
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