1*68d75effSDimitry Andric //===-- asan_fuchsia.cpp -------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===---------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // Fuchsia-specific details. 12*68d75effSDimitry Andric //===---------------------------------------------------------------------===// 13*68d75effSDimitry Andric 14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_fuchsia.h" 15*68d75effSDimitry Andric #if SANITIZER_FUCHSIA 16*68d75effSDimitry Andric 17*68d75effSDimitry Andric #include "asan_interceptors.h" 18*68d75effSDimitry Andric #include "asan_internal.h" 19*68d75effSDimitry Andric #include "asan_stack.h" 20*68d75effSDimitry Andric #include "asan_thread.h" 21*68d75effSDimitry Andric 22*68d75effSDimitry Andric #include <limits.h> 23*68d75effSDimitry Andric #include <zircon/sanitizer.h> 24*68d75effSDimitry Andric #include <zircon/syscalls.h> 25*68d75effSDimitry Andric #include <zircon/threads.h> 26*68d75effSDimitry Andric 27*68d75effSDimitry Andric namespace __asan { 28*68d75effSDimitry Andric 29*68d75effSDimitry Andric // The system already set up the shadow memory for us. 30*68d75effSDimitry Andric // __sanitizer::GetMaxUserVirtualAddress has already been called by 31*68d75effSDimitry Andric // AsanInitInternal->InitializeHighMemEnd (asan_rtl.cpp). 32*68d75effSDimitry Andric // Just do some additional sanity checks here. 33*68d75effSDimitry Andric void InitializeShadowMemory() { 34*68d75effSDimitry Andric if (Verbosity()) PrintAddressSpaceLayout(); 35*68d75effSDimitry Andric 36*68d75effSDimitry Andric // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address. 37*68d75effSDimitry Andric __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; 38*68d75effSDimitry Andric DCHECK(kLowShadowBeg != kDefaultShadowSentinel); 39*68d75effSDimitry Andric __asan_shadow_memory_dynamic_address = kLowShadowBeg; 40*68d75effSDimitry Andric 41*68d75effSDimitry Andric CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); 42*68d75effSDimitry Andric CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1); 43*68d75effSDimitry Andric CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit); 44*68d75effSDimitry Andric CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base); 45*68d75effSDimitry Andric CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1); 46*68d75effSDimitry Andric CHECK_EQ(kLowShadowEnd, 0); 47*68d75effSDimitry Andric CHECK_EQ(kLowShadowBeg, 0); 48*68d75effSDimitry Andric } 49*68d75effSDimitry Andric 50*68d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 51*68d75effSDimitry Andric UNIMPLEMENTED(); 52*68d75effSDimitry Andric } 53*68d75effSDimitry Andric 54*68d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {} 55*68d75effSDimitry Andric void AsanCheckIncompatibleRT() {} 56*68d75effSDimitry Andric void InitializeAsanInterceptors() {} 57*68d75effSDimitry Andric 58*68d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { return nullptr; } 59*68d75effSDimitry Andric 60*68d75effSDimitry Andric void InitializePlatformExceptionHandlers() {} 61*68d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 62*68d75effSDimitry Andric UNIMPLEMENTED(); 63*68d75effSDimitry Andric } 64*68d75effSDimitry Andric 65*68d75effSDimitry Andric // We can use a plain thread_local variable for TSD. 66*68d75effSDimitry Andric static thread_local void *per_thread; 67*68d75effSDimitry Andric 68*68d75effSDimitry Andric void *AsanTSDGet() { return per_thread; } 69*68d75effSDimitry Andric 70*68d75effSDimitry Andric void AsanTSDSet(void *tsd) { per_thread = tsd; } 71*68d75effSDimitry Andric 72*68d75effSDimitry Andric // There's no initialization needed, and the passed-in destructor 73*68d75effSDimitry Andric // will never be called. Instead, our own thread destruction hook 74*68d75effSDimitry Andric // (below) will call AsanThread::TSDDtor directly. 75*68d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) { 76*68d75effSDimitry Andric DCHECK(destructor == &PlatformTSDDtor); 77*68d75effSDimitry Andric } 78*68d75effSDimitry Andric 79*68d75effSDimitry Andric void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } 80*68d75effSDimitry Andric 81*68d75effSDimitry Andric static inline size_t AsanThreadMmapSize() { 82*68d75effSDimitry Andric return RoundUpTo(sizeof(AsanThread), PAGE_SIZE); 83*68d75effSDimitry Andric } 84*68d75effSDimitry Andric 85*68d75effSDimitry Andric struct AsanThread::InitOptions { 86*68d75effSDimitry Andric uptr stack_bottom, stack_size; 87*68d75effSDimitry Andric }; 88*68d75effSDimitry Andric 89*68d75effSDimitry Andric // Shared setup between thread creation and startup for the initial thread. 90*68d75effSDimitry Andric static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, 91*68d75effSDimitry Andric uptr user_id, bool detached, 92*68d75effSDimitry Andric const char *name, uptr stack_bottom, 93*68d75effSDimitry Andric uptr stack_size) { 94*68d75effSDimitry Andric // In lieu of AsanThread::Create. 95*68d75effSDimitry Andric AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__); 96*68d75effSDimitry Andric 97*68d75effSDimitry Andric AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 98*68d75effSDimitry Andric u32 tid = 99*68d75effSDimitry Andric asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); 100*68d75effSDimitry Andric asanThreadRegistry().SetThreadName(tid, name); 101*68d75effSDimitry Andric 102*68d75effSDimitry Andric // On other systems, AsanThread::Init() is called from the new 103*68d75effSDimitry Andric // thread itself. But on Fuchsia we already know the stack address 104*68d75effSDimitry Andric // range beforehand, so we can do most of the setup right now. 105*68d75effSDimitry Andric const AsanThread::InitOptions options = {stack_bottom, stack_size}; 106*68d75effSDimitry Andric thread->Init(&options); 107*68d75effSDimitry Andric 108*68d75effSDimitry Andric return thread; 109*68d75effSDimitry Andric } 110*68d75effSDimitry Andric 111*68d75effSDimitry Andric // This gets the same arguments passed to Init by CreateAsanThread, above. 112*68d75effSDimitry Andric // We're in the creator thread before the new thread is actually started, 113*68d75effSDimitry Andric // but its stack address range is already known. We don't bother tracking 114*68d75effSDimitry Andric // the static TLS address range because the system itself already uses an 115*68d75effSDimitry Andric // ASan-aware allocator for that. 116*68d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { 117*68d75effSDimitry Andric DCHECK_NE(GetCurrentThread(), this); 118*68d75effSDimitry Andric DCHECK_NE(GetCurrentThread(), nullptr); 119*68d75effSDimitry Andric CHECK_NE(options->stack_bottom, 0); 120*68d75effSDimitry Andric CHECK_NE(options->stack_size, 0); 121*68d75effSDimitry Andric stack_bottom_ = options->stack_bottom; 122*68d75effSDimitry Andric stack_top_ = options->stack_bottom + options->stack_size; 123*68d75effSDimitry Andric } 124*68d75effSDimitry Andric 125*68d75effSDimitry Andric // Called by __asan::AsanInitInternal (asan_rtl.c). 126*68d75effSDimitry Andric AsanThread *CreateMainThread() { 127*68d75effSDimitry Andric thrd_t self = thrd_current(); 128*68d75effSDimitry Andric char name[ZX_MAX_NAME_LEN]; 129*68d75effSDimitry Andric CHECK_NE(__sanitizer::MainThreadStackBase, 0); 130*68d75effSDimitry Andric CHECK_GT(__sanitizer::MainThreadStackSize, 0); 131*68d75effSDimitry Andric AsanThread *t = CreateAsanThread( 132*68d75effSDimitry Andric nullptr, 0, reinterpret_cast<uptr>(self), true, 133*68d75effSDimitry Andric _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name, 134*68d75effSDimitry Andric sizeof(name)) == ZX_OK 135*68d75effSDimitry Andric ? name 136*68d75effSDimitry Andric : nullptr, 137*68d75effSDimitry Andric __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize); 138*68d75effSDimitry Andric SetCurrentThread(t); 139*68d75effSDimitry Andric return t; 140*68d75effSDimitry Andric } 141*68d75effSDimitry Andric 142*68d75effSDimitry Andric // This is called before each thread creation is attempted. So, in 143*68d75effSDimitry Andric // its first call, the calling thread is the initial and sole thread. 144*68d75effSDimitry Andric static void *BeforeThreadCreateHook(uptr user_id, bool detached, 145*68d75effSDimitry Andric const char *name, uptr stack_bottom, 146*68d75effSDimitry Andric uptr stack_size) { 147*68d75effSDimitry Andric EnsureMainThreadIDIsCorrect(); 148*68d75effSDimitry Andric // Strict init-order checking is thread-hostile. 149*68d75effSDimitry Andric if (flags()->strict_init_order) StopInitOrderChecking(); 150*68d75effSDimitry Andric 151*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; 152*68d75effSDimitry Andric u32 parent_tid = GetCurrentTidOrInvalid(); 153*68d75effSDimitry Andric 154*68d75effSDimitry Andric return CreateAsanThread(&stack, parent_tid, user_id, detached, name, 155*68d75effSDimitry Andric stack_bottom, stack_size); 156*68d75effSDimitry Andric } 157*68d75effSDimitry Andric 158*68d75effSDimitry Andric // This is called after creating a new thread (in the creating thread), 159*68d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above). 160*68d75effSDimitry Andric static void ThreadCreateHook(void *hook, bool aborted) { 161*68d75effSDimitry Andric AsanThread *thread = static_cast<AsanThread *>(hook); 162*68d75effSDimitry Andric if (!aborted) { 163*68d75effSDimitry Andric // The thread was created successfully. 164*68d75effSDimitry Andric // ThreadStartHook is already running in the new thread. 165*68d75effSDimitry Andric } else { 166*68d75effSDimitry Andric // The thread wasn't created after all. 167*68d75effSDimitry Andric // Clean up everything we set up in BeforeThreadCreateHook. 168*68d75effSDimitry Andric asanThreadRegistry().FinishThread(thread->tid()); 169*68d75effSDimitry Andric UnmapOrDie(thread, AsanThreadMmapSize()); 170*68d75effSDimitry Andric } 171*68d75effSDimitry Andric } 172*68d75effSDimitry Andric 173*68d75effSDimitry Andric // This is called in the newly-created thread before it runs anything else, 174*68d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above). 175*68d75effSDimitry Andric // cf. asan_interceptors.cpp:asan_thread_start 176*68d75effSDimitry Andric static void ThreadStartHook(void *hook, uptr os_id) { 177*68d75effSDimitry Andric AsanThread *thread = static_cast<AsanThread *>(hook); 178*68d75effSDimitry Andric SetCurrentThread(thread); 179*68d75effSDimitry Andric 180*68d75effSDimitry Andric // In lieu of AsanThread::ThreadStart. 181*68d75effSDimitry Andric asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular, 182*68d75effSDimitry Andric nullptr); 183*68d75effSDimitry Andric } 184*68d75effSDimitry Andric 185*68d75effSDimitry Andric // Each thread runs this just before it exits, 186*68d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above). 187*68d75effSDimitry Andric // All per-thread destructors have already been called. 188*68d75effSDimitry Andric static void ThreadExitHook(void *hook, uptr os_id) { 189*68d75effSDimitry Andric AsanThread::TSDDtor(per_thread); 190*68d75effSDimitry Andric } 191*68d75effSDimitry Andric 192*68d75effSDimitry Andric bool HandleDlopenInit() { 193*68d75effSDimitry Andric // Not supported on this platform. 194*68d75effSDimitry Andric static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 195*68d75effSDimitry Andric "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 196*68d75effSDimitry Andric return false; 197*68d75effSDimitry Andric } 198*68d75effSDimitry Andric 199*68d75effSDimitry Andric } // namespace __asan 200*68d75effSDimitry Andric 201*68d75effSDimitry Andric // These are declared (in extern "C") by <zircon/sanitizer.h>. 202*68d75effSDimitry Andric // The system runtime will call our definitions directly. 203*68d75effSDimitry Andric 204*68d75effSDimitry Andric void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, 205*68d75effSDimitry Andric const char *name, void *stack_base, 206*68d75effSDimitry Andric size_t stack_size) { 207*68d75effSDimitry Andric return __asan::BeforeThreadCreateHook( 208*68d75effSDimitry Andric reinterpret_cast<uptr>(thread), detached, name, 209*68d75effSDimitry Andric reinterpret_cast<uptr>(stack_base), stack_size); 210*68d75effSDimitry Andric } 211*68d75effSDimitry Andric 212*68d75effSDimitry Andric void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { 213*68d75effSDimitry Andric __asan::ThreadCreateHook(hook, error != thrd_success); 214*68d75effSDimitry Andric } 215*68d75effSDimitry Andric 216*68d75effSDimitry Andric void __sanitizer_thread_start_hook(void *hook, thrd_t self) { 217*68d75effSDimitry Andric __asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self)); 218*68d75effSDimitry Andric } 219*68d75effSDimitry Andric 220*68d75effSDimitry Andric void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { 221*68d75effSDimitry Andric __asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self)); 222*68d75effSDimitry Andric } 223*68d75effSDimitry Andric 224*68d75effSDimitry Andric #endif // SANITIZER_FUCHSIA 225