[asan] Move shadow memory setup into its own file
Submitted on behalf of Roland McGrath. Reviewers: vitalybuka, alekseyshl, kcc Subscribers: kubamracek, mgorny, phosek, filcab, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D36037 llvm-svn: 309542
This commit is contained in:
parent
5703fe37ab
commit
0aeb0fe2ab
|
@ -22,6 +22,7 @@ set(ASAN_SOURCES
|
||||||
asan_posix.cc
|
asan_posix.cc
|
||||||
asan_report.cc
|
asan_report.cc
|
||||||
asan_rtl.cc
|
asan_rtl.cc
|
||||||
|
asan_shadow_setup.cc
|
||||||
asan_stack.cc
|
asan_stack.cc
|
||||||
asan_stats.cc
|
asan_stats.cc
|
||||||
asan_suppressions.cc
|
asan_suppressions.cc
|
||||||
|
|
|
@ -69,8 +69,12 @@ void InitializePlatformExceptionHandlers();
|
||||||
bool IsSystemHeapAddress(uptr addr);
|
bool IsSystemHeapAddress(uptr addr);
|
||||||
|
|
||||||
// asan_rtl.cc
|
// asan_rtl.cc
|
||||||
|
void PrintAddressSpaceLayout();
|
||||||
void NORETURN ShowStatsAndAbort();
|
void NORETURN ShowStatsAndAbort();
|
||||||
|
|
||||||
|
// asan_shadow_setup.cc
|
||||||
|
void InitializeShadowMemory();
|
||||||
|
|
||||||
// asan_malloc_linux.cc / asan_malloc_mac.cc
|
// asan_malloc_linux.cc / asan_malloc_mac.cc
|
||||||
void ReplaceSystemMalloc();
|
void ReplaceSystemMalloc();
|
||||||
|
|
||||||
|
|
|
@ -84,26 +84,6 @@ void ShowStatsAndAbort() {
|
||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------- mmap -------------------- {{{1
|
|
||||||
// Reserve memory range [beg, end].
|
|
||||||
// We need to use inclusive range because end+1 may not be representable.
|
|
||||||
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
|
|
||||||
CHECK_EQ((beg % GetMmapGranularity()), 0);
|
|
||||||
CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
|
|
||||||
uptr size = end - beg + 1;
|
|
||||||
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
|
|
||||||
void *res = MmapFixedNoReserve(beg, size, name);
|
|
||||||
if (res != (void*)beg) {
|
|
||||||
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
|
|
||||||
"Perhaps you're using ulimit -v\n", size);
|
|
||||||
Abort();
|
|
||||||
}
|
|
||||||
if (common_flags()->no_huge_pages_for_shadow)
|
|
||||||
NoHugePagesInRegion(beg, size);
|
|
||||||
if (common_flags()->use_madv_dontdump)
|
|
||||||
DontDumpShadowMemory(beg, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- LowLevelAllocateCallbac ---------- {{{1
|
// --------------- LowLevelAllocateCallbac ---------- {{{1
|
||||||
static void OnLowLevelAllocate(uptr ptr, uptr size) {
|
static void OnLowLevelAllocate(uptr ptr, uptr size) {
|
||||||
PoisonShadow(ptr, size, kAsanInternalHeapMagic);
|
PoisonShadow(ptr, size, kAsanInternalHeapMagic);
|
||||||
|
@ -335,46 +315,7 @@ static void InitializeHighMemEnd() {
|
||||||
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
|
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ProtectGap(uptr addr, uptr size) {
|
void PrintAddressSpaceLayout() {
|
||||||
if (!flags()->protect_shadow_gap) {
|
|
||||||
// The shadow gap is unprotected, so there is a chance that someone
|
|
||||||
// is actually using this memory. Which means it needs a shadow...
|
|
||||||
uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
|
|
||||||
uptr GapShadowEnd =
|
|
||||||
RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
|
|
||||||
if (Verbosity())
|
|
||||||
Printf("protect_shadow_gap=0:"
|
|
||||||
" not protecting shadow gap, allocating gap's shadow\n"
|
|
||||||
"|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg,
|
|
||||||
GapShadowEnd);
|
|
||||||
ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
|
|
||||||
"unprotected gap shadow");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
|
||||||
if (addr == (uptr)res)
|
|
||||||
return;
|
|
||||||
// A few pages at the start of the address space can not be protected.
|
|
||||||
// But we really want to protect as much as possible, to prevent this memory
|
|
||||||
// being returned as a result of a non-FIXED mmap().
|
|
||||||
if (addr == kZeroBaseShadowStart) {
|
|
||||||
uptr step = GetMmapGranularity();
|
|
||||||
while (size > step && addr < kZeroBaseMaxShadowStart) {
|
|
||||||
addr += step;
|
|
||||||
size -= step;
|
|
||||||
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
|
||||||
if (addr == (uptr)res)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Report("ERROR: Failed to protect the shadow gap. "
|
|
||||||
"ASan cannot proceed correctly. ABORTING.\n");
|
|
||||||
DumpProcessMap();
|
|
||||||
Die();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PrintAddressSpaceLayout() {
|
|
||||||
Printf("|| `[%p, %p]` || HighMem ||\n",
|
Printf("|| `[%p, %p]` || HighMem ||\n",
|
||||||
(void*)kHighMemBeg, (void*)kHighMemEnd);
|
(void*)kHighMemBeg, (void*)kHighMemEnd);
|
||||||
Printf("|| `[%p, %p]` || HighShadow ||\n",
|
Printf("|| `[%p, %p]` || HighShadow ||\n",
|
||||||
|
@ -426,71 +367,6 @@ static void PrintAddressSpaceLayout() {
|
||||||
kHighShadowBeg > kMidMemEnd);
|
kHighShadowBeg > kMidMemEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeShadowMemory() {
|
|
||||||
// Set the shadow memory address to uninitialized.
|
|
||||||
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
|
|
||||||
|
|
||||||
uptr shadow_start = kLowShadowBeg;
|
|
||||||
// Detect if a dynamic shadow address must used and find a available location
|
|
||||||
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
|
|
||||||
// expands to |__asan_shadow_memory_dynamic_address| which is
|
|
||||||
// |kDefaultShadowSentinel|.
|
|
||||||
if (shadow_start == kDefaultShadowSentinel) {
|
|
||||||
__asan_shadow_memory_dynamic_address = 0;
|
|
||||||
CHECK_EQ(0, kLowShadowBeg);
|
|
||||||
shadow_start = FindDynamicShadowStart();
|
|
||||||
}
|
|
||||||
// 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 SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
|
|
||||||
!ASAN_FIXED_MAPPING
|
|
||||||
if (!full_shadow_is_available) {
|
|
||||||
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
|
||||||
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (Verbosity()) PrintAddressSpaceLayout();
|
|
||||||
|
|
||||||
if (full_shadow_is_available) {
|
|
||||||
// mmap the low shadow plus at least one page at the left.
|
|
||||||
if (kLowShadowBeg)
|
|
||||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
|
||||||
// mmap the high shadow.
|
|
||||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
|
||||||
// protect the gap.
|
|
||||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
|
||||||
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
|
|
||||||
} else if (kMidMemBeg &&
|
|
||||||
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
|
|
||||||
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
|
|
||||||
CHECK(kLowShadowBeg != kLowShadowEnd);
|
|
||||||
// mmap the low shadow plus at least one page at the left.
|
|
||||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
|
||||||
// mmap the mid shadow.
|
|
||||||
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
|
|
||||||
// mmap the high shadow.
|
|
||||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
|
||||||
// protect the gaps.
|
|
||||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
|
||||||
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
|
|
||||||
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
|
|
||||||
} else {
|
|
||||||
Report("Shadow memory range interleaves with an existing memory mapping. "
|
|
||||||
"ASan cannot proceed correctly. ABORTING.\n");
|
|
||||||
Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
|
|
||||||
shadow_start, kHighShadowEnd);
|
|
||||||
DumpProcessMap();
|
|
||||||
Die();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AsanInitInternal() {
|
static void AsanInitInternal() {
|
||||||
if (LIKELY(asan_inited)) return;
|
if (LIKELY(asan_inited)) return;
|
||||||
SanitizerToolName = "AddressSanitizer";
|
SanitizerToolName = "AddressSanitizer";
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
//===-- asan_shadow_setup.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.
|
||||||
|
//
|
||||||
|
// Set up the shadow memory.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "asan_internal.h"
|
||||||
|
#include "asan_mapping.h"
|
||||||
|
|
||||||
|
namespace __asan {
|
||||||
|
|
||||||
|
// ---------------------- mmap -------------------- {{{1
|
||||||
|
// Reserve memory range [beg, end].
|
||||||
|
// We need to use inclusive range because end+1 may not be representable.
|
||||||
|
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
|
||||||
|
CHECK_EQ((beg % GetMmapGranularity()), 0);
|
||||||
|
CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
|
||||||
|
uptr size = end - beg + 1;
|
||||||
|
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
|
||||||
|
void *res = MmapFixedNoReserve(beg, size, name);
|
||||||
|
if (res != (void *)beg) {
|
||||||
|
Report(
|
||||||
|
"ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
|
||||||
|
"Perhaps you're using ulimit -v\n",
|
||||||
|
size);
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
|
if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
|
||||||
|
if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ProtectGap(uptr addr, uptr size) {
|
||||||
|
if (!flags()->protect_shadow_gap) {
|
||||||
|
// The shadow gap is unprotected, so there is a chance that someone
|
||||||
|
// is actually using this memory. Which means it needs a shadow...
|
||||||
|
uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
|
||||||
|
uptr GapShadowEnd =
|
||||||
|
RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
|
||||||
|
if (Verbosity())
|
||||||
|
Printf(
|
||||||
|
"protect_shadow_gap=0:"
|
||||||
|
" not protecting shadow gap, allocating gap's shadow\n"
|
||||||
|
"|| `[%p, %p]` || ShadowGap's shadow ||\n",
|
||||||
|
GapShadowBeg, GapShadowEnd);
|
||||||
|
ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
|
||||||
|
"unprotected gap shadow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
||||||
|
if (addr == (uptr)res) return;
|
||||||
|
// A few pages at the start of the address space can not be protected.
|
||||||
|
// But we really want to protect as much as possible, to prevent this memory
|
||||||
|
// being returned as a result of a non-FIXED mmap().
|
||||||
|
if (addr == kZeroBaseShadowStart) {
|
||||||
|
uptr step = GetMmapGranularity();
|
||||||
|
while (size > step && addr < kZeroBaseMaxShadowStart) {
|
||||||
|
addr += step;
|
||||||
|
size -= step;
|
||||||
|
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
||||||
|
if (addr == (uptr)res) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Report(
|
||||||
|
"ERROR: Failed to protect the shadow gap. "
|
||||||
|
"ASan cannot proceed correctly. ABORTING.\n");
|
||||||
|
DumpProcessMap();
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeShadowMemory() {
|
||||||
|
// Set the shadow memory address to uninitialized.
|
||||||
|
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
|
||||||
|
|
||||||
|
uptr shadow_start = kLowShadowBeg;
|
||||||
|
// Detect if a dynamic shadow address must used and find a available location
|
||||||
|
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
|
||||||
|
// expands to |__asan_shadow_memory_dynamic_address| which is
|
||||||
|
// |kDefaultShadowSentinel|.
|
||||||
|
if (shadow_start == kDefaultShadowSentinel) {
|
||||||
|
__asan_shadow_memory_dynamic_address = 0;
|
||||||
|
CHECK_EQ(0, kLowShadowBeg);
|
||||||
|
shadow_start = FindDynamicShadowStart();
|
||||||
|
}
|
||||||
|
// 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 SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
|
||||||
|
!ASAN_FIXED_MAPPING
|
||||||
|
if (!full_shadow_is_available) {
|
||||||
|
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
||||||
|
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (Verbosity()) PrintAddressSpaceLayout();
|
||||||
|
|
||||||
|
if (full_shadow_is_available) {
|
||||||
|
// mmap the low shadow plus at least one page at the left.
|
||||||
|
if (kLowShadowBeg)
|
||||||
|
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
||||||
|
// mmap the high shadow.
|
||||||
|
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
||||||
|
// protect the gap.
|
||||||
|
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||||
|
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
|
||||||
|
} else if (kMidMemBeg &&
|
||||||
|
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
|
||||||
|
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
|
||||||
|
CHECK(kLowShadowBeg != kLowShadowEnd);
|
||||||
|
// mmap the low shadow plus at least one page at the left.
|
||||||
|
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
||||||
|
// mmap the mid shadow.
|
||||||
|
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
|
||||||
|
// mmap the high shadow.
|
||||||
|
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
||||||
|
// protect the gaps.
|
||||||
|
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||||
|
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
|
||||||
|
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
|
||||||
|
} else {
|
||||||
|
Report(
|
||||||
|
"Shadow memory range interleaves with an existing memory mapping. "
|
||||||
|
"ASan cannot proceed correctly. ABORTING.\n");
|
||||||
|
Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
|
||||||
|
shadow_start, kHighShadowEnd);
|
||||||
|
DumpProcessMap();
|
||||||
|
Die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __asan
|
Loading…
Reference in New Issue