Home | History | Annotate | Line # | Download | only in hwasan
hwasan_fuchsia.cpp revision 1.1.1.2
      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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 ///
      9 /// \file
     10 /// This file is a part of HWAddressSanitizer and contains Fuchsia-specific
     11 /// code.
     12 ///
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_fuchsia.h"
     16 #if SANITIZER_FUCHSIA
     17 
     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 be
     28 // used to always find the hwasan thread object associated with the current
     29 // running thread.
     30 [[gnu::tls_model("initial-exec")]]
     31 SANITIZER_INTERFACE_ATTRIBUTE
     32 THREADLOCAL uptr __hwasan_tls;
     33 
     34 namespace __hwasan {
     35 
     36 bool InitShadow() {
     37   __sanitizer::InitShadowBounds();
     38   CHECK_NE(__sanitizer::ShadowBounds.shadow_limit, 0);
     39 
     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.
     44   kLowShadowStart = 0;
     45   kLowShadowEnd = 0;
     46   kHighShadowStart = __sanitizer::ShadowBounds.shadow_base;
     47   kHighShadowEnd = __sanitizer::ShadowBounds.shadow_limit - 1;
     48 
     49   return true;
     50 }
     51 
     52 bool MemIsApp(uptr p) {
     53   CHECK(GetTagFromPointer(p) == 0);
     54   return __sanitizer::ShadowBounds.shadow_limit <= p &&
     55          p <= (__sanitizer::ShadowBounds.memory_limit - 1);
     56 }
     57 
     58 // These are known parameters passed to the hwasan runtime on thread creation.
     59 struct Thread::InitState {
     60   uptr stack_bottom, stack_top;
     61 };
     62 
     63 static void FinishThreadInitialization(Thread *thread);
     64 
     65 void InitThreads() {
     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__));
     74 
     75   InitThreadList(thread_start, alloc_size);
     76 
     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,
     82       .stack_top =
     83           __sanitizer::MainThreadStackBase + __sanitizer::MainThreadStackSize,
     84   };
     85   FinishThreadInitialization(hwasanThreadList().CreateCurrentThread(&state));
     86 }
     87 
     88 uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; }
     89 
     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,
     96                                     uptr stack_size) {
     97   const Thread::InitState state = {
     98       .stack_bottom = stack_bottom,
     99       .stack_top = stack_bottom + stack_size,
    100   };
    101   return hwasanThreadList().CreateCurrentThread(&state);
    102 }
    103 
    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;
    112 }
    113 
    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);
    119   if (!aborted) {
    120     // The thread was created successfully.
    121     // ThreadStartHook can already be running in the new thread.
    122   } else {
    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);
    127   }
    128 }
    129 
    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();
    137 }
    138 
    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);
    145 
    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);
    150 }
    151 
    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);
    156 }
    157 
    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);
    164 }
    165 
    166 // Not implemented because Fuchsia does not use signal handlers.
    167 void HwasanOnDeadlySignal(int signo, void *info, void *context) {}
    168 
    169 // Not implemented because Fuchsia does not use interceptors.
    170 void InitializeInterceptors() {}
    171 
    172 // Not implemented because this is only relevant for Android.
    173 void AndroidTestTlsSlot() {}
    174 
    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() {}
    180 
    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() {}
    185 
    186 void HwasanInstallAtForkHandler() {}
    187 
    188 void InstallAtExitCheckLeaks() {}
    189 
    190 void InitializeOsSupport() {
    191 #ifdef __aarch64__
    192   uint32_t features = 0;
    193   CHECK_EQ(zx_system_get_features(ZX_FEATURE_KIND_ADDRESS_TAGGING, &features),
    194            ZX_OK);
    195   if (!(features & ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI) &&
    196       flags()->fail_without_syscall_abi) {
    197     Printf(
    198         "FATAL: HWAddressSanitizer requires "
    199         "ZX_ARM64_FEATURE_ADDRESS_TAGGING_TBI.\n");
    200     Die();
    201   }
    202 #endif
    203 }
    204 
    205 }  // namespace __hwasan
    206 
    207 namespace __lsan {
    208 
    209 bool UseExitcodeOnLeak() { return __hwasan::flags()->halt_on_error; }
    210 
    211 }  // namespace __lsan
    212 
    213 extern "C" {
    214 
    215 void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
    216                                             const char *name, void *stack_base,
    217                                             size_t stack_size) {
    218   return __hwasan::BeforeThreadCreateHook(
    219       reinterpret_cast<uptr>(thread), detached, name,
    220       reinterpret_cast<uptr>(stack_base), stack_size);
    221 }
    222 
    223 void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
    224   __hwasan::ThreadCreateHook(hook, error != thrd_success);
    225 }
    226 
    227 void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
    228   __hwasan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
    229 }
    230 
    231 void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
    232   __hwasan::ThreadExitHook(hook, self);
    233 }
    234 
    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);
    237 }
    238 
    239 }  // extern "C"
    240 
    241 #endif  // SANITIZER_FUCHSIA
    242