xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/asan/asan_fuchsia.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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