hwasan_interceptors.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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. #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
  17. #include "hwasan.h"
  18. #include "hwasan_allocator.h"
  19. #include "hwasan_checks.h"
  20. #include "hwasan_mapping.h"
  21. #include "hwasan_platform_interceptors.h"
  22. #include "hwasan_thread.h"
  23. #include "hwasan_thread_list.h"
  24. #include "interception/interception.h"
  25. #include "sanitizer_common/sanitizer_errno.h"
  26. #include "sanitizer_common/sanitizer_linux.h"
  27. #include "sanitizer_common/sanitizer_stackdepot.h"
  28. #if !SANITIZER_FUCHSIA
  29. using namespace __hwasan;
  30. struct HWAsanInterceptorContext {
  31. const char *interceptor_name;
  32. };
  33. # define ACCESS_MEMORY_RANGE(offset, size, access) \
  34. do { \
  35. __hwasan::CheckAddressSized<ErrorAction::Recover, access>((uptr)offset, \
  36. size); \
  37. } while (0)
  38. # define HWASAN_READ_RANGE(offset, size) \
  39. ACCESS_MEMORY_RANGE(offset, size, AccessType::Load)
  40. # define HWASAN_WRITE_RANGE(offset, size) \
  41. ACCESS_MEMORY_RANGE(offset, size, AccessType::Store)
  42. # if !SANITIZER_APPLE
  43. # define HWASAN_INTERCEPT_FUNC(name) \
  44. do { \
  45. if (!INTERCEPT_FUNCTION(name)) \
  46. VReport(1, "HWAddressSanitizer: failed to intercept '%s'\n", #name); \
  47. } while (0)
  48. # define HWASAN_INTERCEPT_FUNC_VER(name, ver) \
  49. do { \
  50. if (!INTERCEPT_FUNCTION_VER(name, ver)) \
  51. VReport(1, "HWAddressSanitizer: failed to intercept '%s@@%s'\n", \
  52. #name, ver); \
  53. } while (0)
  54. # define HWASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \
  55. do { \
  56. if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \
  57. VReport( \
  58. 1, "HWAddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \
  59. #name, ver, #name); \
  60. } while (0)
  61. # else
  62. // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
  63. # define HWASAN_INTERCEPT_FUNC(name)
  64. # endif // SANITIZER_APPLE
  65. # if HWASAN_WITH_INTERCEPTORS
  66. # define COMMON_SYSCALL_PRE_READ_RANGE(p, s) HWASAN_READ_RANGE(p, s)
  67. # define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) HWASAN_WRITE_RANGE(p, s)
  68. # define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
  69. do { \
  70. (void)(p); \
  71. (void)(s); \
  72. } while (false)
  73. # define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
  74. do { \
  75. (void)(p); \
  76. (void)(s); \
  77. } while (false)
  78. # include "sanitizer_common/sanitizer_common_syscalls.inc"
  79. # include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
  80. # define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
  81. HWASAN_WRITE_RANGE(ptr, size)
  82. # define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
  83. HWASAN_READ_RANGE(ptr, size)
  84. # define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
  85. HWAsanInterceptorContext _ctx = {#func}; \
  86. ctx = (void *)&_ctx; \
  87. do { \
  88. (void)(ctx); \
  89. (void)(func); \
  90. } while (false)
  91. # define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
  92. do { \
  93. (void)(ctx); \
  94. (void)(path); \
  95. } while (false)
  96. # define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
  97. do { \
  98. (void)(ctx); \
  99. (void)(fd); \
  100. } while (false)
  101. # define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
  102. do { \
  103. (void)(ctx); \
  104. (void)(fd); \
  105. } while (false)
  106. # define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
  107. do { \
  108. (void)(ctx); \
  109. (void)(fd); \
  110. (void)(newfd); \
  111. } while (false)
  112. # define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
  113. do { \
  114. (void)(ctx); \
  115. (void)(name); \
  116. } while (false)
  117. # define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
  118. do { \
  119. (void)(ctx); \
  120. (void)(thread); \
  121. (void)(name); \
  122. } while (false)
  123. # define COMMON_INTERCEPTOR_BLOCK_REAL(name) \
  124. do { \
  125. (void)(name); \
  126. } while (false)
  127. # define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
  128. { \
  129. if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
  130. return internal_memset(dst, v, size); \
  131. COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
  132. if (MemIsApp(UntagAddr(reinterpret_cast<uptr>(dst))) && \
  133. common_flags()->intercept_intrin) \
  134. COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
  135. return REAL(memset)(dst, v, size); \
  136. }
  137. # define COMMON_INTERCEPTOR_STRERROR() \
  138. do { \
  139. } while (false)
  140. # define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
  141. # define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!hwasan_inited)
  142. // The main purpose of the mmap interceptor is to prevent the user from
  143. // allocating on top of shadow pages.
  144. //
  145. // For compatibility, it does not tag pointers, nor does it allow
  146. // MAP_FIXED in combination with a tagged pointer. (Since mmap itself
  147. // will not return a tagged pointer, the tagged pointer must have come
  148. // from elsewhere, such as the secondary allocator, which makes it a
  149. // very odd usecase.)
  150. template <class Mmap>
  151. static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
  152. int prot, int flags, int fd, OFF64_T offset) {
  153. if (addr) {
  154. if (flags & map_fixed) CHECK_EQ(addr, UntagPtr(addr));
  155. addr = UntagPtr(addr);
  156. }
  157. SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
  158. void *end_addr = (char *)addr + (rounded_length - 1);
  159. if (addr && length &&
  160. (!MemIsApp(reinterpret_cast<uptr>(addr)) ||
  161. !MemIsApp(reinterpret_cast<uptr>(end_addr)))) {
  162. // User requested an address that is incompatible with HWASan's
  163. // memory layout. Use a different address if allowed, else fail.
  164. if (flags & map_fixed) {
  165. errno = errno_EINVAL;
  166. return (void *)-1;
  167. } else {
  168. addr = nullptr;
  169. }
  170. }
  171. void *res = real_mmap(addr, length, prot, flags, fd, offset);
  172. if (length && res != (void *)-1) {
  173. uptr beg = reinterpret_cast<uptr>(res);
  174. DCHECK(IsAligned(beg, GetPageSize()));
  175. if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
  176. // Application has attempted to map more memory than is supported by
  177. // HWASan. Act as if we ran out of memory.
  178. internal_munmap(res, length);
  179. errno = errno_ENOMEM;
  180. return (void *)-1;
  181. }
  182. __hwasan::TagMemoryAligned(beg, rounded_length, 0);
  183. }
  184. return res;
  185. }
  186. template <class Munmap>
  187. static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
  188. // We should not tag if munmap fail, but it's to late to tag after
  189. // real_munmap, as the pages could be mmaped by another thread.
  190. uptr beg = reinterpret_cast<uptr>(addr);
  191. if (length && IsAligned(beg, GetPageSize())) {
  192. SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
  193. // Protect from unmapping the shadow.
  194. if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
  195. errno = errno_EINVAL;
  196. return -1;
  197. }
  198. __hwasan::TagMemoryAligned(beg, rounded_length, 0);
  199. }
  200. return real_munmap(addr, length);
  201. }
  202. # define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
  203. fd, offset) \
  204. do { \
  205. (void)(ctx); \
  206. return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \
  207. } while (false)
  208. # define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
  209. do { \
  210. (void)(ctx); \
  211. return munmap_interceptor(REAL(munmap), addr, sz); \
  212. } while (false)
  213. # include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc"
  214. # include "sanitizer_common/sanitizer_common_interceptors.inc"
  215. struct ThreadStartArg {
  216. __sanitizer_sigset_t starting_sigset_;
  217. };
  218. static void *HwasanThreadStartFunc(void *arg) {
  219. __hwasan_thread_enter();
  220. SetSigProcMask(&reinterpret_cast<ThreadStartArg *>(arg)->starting_sigset_,
  221. nullptr);
  222. InternalFree(arg);
  223. auto self = GetThreadSelf();
  224. auto args = hwasanThreadArgRetval().GetArgs(self);
  225. void *retval = (*args.routine)(args.arg_retval);
  226. hwasanThreadArgRetval().Finish(self, retval);
  227. return retval;
  228. }
  229. extern "C" {
  230. int pthread_attr_getdetachstate(void *attr, int *v);
  231. }
  232. INTERCEPTOR(int, pthread_create, void *thread, void *attr,
  233. void *(*callback)(void *), void *param) {
  234. EnsureMainThreadIDIsCorrect();
  235. ScopedTaggingDisabler tagging_disabler;
  236. bool detached = [attr]() {
  237. int d = 0;
  238. return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
  239. }();
  240. ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg));
  241. ScopedBlockSignals block(&A->starting_sigset_);
  242. // ASAN uses the same approach to disable leaks from pthread_create.
  243. # if CAN_SANITIZE_LEAKS
  244. __lsan::ScopedInterceptorDisabler lsan_disabler;
  245. # endif
  246. int result;
  247. hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
  248. result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A);
  249. return result ? 0 : *(uptr *)(thread);
  250. });
  251. if (result != 0)
  252. InternalFree(A);
  253. return result;
  254. }
  255. INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
  256. int result;
  257. hwasanThreadArgRetval().Join((uptr)thread, [&]() {
  258. result = REAL(pthread_join)(thread, retval);
  259. return !result;
  260. });
  261. return result;
  262. }
  263. INTERCEPTOR(int, pthread_detach, void *thread) {
  264. int result;
  265. hwasanThreadArgRetval().Detach((uptr)thread, [&]() {
  266. result = REAL(pthread_detach)(thread);
  267. return !result;
  268. });
  269. return result;
  270. }
  271. INTERCEPTOR(void, pthread_exit, void *retval) {
  272. hwasanThreadArgRetval().Finish(GetThreadSelf(), retval);
  273. REAL(pthread_exit)(retval);
  274. }
  275. # if SANITIZER_GLIBC
  276. INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
  277. int result;
  278. hwasanThreadArgRetval().Join((uptr)thread, [&]() {
  279. result = REAL(pthread_tryjoin_np)(thread, ret);
  280. return !result;
  281. });
  282. return result;
  283. }
  284. INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
  285. const struct timespec *abstime) {
  286. int result;
  287. hwasanThreadArgRetval().Join((uptr)thread, [&]() {
  288. result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
  289. return !result;
  290. });
  291. return result;
  292. }
  293. # endif
  294. DEFINE_REAL_PTHREAD_FUNCTIONS
  295. DEFINE_REAL(int, vfork)
  296. DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
  297. // Get and/or change the set of blocked signals.
  298. extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
  299. __hw_sigset_t *__restrict __oset);
  300. # define SIG_BLOCK 0
  301. # define SIG_SETMASK 2
  302. extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
  303. env[0].__magic = kHwJmpBufMagic;
  304. env[0].__mask_was_saved =
  305. (savemask &&
  306. sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0);
  307. return 0;
  308. }
  309. static void __attribute__((always_inline))
  310. InternalLongjmp(__hw_register_buf env, int retval) {
  311. # if defined(__aarch64__)
  312. constexpr size_t kSpIndex = 13;
  313. # elif defined(__x86_64__)
  314. constexpr size_t kSpIndex = 6;
  315. # elif SANITIZER_RISCV64
  316. constexpr size_t kSpIndex = 13;
  317. # endif
  318. // Clear all memory tags on the stack between here and where we're going.
  319. unsigned long long stack_pointer = env[kSpIndex];
  320. // The stack pointer should never be tagged, so we don't need to clear the
  321. // tag for this function call.
  322. __hwasan_handle_longjmp((void *)stack_pointer);
  323. // Run code for handling a longjmp.
  324. // Need to use a register that isn't going to be loaded from the environment
  325. // buffer -- hence why we need to specify the register to use.
  326. // Must implement this ourselves, since we don't know the order of registers
  327. // in different libc implementations and many implementations mangle the
  328. // stack pointer so we can't use it without knowing the demangling scheme.
  329. # if defined(__aarch64__)
  330. register long int retval_tmp asm("x1") = retval;
  331. register void *env_address asm("x0") = &env[0];
  332. asm volatile(
  333. "ldp x19, x20, [%0, #0<<3];"
  334. "ldp x21, x22, [%0, #2<<3];"
  335. "ldp x23, x24, [%0, #4<<3];"
  336. "ldp x25, x26, [%0, #6<<3];"
  337. "ldp x27, x28, [%0, #8<<3];"
  338. "ldp x29, x30, [%0, #10<<3];"
  339. "ldp d8, d9, [%0, #14<<3];"
  340. "ldp d10, d11, [%0, #16<<3];"
  341. "ldp d12, d13, [%0, #18<<3];"
  342. "ldp d14, d15, [%0, #20<<3];"
  343. "ldr x5, [%0, #13<<3];"
  344. "mov sp, x5;"
  345. // Return the value requested to return through arguments.
  346. // This should be in x1 given what we requested above.
  347. "cmp %1, #0;"
  348. "mov x0, #1;"
  349. "csel x0, %1, x0, ne;"
  350. "br x30;"
  351. : "+r"(env_address)
  352. : "r"(retval_tmp));
  353. # elif defined(__x86_64__)
  354. register long int retval_tmp asm("%rsi") = retval;
  355. register void *env_address asm("%rdi") = &env[0];
  356. asm volatile(
  357. // Restore registers.
  358. "mov (0*8)(%0),%%rbx;"
  359. "mov (1*8)(%0),%%rbp;"
  360. "mov (2*8)(%0),%%r12;"
  361. "mov (3*8)(%0),%%r13;"
  362. "mov (4*8)(%0),%%r14;"
  363. "mov (5*8)(%0),%%r15;"
  364. "mov (6*8)(%0),%%rsp;"
  365. "mov (7*8)(%0),%%rdx;"
  366. // Return 1 if retval is 0.
  367. "mov $1,%%rax;"
  368. "test %1,%1;"
  369. "cmovnz %1,%%rax;"
  370. "jmp *%%rdx;" ::"r"(env_address),
  371. "r"(retval_tmp));
  372. # elif SANITIZER_RISCV64
  373. register long int retval_tmp asm("x11") = retval;
  374. register void *env_address asm("x10") = &env[0];
  375. asm volatile(
  376. "ld ra, 0<<3(%0);"
  377. "ld s0, 1<<3(%0);"
  378. "ld s1, 2<<3(%0);"
  379. "ld s2, 3<<3(%0);"
  380. "ld s3, 4<<3(%0);"
  381. "ld s4, 5<<3(%0);"
  382. "ld s5, 6<<3(%0);"
  383. "ld s6, 7<<3(%0);"
  384. "ld s7, 8<<3(%0);"
  385. "ld s8, 9<<3(%0);"
  386. "ld s9, 10<<3(%0);"
  387. "ld s10, 11<<3(%0);"
  388. "ld s11, 12<<3(%0);"
  389. # if __riscv_float_abi_double
  390. "fld fs0, 14<<3(%0);"
  391. "fld fs1, 15<<3(%0);"
  392. "fld fs2, 16<<3(%0);"
  393. "fld fs3, 17<<3(%0);"
  394. "fld fs4, 18<<3(%0);"
  395. "fld fs5, 19<<3(%0);"
  396. "fld fs6, 20<<3(%0);"
  397. "fld fs7, 21<<3(%0);"
  398. "fld fs8, 22<<3(%0);"
  399. "fld fs9, 23<<3(%0);"
  400. "fld fs10, 24<<3(%0);"
  401. "fld fs11, 25<<3(%0);"
  402. # elif __riscv_float_abi_soft
  403. # else
  404. # error "Unsupported case"
  405. # endif
  406. "ld a4, 13<<3(%0);"
  407. "mv sp, a4;"
  408. // Return the value requested to return through arguments.
  409. // This should be in x11 given what we requested above.
  410. "seqz a0, %1;"
  411. "add a0, a0, %1;"
  412. "ret;"
  413. : "+r"(env_address)
  414. : "r"(retval_tmp));
  415. # endif
  416. }
  417. INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
  418. if (env[0].__magic != kHwJmpBufMagic) {
  419. Printf(
  420. "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
  421. "there is a bug in HWASan.\n");
  422. return REAL(siglongjmp)(env, val);
  423. }
  424. if (env[0].__mask_was_saved)
  425. // Restore the saved signal mask.
  426. (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (__hw_sigset_t *)0);
  427. InternalLongjmp(env[0].__jmpbuf, val);
  428. }
  429. // Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
  430. // _setjmp on start_thread. Hence we have to intercept the longjmp on
  431. // pthread_exit so the __hw_jmp_buf order matches.
  432. INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
  433. if (env[0].__magic != kHwJmpBufMagic)
  434. return REAL(__libc_longjmp)(env, val);
  435. InternalLongjmp(env[0].__jmpbuf, val);
  436. }
  437. INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
  438. if (env[0].__magic != kHwJmpBufMagic) {
  439. Printf(
  440. "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
  441. "there is a bug in HWASan.\n");
  442. return REAL(longjmp)(env, val);
  443. }
  444. InternalLongjmp(env[0].__jmpbuf, val);
  445. }
  446. # undef SIG_BLOCK
  447. # undef SIG_SETMASK
  448. # endif // HWASAN_WITH_INTERCEPTORS
  449. namespace __hwasan {
  450. int OnExit() {
  451. if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
  452. __lsan::HasReportedLeaks()) {
  453. return common_flags()->exitcode;
  454. }
  455. // FIXME: ask frontend whether we need to return failure.
  456. return 0;
  457. }
  458. } // namespace __hwasan
  459. namespace __hwasan {
  460. void InitializeInterceptors() {
  461. static int inited = 0;
  462. CHECK_EQ(inited, 0);
  463. # if HWASAN_WITH_INTERCEPTORS
  464. InitializeCommonInterceptors();
  465. (void)(read_iovec);
  466. (void)(write_iovec);
  467. # if defined(__linux__)
  468. INTERCEPT_FUNCTION(__libc_longjmp);
  469. INTERCEPT_FUNCTION(longjmp);
  470. INTERCEPT_FUNCTION(siglongjmp);
  471. INTERCEPT_FUNCTION(vfork);
  472. # endif // __linux__
  473. INTERCEPT_FUNCTION(pthread_create);
  474. INTERCEPT_FUNCTION(pthread_join);
  475. INTERCEPT_FUNCTION(pthread_detach);
  476. INTERCEPT_FUNCTION(pthread_exit);
  477. # if SANITIZER_GLIBC
  478. INTERCEPT_FUNCTION(pthread_tryjoin_np);
  479. INTERCEPT_FUNCTION(pthread_timedjoin_np);
  480. # endif
  481. # endif
  482. inited = 1;
  483. }
  484. } // namespace __hwasan
  485. #endif // #if !SANITIZER_FUCHSIA