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