xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_fuchsia.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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() {
34*349cc55cSDimitry Andric   if (Verbosity())
35*349cc55cSDimitry Andric     PrintAddressSpaceLayout();
3668d75effSDimitry Andric 
3768d75effSDimitry Andric   // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address.
3868d75effSDimitry Andric   __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
3968d75effSDimitry Andric   DCHECK(kLowShadowBeg != kDefaultShadowSentinel);
4068d75effSDimitry Andric   __asan_shadow_memory_dynamic_address = kLowShadowBeg;
4168d75effSDimitry Andric 
4268d75effSDimitry Andric   CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
4368d75effSDimitry Andric   CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1);
4468d75effSDimitry Andric   CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit);
4568d75effSDimitry Andric   CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base);
4668d75effSDimitry Andric   CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1);
4768d75effSDimitry Andric   CHECK_EQ(kLowShadowEnd, 0);
4868d75effSDimitry Andric   CHECK_EQ(kLowShadowBeg, 0);
4968d75effSDimitry Andric }
5068d75effSDimitry Andric 
5168d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
5268d75effSDimitry Andric   UNIMPLEMENTED();
5368d75effSDimitry Andric }
5468d75effSDimitry Andric 
5568d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {}
5668d75effSDimitry Andric void AsanCheckIncompatibleRT() {}
5768d75effSDimitry Andric void InitializeAsanInterceptors() {}
5868d75effSDimitry Andric 
5968d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
6068d75effSDimitry Andric 
6168d75effSDimitry Andric void InitializePlatformExceptionHandlers() {}
6268d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
6368d75effSDimitry Andric   UNIMPLEMENTED();
6468d75effSDimitry Andric }
6568d75effSDimitry Andric 
66*349cc55cSDimitry Andric bool PlatformUnpoisonStacks() {
67*349cc55cSDimitry Andric   // The current sp might not point to the default stack. This
68*349cc55cSDimitry Andric   // could be because we are in a crash stack from fuzzing for example.
69*349cc55cSDimitry Andric   // Unpoison the default stack and the current stack page.
70*349cc55cSDimitry Andric   AsanThread *curr_thread = GetCurrentThread();
71*349cc55cSDimitry Andric   CHECK(curr_thread != nullptr);
72*349cc55cSDimitry Andric   uptr top = curr_thread->stack_top();
73*349cc55cSDimitry Andric   uptr bottom = curr_thread->stack_bottom();
74*349cc55cSDimitry Andric   // The default stack grows from top to bottom. (bottom < top).
75*349cc55cSDimitry Andric 
76*349cc55cSDimitry Andric   uptr local_stack = reinterpret_cast<uptr>(__builtin_frame_address(0));
77*349cc55cSDimitry Andric   if (local_stack >= bottom && local_stack <= top) {
78*349cc55cSDimitry Andric     // The current stack is the default stack.
79*349cc55cSDimitry Andric     // We only need to unpoison from where we are using until the end.
80*349cc55cSDimitry Andric     bottom = RoundDownTo(local_stack, GetPageSize());
81*349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "default");
82*349cc55cSDimitry Andric   } else {
83*349cc55cSDimitry Andric     // The current stack is not the default stack.
84*349cc55cSDimitry Andric     // Unpoison the entire default stack and the current stack page.
85*349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "default");
86*349cc55cSDimitry Andric     bottom = RoundDownTo(local_stack, GetPageSize());
87*349cc55cSDimitry Andric     top = bottom + GetPageSize();
88*349cc55cSDimitry Andric     UnpoisonStack(bottom, top, "unknown");
89*349cc55cSDimitry Andric     return true;
90*349cc55cSDimitry Andric   }
91*349cc55cSDimitry Andric 
92*349cc55cSDimitry Andric   return false;
93*349cc55cSDimitry Andric }
945ffd83dbSDimitry Andric 
9568d75effSDimitry Andric // We can use a plain thread_local variable for TSD.
9668d75effSDimitry Andric static thread_local void *per_thread;
9768d75effSDimitry Andric 
9868d75effSDimitry Andric void *AsanTSDGet() { return per_thread; }
9968d75effSDimitry Andric 
10068d75effSDimitry Andric void AsanTSDSet(void *tsd) { per_thread = tsd; }
10168d75effSDimitry Andric 
10268d75effSDimitry Andric // There's no initialization needed, and the passed-in destructor
10368d75effSDimitry Andric // will never be called.  Instead, our own thread destruction hook
10468d75effSDimitry Andric // (below) will call AsanThread::TSDDtor directly.
10568d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
10668d75effSDimitry Andric   DCHECK(destructor == &PlatformTSDDtor);
10768d75effSDimitry Andric }
10868d75effSDimitry Andric 
10968d75effSDimitry Andric void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
11068d75effSDimitry Andric 
11168d75effSDimitry Andric static inline size_t AsanThreadMmapSize() {
112fe6060f1SDimitry Andric   return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
11368d75effSDimitry Andric }
11468d75effSDimitry Andric 
11568d75effSDimitry Andric struct AsanThread::InitOptions {
11668d75effSDimitry Andric   uptr stack_bottom, stack_size;
11768d75effSDimitry Andric };
11868d75effSDimitry Andric 
11968d75effSDimitry Andric // Shared setup between thread creation and startup for the initial thread.
12068d75effSDimitry Andric static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
121*349cc55cSDimitry Andric                                     bool detached, const char *name) {
12268d75effSDimitry Andric   // In lieu of AsanThread::Create.
12368d75effSDimitry Andric   AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
12468d75effSDimitry Andric 
12568d75effSDimitry Andric   AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
126*349cc55cSDimitry Andric   u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
12768d75effSDimitry Andric   asanThreadRegistry().SetThreadName(tid, name);
12868d75effSDimitry Andric 
12968d75effSDimitry Andric   return thread;
13068d75effSDimitry Andric }
13168d75effSDimitry Andric 
13268d75effSDimitry Andric // This gets the same arguments passed to Init by CreateAsanThread, above.
13368d75effSDimitry Andric // We're in the creator thread before the new thread is actually started,
13468d75effSDimitry Andric // but its stack address range is already known.  We don't bother tracking
13568d75effSDimitry Andric // the static TLS address range because the system itself already uses an
13668d75effSDimitry Andric // ASan-aware allocator for that.
13768d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
13868d75effSDimitry Andric   DCHECK_NE(GetCurrentThread(), this);
13968d75effSDimitry Andric   DCHECK_NE(GetCurrentThread(), nullptr);
14068d75effSDimitry Andric   CHECK_NE(options->stack_bottom, 0);
14168d75effSDimitry Andric   CHECK_NE(options->stack_size, 0);
14268d75effSDimitry Andric   stack_bottom_ = options->stack_bottom;
14368d75effSDimitry Andric   stack_top_ = options->stack_bottom + options->stack_size;
14468d75effSDimitry Andric }
14568d75effSDimitry Andric 
14668d75effSDimitry Andric // Called by __asan::AsanInitInternal (asan_rtl.c).
14768d75effSDimitry Andric AsanThread *CreateMainThread() {
14868d75effSDimitry Andric   thrd_t self = thrd_current();
14968d75effSDimitry Andric   char name[ZX_MAX_NAME_LEN];
15068d75effSDimitry Andric   CHECK_NE(__sanitizer::MainThreadStackBase, 0);
15168d75effSDimitry Andric   CHECK_GT(__sanitizer::MainThreadStackSize, 0);
15268d75effSDimitry Andric   AsanThread *t = CreateAsanThread(
153*349cc55cSDimitry Andric       nullptr, 0, true,
15468d75effSDimitry Andric       _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
15568d75effSDimitry Andric                               sizeof(name)) == ZX_OK
15668d75effSDimitry Andric           ? name
157e8d8bef9SDimitry Andric           : nullptr);
158e8d8bef9SDimitry Andric   // We need to set the current thread before calling AsanThread::Init() below,
159e8d8bef9SDimitry Andric   // since it reads the thread ID.
16068d75effSDimitry Andric   SetCurrentThread(t);
161e8d8bef9SDimitry Andric   DCHECK_EQ(t->tid(), 0);
162e8d8bef9SDimitry Andric 
163e8d8bef9SDimitry Andric   const AsanThread::InitOptions options = {__sanitizer::MainThreadStackBase,
164e8d8bef9SDimitry Andric                                            __sanitizer::MainThreadStackSize};
165e8d8bef9SDimitry Andric   t->Init(&options);
166e8d8bef9SDimitry Andric 
16768d75effSDimitry Andric   return t;
16868d75effSDimitry Andric }
16968d75effSDimitry Andric 
17068d75effSDimitry Andric // This is called before each thread creation is attempted.  So, in
17168d75effSDimitry Andric // its first call, the calling thread is the initial and sole thread.
17268d75effSDimitry Andric static void *BeforeThreadCreateHook(uptr user_id, bool detached,
17368d75effSDimitry Andric                                     const char *name, uptr stack_bottom,
17468d75effSDimitry Andric                                     uptr stack_size) {
17568d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
17668d75effSDimitry Andric   // Strict init-order checking is thread-hostile.
177*349cc55cSDimitry Andric   if (flags()->strict_init_order)
178*349cc55cSDimitry Andric     StopInitOrderChecking();
17968d75effSDimitry Andric 
18068d75effSDimitry Andric   GET_STACK_TRACE_THREAD;
18168d75effSDimitry Andric   u32 parent_tid = GetCurrentTidOrInvalid();
18268d75effSDimitry Andric 
183*349cc55cSDimitry Andric   AsanThread *thread = CreateAsanThread(&stack, parent_tid, detached, name);
184e8d8bef9SDimitry Andric 
185e8d8bef9SDimitry Andric   // On other systems, AsanThread::Init() is called from the new
186e8d8bef9SDimitry Andric   // thread itself.  But on Fuchsia we already know the stack address
187e8d8bef9SDimitry Andric   // range beforehand, so we can do most of the setup right now.
188e8d8bef9SDimitry Andric   const AsanThread::InitOptions options = {stack_bottom, stack_size};
189e8d8bef9SDimitry Andric   thread->Init(&options);
190e8d8bef9SDimitry Andric   return thread;
19168d75effSDimitry Andric }
19268d75effSDimitry Andric 
19368d75effSDimitry Andric // This is called after creating a new thread (in the creating thread),
19468d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
19568d75effSDimitry Andric static void ThreadCreateHook(void *hook, bool aborted) {
19668d75effSDimitry Andric   AsanThread *thread = static_cast<AsanThread *>(hook);
19768d75effSDimitry Andric   if (!aborted) {
19868d75effSDimitry Andric     // The thread was created successfully.
19968d75effSDimitry Andric     // ThreadStartHook is already running in the new thread.
20068d75effSDimitry Andric   } else {
20168d75effSDimitry Andric     // The thread wasn't created after all.
20268d75effSDimitry Andric     // Clean up everything we set up in BeforeThreadCreateHook.
20368d75effSDimitry Andric     asanThreadRegistry().FinishThread(thread->tid());
20468d75effSDimitry Andric     UnmapOrDie(thread, AsanThreadMmapSize());
20568d75effSDimitry Andric   }
20668d75effSDimitry Andric }
20768d75effSDimitry Andric 
20868d75effSDimitry Andric // This is called in the newly-created thread before it runs anything else,
20968d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
21068d75effSDimitry Andric // cf. asan_interceptors.cpp:asan_thread_start
21168d75effSDimitry Andric static void ThreadStartHook(void *hook, uptr os_id) {
21268d75effSDimitry Andric   AsanThread *thread = static_cast<AsanThread *>(hook);
21368d75effSDimitry Andric   SetCurrentThread(thread);
21468d75effSDimitry Andric 
21568d75effSDimitry Andric   // In lieu of AsanThread::ThreadStart.
21668d75effSDimitry Andric   asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular,
21768d75effSDimitry Andric                                    nullptr);
21868d75effSDimitry Andric }
21968d75effSDimitry Andric 
22068d75effSDimitry Andric // Each thread runs this just before it exits,
22168d75effSDimitry Andric // with the pointer returned by BeforeThreadCreateHook (above).
22268d75effSDimitry Andric // All per-thread destructors have already been called.
22368d75effSDimitry Andric static void ThreadExitHook(void *hook, uptr os_id) {
22468d75effSDimitry Andric   AsanThread::TSDDtor(per_thread);
22568d75effSDimitry Andric }
22668d75effSDimitry Andric 
22768d75effSDimitry Andric bool HandleDlopenInit() {
22868d75effSDimitry Andric   // Not supported on this platform.
22968d75effSDimitry Andric   static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
23068d75effSDimitry Andric                 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
23168d75effSDimitry Andric   return false;
23268d75effSDimitry Andric }
23368d75effSDimitry Andric 
234e8d8bef9SDimitry Andric void FlushUnneededASanShadowMemory(uptr p, uptr size) {
235e8d8bef9SDimitry Andric   __sanitizer_fill_shadow(p, size, 0, 0);
236e8d8bef9SDimitry Andric }
237e8d8bef9SDimitry Andric 
23868d75effSDimitry Andric }  // namespace __asan
23968d75effSDimitry Andric 
24068d75effSDimitry Andric // These are declared (in extern "C") by <zircon/sanitizer.h>.
24168d75effSDimitry Andric // The system runtime will call our definitions directly.
24268d75effSDimitry Andric 
24368d75effSDimitry Andric void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
24468d75effSDimitry Andric                                             const char *name, void *stack_base,
24568d75effSDimitry Andric                                             size_t stack_size) {
24668d75effSDimitry Andric   return __asan::BeforeThreadCreateHook(
24768d75effSDimitry Andric       reinterpret_cast<uptr>(thread), detached, name,
24868d75effSDimitry Andric       reinterpret_cast<uptr>(stack_base), stack_size);
24968d75effSDimitry Andric }
25068d75effSDimitry Andric 
25168d75effSDimitry Andric void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
25268d75effSDimitry Andric   __asan::ThreadCreateHook(hook, error != thrd_success);
25368d75effSDimitry Andric }
25468d75effSDimitry Andric 
25568d75effSDimitry Andric void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
25668d75effSDimitry Andric   __asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
25768d75effSDimitry Andric }
25868d75effSDimitry Andric 
25968d75effSDimitry Andric void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
26068d75effSDimitry Andric   __asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self));
26168d75effSDimitry Andric }
26268d75effSDimitry Andric 
26368d75effSDimitry Andric #endif  // SANITIZER_FUCHSIA
264