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