Path: blob/main/contrib/llvm-project/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp
35235 views
//===-- hwasan_fuchsia.cpp --------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file is a part of HWAddressSanitizer and contains Fuchsia-specific10/// code.11///12//===----------------------------------------------------------------------===//1314#include "sanitizer_common/sanitizer_fuchsia.h"15#if SANITIZER_FUCHSIA1617#include <zircon/features.h>18#include <zircon/syscalls.h>1920#include "hwasan.h"21#include "hwasan_interface_internal.h"22#include "hwasan_report.h"23#include "hwasan_thread.h"24#include "hwasan_thread_list.h"2526// This TLS variable contains the location of the stack ring buffer and can be27// used to always find the hwasan thread object associated with the current28// running thread.29[[gnu::tls_model("initial-exec")]]30SANITIZER_INTERFACE_ATTRIBUTE31THREADLOCAL uptr __hwasan_tls;3233namespace __hwasan {3435bool InitShadow() {36__sanitizer::InitShadowBounds();37CHECK_NE(__sanitizer::ShadowBounds.shadow_limit, 0);3839// These variables are used by MemIsShadow for asserting we have a correct40// shadow address. On Fuchsia, we only have one region of shadow, so the41// bounds of Low shadow can be zero while High shadow represents the true42// bounds. Note that these are inclusive ranges.43kLowShadowStart = 0;44kLowShadowEnd = 0;45kHighShadowStart = __sanitizer::ShadowBounds.shadow_base;46kHighShadowEnd = __sanitizer::ShadowBounds.shadow_limit - 1;4748return true;49}5051bool MemIsApp(uptr p) {52CHECK(GetTagFromPointer(p) == 0);53return __sanitizer::ShadowBounds.shadow_limit <= p &&54p <= (__sanitizer::ShadowBounds.memory_limit - 1);55}5657// These are known parameters passed to the hwasan runtime on thread creation.58struct Thread::InitState {59uptr stack_bottom, stack_top;60};6162static void FinishThreadInitialization(Thread *thread);6364void InitThreads() {65// This is the minimal alignment needed for the storage where hwasan threads66// and their stack ring buffers are placed. This alignment is necessary so the67// stack ring buffer can perform a simple calculation to get the next element68// in the RB. The instructions for this calculation are emitted by the69// compiler. (Full explanation in hwasan_thread_list.h.)70uptr alloc_size = UINT64_C(1) << kShadowBaseAlignment;71uptr thread_start = reinterpret_cast<uptr>(72MmapAlignedOrDieOnFatalError(alloc_size, alloc_size, __func__));7374InitThreadList(thread_start, alloc_size);7576// Create the hwasan thread object for the current (main) thread. Stack info77// for this thread is known from information passed via78// __sanitizer_startup_hook.79const Thread::InitState state = {80.stack_bottom = __sanitizer::MainThreadStackBase,81.stack_top =82__sanitizer::MainThreadStackBase + __sanitizer::MainThreadStackSize,83};84FinishThreadInitialization(hwasanThreadList().CreateCurrentThread(&state));85}8687uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; }8889// This is called from the parent thread before the new thread is created. Here90// we can propagate known info like the stack bounds to Thread::Init before91// jumping into the thread. We cannot initialize the stack ring buffer yet since92// we have not entered the new thread.93static void *BeforeThreadCreateHook(uptr user_id, bool detached,94const char *name, uptr stack_bottom,95uptr stack_size) {96const Thread::InitState state = {97.stack_bottom = stack_bottom,98.stack_top = stack_bottom + stack_size,99};100return hwasanThreadList().CreateCurrentThread(&state);101}102103// This sets the stack top and bottom according to the InitState passed to104// CreateCurrentThread above.105void Thread::InitStackAndTls(const InitState *state) {106CHECK_NE(state->stack_bottom, 0);107CHECK_NE(state->stack_top, 0);108stack_bottom_ = state->stack_bottom;109stack_top_ = state->stack_top;110tls_end_ = tls_begin_ = 0;111}112113// This is called after creating a new thread with the pointer returned by114// BeforeThreadCreateHook. We are still in the creating thread and should check115// if it was actually created correctly.116static void ThreadCreateHook(void *hook, bool aborted) {117Thread *thread = static_cast<Thread *>(hook);118if (!aborted) {119// The thread was created successfully.120// ThreadStartHook can already be running in the new thread.121} else {122// The thread wasn't created after all.123// Clean up everything we set up in BeforeThreadCreateHook.124atomic_signal_fence(memory_order_seq_cst);125hwasanThreadList().ReleaseThread(thread);126}127}128129// This is called in the newly-created thread before it runs anything else,130// with the pointer returned by BeforeThreadCreateHook (above). Here we can131// setup the stack ring buffer.132static void ThreadStartHook(void *hook, thrd_t self) {133Thread *thread = static_cast<Thread *>(hook);134FinishThreadInitialization(thread);135thread->EnsureRandomStateInited();136}137138// This is the function that sets up the stack ring buffer and enables us to use139// GetCurrentThread. This function should only be called while IN the thread140// that we want to create the hwasan thread object for so __hwasan_tls can be141// properly referenced.142static void FinishThreadInitialization(Thread *thread) {143CHECK_NE(thread, nullptr);144145// The ring buffer is located immediately before the thread object.146uptr stack_buffer_size = hwasanThreadList().GetRingBufferSize();147uptr stack_buffer_start = reinterpret_cast<uptr>(thread) - stack_buffer_size;148thread->InitStackRingBuffer(stack_buffer_start, stack_buffer_size);149}150151static void ThreadExitHook(void *hook, thrd_t self) {152Thread *thread = static_cast<Thread *>(hook);153atomic_signal_fence(memory_order_seq_cst);154hwasanThreadList().ReleaseThread(thread);155}156157uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {158CHECK(IsAligned(p, kShadowAlignment));159CHECK(IsAligned(size, kShadowAlignment));160__sanitizer_fill_shadow(p, size, tag,161common_flags()->clear_shadow_mmap_threshold);162return AddTagToPointer(p, tag);163}164165// Not implemented because Fuchsia does not use signal handlers.166void HwasanOnDeadlySignal(int signo, void *info, void *context) {}167168// Not implemented because Fuchsia does not use interceptors.169void InitializeInterceptors() {}170171// Not implemented because this is only relevant for Android.172void AndroidTestTlsSlot() {}173174// TSD was normally used on linux as a means of calling the hwasan thread exit175// handler passed to pthread_key_create. This is not needed on Fuchsia because176// we will be using __sanitizer_thread_exit_hook.177void HwasanTSDInit() {}178void HwasanTSDThreadInit() {}179180// On linux, this just would call `atexit(HwasanAtExit)`. The functions in181// HwasanAtExit are unimplemented for Fuchsia and effectively no-ops, so this182// function is unneeded.183void InstallAtExitHandler() {}184185void HwasanInstallAtForkHandler() {}186187void InstallAtExitCheckLeaks() {}188189void InitializeOsSupport() {190#ifdef __aarch64__191uint32_t features = 0;192CHECK_EQ(zx_system_get_features(ZX_FEATURE_KIND_ADDRESS_TAGGING, &features),193ZX_OK);194if (!(features & ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI) &&195flags()->fail_without_syscall_abi) {196Printf(197"FATAL: HWAddressSanitizer requires "198"ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI.\n");199Die();200}201#endif202}203204} // namespace __hwasan205206namespace __lsan {207208bool UseExitcodeOnLeak() { return __hwasan::flags()->halt_on_error; }209210} // namespace __lsan211212extern "C" {213214void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,215const char *name, void *stack_base,216size_t stack_size) {217return __hwasan::BeforeThreadCreateHook(218reinterpret_cast<uptr>(thread), detached, name,219reinterpret_cast<uptr>(stack_base), stack_size);220}221222void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {223__hwasan::ThreadCreateHook(hook, error != thrd_success);224}225226void __sanitizer_thread_start_hook(void *hook, thrd_t self) {227__hwasan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));228}229230void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {231__hwasan::ThreadExitHook(hook, self);232}233234void __sanitizer_module_loaded(const struct dl_phdr_info *info, size_t) {235__hwasan_library_loaded(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum);236}237238} // extern "C"239240#endif // SANITIZER_FUCHSIA241242243