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 "asan_interceptors.h" 1868d75effSDimitry Andric #include "asan_internal.h" 1968d75effSDimitry Andric #include "asan_stack.h" 2068d75effSDimitry Andric #include "asan_thread.h" 2168d75effSDimitry Andric 2268d75effSDimitry Andric #include <limits.h> 2368d75effSDimitry Andric #include <zircon/sanitizer.h> 2468d75effSDimitry Andric #include <zircon/syscalls.h> 2568d75effSDimitry Andric #include <zircon/threads.h> 2668d75effSDimitry Andric 2768d75effSDimitry Andric namespace __asan { 2868d75effSDimitry Andric 2968d75effSDimitry Andric // The system already set up the shadow memory for us. 3068d75effSDimitry Andric // __sanitizer::GetMaxUserVirtualAddress has already been called by 3168d75effSDimitry Andric // AsanInitInternal->InitializeHighMemEnd (asan_rtl.cpp). 3268d75effSDimitry Andric // Just do some additional sanity checks here. 3368d75effSDimitry Andric void InitializeShadowMemory() { 3468d75effSDimitry Andric if (Verbosity()) PrintAddressSpaceLayout(); 3568d75effSDimitry Andric 3668d75effSDimitry Andric // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address. 3768d75effSDimitry Andric __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; 3868d75effSDimitry Andric DCHECK(kLowShadowBeg != kDefaultShadowSentinel); 3968d75effSDimitry Andric __asan_shadow_memory_dynamic_address = kLowShadowBeg; 4068d75effSDimitry Andric 4168d75effSDimitry Andric CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); 4268d75effSDimitry Andric CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1); 4368d75effSDimitry Andric CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit); 4468d75effSDimitry Andric CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base); 4568d75effSDimitry Andric CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1); 4668d75effSDimitry Andric CHECK_EQ(kLowShadowEnd, 0); 4768d75effSDimitry Andric CHECK_EQ(kLowShadowBeg, 0); 4868d75effSDimitry Andric } 4968d75effSDimitry Andric 5068d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 5168d75effSDimitry Andric UNIMPLEMENTED(); 5268d75effSDimitry Andric } 5368d75effSDimitry Andric 5468d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {} 5568d75effSDimitry Andric void AsanCheckIncompatibleRT() {} 5668d75effSDimitry Andric void InitializeAsanInterceptors() {} 5768d75effSDimitry Andric 5868d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { return nullptr; } 5968d75effSDimitry Andric 6068d75effSDimitry Andric void InitializePlatformExceptionHandlers() {} 6168d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 6268d75effSDimitry Andric UNIMPLEMENTED(); 6368d75effSDimitry Andric } 6468d75effSDimitry Andric 65*5ffd83dbSDimitry Andric bool PlatformUnpoisonStacks() { return false; } 66*5ffd83dbSDimitry Andric 6768d75effSDimitry Andric // We can use a plain thread_local variable for TSD. 6868d75effSDimitry Andric static thread_local void *per_thread; 6968d75effSDimitry Andric 7068d75effSDimitry Andric void *AsanTSDGet() { return per_thread; } 7168d75effSDimitry Andric 7268d75effSDimitry Andric void AsanTSDSet(void *tsd) { per_thread = tsd; } 7368d75effSDimitry Andric 7468d75effSDimitry Andric // There's no initialization needed, and the passed-in destructor 7568d75effSDimitry Andric // will never be called. Instead, our own thread destruction hook 7668d75effSDimitry Andric // (below) will call AsanThread::TSDDtor directly. 7768d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) { 7868d75effSDimitry Andric DCHECK(destructor == &PlatformTSDDtor); 7968d75effSDimitry Andric } 8068d75effSDimitry Andric 8168d75effSDimitry Andric void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } 8268d75effSDimitry Andric 8368d75effSDimitry Andric static inline size_t AsanThreadMmapSize() { 8468d75effSDimitry Andric return RoundUpTo(sizeof(AsanThread), PAGE_SIZE); 8568d75effSDimitry Andric } 8668d75effSDimitry Andric 8768d75effSDimitry Andric struct AsanThread::InitOptions { 8868d75effSDimitry Andric uptr stack_bottom, stack_size; 8968d75effSDimitry Andric }; 9068d75effSDimitry Andric 9168d75effSDimitry Andric // Shared setup between thread creation and startup for the initial thread. 9268d75effSDimitry Andric static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, 9368d75effSDimitry Andric uptr user_id, bool detached, 9468d75effSDimitry Andric const char *name, uptr stack_bottom, 9568d75effSDimitry Andric uptr stack_size) { 9668d75effSDimitry Andric // In lieu of AsanThread::Create. 9768d75effSDimitry Andric AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__); 9868d75effSDimitry Andric 9968d75effSDimitry Andric AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 10068d75effSDimitry Andric u32 tid = 10168d75effSDimitry Andric asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); 10268d75effSDimitry Andric asanThreadRegistry().SetThreadName(tid, name); 10368d75effSDimitry Andric 10468d75effSDimitry Andric // On other systems, AsanThread::Init() is called from the new 10568d75effSDimitry Andric // thread itself. But on Fuchsia we already know the stack address 10668d75effSDimitry Andric // range beforehand, so we can do most of the setup right now. 10768d75effSDimitry Andric const AsanThread::InitOptions options = {stack_bottom, stack_size}; 10868d75effSDimitry Andric thread->Init(&options); 10968d75effSDimitry Andric 11068d75effSDimitry Andric return thread; 11168d75effSDimitry Andric } 11268d75effSDimitry Andric 11368d75effSDimitry Andric // This gets the same arguments passed to Init by CreateAsanThread, above. 11468d75effSDimitry Andric // We're in the creator thread before the new thread is actually started, 11568d75effSDimitry Andric // but its stack address range is already known. We don't bother tracking 11668d75effSDimitry Andric // the static TLS address range because the system itself already uses an 11768d75effSDimitry Andric // ASan-aware allocator for that. 11868d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { 11968d75effSDimitry Andric DCHECK_NE(GetCurrentThread(), this); 12068d75effSDimitry Andric DCHECK_NE(GetCurrentThread(), nullptr); 12168d75effSDimitry Andric CHECK_NE(options->stack_bottom, 0); 12268d75effSDimitry Andric CHECK_NE(options->stack_size, 0); 12368d75effSDimitry Andric stack_bottom_ = options->stack_bottom; 12468d75effSDimitry Andric stack_top_ = options->stack_bottom + options->stack_size; 12568d75effSDimitry Andric } 12668d75effSDimitry Andric 12768d75effSDimitry Andric // Called by __asan::AsanInitInternal (asan_rtl.c). 12868d75effSDimitry Andric AsanThread *CreateMainThread() { 12968d75effSDimitry Andric thrd_t self = thrd_current(); 13068d75effSDimitry Andric char name[ZX_MAX_NAME_LEN]; 13168d75effSDimitry Andric CHECK_NE(__sanitizer::MainThreadStackBase, 0); 13268d75effSDimitry Andric CHECK_GT(__sanitizer::MainThreadStackSize, 0); 13368d75effSDimitry Andric AsanThread *t = CreateAsanThread( 13468d75effSDimitry Andric nullptr, 0, reinterpret_cast<uptr>(self), true, 13568d75effSDimitry Andric _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name, 13668d75effSDimitry Andric sizeof(name)) == ZX_OK 13768d75effSDimitry Andric ? name 13868d75effSDimitry Andric : nullptr, 13968d75effSDimitry Andric __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize); 14068d75effSDimitry Andric SetCurrentThread(t); 14168d75effSDimitry Andric return t; 14268d75effSDimitry Andric } 14368d75effSDimitry Andric 14468d75effSDimitry Andric // This is called before each thread creation is attempted. So, in 14568d75effSDimitry Andric // its first call, the calling thread is the initial and sole thread. 14668d75effSDimitry Andric static void *BeforeThreadCreateHook(uptr user_id, bool detached, 14768d75effSDimitry Andric const char *name, uptr stack_bottom, 14868d75effSDimitry Andric uptr stack_size) { 14968d75effSDimitry Andric EnsureMainThreadIDIsCorrect(); 15068d75effSDimitry Andric // Strict init-order checking is thread-hostile. 15168d75effSDimitry Andric if (flags()->strict_init_order) StopInitOrderChecking(); 15268d75effSDimitry Andric 15368d75effSDimitry Andric GET_STACK_TRACE_THREAD; 15468d75effSDimitry Andric u32 parent_tid = GetCurrentTidOrInvalid(); 15568d75effSDimitry Andric 15668d75effSDimitry Andric return CreateAsanThread(&stack, parent_tid, user_id, detached, name, 15768d75effSDimitry Andric stack_bottom, stack_size); 15868d75effSDimitry Andric } 15968d75effSDimitry Andric 16068d75effSDimitry Andric // This is called after creating a new thread (in the creating thread), 16168d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above). 16268d75effSDimitry Andric static void ThreadCreateHook(void *hook, bool aborted) { 16368d75effSDimitry Andric AsanThread *thread = static_cast<AsanThread *>(hook); 16468d75effSDimitry Andric if (!aborted) { 16568d75effSDimitry Andric // The thread was created successfully. 16668d75effSDimitry Andric // ThreadStartHook is already running in the new thread. 16768d75effSDimitry Andric } else { 16868d75effSDimitry Andric // The thread wasn't created after all. 16968d75effSDimitry Andric // Clean up everything we set up in BeforeThreadCreateHook. 17068d75effSDimitry Andric asanThreadRegistry().FinishThread(thread->tid()); 17168d75effSDimitry Andric UnmapOrDie(thread, AsanThreadMmapSize()); 17268d75effSDimitry Andric } 17368d75effSDimitry Andric } 17468d75effSDimitry Andric 17568d75effSDimitry Andric // This is called in the newly-created thread before it runs anything else, 17668d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above). 17768d75effSDimitry Andric // cf. asan_interceptors.cpp:asan_thread_start 17868d75effSDimitry Andric static void ThreadStartHook(void *hook, uptr os_id) { 17968d75effSDimitry Andric AsanThread *thread = static_cast<AsanThread *>(hook); 18068d75effSDimitry Andric SetCurrentThread(thread); 18168d75effSDimitry Andric 18268d75effSDimitry Andric // In lieu of AsanThread::ThreadStart. 18368d75effSDimitry Andric asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular, 18468d75effSDimitry Andric nullptr); 18568d75effSDimitry Andric } 18668d75effSDimitry Andric 18768d75effSDimitry Andric // Each thread runs this just before it exits, 18868d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above). 18968d75effSDimitry Andric // All per-thread destructors have already been called. 19068d75effSDimitry Andric static void ThreadExitHook(void *hook, uptr os_id) { 19168d75effSDimitry Andric AsanThread::TSDDtor(per_thread); 19268d75effSDimitry Andric } 19368d75effSDimitry Andric 19468d75effSDimitry Andric bool HandleDlopenInit() { 19568d75effSDimitry Andric // Not supported on this platform. 19668d75effSDimitry Andric static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 19768d75effSDimitry Andric "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 19868d75effSDimitry Andric return false; 19968d75effSDimitry Andric } 20068d75effSDimitry Andric 20168d75effSDimitry Andric } // namespace __asan 20268d75effSDimitry Andric 20368d75effSDimitry Andric // These are declared (in extern "C") by <zircon/sanitizer.h>. 20468d75effSDimitry Andric // The system runtime will call our definitions directly. 20568d75effSDimitry Andric 20668d75effSDimitry Andric void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, 20768d75effSDimitry Andric const char *name, void *stack_base, 20868d75effSDimitry Andric size_t stack_size) { 20968d75effSDimitry Andric return __asan::BeforeThreadCreateHook( 21068d75effSDimitry Andric reinterpret_cast<uptr>(thread), detached, name, 21168d75effSDimitry Andric reinterpret_cast<uptr>(stack_base), stack_size); 21268d75effSDimitry Andric } 21368d75effSDimitry Andric 21468d75effSDimitry Andric void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { 21568d75effSDimitry Andric __asan::ThreadCreateHook(hook, error != thrd_success); 21668d75effSDimitry Andric } 21768d75effSDimitry Andric 21868d75effSDimitry Andric void __sanitizer_thread_start_hook(void *hook, thrd_t self) { 21968d75effSDimitry Andric __asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self)); 22068d75effSDimitry Andric } 22168d75effSDimitry Andric 22268d75effSDimitry Andric void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { 22368d75effSDimitry Andric __asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self)); 22468d75effSDimitry Andric } 22568d75effSDimitry Andric 22668d75effSDimitry Andric #endif // SANITIZER_FUCHSIA 227