1d89ec533Spatrick //===-- hwasan_fuchsia.cpp --------------------------------------*- C++ -*-===//
2d89ec533Spatrick //
3d89ec533Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d89ec533Spatrick // See https://llvm.org/LICENSE.txt for license information.
5d89ec533Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d89ec533Spatrick //
7d89ec533Spatrick //===----------------------------------------------------------------------===//
8d89ec533Spatrick ///
9d89ec533Spatrick /// \file
10d89ec533Spatrick /// This file is a part of HWAddressSanitizer and contains Fuchsia-specific
11d89ec533Spatrick /// code.
12d89ec533Spatrick ///
13d89ec533Spatrick //===----------------------------------------------------------------------===//
14d89ec533Spatrick
15d89ec533Spatrick #include "sanitizer_common/sanitizer_fuchsia.h"
16d89ec533Spatrick #if SANITIZER_FUCHSIA
17d89ec533Spatrick
18*810390e3Srobert #include <zircon/features.h>
19*810390e3Srobert #include <zircon/syscalls.h>
20*810390e3Srobert
21d89ec533Spatrick #include "hwasan.h"
22d89ec533Spatrick #include "hwasan_interface_internal.h"
23d89ec533Spatrick #include "hwasan_report.h"
24d89ec533Spatrick #include "hwasan_thread.h"
25d89ec533Spatrick #include "hwasan_thread_list.h"
26d89ec533Spatrick
27d89ec533Spatrick // This TLS variable contains the location of the stack ring buffer and can be
28d89ec533Spatrick // used to always find the hwasan thread object associated with the current
29d89ec533Spatrick // running thread.
30d89ec533Spatrick [[gnu::tls_model("initial-exec")]]
31d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE
32d89ec533Spatrick THREADLOCAL uptr __hwasan_tls;
33d89ec533Spatrick
34d89ec533Spatrick namespace __hwasan {
35d89ec533Spatrick
InitShadow()36d89ec533Spatrick bool InitShadow() {
37d89ec533Spatrick __sanitizer::InitShadowBounds();
38d89ec533Spatrick CHECK_NE(__sanitizer::ShadowBounds.shadow_limit, 0);
39d89ec533Spatrick
40d89ec533Spatrick // These variables are used by MemIsShadow for asserting we have a correct
41d89ec533Spatrick // shadow address. On Fuchsia, we only have one region of shadow, so the
42d89ec533Spatrick // bounds of Low shadow can be zero while High shadow represents the true
43d89ec533Spatrick // bounds. Note that these are inclusive ranges.
44d89ec533Spatrick kLowShadowStart = 0;
45d89ec533Spatrick kLowShadowEnd = 0;
46d89ec533Spatrick kHighShadowStart = __sanitizer::ShadowBounds.shadow_base;
47d89ec533Spatrick kHighShadowEnd = __sanitizer::ShadowBounds.shadow_limit - 1;
48d89ec533Spatrick
49d89ec533Spatrick return true;
50d89ec533Spatrick }
51d89ec533Spatrick
MemIsApp(uptr p)52d89ec533Spatrick bool MemIsApp(uptr p) {
53d89ec533Spatrick CHECK(GetTagFromPointer(p) == 0);
54d89ec533Spatrick return __sanitizer::ShadowBounds.shadow_limit <= p &&
55d89ec533Spatrick p <= (__sanitizer::ShadowBounds.memory_limit - 1);
56d89ec533Spatrick }
57d89ec533Spatrick
58d89ec533Spatrick // These are known parameters passed to the hwasan runtime on thread creation.
59d89ec533Spatrick struct Thread::InitState {
60d89ec533Spatrick uptr stack_bottom, stack_top;
61d89ec533Spatrick };
62d89ec533Spatrick
63d89ec533Spatrick static void FinishThreadInitialization(Thread *thread);
64d89ec533Spatrick
InitThreads()65d89ec533Spatrick void InitThreads() {
66d89ec533Spatrick // This is the minimal alignment needed for the storage where hwasan threads
67d89ec533Spatrick // and their stack ring buffers are placed. This alignment is necessary so the
68d89ec533Spatrick // stack ring buffer can perform a simple calculation to get the next element
69d89ec533Spatrick // in the RB. The instructions for this calculation are emitted by the
70d89ec533Spatrick // compiler. (Full explanation in hwasan_thread_list.h.)
71d89ec533Spatrick uptr alloc_size = UINT64_C(1) << kShadowBaseAlignment;
72d89ec533Spatrick uptr thread_start = reinterpret_cast<uptr>(
73d89ec533Spatrick MmapAlignedOrDieOnFatalError(alloc_size, alloc_size, __func__));
74d89ec533Spatrick
75d89ec533Spatrick InitThreadList(thread_start, alloc_size);
76d89ec533Spatrick
77d89ec533Spatrick // Create the hwasan thread object for the current (main) thread. Stack info
78d89ec533Spatrick // for this thread is known from information passed via
79d89ec533Spatrick // __sanitizer_startup_hook.
80d89ec533Spatrick const Thread::InitState state = {
81d89ec533Spatrick .stack_bottom = __sanitizer::MainThreadStackBase,
82d89ec533Spatrick .stack_top =
83d89ec533Spatrick __sanitizer::MainThreadStackBase + __sanitizer::MainThreadStackSize,
84d89ec533Spatrick };
85d89ec533Spatrick FinishThreadInitialization(hwasanThreadList().CreateCurrentThread(&state));
86d89ec533Spatrick }
87d89ec533Spatrick
GetCurrentThreadLongPtr()88d89ec533Spatrick uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; }
89d89ec533Spatrick
90d89ec533Spatrick // This is called from the parent thread before the new thread is created. Here
91d89ec533Spatrick // we can propagate known info like the stack bounds to Thread::Init before
92d89ec533Spatrick // jumping into the thread. We cannot initialize the stack ring buffer yet since
93d89ec533Spatrick // we have not entered the new thread.
BeforeThreadCreateHook(uptr user_id,bool detached,const char * name,uptr stack_bottom,uptr stack_size)94d89ec533Spatrick static void *BeforeThreadCreateHook(uptr user_id, bool detached,
95d89ec533Spatrick const char *name, uptr stack_bottom,
96d89ec533Spatrick uptr stack_size) {
97d89ec533Spatrick const Thread::InitState state = {
98d89ec533Spatrick .stack_bottom = stack_bottom,
99d89ec533Spatrick .stack_top = stack_bottom + stack_size,
100d89ec533Spatrick };
101d89ec533Spatrick return hwasanThreadList().CreateCurrentThread(&state);
102d89ec533Spatrick }
103d89ec533Spatrick
104d89ec533Spatrick // This sets the stack top and bottom according to the InitState passed to
105d89ec533Spatrick // CreateCurrentThread above.
InitStackAndTls(const InitState * state)106d89ec533Spatrick void Thread::InitStackAndTls(const InitState *state) {
107d89ec533Spatrick CHECK_NE(state->stack_bottom, 0);
108d89ec533Spatrick CHECK_NE(state->stack_top, 0);
109d89ec533Spatrick stack_bottom_ = state->stack_bottom;
110d89ec533Spatrick stack_top_ = state->stack_top;
111d89ec533Spatrick tls_end_ = tls_begin_ = 0;
112d89ec533Spatrick }
113d89ec533Spatrick
114d89ec533Spatrick // This is called after creating a new thread with the pointer returned by
115d89ec533Spatrick // BeforeThreadCreateHook. We are still in the creating thread and should check
116d89ec533Spatrick // if it was actually created correctly.
ThreadCreateHook(void * hook,bool aborted)117d89ec533Spatrick static void ThreadCreateHook(void *hook, bool aborted) {
118d89ec533Spatrick Thread *thread = static_cast<Thread *>(hook);
119d89ec533Spatrick if (!aborted) {
120d89ec533Spatrick // The thread was created successfully.
121d89ec533Spatrick // ThreadStartHook can already be running in the new thread.
122d89ec533Spatrick } else {
123d89ec533Spatrick // The thread wasn't created after all.
124d89ec533Spatrick // Clean up everything we set up in BeforeThreadCreateHook.
125d89ec533Spatrick atomic_signal_fence(memory_order_seq_cst);
126d89ec533Spatrick hwasanThreadList().ReleaseThread(thread);
127d89ec533Spatrick }
128d89ec533Spatrick }
129d89ec533Spatrick
130d89ec533Spatrick // This is called in the newly-created thread before it runs anything else,
131d89ec533Spatrick // with the pointer returned by BeforeThreadCreateHook (above). Here we can
132d89ec533Spatrick // setup the stack ring buffer.
ThreadStartHook(void * hook,thrd_t self)133d89ec533Spatrick static void ThreadStartHook(void *hook, thrd_t self) {
134d89ec533Spatrick Thread *thread = static_cast<Thread *>(hook);
135d89ec533Spatrick FinishThreadInitialization(thread);
136*810390e3Srobert thread->EnsureRandomStateInited();
137d89ec533Spatrick }
138d89ec533Spatrick
139d89ec533Spatrick // This is the function that sets up the stack ring buffer and enables us to use
140d89ec533Spatrick // GetCurrentThread. This function should only be called while IN the thread
141d89ec533Spatrick // that we want to create the hwasan thread object for so __hwasan_tls can be
142d89ec533Spatrick // properly referenced.
FinishThreadInitialization(Thread * thread)143d89ec533Spatrick static void FinishThreadInitialization(Thread *thread) {
144d89ec533Spatrick CHECK_NE(thread, nullptr);
145d89ec533Spatrick
146d89ec533Spatrick // The ring buffer is located immediately before the thread object.
147d89ec533Spatrick uptr stack_buffer_size = hwasanThreadList().GetRingBufferSize();
148d89ec533Spatrick uptr stack_buffer_start = reinterpret_cast<uptr>(thread) - stack_buffer_size;
149d89ec533Spatrick thread->InitStackRingBuffer(stack_buffer_start, stack_buffer_size);
150d89ec533Spatrick }
151d89ec533Spatrick
ThreadExitHook(void * hook,thrd_t self)152d89ec533Spatrick static void ThreadExitHook(void *hook, thrd_t self) {
153d89ec533Spatrick Thread *thread = static_cast<Thread *>(hook);
154d89ec533Spatrick atomic_signal_fence(memory_order_seq_cst);
155d89ec533Spatrick hwasanThreadList().ReleaseThread(thread);
156d89ec533Spatrick }
157d89ec533Spatrick
TagMemoryAligned(uptr p,uptr size,tag_t tag)158d89ec533Spatrick uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
159d89ec533Spatrick CHECK(IsAligned(p, kShadowAlignment));
160d89ec533Spatrick CHECK(IsAligned(size, kShadowAlignment));
161d89ec533Spatrick __sanitizer_fill_shadow(p, size, tag,
162d89ec533Spatrick common_flags()->clear_shadow_mmap_threshold);
163d89ec533Spatrick return AddTagToPointer(p, tag);
164d89ec533Spatrick }
165d89ec533Spatrick
166d89ec533Spatrick // Not implemented because Fuchsia does not use signal handlers.
HwasanOnDeadlySignal(int signo,void * info,void * context)167d89ec533Spatrick void HwasanOnDeadlySignal(int signo, void *info, void *context) {}
168d89ec533Spatrick
169d89ec533Spatrick // Not implemented because Fuchsia does not use interceptors.
InitializeInterceptors()170d89ec533Spatrick void InitializeInterceptors() {}
171d89ec533Spatrick
172d89ec533Spatrick // Not implemented because this is only relevant for Android.
AndroidTestTlsSlot()173d89ec533Spatrick void AndroidTestTlsSlot() {}
174d89ec533Spatrick
175d89ec533Spatrick // TSD was normally used on linux as a means of calling the hwasan thread exit
176d89ec533Spatrick // handler passed to pthread_key_create. This is not needed on Fuchsia because
177d89ec533Spatrick // we will be using __sanitizer_thread_exit_hook.
HwasanTSDInit()178d89ec533Spatrick void HwasanTSDInit() {}
HwasanTSDThreadInit()179d89ec533Spatrick void HwasanTSDThreadInit() {}
180d89ec533Spatrick
181d89ec533Spatrick // On linux, this just would call `atexit(HwasanAtExit)`. The functions in
182d89ec533Spatrick // HwasanAtExit are unimplemented for Fuchsia and effectively no-ops, so this
183d89ec533Spatrick // function is unneeded.
InstallAtExitHandler()184d89ec533Spatrick void InstallAtExitHandler() {}
185d89ec533Spatrick
HwasanInstallAtForkHandler()186*810390e3Srobert void HwasanInstallAtForkHandler() {}
187*810390e3Srobert
InstallAtExitCheckLeaks()188*810390e3Srobert void InstallAtExitCheckLeaks() {}
189*810390e3Srobert
InitializeOsSupport()190*810390e3Srobert void InitializeOsSupport() {
191*810390e3Srobert #ifdef __aarch64__
192*810390e3Srobert uint32_t features = 0;
193*810390e3Srobert CHECK_EQ(zx_system_get_features(ZX_FEATURE_KIND_ADDRESS_TAGGING, &features),
194*810390e3Srobert ZX_OK);
195*810390e3Srobert if (!(features & ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI) &&
196*810390e3Srobert flags()->fail_without_syscall_abi) {
197*810390e3Srobert Printf(
198*810390e3Srobert "FATAL: HWAddressSanitizer requires "
199*810390e3Srobert "ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI.\n");
200*810390e3Srobert Die();
201*810390e3Srobert }
202*810390e3Srobert #endif
203*810390e3Srobert }
204d89ec533Spatrick
205d89ec533Spatrick } // namespace __hwasan
206d89ec533Spatrick
207*810390e3Srobert namespace __lsan {
208*810390e3Srobert
UseExitcodeOnLeak()209*810390e3Srobert bool UseExitcodeOnLeak() { return __hwasan::flags()->halt_on_error; }
210*810390e3Srobert
211*810390e3Srobert } // namespace __lsan
212*810390e3Srobert
213d89ec533Spatrick extern "C" {
214d89ec533Spatrick
__sanitizer_before_thread_create_hook(thrd_t thread,bool detached,const char * name,void * stack_base,size_t stack_size)215d89ec533Spatrick void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
216d89ec533Spatrick const char *name, void *stack_base,
217d89ec533Spatrick size_t stack_size) {
218d89ec533Spatrick return __hwasan::BeforeThreadCreateHook(
219d89ec533Spatrick reinterpret_cast<uptr>(thread), detached, name,
220d89ec533Spatrick reinterpret_cast<uptr>(stack_base), stack_size);
221d89ec533Spatrick }
222d89ec533Spatrick
__sanitizer_thread_create_hook(void * hook,thrd_t thread,int error)223d89ec533Spatrick void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
224d89ec533Spatrick __hwasan::ThreadCreateHook(hook, error != thrd_success);
225d89ec533Spatrick }
226d89ec533Spatrick
__sanitizer_thread_start_hook(void * hook,thrd_t self)227d89ec533Spatrick void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
228d89ec533Spatrick __hwasan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
229d89ec533Spatrick }
230d89ec533Spatrick
__sanitizer_thread_exit_hook(void * hook,thrd_t self)231d89ec533Spatrick void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
232d89ec533Spatrick __hwasan::ThreadExitHook(hook, self);
233d89ec533Spatrick }
234d89ec533Spatrick
__sanitizer_module_loaded(const struct dl_phdr_info * info,size_t)235*810390e3Srobert void __sanitizer_module_loaded(const struct dl_phdr_info *info, size_t) {
236*810390e3Srobert __hwasan_library_loaded(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum);
237*810390e3Srobert }
238*810390e3Srobert
239d89ec533Spatrick } // extern "C"
240d89ec533Spatrick
241d89ec533Spatrick #endif // SANITIZER_FUCHSIA
242