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