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 (!MmapFixedSuperNoReserve(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 if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); 41 } 42 43 static void ProtectGap(uptr addr, uptr size) { 44 if (!flags()->protect_shadow_gap) { 45 // The shadow gap is unprotected, so there is a chance that someone 46 // is actually using this memory. Which means it needs a shadow... 47 uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached()); 48 uptr GapShadowEnd = 49 RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1; 50 if (Verbosity()) 51 Printf( 52 "protect_shadow_gap=0:" 53 " not protecting shadow gap, allocating gap's shadow\n" 54 "|| `[%p, %p]` || ShadowGap's shadow ||\n", 55 GapShadowBeg, GapShadowEnd); 56 ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, 57 "unprotected gap shadow"); 58 return; 59 } 60 void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 61 if (addr == (uptr)res) return; 62 // A few pages at the start of the address space can not be protected. 63 // But we really want to protect as much as possible, to prevent this memory 64 // being returned as a result of a non-FIXED mmap(). 65 if (addr == kZeroBaseShadowStart) { 66 uptr step = GetMmapGranularity(); 67 while (size > step && addr < kZeroBaseMaxShadowStart) { 68 addr += step; 69 size -= step; 70 void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 71 if (addr == (uptr)res) return; 72 } 73 } 74 75 Report( 76 "ERROR: Failed to protect the shadow gap. " 77 "ASan cannot proceed correctly. ABORTING.\n"); 78 DumpProcessMap(); 79 Die(); 80 } 81 82 static void MaybeReportLinuxPIEBug() { 83 #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__)) 84 Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n"); 85 Report( 86 "See https://github.com/google/sanitizers/issues/856 for possible " 87 "workarounds.\n"); 88 #endif 89 } 90 91 void InitializeShadowMemory() { 92 // Set the shadow memory address to uninitialized. 93 __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; 94 95 uptr shadow_start = kLowShadowBeg; 96 // Detect if a dynamic shadow address must used and find a available location 97 // when necessary. When dynamic address is used, the macro |kLowShadowBeg| 98 // expands to |__asan_shadow_memory_dynamic_address| which is 99 // |kDefaultShadowSentinel|. 100 bool full_shadow_is_available = false; 101 if (shadow_start == kDefaultShadowSentinel) { 102 __asan_shadow_memory_dynamic_address = 0; 103 CHECK_EQ(0, kLowShadowBeg); 104 shadow_start = FindDynamicShadowStart(); 105 if (SANITIZER_LINUX) full_shadow_is_available = true; 106 } 107 // Update the shadow memory address (potentially) used by instrumentation. 108 __asan_shadow_memory_dynamic_address = shadow_start; 109 110 if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); 111 112 if (!full_shadow_is_available) 113 full_shadow_is_available = 114 MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); 115 116 #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ 117 !ASAN_FIXED_MAPPING 118 if (!full_shadow_is_available) { 119 kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; 120 kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; 121 } 122 #endif 123 124 if (Verbosity()) PrintAddressSpaceLayout(); 125 126 if (full_shadow_is_available) { 127 // mmap the low shadow plus at least one page at the left. 128 if (kLowShadowBeg) 129 ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); 130 // mmap the high shadow. 131 ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); 132 // protect the gap. 133 ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); 134 CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); 135 } else if (kMidMemBeg && 136 MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && 137 MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { 138 CHECK(kLowShadowBeg != kLowShadowEnd); 139 // mmap the low shadow plus at least one page at the left. 140 ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); 141 // mmap the mid shadow. 142 ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); 143 // mmap the high shadow. 144 ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); 145 // protect the gaps. 146 ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); 147 ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); 148 ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); 149 } else { 150 Report( 151 "Shadow memory range interleaves with an existing memory mapping. " 152 "ASan cannot proceed correctly. ABORTING.\n"); 153 Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", 154 shadow_start, kHighShadowEnd); 155 MaybeReportLinuxPIEBug(); 156 DumpProcessMap(); 157 Die(); 158 } 159 } 160 161 } // namespace __asan 162 163 #endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 164