1 //===-- asan_thread.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 // Thread-related code.
11 //===----------------------------------------------------------------------===//
12 #include "asan_allocator.h"
13 #include "asan_interceptors.h"
14 #include "asan_poisoning.h"
15 #include "asan_stack.h"
16 #include "asan_thread.h"
17 #include "asan_mapping.h"
18 #include "sanitizer_common/sanitizer_common.h"
19 #include "sanitizer_common/sanitizer_placement_new.h"
20 #include "sanitizer_common/sanitizer_stackdepot.h"
21 #include "sanitizer_common/sanitizer_tls_get_addr.h"
22 #include "lsan/lsan_common.h"
23 
24 namespace __asan {
25 
26 // AsanThreadContext implementation.
27 
OnCreated(void * arg)28 void AsanThreadContext::OnCreated(void *arg) {
29   CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
30   if (args->stack)
31     stack_id = StackDepotPut(*args->stack);
32   thread = args->thread;
33   thread->set_context(this);
34 }
35 
OnFinished()36 void AsanThreadContext::OnFinished() {
37   // Drop the link to the AsanThread object.
38   thread = nullptr;
39 }
40 
41 // MIPS requires aligned address
42 static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
43 static ThreadRegistry *asan_thread_registry;
44 
45 static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
46 static LowLevelAllocator allocator_for_thread_context;
47 
GetAsanThreadContext(u32 tid)48 static ThreadContextBase *GetAsanThreadContext(u32 tid) {
49   BlockingMutexLock lock(&mu_for_thread_context);
50   return new(allocator_for_thread_context) AsanThreadContext(tid);
51 }
52 
asanThreadRegistry()53 ThreadRegistry &asanThreadRegistry() {
54   static bool initialized;
55   // Don't worry about thread_safety - this should be called when there is
56   // a single thread.
57   if (!initialized) {
58     // Never reuse ASan threads: we store pointer to AsanThreadContext
59     // in TSD and can't reliably tell when no more TSD destructors will
60     // be called. It would be wrong to reuse AsanThreadContext for another
61     // thread before all TSD destructors will be called for it.
62     asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
63         GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
64     initialized = true;
65   }
66   return *asan_thread_registry;
67 }
68 
GetThreadContextByTidLocked(u32 tid)69 AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
70   return static_cast<AsanThreadContext *>(
71       asanThreadRegistry().GetThreadLocked(tid));
72 }
73 
74 // AsanThread implementation.
75 
Create(thread_callback_t start_routine,void * arg,u32 parent_tid,StackTrace * stack,bool detached)76 AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
77                                u32 parent_tid, StackTrace *stack,
78                                bool detached) {
79   uptr PageSize = GetPageSizeCached();
80   uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
81   AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
82   thread->start_routine_ = start_routine;
83   thread->arg_ = arg;
84   AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
85   asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
86                                     parent_tid, &args);
87 
88   return thread;
89 }
90 
TSDDtor(void * tsd)91 void AsanThread::TSDDtor(void *tsd) {
92   AsanThreadContext *context = (AsanThreadContext*)tsd;
93   VReport(1, "T%d TSDDtor\n", context->tid);
94   if (context->thread)
95     context->thread->Destroy();
96 }
97 
Destroy()98 void AsanThread::Destroy() {
99   int tid = this->tid();
100   VReport(1, "T%d exited\n", tid);
101 
102   malloc_storage().CommitBack();
103   if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
104   asanThreadRegistry().FinishThread(tid);
105   FlushToDeadThreadStats(&stats_);
106   // We also clear the shadow on thread destruction because
107   // some code may still be executing in later TSD destructors
108   // and we don't want it to have any poisoned stack.
109   ClearShadowForThreadStackAndTLS();
110   DeleteFakeStack(tid);
111   uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
112   UnmapOrDie(this, size);
113   DTLS_Destroy();
114 }
115 
StartSwitchFiber(FakeStack ** fake_stack_save,uptr bottom,uptr size)116 void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
117                                   uptr size) {
118   if (atomic_load(&stack_switching_, memory_order_relaxed)) {
119     Report("ERROR: starting fiber switch while in fiber switch\n");
120     Die();
121   }
122 
123   next_stack_bottom_ = bottom;
124   next_stack_top_ = bottom + size;
125   atomic_store(&stack_switching_, 1, memory_order_release);
126 
127   FakeStack *current_fake_stack = fake_stack_;
128   if (fake_stack_save)
129     *fake_stack_save = fake_stack_;
130   fake_stack_ = nullptr;
131   SetTLSFakeStack(nullptr);
132   // if fake_stack_save is null, the fiber will die, delete the fakestack
133   if (!fake_stack_save && current_fake_stack)
134     current_fake_stack->Destroy(this->tid());
135 }
136 
FinishSwitchFiber(FakeStack * fake_stack_save,uptr * bottom_old,uptr * size_old)137 void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
138                                    uptr *bottom_old,
139                                    uptr *size_old) {
140   if (!atomic_load(&stack_switching_, memory_order_relaxed)) {
141     Report("ERROR: finishing a fiber switch that has not started\n");
142     Die();
143   }
144 
145   if (fake_stack_save) {
146     SetTLSFakeStack(fake_stack_save);
147     fake_stack_ = fake_stack_save;
148   }
149 
150   if (bottom_old)
151     *bottom_old = stack_bottom_;
152   if (size_old)
153     *size_old = stack_top_ - stack_bottom_;
154   stack_bottom_ = next_stack_bottom_;
155   stack_top_ = next_stack_top_;
156   atomic_store(&stack_switching_, 0, memory_order_release);
157   next_stack_top_ = 0;
158   next_stack_bottom_ = 0;
159 }
160 
GetStackBounds() const161 inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
162   if (!atomic_load(&stack_switching_, memory_order_acquire)) {
163     // Make sure the stack bounds are fully initialized.
164     if (stack_bottom_ >= stack_top_) return {0, 0};
165     return {stack_bottom_, stack_top_};
166   }
167   char local;
168   const uptr cur_stack = (uptr)&local;
169   // Note: need to check next stack first, because FinishSwitchFiber
170   // may be in process of overwriting stack_top_/bottom_. But in such case
171   // we are already on the next stack.
172   if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
173     return {next_stack_bottom_, next_stack_top_};
174   return {stack_bottom_, stack_top_};
175 }
176 
stack_top()177 uptr AsanThread::stack_top() {
178   return GetStackBounds().top;
179 }
180 
stack_bottom()181 uptr AsanThread::stack_bottom() {
182   return GetStackBounds().bottom;
183 }
184 
stack_size()185 uptr AsanThread::stack_size() {
186   const auto bounds = GetStackBounds();
187   return bounds.top - bounds.bottom;
188 }
189 
190 // We want to create the FakeStack lazyly on the first use, but not eralier
191 // than the stack size is known and the procedure has to be async-signal safe.
AsyncSignalSafeLazyInitFakeStack()192 FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
193   uptr stack_size = this->stack_size();
194   if (stack_size == 0)  // stack_size is not yet available, don't use FakeStack.
195     return nullptr;
196   uptr old_val = 0;
197   // fake_stack_ has 3 states:
198   // 0   -- not initialized
199   // 1   -- being initialized
200   // ptr -- initialized
201   // This CAS checks if the state was 0 and if so changes it to state 1,
202   // if that was successful, it initializes the pointer.
203   if (atomic_compare_exchange_strong(
204       reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
205       memory_order_relaxed)) {
206     uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
207     CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
208     stack_size_log =
209         Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
210     stack_size_log =
211         Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
212     fake_stack_ = FakeStack::Create(stack_size_log);
213     SetTLSFakeStack(fake_stack_);
214     return fake_stack_;
215   }
216   return nullptr;
217 }
218 
Init(const InitOptions * options)219 void AsanThread::Init(const InitOptions *options) {
220   next_stack_top_ = next_stack_bottom_ = 0;
221   atomic_store(&stack_switching_, false, memory_order_release);
222   fake_stack_ = nullptr;  // Will be initialized lazily if needed.
223   CHECK_EQ(this->stack_size(), 0U);
224   SetThreadStackAndTls(options);
225   CHECK_GT(this->stack_size(), 0U);
226   CHECK(AddrIsInMem(stack_bottom_));
227   CHECK(AddrIsInMem(stack_top_ - 1));
228   ClearShadowForThreadStackAndTLS();
229   int local = 0;
230   VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
231           (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
232           &local);
233 }
234 
235 // Fuchsia doesn't use ThreadStart.
236 // asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls.
237 #if !SANITIZER_FUCHSIA
238 
ThreadStart(tid_t os_id,atomic_uintptr_t * signal_thread_is_registered)239 thread_return_t AsanThread::ThreadStart(
240     tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
241   Init();
242   asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false,
243                                    nullptr);
244   if (signal_thread_is_registered)
245     atomic_store(signal_thread_is_registered, 1, memory_order_release);
246 
247   if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
248 
249   if (!start_routine_) {
250     // start_routine_ == 0 if we're on the main thread or on one of the
251     // OS X libdispatch worker threads. But nobody is supposed to call
252     // ThreadStart() for the worker threads.
253     CHECK_EQ(tid(), 0);
254     return 0;
255   }
256 
257   thread_return_t res = start_routine_(arg_);
258 
259   // On POSIX systems we defer this to the TSD destructor. LSan will consider
260   // the thread's memory as non-live from the moment we call Destroy(), even
261   // though that memory might contain pointers to heap objects which will be
262   // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
263   // the TSD destructors have run might cause false positives in LSan.
264   if (!SANITIZER_POSIX)
265     this->Destroy();
266 
267   return res;
268 }
269 
CreateMainThread()270 AsanThread *CreateMainThread() {
271   AsanThread *main_thread = AsanThread::Create(
272       /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
273       /* stack */ nullptr, /* detached */ true);
274   SetCurrentThread(main_thread);
275   main_thread->ThreadStart(internal_getpid(),
276                            /* signal_thread_is_registered */ nullptr);
277   return main_thread;
278 }
279 
280 // This implementation doesn't use the argument, which is just passed down
281 // from the caller of Init (which see, above).  It's only there to support
282 // OS-specific implementations that need more information passed through.
SetThreadStackAndTls(const InitOptions * options)283 void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
284   DCHECK_EQ(options, nullptr);
285   uptr tls_size = 0;
286   uptr stack_size = 0;
287   GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
288                        const_cast<uptr *>(&stack_size), &tls_begin_, &tls_size);
289   stack_top_ = stack_bottom_ + stack_size;
290   tls_end_ = tls_begin_ + tls_size;
291   dtls_ = DTLS_Get();
292 
293   int local;
294   CHECK(AddrIsInStack((uptr)&local));
295 }
296 
297 #endif  // !SANITIZER_FUCHSIA
298 
ClearShadowForThreadStackAndTLS()299 void AsanThread::ClearShadowForThreadStackAndTLS() {
300   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
301   if (tls_begin_ != tls_end_)
302     PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
303 }
304 
GetStackFrameAccessByAddr(uptr addr,StackFrameAccess * access)305 bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
306                                            StackFrameAccess *access) {
307   uptr bottom = 0;
308   if (AddrIsInStack(addr)) {
309     bottom = stack_bottom();
310   } else if (has_fake_stack()) {
311     bottom = fake_stack()->AddrIsInFakeStack(addr);
312     CHECK(bottom);
313     access->offset = addr - bottom;
314     access->frame_pc = ((uptr*)bottom)[2];
315     access->frame_descr = (const char *)((uptr*)bottom)[1];
316     return true;
317   }
318   uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
319   uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
320   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
321   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
322 
323   while (shadow_ptr >= shadow_bottom &&
324          *shadow_ptr != kAsanStackLeftRedzoneMagic) {
325     shadow_ptr--;
326     mem_ptr -= SHADOW_GRANULARITY;
327   }
328 
329   while (shadow_ptr >= shadow_bottom &&
330          *shadow_ptr == kAsanStackLeftRedzoneMagic) {
331     shadow_ptr--;
332     mem_ptr -= SHADOW_GRANULARITY;
333   }
334 
335   if (shadow_ptr < shadow_bottom) {
336     return false;
337   }
338 
339   uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY);
340   CHECK(ptr[0] == kCurrentStackFrameMagic);
341   access->offset = addr - (uptr)ptr;
342   access->frame_pc = ptr[2];
343   access->frame_descr = (const char*)ptr[1];
344   return true;
345 }
346 
GetStackVariableShadowStart(uptr addr)347 uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
348   uptr bottom = 0;
349   if (AddrIsInStack(addr)) {
350     bottom = stack_bottom();
351   } else if (has_fake_stack()) {
352     bottom = fake_stack()->AddrIsInFakeStack(addr);
353     CHECK(bottom);
354   } else
355     return 0;
356 
357   uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
358   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
359   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
360 
361   while (shadow_ptr >= shadow_bottom &&
362          (*shadow_ptr != kAsanStackLeftRedzoneMagic &&
363           *shadow_ptr != kAsanStackMidRedzoneMagic &&
364           *shadow_ptr != kAsanStackRightRedzoneMagic))
365     shadow_ptr--;
366 
367   return (uptr)shadow_ptr + 1;
368 }
369 
AddrIsInStack(uptr addr)370 bool AsanThread::AddrIsInStack(uptr addr) {
371   const auto bounds = GetStackBounds();
372   return addr >= bounds.bottom && addr < bounds.top;
373 }
374 
ThreadStackContainsAddress(ThreadContextBase * tctx_base,void * addr)375 static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
376                                        void *addr) {
377   AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
378   AsanThread *t = tctx->thread;
379   if (!t) return false;
380   if (t->AddrIsInStack((uptr)addr)) return true;
381   if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
382     return true;
383   return false;
384 }
385 
GetCurrentThread()386 AsanThread *GetCurrentThread() {
387   AsanThreadContext *context =
388       reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
389   if (!context) {
390     if (SANITIZER_ANDROID) {
391       // On Android, libc constructor is called _after_ asan_init, and cleans up
392       // TSD. Try to figure out if this is still the main thread by the stack
393       // address. We are not entirely sure that we have correct main thread
394       // limits, so only do this magic on Android, and only if the found thread
395       // is the main thread.
396       AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
397       if (tctx && ThreadStackContainsAddress(tctx, &context)) {
398         SetCurrentThread(tctx->thread);
399         return tctx->thread;
400       }
401     }
402     return nullptr;
403   }
404   return context->thread;
405 }
406 
SetCurrentThread(AsanThread * t)407 void SetCurrentThread(AsanThread *t) {
408   CHECK(t->context());
409   VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
410           (void *)GetThreadSelf());
411   // Make sure we do not reset the current AsanThread.
412   CHECK_EQ(0, AsanTSDGet());
413   AsanTSDSet(t->context());
414   CHECK_EQ(t->context(), AsanTSDGet());
415 }
416 
GetCurrentTidOrInvalid()417 u32 GetCurrentTidOrInvalid() {
418   AsanThread *t = GetCurrentThread();
419   return t ? t->tid() : kInvalidTid;
420 }
421 
FindThreadByStackAddress(uptr addr)422 AsanThread *FindThreadByStackAddress(uptr addr) {
423   asanThreadRegistry().CheckLocked();
424   AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
425       asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
426                                                    (void *)addr));
427   return tctx ? tctx->thread : nullptr;
428 }
429 
EnsureMainThreadIDIsCorrect()430 void EnsureMainThreadIDIsCorrect() {
431   AsanThreadContext *context =
432       reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
433   if (context && (context->tid == 0))
434     context->os_id = GetTid();
435 }
436 
GetAsanThreadByOsIDLocked(tid_t os_id)437 __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
438   __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
439       __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
440   if (!context) return nullptr;
441   return context->thread;
442 }
443 } // namespace __asan
444 
445 // --- Implementation of LSan-specific functions --- {{{1
446 namespace __lsan {
GetThreadRangesLocked(tid_t os_id,uptr * stack_begin,uptr * stack_end,uptr * tls_begin,uptr * tls_end,uptr * cache_begin,uptr * cache_end,DTLS ** dtls)447 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
448                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
449                            uptr *cache_end, DTLS **dtls) {
450   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
451   if (!t) return false;
452   *stack_begin = t->stack_bottom();
453   *stack_end = t->stack_top();
454   *tls_begin = t->tls_begin();
455   *tls_end = t->tls_end();
456   // ASan doesn't keep allocator caches in TLS, so these are unused.
457   *cache_begin = 0;
458   *cache_end = 0;
459   *dtls = t->dtls();
460   return true;
461 }
462 
ForEachExtraStackRange(tid_t os_id,RangeIteratorCallback callback,void * arg)463 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
464                             void *arg) {
465   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
466   if (t && t->has_fake_stack())
467     t->fake_stack()->ForEachFakeFrame(callback, arg);
468 }
469 
LockThreadRegistry()470 void LockThreadRegistry() {
471   __asan::asanThreadRegistry().Lock();
472 }
473 
UnlockThreadRegistry()474 void UnlockThreadRegistry() {
475   __asan::asanThreadRegistry().Unlock();
476 }
477 
EnsureMainThreadIDIsCorrect()478 void EnsureMainThreadIDIsCorrect() {
479   __asan::EnsureMainThreadIDIsCorrect();
480 }
481 } // namespace __lsan
482 
483 // ---------------------- Interface ---------------- {{{1
484 using namespace __asan;  // NOLINT
485 
486 extern "C" {
487 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_start_switch_fiber(void ** fakestacksave,const void * bottom,uptr size)488 void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom,
489                                     uptr size) {
490   AsanThread *t = GetCurrentThread();
491   if (!t) {
492     VReport(1, "__asan_start_switch_fiber called from unknown thread\n");
493     return;
494   }
495   t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size);
496 }
497 
498 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_finish_switch_fiber(void * fakestack,const void ** bottom_old,uptr * size_old)499 void __sanitizer_finish_switch_fiber(void* fakestack,
500                                      const void **bottom_old,
501                                      uptr *size_old) {
502   AsanThread *t = GetCurrentThread();
503   if (!t) {
504     VReport(1, "__asan_finish_switch_fiber called from unknown thread\n");
505     return;
506   }
507   t->FinishSwitchFiber((FakeStack*)fakestack,
508                        (uptr*)bottom_old,
509                        (uptr*)size_old);
510 }
511 }
512