10b57cec5SDimitry Andric //===-- hwasan_interceptors.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of HWAddressSanitizer.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // Interceptors for standard library functions.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // FIXME: move as many interceptors as possible into
140b57cec5SDimitry Andric // sanitizer_common/sanitizer_common_interceptors.h
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric 
1706c3fb27SDimitry Andric #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
1806c3fb27SDimitry Andric 
190b57cec5SDimitry Andric #include "hwasan.h"
2006c3fb27SDimitry Andric #include "hwasan_allocator.h"
2106c3fb27SDimitry Andric #include "hwasan_checks.h"
225f757f3fSDimitry Andric #include "hwasan_mapping.h"
2306c3fb27SDimitry Andric #include "hwasan_platform_interceptors.h"
240b57cec5SDimitry Andric #include "hwasan_thread.h"
2506c3fb27SDimitry Andric #include "hwasan_thread_list.h"
2606c3fb27SDimitry Andric #include "interception/interception.h"
2706c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_errno.h"
2806c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
290b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
300b57cec5SDimitry Andric 
31fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric using namespace __hwasan;
340b57cec5SDimitry Andric 
355f757f3fSDimitry Andric struct HWAsanInterceptorContext {
365f757f3fSDimitry Andric   const char *interceptor_name;
375f757f3fSDimitry Andric };
385f757f3fSDimitry Andric 
395f757f3fSDimitry Andric #  define ACCESS_MEMORY_RANGE(offset, size, access)                           \
405f757f3fSDimitry Andric     do {                                                                      \
415f757f3fSDimitry Andric       __hwasan::CheckAddressSized<ErrorAction::Recover, access>((uptr)offset, \
425f757f3fSDimitry Andric                                                                 size);        \
435f757f3fSDimitry Andric     } while (0)
445f757f3fSDimitry Andric 
455f757f3fSDimitry Andric #  define HWASAN_READ_RANGE(offset, size) \
465f757f3fSDimitry Andric     ACCESS_MEMORY_RANGE(offset, size, AccessType::Load)
475f757f3fSDimitry Andric #  define HWASAN_WRITE_RANGE(offset, size) \
485f757f3fSDimitry Andric     ACCESS_MEMORY_RANGE(offset, size, AccessType::Store)
495f757f3fSDimitry Andric 
5006c3fb27SDimitry Andric #  if !SANITIZER_APPLE
5106c3fb27SDimitry Andric #    define HWASAN_INTERCEPT_FUNC(name)                                        \
5206c3fb27SDimitry Andric       do {                                                                     \
5306c3fb27SDimitry Andric         if (!INTERCEPT_FUNCTION(name))                                         \
5406c3fb27SDimitry Andric           VReport(1, "HWAddressSanitizer: failed to intercept '%s'\n", #name); \
5506c3fb27SDimitry Andric       } while (0)
5606c3fb27SDimitry Andric #    define HWASAN_INTERCEPT_FUNC_VER(name, ver)                           \
5706c3fb27SDimitry Andric       do {                                                                 \
5806c3fb27SDimitry Andric         if (!INTERCEPT_FUNCTION_VER(name, ver))                            \
5906c3fb27SDimitry Andric           VReport(1, "HWAddressSanitizer: failed to intercept '%s@@%s'\n", \
6006c3fb27SDimitry Andric                   #name, ver);                                             \
6106c3fb27SDimitry Andric       } while (0)
6206c3fb27SDimitry Andric #    define HWASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)          \
6306c3fb27SDimitry Andric       do {                                                                     \
6406c3fb27SDimitry Andric         if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name))   \
6506c3fb27SDimitry Andric           VReport(                                                             \
6606c3fb27SDimitry Andric               1, "HWAddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \
6706c3fb27SDimitry Andric               #name, ver, #name);                                              \
6806c3fb27SDimitry Andric       } while (0)
6906c3fb27SDimitry Andric 
7006c3fb27SDimitry Andric #  else
7106c3fb27SDimitry Andric // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
7206c3fb27SDimitry Andric #    define HWASAN_INTERCEPT_FUNC(name)
7306c3fb27SDimitry Andric #  endif  // SANITIZER_APPLE
7406c3fb27SDimitry Andric 
750b57cec5SDimitry Andric #  if HWASAN_WITH_INTERCEPTORS
760b57cec5SDimitry Andric 
775f757f3fSDimitry Andric #    define COMMON_SYSCALL_PRE_READ_RANGE(p, s) HWASAN_READ_RANGE(p, s)
785f757f3fSDimitry Andric #    define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) HWASAN_WRITE_RANGE(p, s)
7906c3fb27SDimitry Andric #    define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
8006c3fb27SDimitry Andric       do {                                       \
8106c3fb27SDimitry Andric         (void)(p);                               \
8206c3fb27SDimitry Andric         (void)(s);                               \
8306c3fb27SDimitry Andric       } while (false)
8406c3fb27SDimitry Andric #    define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
8506c3fb27SDimitry Andric       do {                                        \
8606c3fb27SDimitry Andric         (void)(p);                                \
8706c3fb27SDimitry Andric         (void)(s);                                \
8806c3fb27SDimitry Andric       } while (false)
8906c3fb27SDimitry Andric #    include "sanitizer_common/sanitizer_common_syscalls.inc"
9006c3fb27SDimitry Andric #    include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
935f757f3fSDimitry Andric       HWASAN_WRITE_RANGE(ptr, size)
9406c3fb27SDimitry Andric 
9506c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
965f757f3fSDimitry Andric       HWASAN_READ_RANGE(ptr, size)
9706c3fb27SDimitry Andric 
9806c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
995f757f3fSDimitry Andric       HWAsanInterceptorContext _ctx = {#func};       \
1005f757f3fSDimitry Andric       ctx = (void *)&_ctx;                           \
10106c3fb27SDimitry Andric       do {                                           \
10206c3fb27SDimitry Andric         (void)(ctx);                                 \
10306c3fb27SDimitry Andric         (void)(func);                                \
10406c3fb27SDimitry Andric       } while (false)
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
10706c3fb27SDimitry Andric       do {                                            \
10806c3fb27SDimitry Andric         (void)(ctx);                                  \
10906c3fb27SDimitry Andric         (void)(path);                                 \
11006c3fb27SDimitry Andric       } while (false)
11106c3fb27SDimitry Andric 
11206c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
11306c3fb27SDimitry Andric       do {                                         \
11406c3fb27SDimitry Andric         (void)(ctx);                               \
11506c3fb27SDimitry Andric         (void)(fd);                                \
11606c3fb27SDimitry Andric       } while (false)
11706c3fb27SDimitry Andric 
11806c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
11906c3fb27SDimitry Andric       do {                                         \
12006c3fb27SDimitry Andric         (void)(ctx);                               \
12106c3fb27SDimitry Andric         (void)(fd);                                \
12206c3fb27SDimitry Andric       } while (false)
12306c3fb27SDimitry Andric 
12406c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
12506c3fb27SDimitry Andric       do {                                                      \
12606c3fb27SDimitry Andric         (void)(ctx);                                            \
12706c3fb27SDimitry Andric         (void)(fd);                                             \
12806c3fb27SDimitry Andric         (void)(newfd);                                          \
12906c3fb27SDimitry Andric       } while (false)
13006c3fb27SDimitry Andric 
13106c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
13206c3fb27SDimitry Andric       do {                                                \
13306c3fb27SDimitry Andric         (void)(ctx);                                      \
13406c3fb27SDimitry Andric         (void)(name);                                     \
13506c3fb27SDimitry Andric       } while (false)
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
13806c3fb27SDimitry Andric       do {                                                         \
13906c3fb27SDimitry Andric         (void)(ctx);                                               \
14006c3fb27SDimitry Andric         (void)(thread);                                            \
14106c3fb27SDimitry Andric         (void)(name);                                              \
14206c3fb27SDimitry Andric       } while (false)
14306c3fb27SDimitry Andric 
14406c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_BLOCK_REAL(name) \
14506c3fb27SDimitry Andric       do {                                      \
14606c3fb27SDimitry Andric         (void)(name);                           \
14706c3fb27SDimitry Andric       } while (false)
14806c3fb27SDimitry Andric 
1495f757f3fSDimitry Andric #    define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size)   \
1505f757f3fSDimitry Andric       {                                                         \
1515f757f3fSDimitry Andric         if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)          \
1525f757f3fSDimitry Andric           return internal_memset(dst, v, size);                 \
1535f757f3fSDimitry Andric         COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size);    \
1545f757f3fSDimitry Andric         if (MemIsApp(UntagAddr(reinterpret_cast<uptr>(dst))) && \
1555f757f3fSDimitry Andric             common_flags()->intercept_intrin)                   \
1565f757f3fSDimitry Andric           COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);       \
1575f757f3fSDimitry Andric         return REAL(memset)(dst, v, size);                      \
1585f757f3fSDimitry Andric       }
15906c3fb27SDimitry Andric 
16006c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_STRERROR() \
16106c3fb27SDimitry Andric       do {                                \
16206c3fb27SDimitry Andric       } while (false)
16306c3fb27SDimitry Andric 
16406c3fb27SDimitry Andric #    define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
16506c3fb27SDimitry Andric 
16606c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!hwasan_inited)
16706c3fb27SDimitry Andric 
16806c3fb27SDimitry Andric // The main purpose of the mmap interceptor is to prevent the user from
16906c3fb27SDimitry Andric // allocating on top of shadow pages.
17006c3fb27SDimitry Andric //
17106c3fb27SDimitry Andric // For compatibility, it does not tag pointers, nor does it allow
17206c3fb27SDimitry Andric // MAP_FIXED in combination with a tagged pointer. (Since mmap itself
17306c3fb27SDimitry Andric // will not return a tagged pointer, the tagged pointer must have come
17406c3fb27SDimitry Andric // from elsewhere, such as the secondary allocator, which makes it a
17506c3fb27SDimitry Andric // very odd usecase.)
17606c3fb27SDimitry Andric template <class Mmap>
mmap_interceptor(Mmap real_mmap,void * addr,SIZE_T length,int prot,int flags,int fd,OFF64_T offset)17706c3fb27SDimitry Andric static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
17806c3fb27SDimitry Andric                               int prot, int flags, int fd, OFF64_T offset) {
17906c3fb27SDimitry Andric   if (addr) {
18006c3fb27SDimitry Andric     if (flags & map_fixed) CHECK_EQ(addr, UntagPtr(addr));
18106c3fb27SDimitry Andric 
18206c3fb27SDimitry Andric     addr = UntagPtr(addr);
18306c3fb27SDimitry Andric   }
18406c3fb27SDimitry Andric   SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
18506c3fb27SDimitry Andric   void *end_addr = (char *)addr + (rounded_length - 1);
18606c3fb27SDimitry Andric   if (addr && length &&
18706c3fb27SDimitry Andric       (!MemIsApp(reinterpret_cast<uptr>(addr)) ||
18806c3fb27SDimitry Andric        !MemIsApp(reinterpret_cast<uptr>(end_addr)))) {
18906c3fb27SDimitry Andric     // User requested an address that is incompatible with HWASan's
19006c3fb27SDimitry Andric     // memory layout. Use a different address if allowed, else fail.
19106c3fb27SDimitry Andric     if (flags & map_fixed) {
19206c3fb27SDimitry Andric       errno = errno_EINVAL;
19306c3fb27SDimitry Andric       return (void *)-1;
19406c3fb27SDimitry Andric     } else {
19506c3fb27SDimitry Andric       addr = nullptr;
19606c3fb27SDimitry Andric     }
19706c3fb27SDimitry Andric   }
19806c3fb27SDimitry Andric   void *res = real_mmap(addr, length, prot, flags, fd, offset);
19906c3fb27SDimitry Andric   if (length && res != (void *)-1) {
20006c3fb27SDimitry Andric     uptr beg = reinterpret_cast<uptr>(res);
20106c3fb27SDimitry Andric     DCHECK(IsAligned(beg, GetPageSize()));
20206c3fb27SDimitry Andric     if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
20306c3fb27SDimitry Andric       // Application has attempted to map more memory than is supported by
20406c3fb27SDimitry Andric       // HWASan. Act as if we ran out of memory.
20506c3fb27SDimitry Andric       internal_munmap(res, length);
20606c3fb27SDimitry Andric       errno = errno_ENOMEM;
20706c3fb27SDimitry Andric       return (void *)-1;
20806c3fb27SDimitry Andric     }
20906c3fb27SDimitry Andric     __hwasan::TagMemoryAligned(beg, rounded_length, 0);
21006c3fb27SDimitry Andric   }
21106c3fb27SDimitry Andric 
21206c3fb27SDimitry Andric   return res;
21306c3fb27SDimitry Andric }
21406c3fb27SDimitry Andric 
21506c3fb27SDimitry Andric template <class Munmap>
munmap_interceptor(Munmap real_munmap,void * addr,SIZE_T length)21606c3fb27SDimitry Andric static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
21706c3fb27SDimitry Andric   // We should not tag if munmap fail, but it's to late to tag after
21806c3fb27SDimitry Andric   // real_munmap, as the pages could be mmaped by another thread.
21906c3fb27SDimitry Andric   uptr beg = reinterpret_cast<uptr>(addr);
22006c3fb27SDimitry Andric   if (length && IsAligned(beg, GetPageSize())) {
22106c3fb27SDimitry Andric     SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
22206c3fb27SDimitry Andric     // Protect from unmapping the shadow.
22306c3fb27SDimitry Andric     if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
22406c3fb27SDimitry Andric       errno = errno_EINVAL;
22506c3fb27SDimitry Andric       return -1;
22606c3fb27SDimitry Andric     }
22706c3fb27SDimitry Andric     __hwasan::TagMemoryAligned(beg, rounded_length, 0);
22806c3fb27SDimitry Andric   }
22906c3fb27SDimitry Andric   return real_munmap(addr, length);
23006c3fb27SDimitry Andric }
23106c3fb27SDimitry Andric 
23206c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
23306c3fb27SDimitry Andric                                          fd, offset)                           \
23406c3fb27SDimitry Andric       do {                                                                     \
23506c3fb27SDimitry Andric         (void)(ctx);                                                           \
23606c3fb27SDimitry Andric         return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off);   \
23706c3fb27SDimitry Andric       } while (false)
23806c3fb27SDimitry Andric 
23906c3fb27SDimitry Andric #    define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length)          \
24006c3fb27SDimitry Andric       do {                                                             \
24106c3fb27SDimitry Andric         (void)(ctx);                                                   \
24206c3fb27SDimitry Andric         return munmap_interceptor(REAL(munmap), addr, sz);             \
24306c3fb27SDimitry Andric       } while (false)
24406c3fb27SDimitry Andric 
24506c3fb27SDimitry Andric #    include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc"
24606c3fb27SDimitry Andric #    include "sanitizer_common/sanitizer_common_interceptors.inc"
24706c3fb27SDimitry Andric 
248480093f4SDimitry Andric struct ThreadStartArg {
24906c3fb27SDimitry Andric   __sanitizer_sigset_t starting_sigset_;
250480093f4SDimitry Andric };
2510b57cec5SDimitry Andric 
HwasanThreadStartFunc(void * arg)252480093f4SDimitry Andric static void *HwasanThreadStartFunc(void *arg) {
253480093f4SDimitry Andric   __hwasan_thread_enter();
25406c3fb27SDimitry Andric   SetSigProcMask(&reinterpret_cast<ThreadStartArg *>(arg)->starting_sigset_,
25506c3fb27SDimitry Andric                  nullptr);
25606c3fb27SDimitry Andric   InternalFree(arg);
25706c3fb27SDimitry Andric   auto self = GetThreadSelf();
25806c3fb27SDimitry Andric   auto args = hwasanThreadArgRetval().GetArgs(self);
25906c3fb27SDimitry Andric   void *retval = (*args.routine)(args.arg_retval);
26006c3fb27SDimitry Andric   hwasanThreadArgRetval().Finish(self, retval);
26106c3fb27SDimitry Andric   return retval;
262480093f4SDimitry Andric }
263480093f4SDimitry Andric 
26406c3fb27SDimitry Andric extern "C" {
26506c3fb27SDimitry Andric int pthread_attr_getdetachstate(void *attr, int *v);
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric 
INTERCEPTOR(int,pthread_create,void * thread,void * attr,void * (* callback)(void *),void * param)26806c3fb27SDimitry Andric INTERCEPTOR(int, pthread_create, void *thread, void *attr,
26906c3fb27SDimitry Andric             void *(*callback)(void *), void *param) {
27006c3fb27SDimitry Andric   EnsureMainThreadIDIsCorrect();
27106c3fb27SDimitry Andric   ScopedTaggingDisabler tagging_disabler;
27206c3fb27SDimitry Andric   bool detached = [attr]() {
27306c3fb27SDimitry Andric     int d = 0;
27406c3fb27SDimitry Andric     return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
27506c3fb27SDimitry Andric   }();
27606c3fb27SDimitry Andric   ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg));
27706c3fb27SDimitry Andric   ScopedBlockSignals block(&A->starting_sigset_);
27806c3fb27SDimitry Andric   // ASAN uses the same approach to disable leaks from pthread_create.
27906c3fb27SDimitry Andric #    if CAN_SANITIZE_LEAKS
28006c3fb27SDimitry Andric   __lsan::ScopedInterceptorDisabler lsan_disabler;
28106c3fb27SDimitry Andric #    endif
28206c3fb27SDimitry Andric 
28306c3fb27SDimitry Andric   int result;
28406c3fb27SDimitry Andric   hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
28506c3fb27SDimitry Andric     result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A);
28606c3fb27SDimitry Andric     return result ? 0 : *(uptr *)(thread);
28706c3fb27SDimitry Andric   });
28806c3fb27SDimitry Andric   if (result != 0)
28906c3fb27SDimitry Andric     InternalFree(A);
29006c3fb27SDimitry Andric   return result;
2910eae32dcSDimitry Andric }
2920eae32dcSDimitry Andric 
INTERCEPTOR(int,pthread_join,void * thread,void ** retval)29306c3fb27SDimitry Andric INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
29406c3fb27SDimitry Andric   int result;
29506c3fb27SDimitry Andric   hwasanThreadArgRetval().Join((uptr)thread, [&]() {
29606c3fb27SDimitry Andric     result = REAL(pthread_join)(thread, retval);
29706c3fb27SDimitry Andric     return !result;
29806c3fb27SDimitry Andric   });
29906c3fb27SDimitry Andric   return result;
30006c3fb27SDimitry Andric }
30106c3fb27SDimitry Andric 
INTERCEPTOR(int,pthread_detach,void * thread)30206c3fb27SDimitry Andric INTERCEPTOR(int, pthread_detach, void *thread) {
30306c3fb27SDimitry Andric   int result;
30406c3fb27SDimitry Andric   hwasanThreadArgRetval().Detach((uptr)thread, [&]() {
30506c3fb27SDimitry Andric     result = REAL(pthread_detach)(thread);
30606c3fb27SDimitry Andric     return !result;
30706c3fb27SDimitry Andric   });
30806c3fb27SDimitry Andric   return result;
30906c3fb27SDimitry Andric }
31006c3fb27SDimitry Andric 
INTERCEPTOR(void,pthread_exit,void * retval)3115f757f3fSDimitry Andric INTERCEPTOR(void, pthread_exit, void *retval) {
31206c3fb27SDimitry Andric   hwasanThreadArgRetval().Finish(GetThreadSelf(), retval);
3135f757f3fSDimitry Andric   REAL(pthread_exit)(retval);
31406c3fb27SDimitry Andric }
31506c3fb27SDimitry Andric 
31606c3fb27SDimitry Andric #    if SANITIZER_GLIBC
INTERCEPTOR(int,pthread_tryjoin_np,void * thread,void ** ret)31706c3fb27SDimitry Andric INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
31806c3fb27SDimitry Andric   int result;
31906c3fb27SDimitry Andric   hwasanThreadArgRetval().Join((uptr)thread, [&]() {
32006c3fb27SDimitry Andric     result = REAL(pthread_tryjoin_np)(thread, ret);
32106c3fb27SDimitry Andric     return !result;
32206c3fb27SDimitry Andric   });
32306c3fb27SDimitry Andric   return result;
32406c3fb27SDimitry Andric }
32506c3fb27SDimitry Andric 
INTERCEPTOR(int,pthread_timedjoin_np,void * thread,void ** ret,const struct timespec * abstime)32606c3fb27SDimitry Andric INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
32706c3fb27SDimitry Andric             const struct timespec *abstime) {
32806c3fb27SDimitry Andric   int result;
32906c3fb27SDimitry Andric   hwasanThreadArgRetval().Join((uptr)thread, [&]() {
33006c3fb27SDimitry Andric     result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
33106c3fb27SDimitry Andric     return !result;
33206c3fb27SDimitry Andric   });
33306c3fb27SDimitry Andric   return result;
33406c3fb27SDimitry Andric }
33506c3fb27SDimitry Andric #    endif
33606c3fb27SDimitry Andric 
3370eae32dcSDimitry Andric DEFINE_REAL_PTHREAD_FUNCTIONS
3380eae32dcSDimitry Andric 
3390b57cec5SDimitry Andric DEFINE_REAL(int, vfork)
3400b57cec5SDimitry Andric DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
341480093f4SDimitry Andric 
342480093f4SDimitry Andric // Get and/or change the set of blocked signals.
343480093f4SDimitry Andric extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
344480093f4SDimitry Andric                            __hw_sigset_t *__restrict __oset);
345480093f4SDimitry Andric #    define SIG_BLOCK 0
346480093f4SDimitry Andric #    define SIG_SETMASK 2
__sigjmp_save(__hw_sigjmp_buf env,int savemask)347480093f4SDimitry Andric extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
348349cc55cSDimitry Andric   env[0].__magic = kHwJmpBufMagic;
349480093f4SDimitry Andric   env[0].__mask_was_saved =
35006c3fb27SDimitry Andric       (savemask &&
35106c3fb27SDimitry Andric        sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0);
352480093f4SDimitry Andric   return 0;
353480093f4SDimitry Andric }
354480093f4SDimitry Andric 
355480093f4SDimitry Andric static void __attribute__((always_inline))
InternalLongjmp(__hw_register_buf env,int retval)356480093f4SDimitry Andric InternalLongjmp(__hw_register_buf env, int retval) {
357349cc55cSDimitry Andric #    if defined(__aarch64__)
358349cc55cSDimitry Andric   constexpr size_t kSpIndex = 13;
359349cc55cSDimitry Andric #    elif defined(__x86_64__)
360349cc55cSDimitry Andric   constexpr size_t kSpIndex = 6;
361bdd1243dSDimitry Andric #    elif SANITIZER_RISCV64
362bdd1243dSDimitry Andric   constexpr size_t kSpIndex = 13;
363349cc55cSDimitry Andric #    endif
364349cc55cSDimitry Andric 
365480093f4SDimitry Andric   // Clear all memory tags on the stack between here and where we're going.
366349cc55cSDimitry Andric   unsigned long long stack_pointer = env[kSpIndex];
367480093f4SDimitry Andric   // The stack pointer should never be tagged, so we don't need to clear the
368480093f4SDimitry Andric   // tag for this function call.
369480093f4SDimitry Andric   __hwasan_handle_longjmp((void *)stack_pointer);
370480093f4SDimitry Andric 
371480093f4SDimitry Andric   // Run code for handling a longjmp.
372480093f4SDimitry Andric   // Need to use a register that isn't going to be loaded from the environment
373480093f4SDimitry Andric   // buffer -- hence why we need to specify the register to use.
374480093f4SDimitry Andric   // Must implement this ourselves, since we don't know the order of registers
375480093f4SDimitry Andric   // in different libc implementations and many implementations mangle the
376480093f4SDimitry Andric   // stack pointer so we can't use it without knowing the demangling scheme.
377349cc55cSDimitry Andric #    if defined(__aarch64__)
378480093f4SDimitry Andric   register long int retval_tmp asm("x1") = retval;
379480093f4SDimitry Andric   register void *env_address asm("x0") = &env[0];
38006c3fb27SDimitry Andric   asm volatile(
38106c3fb27SDimitry Andric       "ldp	x19, x20, [%0, #0<<3];"
382480093f4SDimitry Andric       "ldp	x21, x22, [%0, #2<<3];"
383480093f4SDimitry Andric       "ldp	x23, x24, [%0, #4<<3];"
384480093f4SDimitry Andric       "ldp	x25, x26, [%0, #6<<3];"
385480093f4SDimitry Andric       "ldp	x27, x28, [%0, #8<<3];"
386480093f4SDimitry Andric       "ldp	x29, x30, [%0, #10<<3];"
387480093f4SDimitry Andric       "ldp	 d8,  d9, [%0, #14<<3];"
388480093f4SDimitry Andric       "ldp	d10, d11, [%0, #16<<3];"
389480093f4SDimitry Andric       "ldp	d12, d13, [%0, #18<<3];"
390480093f4SDimitry Andric       "ldp	d14, d15, [%0, #20<<3];"
391480093f4SDimitry Andric       "ldr	x5, [%0, #13<<3];"
392480093f4SDimitry Andric       "mov	sp, x5;"
393480093f4SDimitry Andric       // Return the value requested to return through arguments.
394480093f4SDimitry Andric       // This should be in x1 given what we requested above.
395480093f4SDimitry Andric       "cmp	%1, #0;"
396480093f4SDimitry Andric       "mov	x0, #1;"
397480093f4SDimitry Andric       "csel	x0, %1, x0, ne;"
398480093f4SDimitry Andric       "br	x30;"
399480093f4SDimitry Andric       : "+r"(env_address)
400480093f4SDimitry Andric       : "r"(retval_tmp));
401349cc55cSDimitry Andric #    elif defined(__x86_64__)
402349cc55cSDimitry Andric   register long int retval_tmp asm("%rsi") = retval;
403349cc55cSDimitry Andric   register void *env_address asm("%rdi") = &env[0];
404349cc55cSDimitry Andric   asm volatile(
405349cc55cSDimitry Andric       // Restore registers.
406349cc55cSDimitry Andric       "mov (0*8)(%0),%%rbx;"
407349cc55cSDimitry Andric       "mov (1*8)(%0),%%rbp;"
408349cc55cSDimitry Andric       "mov (2*8)(%0),%%r12;"
409349cc55cSDimitry Andric       "mov (3*8)(%0),%%r13;"
410349cc55cSDimitry Andric       "mov (4*8)(%0),%%r14;"
411349cc55cSDimitry Andric       "mov (5*8)(%0),%%r15;"
412349cc55cSDimitry Andric       "mov (6*8)(%0),%%rsp;"
413349cc55cSDimitry Andric       "mov (7*8)(%0),%%rdx;"
414349cc55cSDimitry Andric       // Return 1 if retval is 0.
415349cc55cSDimitry Andric       "mov $1,%%rax;"
416349cc55cSDimitry Andric       "test %1,%1;"
417349cc55cSDimitry Andric       "cmovnz %1,%%rax;"
418349cc55cSDimitry Andric       "jmp *%%rdx;" ::"r"(env_address),
419349cc55cSDimitry Andric       "r"(retval_tmp));
420bdd1243dSDimitry Andric #    elif SANITIZER_RISCV64
421bdd1243dSDimitry Andric   register long int retval_tmp asm("x11") = retval;
422bdd1243dSDimitry Andric   register void *env_address asm("x10") = &env[0];
423bdd1243dSDimitry Andric   asm volatile(
424bdd1243dSDimitry Andric       "ld     ra,   0<<3(%0);"
425bdd1243dSDimitry Andric       "ld     s0,   1<<3(%0);"
426bdd1243dSDimitry Andric       "ld     s1,   2<<3(%0);"
427bdd1243dSDimitry Andric       "ld     s2,   3<<3(%0);"
428bdd1243dSDimitry Andric       "ld     s3,   4<<3(%0);"
429bdd1243dSDimitry Andric       "ld     s4,   5<<3(%0);"
430bdd1243dSDimitry Andric       "ld     s5,   6<<3(%0);"
431bdd1243dSDimitry Andric       "ld     s6,   7<<3(%0);"
432bdd1243dSDimitry Andric       "ld     s7,   8<<3(%0);"
433bdd1243dSDimitry Andric       "ld     s8,   9<<3(%0);"
434bdd1243dSDimitry Andric       "ld     s9,   10<<3(%0);"
435bdd1243dSDimitry Andric       "ld     s10,  11<<3(%0);"
436bdd1243dSDimitry Andric       "ld     s11,  12<<3(%0);"
437bdd1243dSDimitry Andric #      if __riscv_float_abi_double
438bdd1243dSDimitry Andric       "fld    fs0,  14<<3(%0);"
439bdd1243dSDimitry Andric       "fld    fs1,  15<<3(%0);"
440bdd1243dSDimitry Andric       "fld    fs2,  16<<3(%0);"
441bdd1243dSDimitry Andric       "fld    fs3,  17<<3(%0);"
442bdd1243dSDimitry Andric       "fld    fs4,  18<<3(%0);"
443bdd1243dSDimitry Andric       "fld    fs5,  19<<3(%0);"
444bdd1243dSDimitry Andric       "fld    fs6,  20<<3(%0);"
445bdd1243dSDimitry Andric       "fld    fs7,  21<<3(%0);"
446bdd1243dSDimitry Andric       "fld    fs8,  22<<3(%0);"
447bdd1243dSDimitry Andric       "fld    fs9,  23<<3(%0);"
448bdd1243dSDimitry Andric       "fld    fs10, 24<<3(%0);"
449bdd1243dSDimitry Andric       "fld    fs11, 25<<3(%0);"
450bdd1243dSDimitry Andric #      elif __riscv_float_abi_soft
451bdd1243dSDimitry Andric #      else
452bdd1243dSDimitry Andric #        error "Unsupported case"
453bdd1243dSDimitry Andric #      endif
454bdd1243dSDimitry Andric       "ld     a4, 13<<3(%0);"
455bdd1243dSDimitry Andric       "mv     sp, a4;"
456bdd1243dSDimitry Andric       // Return the value requested to return through arguments.
457bdd1243dSDimitry Andric       // This should be in x11 given what we requested above.
458bdd1243dSDimitry Andric       "seqz   a0, %1;"
459bdd1243dSDimitry Andric       "add    a0, a0, %1;"
460bdd1243dSDimitry Andric       "ret;"
461bdd1243dSDimitry Andric       : "+r"(env_address)
462bdd1243dSDimitry Andric       : "r"(retval_tmp));
463349cc55cSDimitry Andric #    endif
464480093f4SDimitry Andric }
465480093f4SDimitry Andric 
INTERCEPTOR(void,siglongjmp,__hw_sigjmp_buf env,int val)466480093f4SDimitry Andric INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
467349cc55cSDimitry Andric   if (env[0].__magic != kHwJmpBufMagic) {
468349cc55cSDimitry Andric     Printf(
469349cc55cSDimitry Andric         "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
470349cc55cSDimitry Andric         "there is a bug in HWASan.\n");
471349cc55cSDimitry Andric     return REAL(siglongjmp)(env, val);
472349cc55cSDimitry Andric   }
473349cc55cSDimitry Andric 
474480093f4SDimitry Andric   if (env[0].__mask_was_saved)
475480093f4SDimitry Andric     // Restore the saved signal mask.
47606c3fb27SDimitry Andric     (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (__hw_sigset_t *)0);
477480093f4SDimitry Andric   InternalLongjmp(env[0].__jmpbuf, val);
478480093f4SDimitry Andric }
479480093f4SDimitry Andric 
480480093f4SDimitry Andric // Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
481480093f4SDimitry Andric // _setjmp on start_thread.  Hence we have to intercept the longjmp on
482480093f4SDimitry Andric // pthread_exit so the __hw_jmp_buf order matches.
INTERCEPTOR(void,__libc_longjmp,__hw_jmp_buf env,int val)483480093f4SDimitry Andric INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
484349cc55cSDimitry Andric   if (env[0].__magic != kHwJmpBufMagic)
485349cc55cSDimitry Andric     return REAL(__libc_longjmp)(env, val);
486480093f4SDimitry Andric   InternalLongjmp(env[0].__jmpbuf, val);
487480093f4SDimitry Andric }
488480093f4SDimitry Andric 
INTERCEPTOR(void,longjmp,__hw_jmp_buf env,int val)489480093f4SDimitry Andric INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
490349cc55cSDimitry Andric   if (env[0].__magic != kHwJmpBufMagic) {
491349cc55cSDimitry Andric     Printf(
492349cc55cSDimitry Andric         "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
493349cc55cSDimitry Andric         "there is a bug in HWASan.\n");
494349cc55cSDimitry Andric     return REAL(longjmp)(env, val);
495349cc55cSDimitry Andric   }
496480093f4SDimitry Andric   InternalLongjmp(env[0].__jmpbuf, val);
497480093f4SDimitry Andric }
498480093f4SDimitry Andric #    undef SIG_BLOCK
499480093f4SDimitry Andric #    undef SIG_SETMASK
500480093f4SDimitry Andric 
501349cc55cSDimitry Andric #  endif  // HWASAN_WITH_INTERCEPTORS
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric namespace __hwasan {
5040b57cec5SDimitry Andric 
OnExit()5050b57cec5SDimitry Andric int OnExit() {
506bdd1243dSDimitry Andric   if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
507bdd1243dSDimitry Andric       __lsan::HasReportedLeaks()) {
508bdd1243dSDimitry Andric     return common_flags()->exitcode;
509bdd1243dSDimitry Andric   }
5100b57cec5SDimitry Andric   // FIXME: ask frontend whether we need to return failure.
5110b57cec5SDimitry Andric   return 0;
5120b57cec5SDimitry Andric }
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric }  // namespace __hwasan
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric namespace __hwasan {
5170b57cec5SDimitry Andric 
InitializeInterceptors()5180b57cec5SDimitry Andric void InitializeInterceptors() {
5190b57cec5SDimitry Andric   static int inited = 0;
5200b57cec5SDimitry Andric   CHECK_EQ(inited, 0);
5210b57cec5SDimitry Andric 
5225f757f3fSDimitry Andric #  if HWASAN_WITH_INTERCEPTORS
52306c3fb27SDimitry Andric   InitializeCommonInterceptors();
52406c3fb27SDimitry Andric 
52506c3fb27SDimitry Andric   (void)(read_iovec);
52606c3fb27SDimitry Andric   (void)(write_iovec);
52706c3fb27SDimitry Andric 
5280b57cec5SDimitry Andric #    if defined(__linux__)
529349cc55cSDimitry Andric   INTERCEPT_FUNCTION(__libc_longjmp);
530349cc55cSDimitry Andric   INTERCEPT_FUNCTION(longjmp);
531349cc55cSDimitry Andric   INTERCEPT_FUNCTION(siglongjmp);
5320b57cec5SDimitry Andric   INTERCEPT_FUNCTION(vfork);
5330b57cec5SDimitry Andric #    endif  // __linux__
5340b57cec5SDimitry Andric   INTERCEPT_FUNCTION(pthread_create);
5350eae32dcSDimitry Andric   INTERCEPT_FUNCTION(pthread_join);
53606c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_detach);
53706c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_exit);
53806c3fb27SDimitry Andric #    if SANITIZER_GLIBC
53906c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_tryjoin_np);
54006c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_timedjoin_np);
54106c3fb27SDimitry Andric #    endif
5420b57cec5SDimitry Andric #  endif
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   inited = 1;
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric }  // namespace __hwasan
547fe6060f1SDimitry Andric 
548fe6060f1SDimitry Andric #endif  // #if !SANITIZER_FUCHSIA
549