1353944Sdim//===-- asan_shadow_setup.cpp ---------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker. 10353944Sdim// 11353944Sdim// Set up the shadow memory. 12353944Sdim//===----------------------------------------------------------------------===// 13353944Sdim 14353944Sdim#include "sanitizer_common/sanitizer_platform.h" 15353944Sdim 16353944Sdim// asan_fuchsia.cpp and asan_rtems.cpp have their own 17353944Sdim// InitializeShadowMemory implementation. 18353944Sdim#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 19353944Sdim 20353944Sdim#include "asan_internal.h" 21353944Sdim#include "asan_mapping.h" 22353944Sdim 23353944Sdimnamespace __asan { 24353944Sdim 25353944Sdim// ---------------------- mmap -------------------- {{{1 26353944Sdim// Reserve memory range [beg, end]. 27353944Sdim// We need to use inclusive range because end+1 may not be representable. 28353944Sdimvoid ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { 29353944Sdim CHECK_EQ((beg % GetMmapGranularity()), 0); 30353944Sdim CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); 31353944Sdim uptr size = end - beg + 1; 32353944Sdim DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. 33353944Sdim if (!MmapFixedSuperNoReserve(beg, size, name)) { 34353944Sdim Report( 35353944Sdim "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " 36353944Sdim "Perhaps you're using ulimit -v\n", 37353944Sdim size); 38353944Sdim Abort(); 39353944Sdim } 40353944Sdim if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); 41353944Sdim} 42353944Sdim 43353944Sdimstatic void ProtectGap(uptr addr, uptr size) { 44353944Sdim if (!flags()->protect_shadow_gap) { 45353944Sdim // The shadow gap is unprotected, so there is a chance that someone 46353944Sdim // is actually using this memory. Which means it needs a shadow... 47353944Sdim uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached()); 48353944Sdim uptr GapShadowEnd = 49353944Sdim RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1; 50353944Sdim if (Verbosity()) 51353944Sdim Printf( 52353944Sdim "protect_shadow_gap=0:" 53353944Sdim " not protecting shadow gap, allocating gap's shadow\n" 54353944Sdim "|| `[%p, %p]` || ShadowGap's shadow ||\n", 55353944Sdim GapShadowBeg, GapShadowEnd); 56353944Sdim ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, 57353944Sdim "unprotected gap shadow"); 58353944Sdim return; 59353944Sdim } 60353944Sdim void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 61353944Sdim if (addr == (uptr)res) return; 62353944Sdim // A few pages at the start of the address space can not be protected. 63353944Sdim // But we really want to protect as much as possible, to prevent this memory 64353944Sdim // being returned as a result of a non-FIXED mmap(). 65353944Sdim if (addr == kZeroBaseShadowStart) { 66353944Sdim uptr step = GetMmapGranularity(); 67353944Sdim while (size > step && addr < kZeroBaseMaxShadowStart) { 68353944Sdim addr += step; 69353944Sdim size -= step; 70353944Sdim void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 71353944Sdim if (addr == (uptr)res) return; 72353944Sdim } 73353944Sdim } 74353944Sdim 75353944Sdim Report( 76353944Sdim "ERROR: Failed to protect the shadow gap. " 77353944Sdim "ASan cannot proceed correctly. ABORTING.\n"); 78353944Sdim DumpProcessMap(); 79353944Sdim Die(); 80353944Sdim} 81353944Sdim 82353944Sdimstatic void MaybeReportLinuxPIEBug() { 83353944Sdim#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__)) 84353944Sdim Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n"); 85353944Sdim Report( 86353944Sdim "See https://github.com/google/sanitizers/issues/856 for possible " 87353944Sdim "workarounds.\n"); 88353944Sdim#endif 89353944Sdim} 90353944Sdim 91353944Sdimvoid InitializeShadowMemory() { 92353944Sdim // Set the shadow memory address to uninitialized. 93353944Sdim __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; 94353944Sdim 95353944Sdim uptr shadow_start = kLowShadowBeg; 96353944Sdim // Detect if a dynamic shadow address must used and find a available location 97353944Sdim // when necessary. When dynamic address is used, the macro |kLowShadowBeg| 98353944Sdim // expands to |__asan_shadow_memory_dynamic_address| which is 99353944Sdim // |kDefaultShadowSentinel|. 100353944Sdim bool full_shadow_is_available = false; 101353944Sdim if (shadow_start == kDefaultShadowSentinel) { 102353944Sdim __asan_shadow_memory_dynamic_address = 0; 103353944Sdim CHECK_EQ(0, kLowShadowBeg); 104353944Sdim shadow_start = FindDynamicShadowStart(); 105353944Sdim if (SANITIZER_LINUX) full_shadow_is_available = true; 106353944Sdim } 107353944Sdim // Update the shadow memory address (potentially) used by instrumentation. 108353944Sdim __asan_shadow_memory_dynamic_address = shadow_start; 109353944Sdim 110353944Sdim if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); 111353944Sdim 112353944Sdim if (!full_shadow_is_available) 113353944Sdim full_shadow_is_available = 114353944Sdim MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); 115353944Sdim 116353944Sdim#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ 117353944Sdim !ASAN_FIXED_MAPPING 118353944Sdim if (!full_shadow_is_available) { 119353944Sdim kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; 120353944Sdim kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; 121353944Sdim } 122353944Sdim#endif 123353944Sdim 124353944Sdim if (Verbosity()) PrintAddressSpaceLayout(); 125353944Sdim 126353944Sdim if (full_shadow_is_available) { 127353944Sdim // mmap the low shadow plus at least one page at the left. 128353944Sdim if (kLowShadowBeg) 129353944Sdim ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); 130353944Sdim // mmap the high shadow. 131353944Sdim ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); 132353944Sdim // protect the gap. 133353944Sdim ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); 134353944Sdim CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); 135353944Sdim } else if (kMidMemBeg && 136353944Sdim MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && 137353944Sdim MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { 138353944Sdim CHECK(kLowShadowBeg != kLowShadowEnd); 139353944Sdim // mmap the low shadow plus at least one page at the left. 140353944Sdim ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); 141353944Sdim // mmap the mid shadow. 142353944Sdim ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); 143353944Sdim // mmap the high shadow. 144353944Sdim ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); 145353944Sdim // protect the gaps. 146353944Sdim ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); 147353944Sdim ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); 148353944Sdim ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); 149353944Sdim } else { 150353944Sdim Report( 151353944Sdim "Shadow memory range interleaves with an existing memory mapping. " 152353944Sdim "ASan cannot proceed correctly. ABORTING.\n"); 153353944Sdim Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", 154353944Sdim shadow_start, kHighShadowEnd); 155353944Sdim MaybeReportLinuxPIEBug(); 156353944Sdim DumpProcessMap(); 157353944Sdim Die(); 158353944Sdim } 159353944Sdim} 160353944Sdim 161353944Sdim} // namespace __asan 162353944Sdim 163353944Sdim#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 164