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> 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> 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 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 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 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 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 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 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 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 337*0fca6ea1SDimitry Andric DEFINE_INTERNAL_PTHREAD_FUNCTIONS 3380eae32dcSDimitry Andric 339*0fca6ea1SDimitry Andric DEFINE_REAL(int, vfork,) 340*0fca6ea1SDimitry 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 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)) 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 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. 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 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 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 5180b57cec5SDimitry Andric void InitializeInterceptors() { 5190b57cec5SDimitry Andric static int inited = 0; 5200b57cec5SDimitry Andric CHECK_EQ(inited, 0); 5210b57cec5SDimitry Andric 5225f757f3fSDimitry Andric # if HWASAN_WITH_INTERCEPTORS 523*0fca6ea1SDimitry Andric __interception::DoesNotSupportStaticLinking(); 52406c3fb27SDimitry Andric InitializeCommonInterceptors(); 52506c3fb27SDimitry Andric 52606c3fb27SDimitry Andric (void)(read_iovec); 52706c3fb27SDimitry Andric (void)(write_iovec); 52806c3fb27SDimitry Andric 5290b57cec5SDimitry Andric # if defined(__linux__) 530349cc55cSDimitry Andric INTERCEPT_FUNCTION(__libc_longjmp); 531349cc55cSDimitry Andric INTERCEPT_FUNCTION(longjmp); 532349cc55cSDimitry Andric INTERCEPT_FUNCTION(siglongjmp); 5330b57cec5SDimitry Andric INTERCEPT_FUNCTION(vfork); 5340b57cec5SDimitry Andric # endif // __linux__ 5350b57cec5SDimitry Andric INTERCEPT_FUNCTION(pthread_create); 5360eae32dcSDimitry Andric INTERCEPT_FUNCTION(pthread_join); 53706c3fb27SDimitry Andric INTERCEPT_FUNCTION(pthread_detach); 53806c3fb27SDimitry Andric INTERCEPT_FUNCTION(pthread_exit); 53906c3fb27SDimitry Andric # if SANITIZER_GLIBC 54006c3fb27SDimitry Andric INTERCEPT_FUNCTION(pthread_tryjoin_np); 54106c3fb27SDimitry Andric INTERCEPT_FUNCTION(pthread_timedjoin_np); 54206c3fb27SDimitry Andric # endif 5430b57cec5SDimitry Andric # endif 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric inited = 1; 5460b57cec5SDimitry Andric } 5470b57cec5SDimitry Andric } // namespace __hwasan 548fe6060f1SDimitry Andric 549fe6060f1SDimitry Andric #endif // #if !SANITIZER_FUCHSIA 550