hwasan_fuchsia.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. #include "sanitizer_common/sanitizer_fuchsia.h"
  15. #if SANITIZER_FUCHSIA
  16. #include "hwasan.h"
  17. #include "hwasan_interface_internal.h"
  18. #include "hwasan_report.h"
  19. #include "hwasan_thread.h"
  20. #include "hwasan_thread_list.h"
  21. // This TLS variable contains the location of the stack ring buffer and can be
  22. // used to always find the hwasan thread object associated with the current
  23. // running thread.
  24. [[gnu::tls_model("initial-exec")]]
  25. SANITIZER_INTERFACE_ATTRIBUTE
  26. THREADLOCAL uptr __hwasan_tls;
  27. namespace __hwasan {
  28. bool InitShadow() {
  29. __sanitizer::InitShadowBounds();
  30. CHECK_NE(__sanitizer::ShadowBounds.shadow_limit, 0);
  31. // These variables are used by MemIsShadow for asserting we have a correct
  32. // shadow address. On Fuchsia, we only have one region of shadow, so the
  33. // bounds of Low shadow can be zero while High shadow represents the true
  34. // bounds. Note that these are inclusive ranges.
  35. kLowShadowStart = 0;
  36. kLowShadowEnd = 0;
  37. kHighShadowStart = __sanitizer::ShadowBounds.shadow_base;
  38. kHighShadowEnd = __sanitizer::ShadowBounds.shadow_limit - 1;
  39. return true;
  40. }
  41. bool MemIsApp(uptr p) {
  42. CHECK(GetTagFromPointer(p) == 0);
  43. return __sanitizer::ShadowBounds.shadow_limit <= p &&
  44. p <= (__sanitizer::ShadowBounds.memory_limit - 1);
  45. }
  46. // These are known parameters passed to the hwasan runtime on thread creation.
  47. struct Thread::InitState {
  48. uptr stack_bottom, stack_top;
  49. };
  50. static void FinishThreadInitialization(Thread *thread);
  51. void InitThreads() {
  52. // This is the minimal alignment needed for the storage where hwasan threads
  53. // and their stack ring buffers are placed. This alignment is necessary so the
  54. // stack ring buffer can perform a simple calculation to get the next element
  55. // in the RB. The instructions for this calculation are emitted by the
  56. // compiler. (Full explanation in hwasan_thread_list.h.)
  57. uptr alloc_size = UINT64_C(1) << kShadowBaseAlignment;
  58. uptr thread_start = reinterpret_cast<uptr>(
  59. MmapAlignedOrDieOnFatalError(alloc_size, alloc_size, __func__));
  60. InitThreadList(thread_start, alloc_size);
  61. // Create the hwasan thread object for the current (main) thread. Stack info
  62. // for this thread is known from information passed via
  63. // __sanitizer_startup_hook.
  64. const Thread::InitState state = {
  65. .stack_bottom = __sanitizer::MainThreadStackBase,
  66. .stack_top =
  67. __sanitizer::MainThreadStackBase + __sanitizer::MainThreadStackSize,
  68. };
  69. FinishThreadInitialization(hwasanThreadList().CreateCurrentThread(&state));
  70. }
  71. uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; }
  72. // This is called from the parent thread before the new thread is created. Here
  73. // we can propagate known info like the stack bounds to Thread::Init before
  74. // jumping into the thread. We cannot initialize the stack ring buffer yet since
  75. // we have not entered the new thread.
  76. static void *BeforeThreadCreateHook(uptr user_id, bool detached,
  77. const char *name, uptr stack_bottom,
  78. uptr stack_size) {
  79. const Thread::InitState state = {
  80. .stack_bottom = stack_bottom,
  81. .stack_top = stack_bottom + stack_size,
  82. };
  83. return hwasanThreadList().CreateCurrentThread(&state);
  84. }
  85. // This sets the stack top and bottom according to the InitState passed to
  86. // CreateCurrentThread above.
  87. void Thread::InitStackAndTls(const InitState *state) {
  88. CHECK_NE(state->stack_bottom, 0);
  89. CHECK_NE(state->stack_top, 0);
  90. stack_bottom_ = state->stack_bottom;
  91. stack_top_ = state->stack_top;
  92. tls_end_ = tls_begin_ = 0;
  93. }
  94. // This is called after creating a new thread with the pointer returned by
  95. // BeforeThreadCreateHook. We are still in the creating thread and should check
  96. // if it was actually created correctly.
  97. static void ThreadCreateHook(void *hook, bool aborted) {
  98. Thread *thread = static_cast<Thread *>(hook);
  99. if (!aborted) {
  100. // The thread was created successfully.
  101. // ThreadStartHook can already be running in the new thread.
  102. } else {
  103. // The thread wasn't created after all.
  104. // Clean up everything we set up in BeforeThreadCreateHook.
  105. atomic_signal_fence(memory_order_seq_cst);
  106. hwasanThreadList().ReleaseThread(thread);
  107. }
  108. }
  109. // This is called in the newly-created thread before it runs anything else,
  110. // with the pointer returned by BeforeThreadCreateHook (above). Here we can
  111. // setup the stack ring buffer.
  112. static void ThreadStartHook(void *hook, thrd_t self) {
  113. Thread *thread = static_cast<Thread *>(hook);
  114. FinishThreadInitialization(thread);
  115. thread->EnsureRandomStateInited();
  116. }
  117. // This is the function that sets up the stack ring buffer and enables us to use
  118. // GetCurrentThread. This function should only be called while IN the thread
  119. // that we want to create the hwasan thread object for so __hwasan_tls can be
  120. // properly referenced.
  121. static void FinishThreadInitialization(Thread *thread) {
  122. CHECK_NE(thread, nullptr);
  123. // The ring buffer is located immediately before the thread object.
  124. uptr stack_buffer_size = hwasanThreadList().GetRingBufferSize();
  125. uptr stack_buffer_start = reinterpret_cast<uptr>(thread) - stack_buffer_size;
  126. thread->InitStackRingBuffer(stack_buffer_start, stack_buffer_size);
  127. }
  128. static void ThreadExitHook(void *hook, thrd_t self) {
  129. Thread *thread = static_cast<Thread *>(hook);
  130. atomic_signal_fence(memory_order_seq_cst);
  131. hwasanThreadList().ReleaseThread(thread);
  132. }
  133. uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
  134. CHECK(IsAligned(p, kShadowAlignment));
  135. CHECK(IsAligned(size, kShadowAlignment));
  136. __sanitizer_fill_shadow(p, size, tag,
  137. common_flags()->clear_shadow_mmap_threshold);
  138. return AddTagToPointer(p, tag);
  139. }
  140. // Not implemented because Fuchsia does not use signal handlers.
  141. void HwasanOnDeadlySignal(int signo, void *info, void *context) {}
  142. // Not implemented because Fuchsia does not use interceptors.
  143. void InitializeInterceptors() {}
  144. // Not implemented because this is only relevant for Android.
  145. void AndroidTestTlsSlot() {}
  146. // TSD was normally used on linux as a means of calling the hwasan thread exit
  147. // handler passed to pthread_key_create. This is not needed on Fuchsia because
  148. // we will be using __sanitizer_thread_exit_hook.
  149. void HwasanTSDInit() {}
  150. void HwasanTSDThreadInit() {}
  151. // On linux, this just would call `atexit(HwasanAtExit)`. The functions in
  152. // HwasanAtExit are unimplemented for Fuchsia and effectively no-ops, so this
  153. // function is unneeded.
  154. void InstallAtExitHandler() {}
  155. void HwasanInstallAtForkHandler() {}
  156. // TODO(fxbug.dev/81499): Once we finalize the tagged pointer ABI in zircon, we should come back
  157. // here and implement the appropriate check that TBI is enabled.
  158. void InitializeOsSupport() {}
  159. } // namespace __hwasan
  160. extern "C" {
  161. void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
  162. const char *name, void *stack_base,
  163. size_t stack_size) {
  164. return __hwasan::BeforeThreadCreateHook(
  165. reinterpret_cast<uptr>(thread), detached, name,
  166. reinterpret_cast<uptr>(stack_base), stack_size);
  167. }
  168. void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
  169. __hwasan::ThreadCreateHook(hook, error != thrd_success);
  170. }
  171. void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
  172. __hwasan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
  173. }
  174. void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
  175. __hwasan::ThreadExitHook(hook, self);
  176. }
  177. } // extern "C"
  178. #endif // SANITIZER_FUCHSIA