1 //===-- asan_globals.cc ---------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of AddressSanitizer, an address sanity checker. 11 // 12 // Handle globals. 13 //===----------------------------------------------------------------------===// 14 #include "asan_interceptors.h" 15 #include "asan_internal.h" 16 #include "asan_lock.h" 17 #include "asan_mapping.h" 18 #include "asan_report.h" 19 #include "asan_stack.h" 20 #include "asan_stats.h" 21 #include "asan_thread.h" 22 #include "sanitizer/asan_interface.h" 23 24 namespace __asan { 25 26 typedef __asan_global Global; 27 28 struct ListOfGlobals { 29 const Global *g; 30 ListOfGlobals *next; 31 }; 32 33 static AsanLock mu_for_globals(LINKER_INITIALIZED); 34 static LowLevelAllocator allocator_for_globals; 35 static ListOfGlobals *list_of_all_globals; 36 static ListOfGlobals *list_of_dynamic_init_globals; 37 38 void PoisonRedZones(const Global &g) { 39 uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE; 40 CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4); 41 // full right redzone 42 uptr g_aligned_size = kGlobalAndStackRedzone * 43 ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone); 44 PoisonShadow(g.beg + g_aligned_size, 45 kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic); 46 if ((g.size % kGlobalAndStackRedzone) != 0) { 47 // partial right redzone 48 u64 g_aligned_down_size = kGlobalAndStackRedzone * 49 (g.size / kGlobalAndStackRedzone); 50 CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone); 51 PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size, 52 g.size % kGlobalAndStackRedzone, 53 kGlobalAndStackRedzone, 54 kAsanGlobalRedzoneMagic); 55 } 56 } 57 58 static uptr GetAlignedSize(uptr size) { 59 return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone) 60 * kGlobalAndStackRedzone; 61 } 62 63 bool DescribeAddressIfGlobal(uptr addr) { 64 if (!flags()->report_globals) return false; 65 ScopedLock lock(&mu_for_globals); 66 bool res = false; 67 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 68 const Global &g = *l->g; 69 if (flags()->report_globals >= 2) 70 Report("Search Global: beg=%p size=%zu name=%s\n", 71 (void*)g.beg, g.size, (char*)g.name); 72 res |= DescribeAddressRelativeToGlobal(addr, g); 73 } 74 return res; 75 } 76 77 // Register a global variable. 78 // This function may be called more than once for every global 79 // so we store the globals in a map. 80 static void RegisterGlobal(const Global *g) { 81 CHECK(asan_inited); 82 if (flags()->report_globals >= 2) 83 Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n", 84 (void*)g->beg, g->size, g->size_with_redzone, g->name, 85 g->has_dynamic_init); 86 CHECK(flags()->report_globals); 87 CHECK(AddrIsInMem(g->beg)); 88 CHECK(AddrIsAlignedByGranularity(g->beg)); 89 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 90 PoisonRedZones(*g); 91 ListOfGlobals *l = 92 (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals)); 93 l->g = g; 94 l->next = list_of_all_globals; 95 list_of_all_globals = l; 96 if (g->has_dynamic_init) { 97 l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals)); 98 l->g = g; 99 l->next = list_of_dynamic_init_globals; 100 list_of_dynamic_init_globals = l; 101 } 102 } 103 104 static void UnregisterGlobal(const Global *g) { 105 CHECK(asan_inited); 106 CHECK(flags()->report_globals); 107 CHECK(AddrIsInMem(g->beg)); 108 CHECK(AddrIsAlignedByGranularity(g->beg)); 109 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 110 PoisonShadow(g->beg, g->size_with_redzone, 0); 111 // We unpoison the shadow memory for the global but we do not remove it from 112 // the list because that would require O(n^2) time with the current list 113 // implementation. It might not be worth doing anyway. 114 } 115 116 // Poison all shadow memory for a single global. 117 static void PoisonGlobalAndRedzones(const Global *g) { 118 CHECK(asan_inited); 119 CHECK(flags()->check_initialization_order); 120 CHECK(AddrIsInMem(g->beg)); 121 CHECK(AddrIsAlignedByGranularity(g->beg)); 122 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 123 if (flags()->report_globals >= 3) 124 Printf("DynInitPoison : %s\n", g->name); 125 PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic); 126 } 127 128 static void UnpoisonGlobal(const Global *g) { 129 CHECK(asan_inited); 130 CHECK(flags()->check_initialization_order); 131 CHECK(AddrIsInMem(g->beg)); 132 CHECK(AddrIsAlignedByGranularity(g->beg)); 133 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 134 if (flags()->report_globals >= 3) 135 Printf("DynInitUnpoison: %s\n", g->name); 136 PoisonShadow(g->beg, g->size_with_redzone, 0); 137 PoisonRedZones(*g); 138 } 139 140 } // namespace __asan 141 142 // ---------------------- Interface ---------------- {{{1 143 using namespace __asan; // NOLINT 144 145 // Register one global with a default redzone. 146 void __asan_register_global(uptr addr, uptr size, 147 const char *name) { 148 if (!flags()->report_globals) return; 149 ScopedLock lock(&mu_for_globals); 150 Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global)); 151 g->beg = addr; 152 g->size = size; 153 g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone; 154 g->name = name; 155 RegisterGlobal(g); 156 } 157 158 // Register an array of globals. 159 void __asan_register_globals(__asan_global *globals, uptr n) { 160 if (!flags()->report_globals) return; 161 ScopedLock lock(&mu_for_globals); 162 for (uptr i = 0; i < n; i++) { 163 RegisterGlobal(&globals[i]); 164 } 165 } 166 167 // Unregister an array of globals. 168 // We must do this when a shared objects gets dlclosed. 169 void __asan_unregister_globals(__asan_global *globals, uptr n) { 170 if (!flags()->report_globals) return; 171 ScopedLock lock(&mu_for_globals); 172 for (uptr i = 0; i < n; i++) { 173 UnregisterGlobal(&globals[i]); 174 } 175 } 176 177 // This method runs immediately prior to dynamic initialization in each TU, 178 // when all dynamically initialized globals are unpoisoned. This method 179 // poisons all global variables not defined in this TU, so that a dynamic 180 // initializer can only touch global variables in the same TU. 181 void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) { 182 if (!flags()->check_initialization_order) return; 183 CHECK(list_of_dynamic_init_globals); 184 ScopedLock lock(&mu_for_globals); 185 bool from_current_tu = false; 186 // The list looks like: 187 // a => ... => b => last_addr => ... => first_addr => c => ... 188 // The globals of the current TU reside between last_addr and first_addr. 189 for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) { 190 if (l->g->beg == last_addr) 191 from_current_tu = true; 192 if (!from_current_tu) 193 PoisonGlobalAndRedzones(l->g); 194 if (l->g->beg == first_addr) 195 from_current_tu = false; 196 } 197 CHECK(!from_current_tu); 198 } 199 200 // This method runs immediately after dynamic initialization in each TU, when 201 // all dynamically initialized globals except for those defined in the current 202 // TU are poisoned. It simply unpoisons all dynamically initialized globals. 203 void __asan_after_dynamic_init() { 204 if (!flags()->check_initialization_order) return; 205 ScopedLock lock(&mu_for_globals); 206 for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) 207 UnpoisonGlobal(l->g); 208 } 209