brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 647211b Raw
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