xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/asan/asan_fuchsia.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
168d75effSDimitry Andric //===-- asan_fuchsia.cpp -------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===---------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Fuchsia-specific details.
1268d75effSDimitry Andric //===---------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_fuchsia.h"
1568d75effSDimitry Andric #if SANITIZER_FUCHSIA
1668d75effSDimitry Andric 
1768d75effSDimitry Andric #include <limits.h>
1868d75effSDimitry Andric #include <zircon/sanitizer.h>
1968d75effSDimitry Andric #include <zircon/syscalls.h>
2068d75effSDimitry Andric #include <zircon/threads.h>
2168d75effSDimitry Andric 
22*81ad6265SDimitry Andric #  include "asan_interceptors.h"
23*81ad6265SDimitry Andric #  include "asan_internal.h"
24*81ad6265SDimitry Andric #  include "asan_stack.h"
25*81ad6265SDimitry Andric #  include "asan_thread.h"
26*81ad6265SDimitry Andric #  include "lsan/lsan_common.h"
27*81ad6265SDimitry Andric 
2868d75effSDimitry Andric namespace __asan {
2968d75effSDimitry Andric 
3068d75effSDimitry Andric // The system already set up the shadow memory for us.
3168d75effSDimitry Andric // __sanitizer::GetMaxUserVirtualAddress has already been called by
3268d75effSDimitry Andric // AsanInitInternal->InitializeHighMemEnd (asan_rtl.cpp).
3368d75effSDimitry Andric // Just do some additional sanity checks here.
3468d75effSDimitry Andric void InitializeShadowMemory() {
35349cc55cSDimitry Andric   if (Verbosity())
36349cc55cSDimitry Andric     PrintAddressSpaceLayout();
3768d75effSDimitry Andric 
3868d75effSDimitry Andric   // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address.
3968d75effSDimitry Andric   __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
4068d75effSDimitry Andric   DCHECK(kLowShadowBeg != kDefaultShadowSentinel);
4168d75effSDimitry Andric   __asan_shadow_memory_dynamic_address = kLowShadowBeg;
4268d75effSDimitry Andric 
4368d75effSDimitry Andric   CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
4468d75effSDimitry Andric   CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1);
4568d75effSDimitry Andric   CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit);
4668d75effSDimitry Andric   CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base);
4768d75effSDimitry Andric   CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1);
4868d75effSDimitry Andric   CHECK_EQ(kLowShadowEnd, 0);
4968d75effSDimitry Andric   CHECK_EQ(kLowShadowBeg, 0);
5068d75effSDimitry Andric }
5168d75effSDimitry Andric 
5268d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
5368d75effSDimitry Andric   UNIMPLEMENTED();
5468d75effSDimitry Andric }
5568d75effSDimitry Andric 
5668d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {}
5768d75effSDimitry Andric void AsanCheckIncompatibleRT() {}
5868d75effSDimitry Andric void InitializeAsanInterceptors() {}
5968d75effSDimitry Andric 
6068d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
6168d75effSDimitry Andric 
6268d75effSDimitry Andric void InitializePlatformExceptionHandlers() {}
6368d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
6468d75effSDimitry Andric   UNIMPLEMENTED();
6568d75effSDimitry Andric }
6668d75effSDimitry Andric 
67349cc55cSDimitry Andric bool PlatformUnpoisonStacks() {
68349cc55cSDimitry Andric   // The current sp might not point to the default stack. This
69349cc55cSDimitry Andric   // could be because we are in a crash stack from fuzzing for example.
70349cc55cSDimitry Andric   // Unpoison the default stack and the current stack page.
71349cc55cSDimitry Andric   AsanThread *curr_thread = GetCurrentThread();
72349cc55cSDimitry Andric   CHECK(curr_thread != nullptr);
73349cc55cSDimitry Andric   uptr top = curr_thread->stack_top();
74349cc55cSDimitry Andric   uptr bottom = curr_thread->stack_bottom();
75349cc55cSDimitry Andric   // The default stack grows from top to bottom. (bottom < top).
76349cc55cSDimitry Andric 
77349cc55cSDimitry Andric   uptr local_stack = reinterpret_cast<uptr>(__builtin_frame_address(0));
78349cc55cSDimitry Andric   if (local_stack >= bottom && local_stack <= top) {
79349cc55cSDimitry Andric     // The current stack is the default stack.
80349cc55cSDimitry Andric     // We only need to unpoison from where we are using until the end.
81349cc55cSDimitry Andric     bottom = RoundDownTo(local_stack, GetPageSize());
82349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "default");
83349cc55cSDimitry Andric   } else {
84349cc55cSDimitry Andric     // The current stack is not the default stack.
85349cc55cSDimitry Andric     // Unpoison the entire default stack and the current stack page.
86349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "default");
87349cc55cSDimitry Andric     bottom = RoundDownTo(local_stack, GetPageSize());
88349cc55cSDimitry Andric     top = bottom + GetPageSize();
89349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "unknown");
90349cc55cSDimitry Andric     return true;
91349cc55cSDimitry Andric   }
92349cc55cSDimitry Andric 
93349cc55cSDimitry Andric   return false;
94349cc55cSDimitry Andric }
955ffd83dbSDimitry Andric 
9668d75effSDimitry Andric // We can use a plain thread_local variable for TSD.
9768d75effSDimitry Andric static thread_local void *per_thread;
9868d75effSDimitry Andric 
9968d75effSDimitry Andric void *AsanTSDGet() { return per_thread; }
10068d75effSDimitry Andric 
10168d75effSDimitry Andric void AsanTSDSet(void *tsd) { per_thread = tsd; }
10268d75effSDimitry Andric 
10368d75effSDimitry Andric // There's no initialization needed, and the passed-in destructor
10468d75effSDimitry Andric // will never be called.  Instead, our own thread destruction hook
10568d75effSDimitry Andric // (below) will call AsanThread::TSDDtor directly.
10668d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
10768d75effSDimitry Andric   DCHECK(destructor == &PlatformTSDDtor);
10868d75effSDimitry Andric }
10968d75effSDimitry Andric 
11068d75effSDimitry Andric void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
11168d75effSDimitry Andric 
11268d75effSDimitry Andric static inline size_t AsanThreadMmapSize() {
113fe6060f1SDimitry Andric   return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
11468d75effSDimitry Andric }
11568d75effSDimitry Andric 
11668d75effSDimitry Andric struct AsanThread::InitOptions {
11768d75effSDimitry Andric   uptr stack_bottom, stack_size;
11868d75effSDimitry Andric };
11968d75effSDimitry Andric 
12068d75effSDimitry Andric // Shared setup between thread creation and startup for the initial thread.
12168d75effSDimitry Andric static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
122349cc55cSDimitry Andric                                     bool detached, const char *name) {
12368d75effSDimitry Andric   // In lieu of AsanThread::Create.
12468d75effSDimitry Andric   AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
12568d75effSDimitry Andric 
12668d75effSDimitry Andric   AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
127349cc55cSDimitry Andric   u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
12868d75effSDimitry Andric   asanThreadRegistry().SetThreadName(tid, name);
12968d75effSDimitry Andric 
13068d75effSDimitry Andric   return thread;
13168d75effSDimitry Andric }
13268d75effSDimitry Andric 
13368d75effSDimitry Andric // This gets the same arguments passed to Init by CreateAsanThread, above.
13468d75effSDimitry Andric // We're in the creator thread before the new thread is actually started,
13568d75effSDimitry Andric // but its stack address range is already known.  We don't bother tracking
13668d75effSDimitry Andric // the static TLS address range because the system itself already uses an
13768d75effSDimitry Andric // ASan-aware allocator for that.
13868d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
13968d75effSDimitry Andric   DCHECK_NE(GetCurrentThread(), this);
14068d75effSDimitry Andric   DCHECK_NE(GetCurrentThread(), nullptr);
14168d75effSDimitry Andric   CHECK_NE(options->stack_bottom, 0);
14268d75effSDimitry Andric   CHECK_NE(options->stack_size, 0);
14368d75effSDimitry Andric   stack_bottom_ = options->stack_bottom;
14468d75effSDimitry Andric   stack_top_ = options->stack_bottom + options->stack_size;
14568d75effSDimitry Andric }
14668d75effSDimitry Andric 
14768d75effSDimitry Andric // Called by __asan::AsanInitInternal (asan_rtl.c).
14868d75effSDimitry Andric AsanThread *CreateMainThread() {
14968d75effSDimitry Andric   thrd_t self = thrd_current();
15068d75effSDimitry Andric   char name[ZX_MAX_NAME_LEN];
15168d75effSDimitry Andric   CHECK_NE(__sanitizer::MainThreadStackBase, 0);
15268d75effSDimitry Andric   CHECK_GT(__sanitizer::MainThreadStackSize, 0);
15368d75effSDimitry Andric   AsanThread *t = CreateAsanThread(
154349cc55cSDimitry Andric       nullptr, 0, true,
15568d75effSDimitry Andric       _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
15668d75effSDimitry Andric                               sizeof(name)) == ZX_OK
15768d75effSDimitry Andric           ? name
158e8d8bef9SDimitry Andric           : nullptr);
159e8d8bef9SDimitry Andric   // We need to set the current thread before calling AsanThread::Init() below,
160e8d8bef9SDimitry Andric   // since it reads the thread ID.
16168d75effSDimitry Andric   SetCurrentThread(t);
162e8d8bef9SDimitry Andric   DCHECK_EQ(t->tid(), 0);
163e8d8bef9SDimitry Andric 
164e8d8bef9SDimitry Andric   const AsanThread::InitOptions options = {__sanitizer::MainThreadStackBase,
165e8d8bef9SDimitry Andric                                            __sanitizer::MainThreadStackSize};
166e8d8bef9SDimitry Andric   t->Init(&options);
167e8d8bef9SDimitry Andric 
16868d75effSDimitry Andric   return t;
16968d75effSDimitry Andric }
17068d75effSDimitry Andric 
17168d75effSDimitry Andric // This is called before each thread creation is attempted.  So, in
17268d75effSDimitry Andric // its first call, the calling thread is the initial and sole thread.
17368d75effSDimitry Andric static void *BeforeThreadCreateHook(uptr user_id, bool detached,
17468d75effSDimitry Andric                                     const char *name, uptr stack_bottom,
17568d75effSDimitry Andric                                     uptr stack_size) {
17668d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
17768d75effSDimitry Andric   // Strict init-order checking is thread-hostile.
178349cc55cSDimitry Andric   if (flags()->strict_init_order)
179349cc55cSDimitry Andric     StopInitOrderChecking();
18068d75effSDimitry Andric 
18168d75effSDimitry Andric   GET_STACK_TRACE_THREAD;
18268d75effSDimitry Andric   u32 parent_tid = GetCurrentTidOrInvalid();
18368d75effSDimitry Andric 
184349cc55cSDimitry Andric   AsanThread *thread = CreateAsanThread(&stack, parent_tid, detached, name);
185e8d8bef9SDimitry Andric 
186e8d8bef9SDimitry Andric   // On other systems, AsanThread::Init() is called from the new
187e8d8bef9SDimitry Andric   // thread itself.  But on Fuchsia we already know the stack address
188e8d8bef9SDimitry Andric   // range beforehand, so we can do most of the setup right now.
189e8d8bef9SDimitry Andric   const AsanThread::InitOptions options = {stack_bottom, stack_size};
190e8d8bef9SDimitry Andric   thread->Init(&options);
191e8d8bef9SDimitry Andric   return thread;
19268d75effSDimitry Andric }
19368d75effSDimitry Andric 
19468d75effSDimitry Andric // This is called after creating a new thread (in the creating thread),
19568d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
19668d75effSDimitry Andric static void ThreadCreateHook(void *hook, bool aborted) {
19768d75effSDimitry Andric   AsanThread *thread = static_cast<AsanThread *>(hook);
19868d75effSDimitry Andric   if (!aborted) {
19968d75effSDimitry Andric     // The thread was created successfully.
20068d75effSDimitry Andric     // ThreadStartHook is already running in the new thread.
20168d75effSDimitry Andric   } else {
20268d75effSDimitry Andric     // The thread wasn't created after all.
20368d75effSDimitry Andric     // Clean up everything we set up in BeforeThreadCreateHook.
20468d75effSDimitry Andric     asanThreadRegistry().FinishThread(thread->tid());
20568d75effSDimitry Andric     UnmapOrDie(thread, AsanThreadMmapSize());
20668d75effSDimitry Andric   }
20768d75effSDimitry Andric }
20868d75effSDimitry Andric 
20968d75effSDimitry Andric // This is called in the newly-created thread before it runs anything else,
21068d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
21168d75effSDimitry Andric // cf. asan_interceptors.cpp:asan_thread_start
21268d75effSDimitry Andric static void ThreadStartHook(void *hook, uptr os_id) {
21368d75effSDimitry Andric   AsanThread *thread = static_cast<AsanThread *>(hook);
21468d75effSDimitry Andric   SetCurrentThread(thread);
21568d75effSDimitry Andric 
21668d75effSDimitry Andric   // In lieu of AsanThread::ThreadStart.
21768d75effSDimitry Andric   asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular,
21868d75effSDimitry Andric                                    nullptr);
21968d75effSDimitry Andric }
22068d75effSDimitry Andric 
22168d75effSDimitry Andric // Each thread runs this just before it exits,
22268d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
22368d75effSDimitry Andric // All per-thread destructors have already been called.
22468d75effSDimitry Andric static void ThreadExitHook(void *hook, uptr os_id) {
22568d75effSDimitry Andric   AsanThread::TSDDtor(per_thread);
22668d75effSDimitry Andric }
22768d75effSDimitry Andric 
22868d75effSDimitry Andric bool HandleDlopenInit() {
22968d75effSDimitry Andric   // Not supported on this platform.
23068d75effSDimitry Andric   static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
23168d75effSDimitry Andric                 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
23268d75effSDimitry Andric   return false;
23368d75effSDimitry Andric }
23468d75effSDimitry Andric 
235e8d8bef9SDimitry Andric void FlushUnneededASanShadowMemory(uptr p, uptr size) {
236e8d8bef9SDimitry Andric   __sanitizer_fill_shadow(p, size, 0, 0);
237e8d8bef9SDimitry Andric }
238e8d8bef9SDimitry Andric 
239*81ad6265SDimitry Andric // On Fuchsia, leak detection is done by a special hook after atexit hooks.
240*81ad6265SDimitry Andric // So this doesn't install any atexit hook like on other platforms.
241*81ad6265SDimitry Andric void InstallAtExitCheckLeaks() {}
242*81ad6265SDimitry Andric 
24368d75effSDimitry Andric }  // namespace __asan
24468d75effSDimitry Andric 
245*81ad6265SDimitry Andric namespace __lsan {
246*81ad6265SDimitry Andric 
247*81ad6265SDimitry Andric bool UseExitcodeOnLeak() { return __asan::flags()->halt_on_error; }
248*81ad6265SDimitry Andric 
249*81ad6265SDimitry Andric }  // namespace __lsan
250*81ad6265SDimitry Andric 
25168d75effSDimitry Andric // These are declared (in extern "C") by <zircon/sanitizer.h>.
25268d75effSDimitry Andric // The system runtime will call our definitions directly.
25368d75effSDimitry Andric 
25468d75effSDimitry Andric void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
25568d75effSDimitry Andric                                             const char *name, void *stack_base,
25668d75effSDimitry Andric                                             size_t stack_size) {
25768d75effSDimitry Andric   return __asan::BeforeThreadCreateHook(
25868d75effSDimitry Andric       reinterpret_cast<uptr>(thread), detached, name,
25968d75effSDimitry Andric       reinterpret_cast<uptr>(stack_base), stack_size);
26068d75effSDimitry Andric }
26168d75effSDimitry Andric 
26268d75effSDimitry Andric void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
26368d75effSDimitry Andric   __asan::ThreadCreateHook(hook, error != thrd_success);
26468d75effSDimitry Andric }
26568d75effSDimitry Andric 
26668d75effSDimitry Andric void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
26768d75effSDimitry Andric   __asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
26868d75effSDimitry Andric }
26968d75effSDimitry Andric 
27068d75effSDimitry Andric void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
27168d75effSDimitry Andric   __asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self));
27268d75effSDimitry Andric }
27368d75effSDimitry Andric 
27468d75effSDimitry Andric #endif  // SANITIZER_FUCHSIA
275