1 //===-- hwasan_dynamic_shadow.cpp -------------------------------*- C++ -*-===// 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 /// \file 10 /// This file is a part of HWAddressSanitizer. It reserves dynamic shadow memory 11 /// region and handles ifunc resolver case, when necessary. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "hwasan.h" 16 #include "hwasan_dynamic_shadow.h" 17 #include "hwasan_mapping.h" 18 #include "sanitizer_common/sanitizer_common.h" 19 #include "sanitizer_common/sanitizer_posix.h" 20 21 #include <elf.h> 22 #include <link.h> 23 24 // The code in this file needs to run in an unrelocated binary. It should not 25 // access any external symbol, including its own non-hidden globals. 26 27 #if SANITIZER_ANDROID 28 extern "C" { 29 30 INTERFACE_ATTRIBUTE void __hwasan_shadow(); 31 decltype(__hwasan_shadow)* __hwasan_premap_shadow(); 32 33 } // extern "C" 34 35 namespace __hwasan { 36 37 // Conservative upper limit. 38 static uptr PremapShadowSize() { 39 return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale, 40 GetMmapGranularity()); 41 } 42 43 static uptr PremapShadow() { 44 return MapDynamicShadow(PremapShadowSize(), kShadowScale, 45 kShadowBaseAlignment, kHighMemEnd); 46 } 47 48 static bool IsPremapShadowAvailable() { 49 const uptr shadow = reinterpret_cast<uptr>(&__hwasan_shadow); 50 const uptr resolver = reinterpret_cast<uptr>(&__hwasan_premap_shadow); 51 // shadow == resolver is how Android KitKat and older handles ifunc. 52 // shadow == 0 just in case. 53 return shadow != 0 && shadow != resolver; 54 } 55 56 static uptr FindPremappedShadowStart(uptr shadow_size_bytes) { 57 const uptr granularity = GetMmapGranularity(); 58 const uptr shadow_start = reinterpret_cast<uptr>(&__hwasan_shadow); 59 const uptr premap_shadow_size = PremapShadowSize(); 60 const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); 61 62 // We may have mapped too much. Release extra memory. 63 UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); 64 return shadow_start; 65 } 66 67 } // namespace __hwasan 68 69 extern "C" { 70 71 decltype(__hwasan_shadow)* __hwasan_premap_shadow() { 72 // The resolver might be called multiple times. Map the shadow just once. 73 static __sanitizer::uptr shadow = 0; 74 if (!shadow) 75 shadow = __hwasan::PremapShadow(); 76 return reinterpret_cast<decltype(__hwasan_shadow)*>(shadow); 77 } 78 79 // __hwasan_shadow is a "function" that has the same address as the first byte 80 // of the shadow mapping. 81 INTERFACE_ATTRIBUTE __attribute__((ifunc("__hwasan_premap_shadow"))) 82 void __hwasan_shadow(); 83 84 extern __attribute((weak, visibility("hidden"))) ElfW(Rela) __rela_iplt_start[], 85 __rela_iplt_end[]; 86 87 } // extern "C" 88 89 namespace __hwasan { 90 91 void InitShadowGOT() { 92 // Call the ifunc resolver for __hwasan_shadow and fill in its GOT entry. This 93 // needs to be done before other ifunc resolvers (which are handled by libc) 94 // because a resolver might read __hwasan_shadow. 95 typedef ElfW(Addr) (*ifunc_resolver_t)(void); 96 for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) { 97 ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset); 98 ElfW(Addr) resolver = r->r_addend; 99 if (resolver == reinterpret_cast<ElfW(Addr)>(&__hwasan_premap_shadow)) { 100 *offset = reinterpret_cast<ifunc_resolver_t>(resolver)(); 101 break; 102 } 103 } 104 } 105 106 uptr FindDynamicShadowStart(uptr shadow_size_bytes) { 107 if (IsPremapShadowAvailable()) 108 return FindPremappedShadowStart(shadow_size_bytes); 109 return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment, 110 kHighMemEnd); 111 } 112 113 } // namespace __hwasan 114 #else 115 namespace __hwasan { 116 117 void InitShadowGOT() {} 118 119 uptr FindDynamicShadowStart(uptr shadow_size_bytes) { 120 return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment, 121 kHighMemEnd); 122 } 123 124 } // namespace __hwasan 125 126 #endif // SANITIZER_ANDROID 127