xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/asan/asan_fuchsia.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
2281ad6265SDimitry Andric #  include "asan_interceptors.h"
2381ad6265SDimitry Andric #  include "asan_internal.h"
2481ad6265SDimitry Andric #  include "asan_stack.h"
2581ad6265SDimitry Andric #  include "asan_thread.h"
2681ad6265SDimitry Andric #  include "lsan/lsan_common.h"
2781ad6265SDimitry 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 InitializePlatformExceptionHandlers() {}
6168d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
6268d75effSDimitry Andric   UNIMPLEMENTED();
6368d75effSDimitry Andric }
6468d75effSDimitry Andric 
65349cc55cSDimitry Andric bool PlatformUnpoisonStacks() {
66349cc55cSDimitry Andric   // The current sp might not point to the default stack. This
67349cc55cSDimitry Andric   // could be because we are in a crash stack from fuzzing for example.
68349cc55cSDimitry Andric   // Unpoison the default stack and the current stack page.
69349cc55cSDimitry Andric   AsanThread *curr_thread = GetCurrentThread();
70349cc55cSDimitry Andric   CHECK(curr_thread != nullptr);
71349cc55cSDimitry Andric   uptr top = curr_thread->stack_top();
72349cc55cSDimitry Andric   uptr bottom = curr_thread->stack_bottom();
73349cc55cSDimitry Andric   // The default stack grows from top to bottom. (bottom < top).
74349cc55cSDimitry Andric 
75349cc55cSDimitry Andric   uptr local_stack = reinterpret_cast<uptr>(__builtin_frame_address(0));
76349cc55cSDimitry Andric   if (local_stack >= bottom && local_stack <= top) {
77349cc55cSDimitry Andric     // The current stack is the default stack.
78349cc55cSDimitry Andric     // We only need to unpoison from where we are using until the end.
79349cc55cSDimitry Andric     bottom = RoundDownTo(local_stack, GetPageSize());
80349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "default");
81349cc55cSDimitry Andric   } else {
82349cc55cSDimitry Andric     // The current stack is not the default stack.
83349cc55cSDimitry Andric     // Unpoison the entire default stack and the current stack page.
84349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "default");
85349cc55cSDimitry Andric     bottom = RoundDownTo(local_stack, GetPageSize());
86349cc55cSDimitry Andric     top = bottom + GetPageSize();
87349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "unknown");
88349cc55cSDimitry Andric     return true;
89349cc55cSDimitry Andric   }
90349cc55cSDimitry Andric 
91349cc55cSDimitry Andric   return false;
92349cc55cSDimitry Andric }
935ffd83dbSDimitry Andric 
9468d75effSDimitry Andric // We can use a plain thread_local variable for TSD.
9568d75effSDimitry Andric static thread_local void *per_thread;
9668d75effSDimitry Andric 
9768d75effSDimitry Andric void *AsanTSDGet() { return per_thread; }
9868d75effSDimitry Andric 
9968d75effSDimitry Andric void AsanTSDSet(void *tsd) { per_thread = tsd; }
10068d75effSDimitry Andric 
10168d75effSDimitry Andric // There's no initialization needed, and the passed-in destructor
10268d75effSDimitry Andric // will never be called.  Instead, our own thread destruction hook
10368d75effSDimitry Andric // (below) will call AsanThread::TSDDtor directly.
10468d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
10568d75effSDimitry Andric   DCHECK(destructor == &PlatformTSDDtor);
10668d75effSDimitry Andric }
10768d75effSDimitry Andric 
10868d75effSDimitry Andric void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
10968d75effSDimitry Andric 
11068d75effSDimitry Andric static inline size_t AsanThreadMmapSize() {
111fe6060f1SDimitry Andric   return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
11268d75effSDimitry Andric }
11368d75effSDimitry Andric 
11468d75effSDimitry Andric struct AsanThread::InitOptions {
11568d75effSDimitry Andric   uptr stack_bottom, stack_size;
11668d75effSDimitry Andric };
11768d75effSDimitry Andric 
11868d75effSDimitry Andric // Shared setup between thread creation and startup for the initial thread.
11968d75effSDimitry Andric static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
120349cc55cSDimitry Andric                                     bool detached, const char *name) {
12168d75effSDimitry Andric   // In lieu of AsanThread::Create.
12268d75effSDimitry Andric   AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
12368d75effSDimitry Andric 
12468d75effSDimitry Andric   AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
125349cc55cSDimitry Andric   u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
12668d75effSDimitry Andric   asanThreadRegistry().SetThreadName(tid, name);
12768d75effSDimitry Andric 
12868d75effSDimitry Andric   return thread;
12968d75effSDimitry Andric }
13068d75effSDimitry Andric 
13168d75effSDimitry Andric // This gets the same arguments passed to Init by CreateAsanThread, above.
13268d75effSDimitry Andric // We're in the creator thread before the new thread is actually started,
13368d75effSDimitry Andric // but its stack address range is already known.  We don't bother tracking
13468d75effSDimitry Andric // the static TLS address range because the system itself already uses an
13568d75effSDimitry Andric // ASan-aware allocator for that.
13668d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
13768d75effSDimitry Andric   DCHECK_NE(GetCurrentThread(), this);
13868d75effSDimitry Andric   DCHECK_NE(GetCurrentThread(), nullptr);
13968d75effSDimitry Andric   CHECK_NE(options->stack_bottom, 0);
14068d75effSDimitry Andric   CHECK_NE(options->stack_size, 0);
14168d75effSDimitry Andric   stack_bottom_ = options->stack_bottom;
14268d75effSDimitry Andric   stack_top_ = options->stack_bottom + options->stack_size;
14368d75effSDimitry Andric }
14468d75effSDimitry Andric 
14568d75effSDimitry Andric // Called by __asan::AsanInitInternal (asan_rtl.c).
14668d75effSDimitry Andric AsanThread *CreateMainThread() {
14768d75effSDimitry Andric   thrd_t self = thrd_current();
14868d75effSDimitry Andric   char name[ZX_MAX_NAME_LEN];
14968d75effSDimitry Andric   CHECK_NE(__sanitizer::MainThreadStackBase, 0);
15068d75effSDimitry Andric   CHECK_GT(__sanitizer::MainThreadStackSize, 0);
15168d75effSDimitry Andric   AsanThread *t = CreateAsanThread(
152349cc55cSDimitry Andric       nullptr, 0, true,
15368d75effSDimitry Andric       _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
15468d75effSDimitry Andric                               sizeof(name)) == ZX_OK
15568d75effSDimitry Andric           ? name
156e8d8bef9SDimitry Andric           : nullptr);
157e8d8bef9SDimitry Andric   // We need to set the current thread before calling AsanThread::Init() below,
158e8d8bef9SDimitry Andric   // since it reads the thread ID.
15968d75effSDimitry Andric   SetCurrentThread(t);
160e8d8bef9SDimitry Andric   DCHECK_EQ(t->tid(), 0);
161e8d8bef9SDimitry Andric 
162e8d8bef9SDimitry Andric   const AsanThread::InitOptions options = {__sanitizer::MainThreadStackBase,
163e8d8bef9SDimitry Andric                                            __sanitizer::MainThreadStackSize};
164e8d8bef9SDimitry Andric   t->Init(&options);
165e8d8bef9SDimitry Andric 
16668d75effSDimitry Andric   return t;
16768d75effSDimitry Andric }
16868d75effSDimitry Andric 
16968d75effSDimitry Andric // This is called before each thread creation is attempted.  So, in
17068d75effSDimitry Andric // its first call, the calling thread is the initial and sole thread.
17168d75effSDimitry Andric static void *BeforeThreadCreateHook(uptr user_id, bool detached,
17268d75effSDimitry Andric                                     const char *name, uptr stack_bottom,
17368d75effSDimitry Andric                                     uptr stack_size) {
17468d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
17568d75effSDimitry Andric   // Strict init-order checking is thread-hostile.
176349cc55cSDimitry Andric   if (flags()->strict_init_order)
177349cc55cSDimitry Andric     StopInitOrderChecking();
17868d75effSDimitry Andric 
17968d75effSDimitry Andric   GET_STACK_TRACE_THREAD;
18068d75effSDimitry Andric   u32 parent_tid = GetCurrentTidOrInvalid();
18168d75effSDimitry Andric 
182349cc55cSDimitry Andric   AsanThread *thread = CreateAsanThread(&stack, parent_tid, detached, name);
183e8d8bef9SDimitry Andric 
184e8d8bef9SDimitry Andric   // On other systems, AsanThread::Init() is called from the new
185e8d8bef9SDimitry Andric   // thread itself.  But on Fuchsia we already know the stack address
186e8d8bef9SDimitry Andric   // range beforehand, so we can do most of the setup right now.
187e8d8bef9SDimitry Andric   const AsanThread::InitOptions options = {stack_bottom, stack_size};
188e8d8bef9SDimitry Andric   thread->Init(&options);
189e8d8bef9SDimitry Andric   return thread;
19068d75effSDimitry Andric }
19168d75effSDimitry Andric 
19268d75effSDimitry Andric // This is called after creating a new thread (in the creating thread),
19368d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
19468d75effSDimitry Andric static void ThreadCreateHook(void *hook, bool aborted) {
19568d75effSDimitry Andric   AsanThread *thread = static_cast<AsanThread *>(hook);
19668d75effSDimitry Andric   if (!aborted) {
19768d75effSDimitry Andric     // The thread was created successfully.
19868d75effSDimitry Andric     // ThreadStartHook is already running in the new thread.
19968d75effSDimitry Andric   } else {
20068d75effSDimitry Andric     // The thread wasn't created after all.
20168d75effSDimitry Andric     // Clean up everything we set up in BeforeThreadCreateHook.
20268d75effSDimitry Andric     asanThreadRegistry().FinishThread(thread->tid());
20368d75effSDimitry Andric     UnmapOrDie(thread, AsanThreadMmapSize());
20468d75effSDimitry Andric   }
20568d75effSDimitry Andric }
20668d75effSDimitry Andric 
20768d75effSDimitry Andric // This is called in the newly-created thread before it runs anything else,
20868d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
20968d75effSDimitry Andric // cf. asan_interceptors.cpp:asan_thread_start
21068d75effSDimitry Andric static void ThreadStartHook(void *hook, uptr os_id) {
21168d75effSDimitry Andric   AsanThread *thread = static_cast<AsanThread *>(hook);
21268d75effSDimitry Andric   SetCurrentThread(thread);
21368d75effSDimitry Andric 
21468d75effSDimitry Andric   // In lieu of AsanThread::ThreadStart.
21568d75effSDimitry Andric   asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular,
21668d75effSDimitry Andric                                    nullptr);
21768d75effSDimitry Andric }
21868d75effSDimitry Andric 
21968d75effSDimitry Andric // Each thread runs this just before it exits,
22068d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
22168d75effSDimitry Andric // All per-thread destructors have already been called.
22268d75effSDimitry Andric static void ThreadExitHook(void *hook, uptr os_id) {
22368d75effSDimitry Andric   AsanThread::TSDDtor(per_thread);
22468d75effSDimitry Andric }
22568d75effSDimitry Andric 
22668d75effSDimitry Andric bool HandleDlopenInit() {
22768d75effSDimitry Andric   // Not supported on this platform.
22868d75effSDimitry Andric   static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
22968d75effSDimitry Andric                 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
23068d75effSDimitry Andric   return false;
23168d75effSDimitry Andric }
23268d75effSDimitry Andric 
233e8d8bef9SDimitry Andric void FlushUnneededASanShadowMemory(uptr p, uptr size) {
234e8d8bef9SDimitry Andric   __sanitizer_fill_shadow(p, size, 0, 0);
235e8d8bef9SDimitry Andric }
236e8d8bef9SDimitry Andric 
23781ad6265SDimitry Andric // On Fuchsia, leak detection is done by a special hook after atexit hooks.
23881ad6265SDimitry Andric // So this doesn't install any atexit hook like on other platforms.
23981ad6265SDimitry Andric void InstallAtExitCheckLeaks() {}
24081ad6265SDimitry Andric 
241*5f757f3fSDimitry Andric void InstallAtForkHandler() {}
242*5f757f3fSDimitry Andric 
24368d75effSDimitry Andric }  // namespace __asan
24468d75effSDimitry Andric 
24581ad6265SDimitry Andric namespace __lsan {
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric bool UseExitcodeOnLeak() { return __asan::flags()->halt_on_error; }
24881ad6265SDimitry Andric 
24981ad6265SDimitry Andric }  // namespace __lsan
25081ad6265SDimitry 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