1 //===-- asan_shadow_setup.cc ----------------------------------------------===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // This file is a part of AddressSanitizer, an address sanity checker. 9 // 10 // Set up the shadow memory. 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_common/sanitizer_platform.h" 14 15 // asan_fuchsia.cc and asan_rtems.cc have their own 16 // InitializeShadowMemory implementation. 17 #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 18 19 #include "asan_internal.h" 20 #include "asan_mapping.h" 21 22 namespace __asan { 23 24 // ---------------------- mmap -------------------- {{{1 25 // Reserve memory range [beg, end]. 26 // We need to use inclusive range because end+1 may not be representable. 27 void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { 28 CHECK_EQ((beg % GetMmapGranularity()), 0); 29 CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); 30 uptr size = end - beg + 1; 31 DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. 32 if (!MmapFixedNoReserve(beg, size, name)) { 33 Report( 34 "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " 35 "Perhaps you're using ulimit -v\n", 36 size); 37 Abort(); 38 } 39 if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size); 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