1 //===-- asan_shadow_setup.cpp ---------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of AddressSanitizer, an address sanity checker. 10 // 11 // Set up the shadow memory. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_common/sanitizer_platform.h" 15 16 // asan_fuchsia.cpp and asan_rtems.cpp have their own 17 // InitializeShadowMemory implementation. 18 #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 19 20 #include "asan_internal.h" 21 #include "asan_mapping.h" 22 23 namespace __asan { 24 25 // ---------------------- mmap -------------------- {{{1 26 // Reserve memory range [beg, end]. 27 // We need to use inclusive range because end+1 may not be representable. 28 void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { 29 CHECK_EQ((beg % GetMmapGranularity()), 0); 30 CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); 31 uptr size = end - beg + 1; 32 DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. 33 if (!MmapFixedNoReserve(beg, size, name)) { 34 Report( 35 "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " 36 "Perhaps you're using ulimit -v\n", 37 size); 38 Abort(); 39 } 40 SetShadowRegionHugePageMode(beg, size); 41 if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); 42 } 43 44 static void ProtectGap(uptr addr, uptr size) { 45 if (!flags()->protect_shadow_gap) { 46 // The shadow gap is unprotected, so there is a chance that someone 47 // is actually using this memory. Which means it needs a shadow... 48 uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached()); 49 uptr GapShadowEnd = 50 RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1; 51 if (Verbosity()) 52 Printf( 53 "protect_shadow_gap=0:" 54 " not protecting shadow gap, allocating gap's shadow\n" 55 "|| `[%p, %p]` || ShadowGap's shadow ||\n", 56 GapShadowBeg, GapShadowEnd); 57 ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, 58 "unprotected gap shadow"); 59 return; 60 } 61 void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 62 if (addr == (uptr)res) return; 63 // A few pages at the start of the address space can not be protected. 64 // But we really want to protect as much as possible, to prevent this memory 65 // being returned as a result of a non-FIXED mmap(). 66 if (addr == kZeroBaseShadowStart) { 67 uptr step = GetMmapGranularity(); 68 while (size > step && addr < kZeroBaseMaxShadowStart) { 69 addr += step; 70 size -= step; 71 void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 72 if (addr == (uptr)res) return; 73 } 74 } 75 76 Report( 77 "ERROR: Failed to protect the shadow gap. " 78 "ASan cannot proceed correctly. ABORTING.\n"); 79 DumpProcessMap(); 80 Die(); 81 } 82 83 static void MaybeReportLinuxPIEBug() { 84 #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__)) 85 Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n"); 86 Report( 87 "See https://github.com/google/sanitizers/issues/856 for possible " 88 "workarounds.\n"); 89 #endif 90 } 91 92 void InitializeShadowMemory() { 93 // Set the shadow memory address to uninitialized. 94 __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; 95 96 uptr shadow_start = kLowShadowBeg; 97 // Detect if a dynamic shadow address must used and find a available location 98 // when necessary. When dynamic address is used, the macro |kLowShadowBeg| 99 // expands to |__asan_shadow_memory_dynamic_address| which is 100 // |kDefaultShadowSentinel|. 101 bool full_shadow_is_available = false; 102 if (shadow_start == kDefaultShadowSentinel) { 103 __asan_shadow_memory_dynamic_address = 0; 104 CHECK_EQ(0, kLowShadowBeg); 105 shadow_start = FindDynamicShadowStart(); 106 if (SANITIZER_LINUX) full_shadow_is_available = true; 107 } 108 // Update the shadow memory address (potentially) used by instrumentation. 109 __asan_shadow_memory_dynamic_address = shadow_start; 110 111 if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); 112 113 if (!full_shadow_is_available) 114 full_shadow_is_available = 115 MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); 116 117 #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ 118 !ASAN_FIXED_MAPPING 119 if (!full_shadow_is_available) { 120 kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; 121 kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; 122 } 123 #endif 124 125 if (Verbosity()) PrintAddressSpaceLayout(); 126 127 if (full_shadow_is_available) { 128 // mmap the low shadow plus at least one page at the left. 129 if (kLowShadowBeg) 130 ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); 131 // mmap the high shadow. 132 ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); 133 // protect the gap. 134 ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); 135 CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); 136 } else if (kMidMemBeg && 137 MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && 138 MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { 139 CHECK(kLowShadowBeg != kLowShadowEnd); 140 // mmap the low shadow plus at least one page at the left. 141 ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); 142 // mmap the mid shadow. 143 ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); 144 // mmap the high shadow. 145 ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); 146 // protect the gaps. 147 ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); 148 ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); 149 ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); 150 } else { 151 Report( 152 "Shadow memory range interleaves with an existing memory mapping. " 153 "ASan cannot proceed correctly. ABORTING.\n"); 154 Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", 155 shadow_start, kHighShadowEnd); 156 MaybeReportLinuxPIEBug(); 157 DumpProcessMap(); 158 Die(); 159 } 160 } 161 162 } // namespace __asan 163 164 #endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 165