Skip to content

Commit

Permalink
[asan] Use dynamic shadow on 32-bit Android, try 2.
Browse files Browse the repository at this point in the history
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

llvm-svn: 318666
  • Loading branch information
eugenis committed Nov 20, 2017
1 parent 9541975 commit 8e7018d
Show file tree
Hide file tree
Showing 14 changed files with 310 additions and 22 deletions.
1 change: 1 addition & 0 deletions compiler-rt/lib/asan/CMakeLists.txt
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions compiler-rt/lib/asan/asan_init_version.h
Expand Up @@ -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
Expand All @@ -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
47 changes: 45 additions & 2 deletions compiler-rt/lib/asan/asan_linux.cc
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 7 additions & 1 deletion compiler-rt/lib/asan/asan_mapping.h
Expand Up @@ -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
Expand Down Expand Up @@ -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))

Expand Down
79 changes: 79 additions & 0 deletions compiler-rt/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
30 changes: 30 additions & 0 deletions compiler-rt/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
8 changes: 6 additions & 2 deletions compiler-rt/lib/asan/asan_shadow_setup.cc
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common.h
Expand Up @@ -73,6 +73,7 @@ INLINE uptr GetPageSizeCached() {
return PageSizeCached;
}
uptr GetMmapGranularity();
uptr GetMaxVirtualAddress();
uptr GetMaxUserVirtualAddress();
// Threads
tid_t GetTid();
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc
Expand Up @@ -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);
Expand Down
18 changes: 12 additions & 6 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_mac.cc
Expand Up @@ -864,6 +864,10 @@ uptr GetMaxUserVirtualAddress() {
#endif // SANITIZER_WORDSIZE
}

uptr GetMaxVirtualAddress() {
return GetMaxUserVirtualAddress();
}

uptr FindAvailableMemoryRange(uptr shadow_size,
uptr alignment,
uptr left_padding,
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_win.cc
Expand Up @@ -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;
}
Expand Down

0 comments on commit 8e7018d

Please sign in to comment.