hwasan_interceptors.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. //===-- hwasan_interceptors.cpp -------------------------------------------===//
  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. // This file is a part of HWAddressSanitizer.
  10. //
  11. // Interceptors for standard library functions.
  12. //
  13. // FIXME: move as many interceptors as possible into
  14. // sanitizer_common/sanitizer_common_interceptors.h
  15. //===----------------------------------------------------------------------===//
  16. #include "interception/interception.h"
  17. #include "hwasan.h"
  18. #include "hwasan_thread.h"
  19. #include "sanitizer_common/sanitizer_stackdepot.h"
  20. #if !SANITIZER_FUCHSIA
  21. using namespace __hwasan;
  22. #if HWASAN_WITH_INTERCEPTORS
  23. struct ThreadStartArg {
  24. thread_callback_t callback;
  25. void *param;
  26. };
  27. static void *HwasanThreadStartFunc(void *arg) {
  28. __hwasan_thread_enter();
  29. ThreadStartArg A = *reinterpret_cast<ThreadStartArg*>(arg);
  30. UnmapOrDie(arg, GetPageSizeCached());
  31. return A.callback(A.param);
  32. }
  33. INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
  34. void * param) {
  35. ScopedTaggingDisabler disabler;
  36. ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
  37. GetPageSizeCached(), "pthread_create"));
  38. *A = {callback, param};
  39. int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
  40. return res;
  41. }
  42. INTERCEPTOR(int, pthread_join, void *t, void **arg) {
  43. return REAL(pthread_join)(t, arg);
  44. }
  45. DEFINE_REAL_PTHREAD_FUNCTIONS
  46. DEFINE_REAL(int, vfork)
  47. DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
  48. // Get and/or change the set of blocked signals.
  49. extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
  50. __hw_sigset_t *__restrict __oset);
  51. #define SIG_BLOCK 0
  52. #define SIG_SETMASK 2
  53. extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
  54. env[0].__magic = kHwJmpBufMagic;
  55. env[0].__mask_was_saved =
  56. (savemask && sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0,
  57. &env[0].__saved_mask) == 0);
  58. return 0;
  59. }
  60. static void __attribute__((always_inline))
  61. InternalLongjmp(__hw_register_buf env, int retval) {
  62. # if defined(__aarch64__)
  63. constexpr size_t kSpIndex = 13;
  64. # elif defined(__x86_64__)
  65. constexpr size_t kSpIndex = 6;
  66. # endif
  67. // Clear all memory tags on the stack between here and where we're going.
  68. unsigned long long stack_pointer = env[kSpIndex];
  69. // The stack pointer should never be tagged, so we don't need to clear the
  70. // tag for this function call.
  71. __hwasan_handle_longjmp((void *)stack_pointer);
  72. // Run code for handling a longjmp.
  73. // Need to use a register that isn't going to be loaded from the environment
  74. // buffer -- hence why we need to specify the register to use.
  75. // Must implement this ourselves, since we don't know the order of registers
  76. // in different libc implementations and many implementations mangle the
  77. // stack pointer so we can't use it without knowing the demangling scheme.
  78. # if defined(__aarch64__)
  79. register long int retval_tmp asm("x1") = retval;
  80. register void *env_address asm("x0") = &env[0];
  81. asm volatile("ldp x19, x20, [%0, #0<<3];"
  82. "ldp x21, x22, [%0, #2<<3];"
  83. "ldp x23, x24, [%0, #4<<3];"
  84. "ldp x25, x26, [%0, #6<<3];"
  85. "ldp x27, x28, [%0, #8<<3];"
  86. "ldp x29, x30, [%0, #10<<3];"
  87. "ldp d8, d9, [%0, #14<<3];"
  88. "ldp d10, d11, [%0, #16<<3];"
  89. "ldp d12, d13, [%0, #18<<3];"
  90. "ldp d14, d15, [%0, #20<<3];"
  91. "ldr x5, [%0, #13<<3];"
  92. "mov sp, x5;"
  93. // Return the value requested to return through arguments.
  94. // This should be in x1 given what we requested above.
  95. "cmp %1, #0;"
  96. "mov x0, #1;"
  97. "csel x0, %1, x0, ne;"
  98. "br x30;"
  99. : "+r"(env_address)
  100. : "r"(retval_tmp));
  101. # elif defined(__x86_64__)
  102. register long int retval_tmp asm("%rsi") = retval;
  103. register void *env_address asm("%rdi") = &env[0];
  104. asm volatile(
  105. // Restore registers.
  106. "mov (0*8)(%0),%%rbx;"
  107. "mov (1*8)(%0),%%rbp;"
  108. "mov (2*8)(%0),%%r12;"
  109. "mov (3*8)(%0),%%r13;"
  110. "mov (4*8)(%0),%%r14;"
  111. "mov (5*8)(%0),%%r15;"
  112. "mov (6*8)(%0),%%rsp;"
  113. "mov (7*8)(%0),%%rdx;"
  114. // Return 1 if retval is 0.
  115. "mov $1,%%rax;"
  116. "test %1,%1;"
  117. "cmovnz %1,%%rax;"
  118. "jmp *%%rdx;" ::"r"(env_address),
  119. "r"(retval_tmp));
  120. # endif
  121. }
  122. INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
  123. if (env[0].__magic != kHwJmpBufMagic) {
  124. Printf(
  125. "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
  126. "there is a bug in HWASan.\n");
  127. return REAL(siglongjmp)(env, val);
  128. }
  129. if (env[0].__mask_was_saved)
  130. // Restore the saved signal mask.
  131. (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask,
  132. (__hw_sigset_t *)0);
  133. InternalLongjmp(env[0].__jmpbuf, val);
  134. }
  135. // Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
  136. // _setjmp on start_thread. Hence we have to intercept the longjmp on
  137. // pthread_exit so the __hw_jmp_buf order matches.
  138. INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
  139. if (env[0].__magic != kHwJmpBufMagic)
  140. return REAL(__libc_longjmp)(env, val);
  141. InternalLongjmp(env[0].__jmpbuf, val);
  142. }
  143. INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
  144. if (env[0].__magic != kHwJmpBufMagic) {
  145. Printf(
  146. "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
  147. "there is a bug in HWASan.\n");
  148. return REAL(longjmp)(env, val);
  149. }
  150. InternalLongjmp(env[0].__jmpbuf, val);
  151. }
  152. #undef SIG_BLOCK
  153. #undef SIG_SETMASK
  154. # endif // HWASAN_WITH_INTERCEPTORS
  155. namespace __hwasan {
  156. int OnExit() {
  157. // FIXME: ask frontend whether we need to return failure.
  158. return 0;
  159. }
  160. } // namespace __hwasan
  161. namespace __hwasan {
  162. void InitializeInterceptors() {
  163. static int inited = 0;
  164. CHECK_EQ(inited, 0);
  165. #if HWASAN_WITH_INTERCEPTORS
  166. #if defined(__linux__)
  167. INTERCEPT_FUNCTION(__libc_longjmp);
  168. INTERCEPT_FUNCTION(longjmp);
  169. INTERCEPT_FUNCTION(siglongjmp);
  170. INTERCEPT_FUNCTION(vfork);
  171. #endif // __linux__
  172. INTERCEPT_FUNCTION(pthread_create);
  173. INTERCEPT_FUNCTION(pthread_join);
  174. # endif
  175. inited = 1;
  176. }
  177. } // namespace __hwasan
  178. #endif // #if !SANITIZER_FUCHSIA