• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PoisonRedZones(const Global & g)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 
GetAlignedSize(uptr size)58 static uptr GetAlignedSize(uptr size) {
59   return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
60       * kGlobalAndStackRedzone;
61 }
62 
DescribeAddressIfGlobal(uptr addr)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.
RegisterGlobal(const Global * g)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 
UnregisterGlobal(const Global * g)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.
PoisonGlobalAndRedzones(const Global * g)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 
UnpoisonGlobal(const Global * g)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.
__asan_register_global(uptr addr,uptr size,const char * name)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.
__asan_register_globals(__asan_global * globals,uptr n)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.
__asan_unregister_globals(__asan_global * globals,uptr n)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.
__asan_before_dynamic_init(uptr first_addr,uptr last_addr)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.
__asan_after_dynamic_init()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