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 15 #include "asan_interceptors.h" 16 #include "asan_internal.h" 17 #include "asan_mapping.h" 18 #include "asan_poisoning.h" 19 #include "asan_report.h" 20 #include "asan_stack.h" 21 #include "asan_stats.h" 22 #include "asan_suppressions.h" 23 #include "asan_thread.h" 24 #include "sanitizer_common/sanitizer_common.h" 25 #include "sanitizer_common/sanitizer_mutex.h" 26 #include "sanitizer_common/sanitizer_placement_new.h" 27 #include "sanitizer_common/sanitizer_stackdepot.h" 28 29 namespace __asan { 30 31 typedef __asan_global Global; 32 33 struct ListOfGlobals { 34 const Global *g; 35 ListOfGlobals *next; 36 }; 37 38 static BlockingMutex mu_for_globals(LINKER_INITIALIZED); 39 static LowLevelAllocator allocator_for_globals; 40 static ListOfGlobals *list_of_all_globals; 41 42 static const int kDynamicInitGlobalsInitialCapacity = 512; 43 struct DynInitGlobal { 44 Global g; 45 bool initialized; 46 }; 47 typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals; 48 // Lazy-initialized and never deleted. 49 static VectorOfGlobals *dynamic_init_globals; 50 51 // We want to remember where a certain range of globals was registered. 52 struct GlobalRegistrationSite { 53 u32 stack_id; 54 Global *g_first, *g_last; 55 }; 56 typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector; 57 static GlobalRegistrationSiteVector *global_registration_site_vector; 58 59 ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { 60 FastPoisonShadow(g->beg, g->size_with_redzone, value); 61 } 62 63 ALWAYS_INLINE void PoisonRedZones(const Global &g) { 64 uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY); 65 FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size, 66 kAsanGlobalRedzoneMagic); 67 if (g.size != aligned_size) { 68 FastPoisonShadowPartialRightRedzone( 69 g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY), 70 g.size % SHADOW_GRANULARITY, 71 SHADOW_GRANULARITY, 72 kAsanGlobalRedzoneMagic); 73 } 74 } 75 76 const uptr kMinimalDistanceFromAnotherGlobal = 64; 77 78 static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { 79 if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; 80 if (addr >= g.beg + g.size_with_redzone) return false; 81 return true; 82 } 83 84 static void ReportGlobal(const Global &g, const char *prefix) { 85 Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n", 86 prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name, 87 g.module_name, g.has_dynamic_init); 88 if (g.location) { 89 Report(" location (%p): name=%s[%p], %d %d\n", g.location, 90 g.location->filename, g.location->filename, g.location->line_no, 91 g.location->column_no); 92 } 93 } 94 95 static u32 FindRegistrationSite(const Global *g) { 96 mu_for_globals.CheckLocked(); 97 CHECK(global_registration_site_vector); 98 for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { 99 GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; 100 if (g >= grs.g_first && g <= grs.g_last) 101 return grs.stack_id; 102 } 103 return 0; 104 } 105 106 int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites, 107 int max_globals) { 108 if (!flags()->report_globals) return 0; 109 BlockingMutexLock lock(&mu_for_globals); 110 int res = 0; 111 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 112 const Global &g = *l->g; 113 if (flags()->report_globals >= 2) 114 ReportGlobal(g, "Search"); 115 if (IsAddressNearGlobal(addr, g)) { 116 globals[res] = g; 117 if (reg_sites) 118 reg_sites[res] = FindRegistrationSite(&g); 119 res++; 120 if (res == max_globals) break; 121 } 122 } 123 return res; 124 } 125 126 bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { 127 Global g = {}; 128 if (GetGlobalsForAddress(addr, &g, nullptr, 1)) { 129 internal_strncpy(descr->name, g.name, descr->name_size); 130 descr->region_address = g.beg; 131 descr->region_size = g.size; 132 descr->region_kind = "global"; 133 return true; 134 } 135 return false; 136 } 137 138 enum GlobalSymbolState { 139 UNREGISTERED = 0, 140 REGISTERED = 1 141 }; 142 143 // Check ODR violation for given global G via special ODR indicator. We use 144 // this method in case compiler instruments global variables through their 145 // local aliases. 146 static void CheckODRViolationViaIndicator(const Global *g) { 147 u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator); 148 if (*odr_indicator == UNREGISTERED) { 149 *odr_indicator = REGISTERED; 150 return; 151 } 152 // If *odr_indicator is DEFINED, some module have already registered 153 // externally visible symbol with the same name. This is an ODR violation. 154 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 155 if (g->odr_indicator == l->g->odr_indicator && 156 (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && 157 !IsODRViolationSuppressed(g->name)) 158 ReportODRViolation(g, FindRegistrationSite(g), 159 l->g, FindRegistrationSite(l->g)); 160 } 161 } 162 163 // Check ODR violation for given global G by checking if it's already poisoned. 164 // We use this method in case compiler doesn't use private aliases for global 165 // variables. 166 static void CheckODRViolationViaPoisoning(const Global *g) { 167 if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { 168 // This check may not be enough: if the first global is much larger 169 // the entire redzone of the second global may be within the first global. 170 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 171 if (g->beg == l->g->beg && 172 (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && 173 !IsODRViolationSuppressed(g->name)) 174 ReportODRViolation(g, FindRegistrationSite(g), 175 l->g, FindRegistrationSite(l->g)); 176 } 177 } 178 } 179 180 // Clang provides two different ways for global variables protection: 181 // it can poison the global itself or its private alias. In former 182 // case we may poison same symbol multiple times, that can help us to 183 // cheaply detect ODR violation: if we try to poison an already poisoned 184 // global, we have ODR violation error. 185 // In latter case, we poison each symbol exactly once, so we use special 186 // indicator symbol to perform similar check. 187 // In either case, compiler provides a special odr_indicator field to Global 188 // structure, that can contain two kinds of values: 189 // 1) Non-zero value. In this case, odr_indicator is an address of 190 // corresponding indicator variable for given global. 191 // 2) Zero. This means that we don't use private aliases for global variables 192 // and can freely check ODR violation with the first method. 193 // 194 // This routine chooses between two different methods of ODR violation 195 // detection. 196 static inline bool UseODRIndicator(const Global *g) { 197 // Use ODR indicator method iff use_odr_indicator flag is set and 198 // indicator symbol address is not 0. 199 return flags()->use_odr_indicator && g->odr_indicator > 0; 200 } 201 202 // Register a global variable. 203 // This function may be called more than once for every global 204 // so we store the globals in a map. 205 static void RegisterGlobal(const Global *g) { 206 CHECK(asan_inited); 207 if (flags()->report_globals >= 2) 208 ReportGlobal(*g, "Added"); 209 CHECK(flags()->report_globals); 210 CHECK(AddrIsInMem(g->beg)); 211 if (!AddrIsAlignedByGranularity(g->beg)) { 212 Report("The following global variable is not properly aligned.\n"); 213 Report("This may happen if another global with the same name\n"); 214 Report("resides in another non-instrumented module.\n"); 215 Report("Or the global comes from a C file built w/o -fno-common.\n"); 216 Report("In either case this is likely an ODR violation bug,\n"); 217 Report("but AddressSanitizer can not provide more details.\n"); 218 ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g)); 219 CHECK(AddrIsAlignedByGranularity(g->beg)); 220 } 221 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 222 if (flags()->detect_odr_violation) { 223 // Try detecting ODR (One Definition Rule) violation, i.e. the situation 224 // where two globals with the same name are defined in different modules. 225 if (UseODRIndicator(g)) 226 CheckODRViolationViaIndicator(g); 227 else 228 CheckODRViolationViaPoisoning(g); 229 } 230 if (CanPoisonMemory()) 231 PoisonRedZones(*g); 232 ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals; 233 l->g = g; 234 l->next = list_of_all_globals; 235 list_of_all_globals = l; 236 if (g->has_dynamic_init) { 237 if (!dynamic_init_globals) { 238 dynamic_init_globals = new(allocator_for_globals) 239 VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); 240 } 241 DynInitGlobal dyn_global = { *g, false }; 242 dynamic_init_globals->push_back(dyn_global); 243 } 244 } 245 246 static void UnregisterGlobal(const Global *g) { 247 CHECK(asan_inited); 248 if (flags()->report_globals >= 2) 249 ReportGlobal(*g, "Removed"); 250 CHECK(flags()->report_globals); 251 CHECK(AddrIsInMem(g->beg)); 252 CHECK(AddrIsAlignedByGranularity(g->beg)); 253 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 254 if (CanPoisonMemory()) 255 PoisonShadowForGlobal(g, 0); 256 // We unpoison the shadow memory for the global but we do not remove it from 257 // the list because that would require O(n^2) time with the current list 258 // implementation. It might not be worth doing anyway. 259 260 // Release ODR indicator. 261 if (UseODRIndicator(g)) { 262 u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator); 263 *odr_indicator = UNREGISTERED; 264 } 265 } 266 267 void StopInitOrderChecking() { 268 BlockingMutexLock lock(&mu_for_globals); 269 if (!flags()->check_initialization_order || !dynamic_init_globals) 270 return; 271 flags()->check_initialization_order = false; 272 for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { 273 DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; 274 const Global *g = &dyn_g.g; 275 // Unpoison the whole global. 276 PoisonShadowForGlobal(g, 0); 277 // Poison redzones back. 278 PoisonRedZones(*g); 279 } 280 } 281 282 } // namespace __asan 283 284 // ---------------------- Interface ---------------- {{{1 285 using namespace __asan; // NOLINT 286 287 288 // Apply __asan_register_globals to all globals found in the same loaded 289 // executable or shared library as `flag'. The flag tracks whether globals have 290 // already been registered or not for this image. 291 void __asan_register_image_globals(uptr *flag) { 292 if (*flag) 293 return; 294 AsanApplyToGlobals(__asan_register_globals, flag); 295 *flag = 1; 296 } 297 298 // This mirrors __asan_register_image_globals. 299 void __asan_unregister_image_globals(uptr *flag) { 300 if (!*flag) 301 return; 302 AsanApplyToGlobals(__asan_unregister_globals, flag); 303 *flag = 0; 304 } 305 306 // Register an array of globals. 307 void __asan_register_globals(__asan_global *globals, uptr n) { 308 if (!flags()->report_globals) return; 309 GET_STACK_TRACE_MALLOC; 310 u32 stack_id = StackDepotPut(stack); 311 BlockingMutexLock lock(&mu_for_globals); 312 if (!global_registration_site_vector) 313 global_registration_site_vector = 314 new(allocator_for_globals) GlobalRegistrationSiteVector(128); 315 GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; 316 global_registration_site_vector->push_back(site); 317 if (flags()->report_globals >= 2) { 318 PRINT_CURRENT_STACK(); 319 Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]); 320 } 321 for (uptr i = 0; i < n; i++) { 322 RegisterGlobal(&globals[i]); 323 } 324 } 325 326 // Unregister an array of globals. 327 // We must do this when a shared objects gets dlclosed. 328 void __asan_unregister_globals(__asan_global *globals, uptr n) { 329 if (!flags()->report_globals) return; 330 BlockingMutexLock lock(&mu_for_globals); 331 for (uptr i = 0; i < n; i++) { 332 UnregisterGlobal(&globals[i]); 333 } 334 } 335 336 // This method runs immediately prior to dynamic initialization in each TU, 337 // when all dynamically initialized globals are unpoisoned. This method 338 // poisons all global variables not defined in this TU, so that a dynamic 339 // initializer can only touch global variables in the same TU. 340 void __asan_before_dynamic_init(const char *module_name) { 341 if (!flags()->check_initialization_order || 342 !CanPoisonMemory()) 343 return; 344 bool strict_init_order = flags()->strict_init_order; 345 CHECK(dynamic_init_globals); 346 CHECK(module_name); 347 CHECK(asan_inited); 348 BlockingMutexLock lock(&mu_for_globals); 349 if (flags()->report_globals >= 3) 350 Printf("DynInitPoison module: %s\n", module_name); 351 for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { 352 DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; 353 const Global *g = &dyn_g.g; 354 if (dyn_g.initialized) 355 continue; 356 if (g->module_name != module_name) 357 PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); 358 else if (!strict_init_order) 359 dyn_g.initialized = true; 360 } 361 } 362 363 // This method runs immediately after dynamic initialization in each TU, when 364 // all dynamically initialized globals except for those defined in the current 365 // TU are poisoned. It simply unpoisons all dynamically initialized globals. 366 void __asan_after_dynamic_init() { 367 if (!flags()->check_initialization_order || 368 !CanPoisonMemory()) 369 return; 370 CHECK(asan_inited); 371 BlockingMutexLock lock(&mu_for_globals); 372 // FIXME: Optionally report that we're unpoisoning globals from a module. 373 for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { 374 DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; 375 const Global *g = &dyn_g.g; 376 if (!dyn_g.initialized) { 377 // Unpoison the whole global. 378 PoisonShadowForGlobal(g, 0); 379 // Poison redzones back. 380 PoisonRedZones(*g); 381 } 382 } 383 } 384