1 | #include "dfsan_thread.h" |
2 | |
3 | #include <pthread.h> |
4 | |
5 | #include "dfsan.h" |
6 | #include "sanitizer_common/sanitizer_tls_get_addr.h" |
7 | |
8 | using namespace __dfsan; |
9 | |
10 | DFsanThread *DFsanThread::Create(thread_callback_t start_routine, void *arg, |
11 | bool track_origins) { |
12 | uptr PageSize = GetPageSizeCached(); |
13 | uptr size = RoundUpTo(size: sizeof(DFsanThread), boundary: PageSize); |
14 | DFsanThread *thread = (DFsanThread *)MmapOrDie(size, mem_type: __func__); |
15 | thread->start_routine_ = start_routine; |
16 | thread->arg_ = arg; |
17 | thread->track_origins_ = track_origins; |
18 | thread->destructor_iterations_ = GetPthreadDestructorIterations(); |
19 | |
20 | return thread; |
21 | } |
22 | |
23 | void DFsanThread::SetThreadStackAndTls() { |
24 | GetThreadStackAndTls(main: IsMainThread(), stk_begin: &stack_.bottom, stk_end: &stack_.top, tls_begin: &tls_begin_, |
25 | tls_end: &tls_end_); |
26 | int local; |
27 | CHECK(AddrIsInStack((uptr)&local)); |
28 | } |
29 | |
30 | void DFsanThread::ClearShadowForThreadStackAndTLS() { |
31 | dfsan_set_label(label: 0, addr: (void *)stack_.bottom, size: stack_.top - stack_.bottom); |
32 | if (tls_begin_ != tls_end_) |
33 | dfsan_set_label(label: 0, addr: (void *)tls_begin_, size: tls_end_ - tls_begin_); |
34 | DTLS *dtls = DTLS_Get(); |
35 | CHECK_NE(dtls, 0); |
36 | ForEachDVT(dtls, fn: [](const DTLS::DTV &dtv, int id) { |
37 | dfsan_set_label(label: 0, addr: (void *)(dtv.beg), size: dtv.size); |
38 | }); |
39 | } |
40 | |
41 | void DFsanThread::Init() { |
42 | SetThreadStackAndTls(); |
43 | ClearShadowForThreadStackAndTLS(); |
44 | } |
45 | |
46 | void DFsanThread::TSDDtor(void *tsd) { |
47 | DFsanThread *t = (DFsanThread *)tsd; |
48 | t->Destroy(); |
49 | } |
50 | |
51 | void DFsanThread::Destroy() { |
52 | malloc_storage().CommitBack(); |
53 | // We also clear the shadow on thread destruction because |
54 | // some code may still be executing in later TSD destructors |
55 | // and we don't want it to have any poisoned stack. |
56 | ClearShadowForThreadStackAndTLS(); |
57 | uptr size = RoundUpTo(size: sizeof(DFsanThread), boundary: GetPageSizeCached()); |
58 | UnmapOrDie(addr: this, size); |
59 | DTLS_Destroy(); |
60 | } |
61 | |
62 | thread_return_t DFsanThread::ThreadStart() { |
63 | if (!start_routine_) { |
64 | // start_routine_ == 0 if we're on the main thread or on one of the |
65 | // OS X libdispatch worker threads. But nobody is supposed to call |
66 | // ThreadStart() for the worker threads. |
67 | return 0; |
68 | } |
69 | |
70 | // The only argument is void* arg. |
71 | // |
72 | // We have never supported propagating the pointer arg as tainted, |
73 | // __dfsw_pthread_create/__dfso_pthread_create ignore the taint label. |
74 | // Note that the bytes pointed-to (probably the much more common case) |
75 | // can still have taint labels attached to them. |
76 | dfsan_clear_thread_local_state(); |
77 | |
78 | return start_routine_(arg_); |
79 | } |
80 | |
81 | DFsanThread::StackBounds DFsanThread::GetStackBounds() const { |
82 | return {.bottom: stack_.bottom, .top: stack_.top}; |
83 | } |
84 | |
85 | uptr DFsanThread::stack_top() { return GetStackBounds().top; } |
86 | |
87 | uptr DFsanThread::stack_bottom() { return GetStackBounds().bottom; } |
88 | |
89 | bool DFsanThread::AddrIsInStack(uptr addr) { |
90 | const auto bounds = GetStackBounds(); |
91 | return addr >= bounds.bottom && addr < bounds.top; |
92 | } |
93 | |
94 | static pthread_key_t tsd_key; |
95 | static bool tsd_key_inited = false; |
96 | |
97 | void __dfsan::DFsanTSDInit(void (*destructor)(void *tsd)) { |
98 | CHECK(!tsd_key_inited); |
99 | tsd_key_inited = true; |
100 | CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); |
101 | } |
102 | |
103 | static THREADLOCAL DFsanThread *dfsan_current_thread; |
104 | |
105 | DFsanThread *__dfsan::GetCurrentThread() { return dfsan_current_thread; } |
106 | |
107 | void __dfsan::SetCurrentThread(DFsanThread *t) { |
108 | // Make sure we do not reset the current DFsanThread. |
109 | CHECK_EQ(0, dfsan_current_thread); |
110 | dfsan_current_thread = t; |
111 | // Make sure that DFsanTSDDtor gets called at the end. |
112 | CHECK(tsd_key_inited); |
113 | pthread_setspecific(key: tsd_key, pointer: t); |
114 | } |
115 | |
116 | void __dfsan::DFsanTSDDtor(void *tsd) { |
117 | DFsanThread *t = (DFsanThread *)tsd; |
118 | if (t->destructor_iterations_ > 1) { |
119 | t->destructor_iterations_--; |
120 | CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); |
121 | return; |
122 | } |
123 | dfsan_current_thread = nullptr; |
124 | // Make sure that signal handler can not see a stale current thread pointer. |
125 | atomic_signal_fence(mo: memory_order_seq_cst); |
126 | DFsanThread::TSDDtor(tsd); |
127 | } |
128 | |