251 lines · cpp
1//===-- hwasan_fuchsia.cpp --------------------------------------*- C++ -*-===//2//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file is a part of HWAddressSanitizer and contains Fuchsia-specific11/// code.12///13//===----------------------------------------------------------------------===//14 15#include "sanitizer_common/sanitizer_fuchsia.h"16#if SANITIZER_FUCHSIA17 18#include <zircon/features.h>19#include <zircon/syscalls.h>20 21#include "hwasan.h"22#include "hwasan_interface_internal.h"23#include "hwasan_report.h"24#include "hwasan_thread.h"25#include "hwasan_thread_list.h"26 27// This TLS variable contains the location of the stack ring buffer and can be28// used to always find the hwasan thread object associated with the current29// running thread.30[[gnu::tls_model("initial-exec")]]31SANITIZER_INTERFACE_ATTRIBUTE32THREADLOCAL uptr __hwasan_tls;33 34namespace __sanitizer {35void EarlySanitizerInit() {36 // Setup the hwasan runtime before any `__libc_extensions_init`s are called.37 // This is needed because libraries which define this function (like fdio)38 // may be instrumented and either access `__hwasan_tls` or make runtime calls.39 __hwasan_init();40}41} // namespace __sanitizer42 43namespace __hwasan {44 45bool InitShadow() {46 __sanitizer::InitShadowBounds();47 CHECK_NE(__sanitizer::ShadowBounds.shadow_limit, 0);48 49 // These variables are used by MemIsShadow for asserting we have a correct50 // shadow address. On Fuchsia, we only have one region of shadow, so the51 // bounds of Low shadow can be zero while High shadow represents the true52 // bounds. Note that these are inclusive ranges.53 kLowShadowStart = 0;54 kLowShadowEnd = 0;55 kHighShadowStart = __sanitizer::ShadowBounds.shadow_base;56 kHighShadowEnd = __sanitizer::ShadowBounds.shadow_limit - 1;57 58 return true;59}60 61bool MemIsApp(uptr p) {62 CHECK(GetTagFromPointer(p) == 0);63 return __sanitizer::ShadowBounds.shadow_limit <= p &&64 p <= (__sanitizer::ShadowBounds.memory_limit - 1);65}66 67// These are known parameters passed to the hwasan runtime on thread creation.68struct Thread::InitState {69 uptr stack_bottom, stack_top;70};71 72static void FinishThreadInitialization(Thread *thread);73 74void InitThreads() {75 // This is the minimal alignment needed for the storage where hwasan threads76 // and their stack ring buffers are placed. This alignment is necessary so the77 // stack ring buffer can perform a simple calculation to get the next element78 // in the RB. The instructions for this calculation are emitted by the79 // compiler. (Full explanation in hwasan_thread_list.h.)80 uptr alloc_size = UINT64_C(1) << kShadowBaseAlignment;81 uptr thread_start = reinterpret_cast<uptr>(82 MmapAlignedOrDieOnFatalError(alloc_size, alloc_size, __func__));83 84 InitThreadList(thread_start, alloc_size);85 86 // Create the hwasan thread object for the current (main) thread. Stack info87 // for this thread is known from information passed via88 // __sanitizer_startup_hook.89 const Thread::InitState state = {90 .stack_bottom = __sanitizer::MainThreadStackBase,91 .stack_top =92 __sanitizer::MainThreadStackBase + __sanitizer::MainThreadStackSize,93 };94 FinishThreadInitialization(hwasanThreadList().CreateCurrentThread(&state));95}96 97uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; }98 99// This is called from the parent thread before the new thread is created. Here100// we can propagate known info like the stack bounds to Thread::Init before101// jumping into the thread. We cannot initialize the stack ring buffer yet since102// we have not entered the new thread.103static void *BeforeThreadCreateHook(uptr user_id, bool detached,104 const char *name, uptr stack_bottom,105 uptr stack_size) {106 const Thread::InitState state = {107 .stack_bottom = stack_bottom,108 .stack_top = stack_bottom + stack_size,109 };110 return hwasanThreadList().CreateCurrentThread(&state);111}112 113// This sets the stack top and bottom according to the InitState passed to114// CreateCurrentThread above.115void Thread::InitStackAndTls(const InitState *state) {116 CHECK_NE(state->stack_bottom, 0);117 CHECK_NE(state->stack_top, 0);118 stack_bottom_ = state->stack_bottom;119 stack_top_ = state->stack_top;120 tls_end_ = tls_begin_ = 0;121}122 123// This is called after creating a new thread with the pointer returned by124// BeforeThreadCreateHook. We are still in the creating thread and should check125// if it was actually created correctly.126static void ThreadCreateHook(void *hook, bool aborted) {127 Thread *thread = static_cast<Thread *>(hook);128 if (!aborted) {129 // The thread was created successfully.130 // ThreadStartHook can already be running in the new thread.131 } else {132 // The thread wasn't created after all.133 // Clean up everything we set up in BeforeThreadCreateHook.134 atomic_signal_fence(memory_order_seq_cst);135 hwasanThreadList().ReleaseThread(thread);136 }137}138 139// This is called in the newly-created thread before it runs anything else,140// with the pointer returned by BeforeThreadCreateHook (above). Here we can141// setup the stack ring buffer.142static void ThreadStartHook(void *hook, thrd_t self) {143 Thread *thread = static_cast<Thread *>(hook);144 FinishThreadInitialization(thread);145 thread->EnsureRandomStateInited();146}147 148// This is the function that sets up the stack ring buffer and enables us to use149// GetCurrentThread. This function should only be called while IN the thread150// that we want to create the hwasan thread object for so __hwasan_tls can be151// properly referenced.152static void FinishThreadInitialization(Thread *thread) {153 CHECK_NE(thread, nullptr);154 155 // The ring buffer is located immediately before the thread object.156 uptr stack_buffer_size = hwasanThreadList().GetRingBufferSize();157 uptr stack_buffer_start = reinterpret_cast<uptr>(thread) - stack_buffer_size;158 thread->InitStackRingBuffer(stack_buffer_start, stack_buffer_size);159}160 161static void ThreadExitHook(void *hook, thrd_t self) {162 Thread *thread = static_cast<Thread *>(hook);163 atomic_signal_fence(memory_order_seq_cst);164 hwasanThreadList().ReleaseThread(thread);165}166 167uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {168 CHECK(IsAligned(p, kShadowAlignment));169 CHECK(IsAligned(size, kShadowAlignment));170 __sanitizer_fill_shadow(p, size, tag,171 common_flags()->clear_shadow_mmap_threshold);172 return AddTagToPointer(p, tag);173}174 175// Not implemented because Fuchsia does not use signal handlers.176void HwasanOnDeadlySignal(int signo, void *info, void *context) {}177 178// Not implemented because Fuchsia does not use interceptors.179void InitializeInterceptors() {}180 181// Not implemented because this is only relevant for Android.182void AndroidTestTlsSlot() {}183 184// TSD was normally used on linux as a means of calling the hwasan thread exit185// handler passed to pthread_key_create. This is not needed on Fuchsia because186// we will be using __sanitizer_thread_exit_hook.187void HwasanTSDInit() {}188void HwasanTSDThreadInit() {}189 190// On linux, this just would call `atexit(HwasanAtExit)`. The functions in191// HwasanAtExit are unimplemented for Fuchsia and effectively no-ops, so this192// function is unneeded.193void InstallAtExitHandler() {}194 195void HwasanInstallAtForkHandler() {}196 197void InstallAtExitCheckLeaks() {}198 199void InitializeOsSupport() {200#ifdef __aarch64__201 uint32_t features = 0;202 CHECK_EQ(zx_system_get_features(ZX_FEATURE_KIND_ADDRESS_TAGGING, &features),203 ZX_OK);204 if (!(features & ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI) &&205 flags()->fail_without_syscall_abi) {206 Printf(207 "FATAL: HWAddressSanitizer requires "208 "ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI.\n");209 Die();210 }211#endif212}213 214} // namespace __hwasan215 216namespace __lsan {217 218bool UseExitcodeOnLeak() { return __hwasan::flags()->halt_on_error; }219 220} // namespace __lsan221 222extern "C" {223 224void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,225 const char *name, void *stack_base,226 size_t stack_size) {227 return __hwasan::BeforeThreadCreateHook(228 reinterpret_cast<uptr>(thread), detached, name,229 reinterpret_cast<uptr>(stack_base), stack_size);230}231 232void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {233 __hwasan::ThreadCreateHook(hook, error != thrd_success);234}235 236void __sanitizer_thread_start_hook(void *hook, thrd_t self) {237 __hwasan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));238}239 240void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {241 __hwasan::ThreadExitHook(hook, self);242}243 244void __sanitizer_module_loaded(const struct dl_phdr_info *info, size_t) {245 __hwasan_library_loaded(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum);246}247 248} // extern "C"249 250#endif // SANITIZER_FUCHSIA251