168d75effSDimitry Andric //===-- asan_interceptors.cpp ---------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Intercept various libc functions. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "asan_interceptors.h" 1506c3fb27SDimitry Andric 1668d75effSDimitry Andric #include "asan_allocator.h" 1768d75effSDimitry Andric #include "asan_internal.h" 1868d75effSDimitry Andric #include "asan_mapping.h" 1968d75effSDimitry Andric #include "asan_poisoning.h" 2068d75effSDimitry Andric #include "asan_report.h" 2168d75effSDimitry Andric #include "asan_stack.h" 2268d75effSDimitry Andric #include "asan_stats.h" 2368d75effSDimitry Andric #include "asan_suppressions.h" 2406c3fb27SDimitry Andric #include "asan_thread.h" 2568d75effSDimitry Andric #include "lsan/lsan_common.h" 2606c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_errno.h" 2706c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h" 2868d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h" 2968d75effSDimitry Andric 30fe6060f1SDimitry Andric // There is no general interception at all on Fuchsia. 3168d75effSDimitry Andric // Only the functions in asan_interceptors_memintrinsics.cpp are 3268d75effSDimitry Andric // really defined to replace libc functions. 33fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA 3468d75effSDimitry Andric 3568d75effSDimitry Andric # if SANITIZER_POSIX 3668d75effSDimitry Andric # include "sanitizer_common/sanitizer_posix.h" 3768d75effSDimitry Andric # endif 3868d75effSDimitry Andric 3968d75effSDimitry Andric # if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \ 4068d75effSDimitry Andric ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION 4168d75effSDimitry Andric # include <unwind.h> 4268d75effSDimitry Andric # endif 4368d75effSDimitry Andric 4468d75effSDimitry Andric # if defined(__i386) && SANITIZER_LINUX 4568d75effSDimitry Andric # define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" 4668d75effSDimitry Andric # elif defined(__mips__) && SANITIZER_LINUX 4768d75effSDimitry Andric # define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2" 4868d75effSDimitry Andric # endif 4968d75effSDimitry Andric 5068d75effSDimitry Andric namespace __asan { 5168d75effSDimitry Andric 5268d75effSDimitry Andric #define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \ 5368d75effSDimitry Andric ASAN_READ_RANGE((ctx), (s), \ 5468d75effSDimitry Andric common_flags()->strict_string_checks ? (len) + 1 : (n)) 5568d75effSDimitry Andric 5668d75effSDimitry Andric # define ASAN_READ_STRING(ctx, s, n) \ 57349cc55cSDimitry Andric ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n)) 5868d75effSDimitry Andric 5968d75effSDimitry Andric static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { 6068d75effSDimitry Andric #if SANITIZER_INTERCEPT_STRNLEN 6168d75effSDimitry Andric if (REAL(strnlen)) { 6268d75effSDimitry Andric return REAL(strnlen)(s, maxlen); 6368d75effSDimitry Andric } 6468d75effSDimitry Andric #endif 6568d75effSDimitry Andric return internal_strnlen(s, maxlen); 6668d75effSDimitry Andric } 6768d75effSDimitry Andric 6868d75effSDimitry Andric void SetThreadName(const char *name) { 6968d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 7068d75effSDimitry Andric if (t) 7168d75effSDimitry Andric asanThreadRegistry().SetThreadName(t->tid(), name); 7268d75effSDimitry Andric } 7368d75effSDimitry Andric 7468d75effSDimitry Andric int OnExit() { 7568d75effSDimitry Andric if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks && 7668d75effSDimitry Andric __lsan::HasReportedLeaks()) { 7768d75effSDimitry Andric return common_flags()->exitcode; 7868d75effSDimitry Andric } 7968d75effSDimitry Andric // FIXME: ask frontend whether we need to return failure. 8068d75effSDimitry Andric return 0; 8168d75effSDimitry Andric } 8268d75effSDimitry Andric 8368d75effSDimitry Andric } // namespace __asan 8468d75effSDimitry Andric 8568d75effSDimitry Andric // ---------------------- Wrappers ---------------- {{{1 8668d75effSDimitry Andric using namespace __asan; 8768d75effSDimitry Andric 8868d75effSDimitry Andric DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) 8968d75effSDimitry Andric DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) 9068d75effSDimitry Andric 9168d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ 9268d75effSDimitry Andric ASAN_INTERCEPT_FUNC_VER(name, ver) 93fe6060f1SDimitry Andric #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \ 94fe6060f1SDimitry Andric ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) 9568d75effSDimitry Andric #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ 9668d75effSDimitry Andric ASAN_WRITE_RANGE(ctx, ptr, size) 9768d75effSDimitry Andric #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ 9868d75effSDimitry Andric ASAN_READ_RANGE(ctx, ptr, size) 9968d75effSDimitry Andric # define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ 10068d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, func); \ 10168d75effSDimitry Andric do { \ 1025f757f3fSDimitry Andric if constexpr (SANITIZER_APPLE) { \ 1035f757f3fSDimitry Andric if (UNLIKELY(!AsanInited())) \ 10468d75effSDimitry Andric return REAL(func)(__VA_ARGS__); \ 1055f757f3fSDimitry Andric } else { \ 1065f757f3fSDimitry Andric if (!TryAsanInitFromRtl()) \ 10768d75effSDimitry Andric return REAL(func)(__VA_ARGS__); \ 1085f757f3fSDimitry Andric } \ 10968d75effSDimitry Andric } while (false) 11068d75effSDimitry Andric #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ 11168d75effSDimitry Andric do { \ 11268d75effSDimitry Andric } while (false) 11368d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ 11468d75effSDimitry Andric do { \ 11568d75effSDimitry Andric } while (false) 11668d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ 11768d75effSDimitry Andric do { \ 11868d75effSDimitry Andric } while (false) 11968d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ 12068d75effSDimitry Andric do { \ 12168d75effSDimitry Andric } while (false) 12268d75effSDimitry Andric #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) 12368d75effSDimitry Andric // Should be asanThreadRegistry().SetThreadNameByUserId(thread, name) 12468d75effSDimitry Andric // But asan does not remember UserId's for threads (pthread_t); 12568d75effSDimitry Andric // and remembers all ever existed threads, so the linear search by UserId 12668d75effSDimitry Andric // can be slow. 12768d75effSDimitry Andric #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ 12868d75effSDimitry Andric do { \ 12968d75effSDimitry Andric } while (false) 13068d75effSDimitry Andric #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) 13168d75effSDimitry Andric // Strict init-order checking is dlopen-hostile: 13268d75effSDimitry Andric // https://github.com/google/sanitizers/issues/178 1334824e7fdSDimitry Andric # define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \ 1344824e7fdSDimitry Andric ({ \ 13568d75effSDimitry Andric if (flags()->strict_init_order) \ 13668d75effSDimitry Andric StopInitOrderChecking(); \ 13768d75effSDimitry Andric CheckNoDeepBind(filename, flag); \ 1384824e7fdSDimitry Andric REAL(dlopen)(filename, flag); \ 1394824e7fdSDimitry Andric }) 14068d75effSDimitry Andric # define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() 14168d75effSDimitry Andric # define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) 14268d75effSDimitry Andric # define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() 1435f757f3fSDimitry Andric # define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited()) 14468d75effSDimitry Andric # define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ 14568d75effSDimitry Andric if (AsanThread *t = GetCurrentThread()) { \ 14668d75effSDimitry Andric *begin = t->tls_begin(); \ 14768d75effSDimitry Andric *end = t->tls_end(); \ 14868d75effSDimitry Andric } else { \ 14968d75effSDimitry Andric *begin = *end = 0; \ 15068d75effSDimitry Andric } 15168d75effSDimitry Andric 15206c3fb27SDimitry Andric template <class Mmap> 15306c3fb27SDimitry Andric static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, 15406c3fb27SDimitry Andric int prot, int flags, int fd, OFF64_T offset) { 15506c3fb27SDimitry Andric void *res = real_mmap(addr, length, prot, flags, fd, offset); 15606c3fb27SDimitry Andric if (length && res != (void *)-1) { 15706c3fb27SDimitry Andric const uptr beg = reinterpret_cast<uptr>(res); 15806c3fb27SDimitry Andric DCHECK(IsAligned(beg, GetPageSize())); 15906c3fb27SDimitry Andric SIZE_T rounded_length = RoundUpTo(length, GetPageSize()); 16006c3fb27SDimitry Andric // Only unpoison shadow if it's an ASAN managed address. 16106c3fb27SDimitry Andric if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1)) 16206c3fb27SDimitry Andric PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 0); 16306c3fb27SDimitry Andric } 16406c3fb27SDimitry Andric return res; 16506c3fb27SDimitry Andric } 16606c3fb27SDimitry Andric 16706c3fb27SDimitry Andric template <class Munmap> 16806c3fb27SDimitry Andric static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) { 16906c3fb27SDimitry Andric // We should not tag if munmap fail, but it's to late to tag after 17006c3fb27SDimitry Andric // real_munmap, as the pages could be mmaped by another thread. 17106c3fb27SDimitry Andric const uptr beg = reinterpret_cast<uptr>(addr); 17206c3fb27SDimitry Andric if (length && IsAligned(beg, GetPageSize())) { 17306c3fb27SDimitry Andric SIZE_T rounded_length = RoundUpTo(length, GetPageSize()); 17406c3fb27SDimitry Andric // Protect from unmapping the shadow. 17506c3fb27SDimitry Andric if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1)) 17606c3fb27SDimitry Andric PoisonShadow(beg, rounded_length, 0); 17706c3fb27SDimitry Andric } 17806c3fb27SDimitry Andric return real_munmap(addr, length); 17906c3fb27SDimitry Andric } 18006c3fb27SDimitry Andric 18106c3fb27SDimitry Andric # define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \ 18206c3fb27SDimitry Andric fd, offset) \ 18368d75effSDimitry Andric do { \ 18406c3fb27SDimitry Andric (void)(ctx); \ 18506c3fb27SDimitry Andric return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \ 18668d75effSDimitry Andric } while (false) 18768d75effSDimitry Andric 18806c3fb27SDimitry Andric # define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \ 18968d75effSDimitry Andric do { \ 19006c3fb27SDimitry Andric (void)(ctx); \ 19106c3fb27SDimitry Andric return munmap_interceptor(REAL(munmap), addr, sz); \ 19268d75effSDimitry Andric } while (false) 19368d75effSDimitry Andric 19468d75effSDimitry Andric #if CAN_SANITIZE_LEAKS 19568d75effSDimitry Andric #define COMMON_INTERCEPTOR_STRERROR() \ 19668d75effSDimitry Andric __lsan::ScopedInterceptorDisabler disabler 19768d75effSDimitry Andric #endif 19868d75effSDimitry Andric 1995f757f3fSDimitry Andric # define SIGNAL_INTERCEPTOR_ENTER() \ 2005f757f3fSDimitry Andric do { \ 2015f757f3fSDimitry Andric AsanInitFromRtl(); \ 2025f757f3fSDimitry Andric } while (false) 20306c3fb27SDimitry Andric 20468d75effSDimitry Andric # include "sanitizer_common/sanitizer_common_interceptors.inc" 20568d75effSDimitry Andric # include "sanitizer_common/sanitizer_signal_interceptors.inc" 20668d75effSDimitry Andric 20768d75effSDimitry Andric // Syscall interceptors don't have contexts, we don't support suppressions 20868d75effSDimitry Andric // for them. 20968d75effSDimitry Andric #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s) 21068d75effSDimitry Andric #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s) 21168d75effSDimitry Andric #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ 21268d75effSDimitry Andric do { \ 21368d75effSDimitry Andric (void)(p); \ 21468d75effSDimitry Andric (void)(s); \ 21568d75effSDimitry Andric } while (false) 21668d75effSDimitry Andric #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ 21768d75effSDimitry Andric do { \ 21868d75effSDimitry Andric (void)(p); \ 21968d75effSDimitry Andric (void)(s); \ 22068d75effSDimitry Andric } while (false) 22168d75effSDimitry Andric #include "sanitizer_common/sanitizer_common_syscalls.inc" 22268d75effSDimitry Andric #include "sanitizer_common/sanitizer_syscalls_netbsd.inc" 22368d75effSDimitry Andric 22468d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_CREATE 22568d75effSDimitry Andric static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { 226e8d8bef9SDimitry Andric AsanThread *t = (AsanThread *)arg; 22768d75effSDimitry Andric SetCurrentThread(t); 22806c3fb27SDimitry Andric auto self = GetThreadSelf(); 22906c3fb27SDimitry Andric auto args = asanThreadArgRetval().GetArgs(self); 2305f757f3fSDimitry Andric t->ThreadStart(GetTid()); 2315f757f3fSDimitry Andric 2325f757f3fSDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 2335f757f3fSDimitry Andric SANITIZER_SOLARIS 2345f757f3fSDimitry Andric __sanitizer_sigset_t sigset; 2355f757f3fSDimitry Andric t->GetStartData(sigset); 2365f757f3fSDimitry Andric SetSigProcMask(&sigset, nullptr); 2375f757f3fSDimitry Andric # endif 2385f757f3fSDimitry Andric 2395f757f3fSDimitry Andric thread_return_t retval = (*args.routine)(args.arg_retval); 24006c3fb27SDimitry Andric asanThreadArgRetval().Finish(self, retval); 24106c3fb27SDimitry Andric return retval; 24268d75effSDimitry Andric } 24368d75effSDimitry Andric 24406c3fb27SDimitry Andric INTERCEPTOR(int, pthread_create, void *thread, void *attr, 24506c3fb27SDimitry Andric void *(*start_routine)(void *), void *arg) { 24668d75effSDimitry Andric EnsureMainThreadIDIsCorrect(); 24768d75effSDimitry Andric // Strict init-order checking is thread-hostile. 24868d75effSDimitry Andric if (flags()->strict_init_order) 24968d75effSDimitry Andric StopInitOrderChecking(); 25068d75effSDimitry Andric GET_STACK_TRACE_THREAD; 25106c3fb27SDimitry Andric bool detached = [attr]() { 25206c3fb27SDimitry Andric int d = 0; 25306c3fb27SDimitry Andric return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) && 25406c3fb27SDimitry Andric IsStateDetached(d); 25506c3fb27SDimitry Andric }(); 256e8d8bef9SDimitry Andric 257e8d8bef9SDimitry Andric u32 current_tid = GetCurrentTidOrInvalid(); 2585f757f3fSDimitry Andric 2595f757f3fSDimitry Andric __sanitizer_sigset_t sigset = {}; 2605f757f3fSDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 2615f757f3fSDimitry Andric SANITIZER_SOLARIS 2625f757f3fSDimitry Andric ScopedBlockSignals block(&sigset); 2635f757f3fSDimitry Andric # endif 2645f757f3fSDimitry Andric 2655f757f3fSDimitry Andric AsanThread *t = AsanThread::Create(sigset, current_tid, &stack, detached); 266e8d8bef9SDimitry Andric 26768d75effSDimitry Andric int result; 26868d75effSDimitry Andric { 26968d75effSDimitry Andric // Ignore all allocations made by pthread_create: thread stack/TLS may be 27068d75effSDimitry Andric // stored by pthread for future reuse even after thread destruction, and 27168d75effSDimitry Andric // the linked list it's stored in doesn't even hold valid pointers to the 27268d75effSDimitry Andric // objects, the latter are calculated by obscure pointer arithmetic. 27368d75effSDimitry Andric # if CAN_SANITIZE_LEAKS 27468d75effSDimitry Andric __lsan::ScopedInterceptorDisabler disabler; 27568d75effSDimitry Andric # endif 27606c3fb27SDimitry Andric asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr { 277e8d8bef9SDimitry Andric result = REAL(pthread_create)(thread, attr, asan_thread_start, t); 27806c3fb27SDimitry Andric return result ? 0 : *(uptr *)(thread); 27906c3fb27SDimitry Andric }); 28068d75effSDimitry Andric } 281e8d8bef9SDimitry Andric if (result != 0) { 282e8d8bef9SDimitry Andric // If the thread didn't start delete the AsanThread to avoid leaking it. 283e8d8bef9SDimitry Andric // Note AsanThreadContexts never get destroyed so the AsanThreadContext 284e8d8bef9SDimitry Andric // that was just created for the AsanThread is wasted. 285e8d8bef9SDimitry Andric t->Destroy(); 28668d75effSDimitry Andric } 28768d75effSDimitry Andric return result; 28868d75effSDimitry Andric } 28968d75effSDimitry Andric 29006c3fb27SDimitry Andric INTERCEPTOR(int, pthread_join, void *thread, void **retval) { 29106c3fb27SDimitry Andric int result; 29206c3fb27SDimitry Andric asanThreadArgRetval().Join((uptr)thread, [&]() { 29306c3fb27SDimitry Andric result = REAL(pthread_join)(thread, retval); 29406c3fb27SDimitry Andric return !result; 29506c3fb27SDimitry Andric }); 29606c3fb27SDimitry Andric return result; 29768d75effSDimitry Andric } 29868d75effSDimitry Andric 29906c3fb27SDimitry Andric INTERCEPTOR(int, pthread_detach, void *thread) { 30006c3fb27SDimitry Andric int result; 30106c3fb27SDimitry Andric asanThreadArgRetval().Detach((uptr)thread, [&]() { 30206c3fb27SDimitry Andric result = REAL(pthread_detach)(thread); 30306c3fb27SDimitry Andric return !result; 30406c3fb27SDimitry Andric }); 30506c3fb27SDimitry Andric return result; 30606c3fb27SDimitry Andric } 30706c3fb27SDimitry Andric 3085f757f3fSDimitry Andric INTERCEPTOR(void, pthread_exit, void *retval) { 30906c3fb27SDimitry Andric asanThreadArgRetval().Finish(GetThreadSelf(), retval); 3105f757f3fSDimitry Andric REAL(pthread_exit)(retval); 31106c3fb27SDimitry Andric } 31206c3fb27SDimitry Andric 31306c3fb27SDimitry Andric # if ASAN_INTERCEPT_TRYJOIN 31406c3fb27SDimitry Andric INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { 31506c3fb27SDimitry Andric int result; 31606c3fb27SDimitry Andric asanThreadArgRetval().Join((uptr)thread, [&]() { 31706c3fb27SDimitry Andric result = REAL(pthread_tryjoin_np)(thread, ret); 31806c3fb27SDimitry Andric return !result; 31906c3fb27SDimitry Andric }); 32006c3fb27SDimitry Andric return result; 32106c3fb27SDimitry Andric } 32206c3fb27SDimitry Andric # endif 32306c3fb27SDimitry Andric 32406c3fb27SDimitry Andric # if ASAN_INTERCEPT_TIMEDJOIN 32506c3fb27SDimitry Andric INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, 32606c3fb27SDimitry Andric const struct timespec *abstime) { 32706c3fb27SDimitry Andric int result; 32806c3fb27SDimitry Andric asanThreadArgRetval().Join((uptr)thread, [&]() { 32906c3fb27SDimitry Andric result = REAL(pthread_timedjoin_np)(thread, ret, abstime); 33006c3fb27SDimitry Andric return !result; 33106c3fb27SDimitry Andric }); 33206c3fb27SDimitry Andric return result; 33306c3fb27SDimitry Andric } 33406c3fb27SDimitry Andric # endif 33506c3fb27SDimitry Andric 336*0fca6ea1SDimitry Andric DEFINE_INTERNAL_PTHREAD_FUNCTIONS 33768d75effSDimitry Andric #endif // ASAN_INTERCEPT_PTHREAD_CREATE 33868d75effSDimitry Andric 33968d75effSDimitry Andric #if ASAN_INTERCEPT_SWAPCONTEXT 34068d75effSDimitry Andric static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { 341fcaf7f86SDimitry Andric // Only clear if we know the stack. This should be true only for contexts 342fcaf7f86SDimitry Andric // created with makecontext(). 343fcaf7f86SDimitry Andric if (!ssize) 344fcaf7f86SDimitry Andric return; 34568d75effSDimitry Andric // Align to page size. 34668d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 347fcaf7f86SDimitry Andric uptr bottom = RoundDownTo(stack, PageSize); 348fcaf7f86SDimitry Andric if (!AddrIsInMem(bottom)) 349fcaf7f86SDimitry Andric return; 35068d75effSDimitry Andric ssize += stack - bottom; 35168d75effSDimitry Andric ssize = RoundUpTo(ssize, PageSize); 35268d75effSDimitry Andric PoisonShadow(bottom, ssize, 0); 35368d75effSDimitry Andric } 35468d75effSDimitry Andric 355*0fca6ea1SDimitry Andric // Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address 356*0fca6ea1SDimitry Andric // as on other targets. For binary compatibility, the new version uses a 357*0fca6ea1SDimitry Andric // different external name, so we intercept that. 358*0fca6ea1SDimitry Andric # if SANITIZER_SOLARIS && defined(__sparc__) 359*0fca6ea1SDimitry Andric INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(), 360*0fca6ea1SDimitry Andric int argc, ...) { 361*0fca6ea1SDimitry Andric # else 3629e7101a8SDimitry Andric INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc, 3639e7101a8SDimitry Andric ...) { 364*0fca6ea1SDimitry Andric # endif 3659e7101a8SDimitry Andric va_list ap; 3669e7101a8SDimitry Andric uptr args[64]; 3679e7101a8SDimitry Andric // We don't know a better way to forward ... into REAL function. We can 3689e7101a8SDimitry Andric // increase args size if neccecary. 3699e7101a8SDimitry Andric CHECK_LE(argc, ARRAY_SIZE(args)); 3709e7101a8SDimitry Andric internal_memset(args, 0, sizeof(args)); 3719e7101a8SDimitry Andric va_start(ap, argc); 3729e7101a8SDimitry Andric for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr); 3739e7101a8SDimitry Andric va_end(ap); 3749e7101a8SDimitry Andric 3759e7101a8SDimitry Andric # define ENUMERATE_ARRAY_4(start) \ 3769e7101a8SDimitry Andric args[start], args[start + 1], args[start + 2], args[start + 3] 3779e7101a8SDimitry Andric # define ENUMERATE_ARRAY_16(start) \ 3789e7101a8SDimitry Andric ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \ 3799e7101a8SDimitry Andric ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12) 3809e7101a8SDimitry Andric # define ENUMERATE_ARRAY_64() \ 3819e7101a8SDimitry Andric ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \ 3829e7101a8SDimitry Andric ENUMERATE_ARRAY_16(48) 3839e7101a8SDimitry Andric 384*0fca6ea1SDimitry Andric # if SANITIZER_SOLARIS && defined(__sparc__) 385*0fca6ea1SDimitry Andric REAL(__makecontext_v2) 386*0fca6ea1SDimitry Andric # else 3879e7101a8SDimitry Andric REAL(makecontext) 388*0fca6ea1SDimitry Andric # endif 3899e7101a8SDimitry Andric ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64()); 3909e7101a8SDimitry Andric 3919e7101a8SDimitry Andric # undef ENUMERATE_ARRAY_4 3929e7101a8SDimitry Andric # undef ENUMERATE_ARRAY_16 3939e7101a8SDimitry Andric # undef ENUMERATE_ARRAY_64 3949e7101a8SDimitry Andric 3959e7101a8SDimitry Andric // Sign the stack so we can identify it for unpoisoning. 3969e7101a8SDimitry Andric SignContextStack(ucp); 397fcaf7f86SDimitry Andric } 398fcaf7f86SDimitry Andric 39968d75effSDimitry Andric INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, 40068d75effSDimitry Andric struct ucontext_t *ucp) { 40168d75effSDimitry Andric static bool reported_warning = false; 40268d75effSDimitry Andric if (!reported_warning) { 40368d75effSDimitry Andric Report("WARNING: ASan doesn't fully support makecontext/swapcontext " 40468d75effSDimitry Andric "functions and may produce false positives in some cases!\n"); 40568d75effSDimitry Andric reported_warning = true; 40668d75effSDimitry Andric } 40768d75effSDimitry Andric // Clear shadow memory for new context (it may share stack 40868d75effSDimitry Andric // with current context). 40968d75effSDimitry Andric uptr stack, ssize; 41068d75effSDimitry Andric ReadContextStack(ucp, &stack, &ssize); 41168d75effSDimitry Andric ClearShadowMemoryForContextStack(stack, ssize); 412fcaf7f86SDimitry Andric 41368d75effSDimitry Andric # if __has_attribute(__indirect_return__) && \ 41468d75effSDimitry Andric (defined(__x86_64__) || defined(__i386__)) 41568d75effSDimitry Andric int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *) 416fcaf7f86SDimitry Andric __attribute__((__indirect_return__)) = REAL(swapcontext); 41768d75effSDimitry Andric int res = real_swapcontext(oucp, ucp); 41868d75effSDimitry Andric # else 41968d75effSDimitry Andric int res = REAL(swapcontext)(oucp, ucp); 42068d75effSDimitry Andric # endif 42168d75effSDimitry Andric // swapcontext technically does not return, but program may swap context to 42268d75effSDimitry Andric // "oucp" later, that would look as if swapcontext() returned 0. 42368d75effSDimitry Andric // We need to clear shadow for ucp once again, as it may be in arbitrary 42468d75effSDimitry Andric // state. 42568d75effSDimitry Andric ClearShadowMemoryForContextStack(stack, ssize); 42668d75effSDimitry Andric return res; 42768d75effSDimitry Andric } 42868d75effSDimitry Andric #endif // ASAN_INTERCEPT_SWAPCONTEXT 42968d75effSDimitry Andric 43068d75effSDimitry Andric #if SANITIZER_NETBSD 43168d75effSDimitry Andric #define longjmp __longjmp14 43268d75effSDimitry Andric #define siglongjmp __siglongjmp14 43368d75effSDimitry Andric #endif 43468d75effSDimitry Andric 43568d75effSDimitry Andric INTERCEPTOR(void, longjmp, void *env, int val) { 43668d75effSDimitry Andric __asan_handle_no_return(); 43768d75effSDimitry Andric REAL(longjmp)(env, val); 43868d75effSDimitry Andric } 43968d75effSDimitry Andric 44068d75effSDimitry Andric #if ASAN_INTERCEPT__LONGJMP 44168d75effSDimitry Andric INTERCEPTOR(void, _longjmp, void *env, int val) { 44268d75effSDimitry Andric __asan_handle_no_return(); 44368d75effSDimitry Andric REAL(_longjmp)(env, val); 44468d75effSDimitry Andric } 44568d75effSDimitry Andric #endif 44668d75effSDimitry Andric 44768d75effSDimitry Andric #if ASAN_INTERCEPT___LONGJMP_CHK 44868d75effSDimitry Andric INTERCEPTOR(void, __longjmp_chk, void *env, int val) { 44968d75effSDimitry Andric __asan_handle_no_return(); 45068d75effSDimitry Andric REAL(__longjmp_chk)(env, val); 45168d75effSDimitry Andric } 45268d75effSDimitry Andric #endif 45368d75effSDimitry Andric 45468d75effSDimitry Andric #if ASAN_INTERCEPT_SIGLONGJMP 45568d75effSDimitry Andric INTERCEPTOR(void, siglongjmp, void *env, int val) { 45668d75effSDimitry Andric __asan_handle_no_return(); 45768d75effSDimitry Andric REAL(siglongjmp)(env, val); 45868d75effSDimitry Andric } 45968d75effSDimitry Andric #endif 46068d75effSDimitry Andric 46168d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_THROW 46268d75effSDimitry Andric INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { 46368d75effSDimitry Andric CHECK(REAL(__cxa_throw)); 46468d75effSDimitry Andric __asan_handle_no_return(); 46568d75effSDimitry Andric REAL(__cxa_throw)(a, b, c); 46668d75effSDimitry Andric } 46768d75effSDimitry Andric #endif 46868d75effSDimitry Andric 46968d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 47068d75effSDimitry Andric INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) { 47168d75effSDimitry Andric CHECK(REAL(__cxa_rethrow_primary_exception)); 47268d75effSDimitry Andric __asan_handle_no_return(); 47368d75effSDimitry Andric REAL(__cxa_rethrow_primary_exception)(a); 47468d75effSDimitry Andric } 47568d75effSDimitry Andric #endif 47668d75effSDimitry Andric 47768d75effSDimitry Andric #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 47868d75effSDimitry Andric INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException, 47968d75effSDimitry Andric _Unwind_Exception *object) { 48068d75effSDimitry Andric CHECK(REAL(_Unwind_RaiseException)); 48168d75effSDimitry Andric __asan_handle_no_return(); 48268d75effSDimitry Andric return REAL(_Unwind_RaiseException)(object); 48368d75effSDimitry Andric } 48468d75effSDimitry Andric #endif 48568d75effSDimitry Andric 48668d75effSDimitry Andric #if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION 48768d75effSDimitry Andric INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException, 48868d75effSDimitry Andric _Unwind_Exception *object) { 48968d75effSDimitry Andric CHECK(REAL(_Unwind_SjLj_RaiseException)); 49068d75effSDimitry Andric __asan_handle_no_return(); 49168d75effSDimitry Andric return REAL(_Unwind_SjLj_RaiseException)(object); 49268d75effSDimitry Andric } 49368d75effSDimitry Andric #endif 49468d75effSDimitry Andric 49568d75effSDimitry Andric #if ASAN_INTERCEPT_INDEX 49668d75effSDimitry Andric # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 49768d75effSDimitry Andric INTERCEPTOR(char*, index, const char *string, int c) 49806c3fb27SDimitry Andric ALIAS(WRAP(strchr)); 49968d75effSDimitry Andric # else 50081ad6265SDimitry Andric # if SANITIZER_APPLE 50168d75effSDimitry Andric DECLARE_REAL(char*, index, const char *string, int c) 50268d75effSDimitry Andric OVERRIDE_FUNCTION(index, strchr); 50368d75effSDimitry Andric # else 50468d75effSDimitry Andric DEFINE_REAL(char*, index, const char *string, int c) 50568d75effSDimitry Andric # endif 50668d75effSDimitry Andric # endif 50768d75effSDimitry Andric #endif // ASAN_INTERCEPT_INDEX 50868d75effSDimitry Andric 50968d75effSDimitry Andric // For both strcat() and strncat() we need to check the validity of |to| 51068d75effSDimitry Andric // argument irrespective of the |from| length. 51168d75effSDimitry Andric INTERCEPTOR(char *, strcat, char *to, const char *from) { 51268d75effSDimitry Andric void *ctx; 51368d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, strcat); 5145f757f3fSDimitry Andric AsanInitFromRtl(); 51568d75effSDimitry Andric if (flags()->replace_str) { 516349cc55cSDimitry Andric uptr from_length = internal_strlen(from); 51768d75effSDimitry Andric ASAN_READ_RANGE(ctx, from, from_length + 1); 518349cc55cSDimitry Andric uptr to_length = internal_strlen(to); 51968d75effSDimitry Andric ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); 52068d75effSDimitry Andric ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); 52168d75effSDimitry Andric // If the copying actually happens, the |from| string should not overlap 52268d75effSDimitry Andric // with the resulting string starting at |to|, which has a length of 52368d75effSDimitry Andric // to_length + from_length + 1. 52468d75effSDimitry Andric if (from_length > 0) { 52568d75effSDimitry Andric CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from, 52668d75effSDimitry Andric from_length + 1); 52768d75effSDimitry Andric } 52868d75effSDimitry Andric } 52968d75effSDimitry Andric return REAL(strcat)(to, from); 53068d75effSDimitry Andric } 53168d75effSDimitry Andric 53268d75effSDimitry Andric INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { 53368d75effSDimitry Andric void *ctx; 53468d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, strncat); 5355f757f3fSDimitry Andric AsanInitFromRtl(); 53668d75effSDimitry Andric if (flags()->replace_str) { 53768d75effSDimitry Andric uptr from_length = MaybeRealStrnlen(from, size); 53868d75effSDimitry Andric uptr copy_length = Min(size, from_length + 1); 53968d75effSDimitry Andric ASAN_READ_RANGE(ctx, from, copy_length); 540349cc55cSDimitry Andric uptr to_length = internal_strlen(to); 54168d75effSDimitry Andric ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); 54268d75effSDimitry Andric ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); 54368d75effSDimitry Andric if (from_length > 0) { 54468d75effSDimitry Andric CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1, 54568d75effSDimitry Andric from, copy_length); 54668d75effSDimitry Andric } 54768d75effSDimitry Andric } 54868d75effSDimitry Andric return REAL(strncat)(to, from, size); 54968d75effSDimitry Andric } 55068d75effSDimitry Andric 55168d75effSDimitry Andric INTERCEPTOR(char *, strcpy, char *to, const char *from) { 55268d75effSDimitry Andric void *ctx; 55368d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, strcpy); 5545f757f3fSDimitry Andric if constexpr (SANITIZER_APPLE) { 55568d75effSDimitry Andric // strcpy is called from malloc_default_purgeable_zone() 55668d75effSDimitry Andric // in __asan::ReplaceSystemAlloc() on Mac. 5575f757f3fSDimitry Andric if (UNLIKELY(!AsanInited())) 5585f757f3fSDimitry Andric return REAL(strcpy)(to, from); 5595f757f3fSDimitry Andric } else { 5605f757f3fSDimitry Andric if (!TryAsanInitFromRtl()) 56168d75effSDimitry Andric return REAL(strcpy)(to, from); 56268d75effSDimitry Andric } 5635f757f3fSDimitry Andric 56468d75effSDimitry Andric if (flags()->replace_str) { 565349cc55cSDimitry Andric uptr from_size = internal_strlen(from) + 1; 56668d75effSDimitry Andric CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size); 56768d75effSDimitry Andric ASAN_READ_RANGE(ctx, from, from_size); 56868d75effSDimitry Andric ASAN_WRITE_RANGE(ctx, to, from_size); 56968d75effSDimitry Andric } 57068d75effSDimitry Andric return REAL(strcpy)(to, from); 57168d75effSDimitry Andric } 57268d75effSDimitry Andric 573*0fca6ea1SDimitry Andric // Windows doesn't always define the strdup identifier, 574*0fca6ea1SDimitry Andric // and when it does it's a macro defined to either _strdup 575*0fca6ea1SDimitry Andric // or _strdup_dbg, _strdup_dbg ends up calling _strdup, so 576*0fca6ea1SDimitry Andric // we want to intercept that. push/pop_macro are used to avoid problems 577*0fca6ea1SDimitry Andric // if this file ends up including <string.h> in the future. 578*0fca6ea1SDimitry Andric # if SANITIZER_WINDOWS 579*0fca6ea1SDimitry Andric # pragma push_macro("strdup") 580*0fca6ea1SDimitry Andric # undef strdup 581*0fca6ea1SDimitry Andric # define strdup _strdup 582*0fca6ea1SDimitry Andric # endif 583*0fca6ea1SDimitry Andric 58468d75effSDimitry Andric INTERCEPTOR(char*, strdup, const char *s) { 58568d75effSDimitry Andric void *ctx; 58668d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, strdup); 5875f757f3fSDimitry Andric if (UNLIKELY(!TryAsanInitFromRtl())) 5885f757f3fSDimitry Andric return internal_strdup(s); 589349cc55cSDimitry Andric uptr length = internal_strlen(s); 59068d75effSDimitry Andric if (flags()->replace_str) { 59168d75effSDimitry Andric ASAN_READ_RANGE(ctx, s, length + 1); 59268d75effSDimitry Andric } 59368d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 59468d75effSDimitry Andric void *new_mem = asan_malloc(length + 1, &stack); 59506c3fb27SDimitry Andric if (new_mem) { 59668d75effSDimitry Andric REAL(memcpy)(new_mem, s, length + 1); 59706c3fb27SDimitry Andric } 59868d75effSDimitry Andric return reinterpret_cast<char*>(new_mem); 59968d75effSDimitry Andric } 60068d75effSDimitry Andric 60168d75effSDimitry Andric # if ASAN_INTERCEPT___STRDUP 60268d75effSDimitry Andric INTERCEPTOR(char*, __strdup, const char *s) { 60368d75effSDimitry Andric void *ctx; 60468d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, strdup); 6055f757f3fSDimitry Andric if (UNLIKELY(!TryAsanInitFromRtl())) 6065f757f3fSDimitry Andric return internal_strdup(s); 607349cc55cSDimitry Andric uptr length = internal_strlen(s); 60868d75effSDimitry Andric if (flags()->replace_str) { 60968d75effSDimitry Andric ASAN_READ_RANGE(ctx, s, length + 1); 61068d75effSDimitry Andric } 61168d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 61268d75effSDimitry Andric void *new_mem = asan_malloc(length + 1, &stack); 61306c3fb27SDimitry Andric if (new_mem) { 61468d75effSDimitry Andric REAL(memcpy)(new_mem, s, length + 1); 61506c3fb27SDimitry Andric } 61668d75effSDimitry Andric return reinterpret_cast<char*>(new_mem); 61768d75effSDimitry Andric } 61868d75effSDimitry Andric #endif // ASAN_INTERCEPT___STRDUP 61968d75effSDimitry Andric 62068d75effSDimitry Andric INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { 62168d75effSDimitry Andric void *ctx; 62268d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, strncpy); 6235f757f3fSDimitry Andric AsanInitFromRtl(); 62468d75effSDimitry Andric if (flags()->replace_str) { 62568d75effSDimitry Andric uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1); 62668d75effSDimitry Andric CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size); 62768d75effSDimitry Andric ASAN_READ_RANGE(ctx, from, from_size); 62868d75effSDimitry Andric ASAN_WRITE_RANGE(ctx, to, size); 62968d75effSDimitry Andric } 63068d75effSDimitry Andric return REAL(strncpy)(to, from, size); 63168d75effSDimitry Andric } 63268d75effSDimitry Andric 6338a4dda33SDimitry Andric template <typename Fn> 6348a4dda33SDimitry Andric static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, 6358a4dda33SDimitry Andric char **endptr, int base) 6368a4dda33SDimitry Andric -> decltype(real(nullptr, nullptr, 0)) { 6378a4dda33SDimitry Andric if (!flags()->replace_str) 6388a4dda33SDimitry Andric return real(nptr, endptr, base); 63968d75effSDimitry Andric char *real_endptr; 6408a4dda33SDimitry Andric auto res = real(nptr, &real_endptr, base); 64168d75effSDimitry Andric StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); 6428a4dda33SDimitry Andric return res; 64368d75effSDimitry Andric } 64468d75effSDimitry Andric 6458a4dda33SDimitry Andric # define INTERCEPTOR_STRTO_BASE(ret_type, func) \ 6468a4dda33SDimitry Andric INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \ 6478a4dda33SDimitry Andric void *ctx; \ 6488a4dda33SDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, func); \ 6495f757f3fSDimitry Andric AsanInitFromRtl(); \ 6508a4dda33SDimitry Andric return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \ 6518a4dda33SDimitry Andric } 6528a4dda33SDimitry Andric 6538a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long, strtol) 6548a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long long, strtoll) 6558a4dda33SDimitry Andric 6568a4dda33SDimitry Andric # if SANITIZER_GLIBC 6578a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol) 6588a4dda33SDimitry Andric INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll) 6598a4dda33SDimitry Andric # endif 6608a4dda33SDimitry Andric 66168d75effSDimitry Andric INTERCEPTOR(int, atoi, const char *nptr) { 66268d75effSDimitry Andric void *ctx; 66368d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, atoi); 6645f757f3fSDimitry Andric if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) 6655f757f3fSDimitry Andric return REAL(atoi)(nptr); 6665f757f3fSDimitry Andric AsanInitFromRtl(); 66768d75effSDimitry Andric if (!flags()->replace_str) { 66868d75effSDimitry Andric return REAL(atoi)(nptr); 66968d75effSDimitry Andric } 67068d75effSDimitry Andric char *real_endptr; 67168d75effSDimitry Andric // "man atoi" tells that behavior of atoi(nptr) is the same as 67268d75effSDimitry Andric // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the 67368d75effSDimitry Andric // parsed integer can't be stored in *long* type (even if it's 67468d75effSDimitry Andric // different from int). So, we just imitate this behavior. 67568d75effSDimitry Andric int result = REAL(strtol)(nptr, &real_endptr, 10); 67668d75effSDimitry Andric FixRealStrtolEndptr(nptr, &real_endptr); 67768d75effSDimitry Andric ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); 67868d75effSDimitry Andric return result; 67968d75effSDimitry Andric } 68068d75effSDimitry Andric 68168d75effSDimitry Andric INTERCEPTOR(long, atol, const char *nptr) { 68268d75effSDimitry Andric void *ctx; 68368d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, atol); 6845f757f3fSDimitry Andric if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) 6855f757f3fSDimitry Andric return REAL(atol)(nptr); 6865f757f3fSDimitry Andric AsanInitFromRtl(); 68768d75effSDimitry Andric if (!flags()->replace_str) { 68868d75effSDimitry Andric return REAL(atol)(nptr); 68968d75effSDimitry Andric } 69068d75effSDimitry Andric char *real_endptr; 69168d75effSDimitry Andric long result = REAL(strtol)(nptr, &real_endptr, 10); 69268d75effSDimitry Andric FixRealStrtolEndptr(nptr, &real_endptr); 69368d75effSDimitry Andric ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); 69468d75effSDimitry Andric return result; 69568d75effSDimitry Andric } 69668d75effSDimitry Andric 69768d75effSDimitry Andric INTERCEPTOR(long long, atoll, const char *nptr) { 69868d75effSDimitry Andric void *ctx; 69968d75effSDimitry Andric ASAN_INTERCEPTOR_ENTER(ctx, atoll); 7005f757f3fSDimitry Andric AsanInitFromRtl(); 70168d75effSDimitry Andric if (!flags()->replace_str) { 70268d75effSDimitry Andric return REAL(atoll)(nptr); 70368d75effSDimitry Andric } 70468d75effSDimitry Andric char *real_endptr; 70568d75effSDimitry Andric long long result = REAL(strtoll)(nptr, &real_endptr, 10); 70668d75effSDimitry Andric FixRealStrtolEndptr(nptr, &real_endptr); 70768d75effSDimitry Andric ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); 70868d75effSDimitry Andric return result; 70968d75effSDimitry Andric } 71068d75effSDimitry Andric 71168d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT 71268d75effSDimitry Andric static void AtCxaAtexit(void *unused) { 71368d75effSDimitry Andric (void)unused; 71468d75effSDimitry Andric StopInitOrderChecking(); 71568d75effSDimitry Andric } 71668d75effSDimitry Andric #endif 71768d75effSDimitry Andric 71868d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_ATEXIT 71968d75effSDimitry Andric INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, 72068d75effSDimitry Andric void *dso_handle) { 7215f757f3fSDimitry Andric if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) 7225f757f3fSDimitry Andric return REAL(__cxa_atexit)(func, arg, dso_handle); 7235f757f3fSDimitry Andric AsanInitFromRtl(); 72468d75effSDimitry Andric # if CAN_SANITIZE_LEAKS 72568d75effSDimitry Andric __lsan::ScopedInterceptorDisabler disabler; 72668d75effSDimitry Andric #endif 72768d75effSDimitry Andric int res = REAL(__cxa_atexit)(func, arg, dso_handle); 72868d75effSDimitry Andric REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); 72968d75effSDimitry Andric return res; 73068d75effSDimitry Andric } 73168d75effSDimitry Andric #endif // ASAN_INTERCEPT___CXA_ATEXIT 73268d75effSDimitry Andric 73368d75effSDimitry Andric #if ASAN_INTERCEPT_ATEXIT 73468d75effSDimitry Andric INTERCEPTOR(int, atexit, void (*func)()) { 7355f757f3fSDimitry Andric AsanInitFromRtl(); 73668d75effSDimitry Andric # if CAN_SANITIZE_LEAKS 73768d75effSDimitry Andric __lsan::ScopedInterceptorDisabler disabler; 73868d75effSDimitry Andric #endif 739349cc55cSDimitry Andric // Avoid calling real atexit as it is unreachable on at least on Linux. 74068d75effSDimitry Andric int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr); 74168d75effSDimitry Andric REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); 74268d75effSDimitry Andric return res; 74368d75effSDimitry Andric } 74468d75effSDimitry Andric #endif 74568d75effSDimitry Andric 74668d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_ATFORK 74768d75effSDimitry Andric extern "C" { 74868d75effSDimitry Andric extern int _pthread_atfork(void (*prepare)(), void (*parent)(), 74968d75effSDimitry Andric void (*child)()); 750*0fca6ea1SDimitry Andric } 75168d75effSDimitry Andric 75268d75effSDimitry Andric INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), 75368d75effSDimitry Andric void (*child)()) { 75468d75effSDimitry Andric #if CAN_SANITIZE_LEAKS 75568d75effSDimitry Andric __lsan::ScopedInterceptorDisabler disabler; 75668d75effSDimitry Andric #endif 75768d75effSDimitry Andric // REAL(pthread_atfork) cannot be called due to symbol indirections at least 75868d75effSDimitry Andric // on NetBSD 75968d75effSDimitry Andric return _pthread_atfork(prepare, parent, child); 76068d75effSDimitry Andric } 76168d75effSDimitry Andric #endif 76268d75effSDimitry Andric 76368d75effSDimitry Andric #if ASAN_INTERCEPT_VFORK 764*0fca6ea1SDimitry Andric DEFINE_REAL(int, vfork,) 765*0fca6ea1SDimitry Andric DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) 76668d75effSDimitry Andric #endif 76768d75effSDimitry Andric 76868d75effSDimitry Andric // ---------------------- InitializeAsanInterceptors ---------------- {{{1 76968d75effSDimitry Andric namespace __asan { 77068d75effSDimitry Andric void InitializeAsanInterceptors() { 77168d75effSDimitry Andric static bool was_called_once; 77268d75effSDimitry Andric CHECK(!was_called_once); 77368d75effSDimitry Andric was_called_once = true; 77406c3fb27SDimitry Andric InitializePlatformInterceptors(); 77568d75effSDimitry Andric InitializeCommonInterceptors(); 77668d75effSDimitry Andric InitializeSignalInterceptors(); 77768d75effSDimitry Andric 77868d75effSDimitry Andric // Intercept str* functions. 77968d75effSDimitry Andric ASAN_INTERCEPT_FUNC(strcat); 78068d75effSDimitry Andric ASAN_INTERCEPT_FUNC(strcpy); 78168d75effSDimitry Andric ASAN_INTERCEPT_FUNC(strncat); 78268d75effSDimitry Andric ASAN_INTERCEPT_FUNC(strncpy); 78368d75effSDimitry Andric ASAN_INTERCEPT_FUNC(strdup); 78468d75effSDimitry Andric # if ASAN_INTERCEPT___STRDUP 78568d75effSDimitry Andric ASAN_INTERCEPT_FUNC(__strdup); 78668d75effSDimitry Andric #endif 78768d75effSDimitry Andric #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 78868d75effSDimitry Andric ASAN_INTERCEPT_FUNC(index); 78968d75effSDimitry Andric #endif 79068d75effSDimitry Andric 79168d75effSDimitry Andric ASAN_INTERCEPT_FUNC(atoi); 79268d75effSDimitry Andric ASAN_INTERCEPT_FUNC(atol); 79368d75effSDimitry Andric ASAN_INTERCEPT_FUNC(atoll); 7948a4dda33SDimitry Andric ASAN_INTERCEPT_FUNC(strtol); 79568d75effSDimitry Andric ASAN_INTERCEPT_FUNC(strtoll); 7968a4dda33SDimitry Andric # if SANITIZER_GLIBC 7978a4dda33SDimitry Andric ASAN_INTERCEPT_FUNC(__isoc23_strtol); 7988a4dda33SDimitry Andric ASAN_INTERCEPT_FUNC(__isoc23_strtoll); 79968d75effSDimitry Andric # endif 80068d75effSDimitry Andric 80168d75effSDimitry Andric // Intecept jump-related functions. 80268d75effSDimitry Andric ASAN_INTERCEPT_FUNC(longjmp); 80368d75effSDimitry Andric 80468d75effSDimitry Andric # if ASAN_INTERCEPT_SWAPCONTEXT 80568d75effSDimitry Andric ASAN_INTERCEPT_FUNC(swapcontext); 806*0fca6ea1SDimitry Andric // See the makecontext interceptor above for an explanation. 807*0fca6ea1SDimitry Andric # if SANITIZER_SOLARIS && defined(__sparc__) 808*0fca6ea1SDimitry Andric ASAN_INTERCEPT_FUNC(__makecontext_v2); 809*0fca6ea1SDimitry Andric # else 8109e7101a8SDimitry Andric ASAN_INTERCEPT_FUNC(makecontext); 81168d75effSDimitry Andric # endif 812*0fca6ea1SDimitry Andric # endif 81368d75effSDimitry Andric # if ASAN_INTERCEPT__LONGJMP 81468d75effSDimitry Andric ASAN_INTERCEPT_FUNC(_longjmp); 81568d75effSDimitry Andric #endif 81668d75effSDimitry Andric #if ASAN_INTERCEPT___LONGJMP_CHK 81768d75effSDimitry Andric ASAN_INTERCEPT_FUNC(__longjmp_chk); 81868d75effSDimitry Andric #endif 81968d75effSDimitry Andric #if ASAN_INTERCEPT_SIGLONGJMP 82068d75effSDimitry Andric ASAN_INTERCEPT_FUNC(siglongjmp); 82168d75effSDimitry Andric #endif 82268d75effSDimitry Andric 82368d75effSDimitry Andric // Intercept exception handling functions. 82468d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_THROW 82568d75effSDimitry Andric ASAN_INTERCEPT_FUNC(__cxa_throw); 82668d75effSDimitry Andric #endif 82768d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 82868d75effSDimitry Andric ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception); 82968d75effSDimitry Andric #endif 83068d75effSDimitry Andric // Indirectly intercept std::rethrow_exception. 83168d75effSDimitry Andric #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 83206c3fb27SDimitry Andric ASAN_INTERCEPT_FUNC(_Unwind_RaiseException); 83368d75effSDimitry Andric #endif 83468d75effSDimitry Andric // Indirectly intercept std::rethrow_exception. 83568d75effSDimitry Andric #if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 83606c3fb27SDimitry Andric ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException); 83768d75effSDimitry Andric #endif 83868d75effSDimitry Andric 83968d75effSDimitry Andric // Intercept threading-related functions 84068d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_CREATE 841fe6060f1SDimitry Andric // TODO: this should probably have an unversioned fallback for newer arches? 84268d75effSDimitry Andric #if defined(ASAN_PTHREAD_CREATE_VERSION) 84368d75effSDimitry Andric ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION); 84468d75effSDimitry Andric #else 84568d75effSDimitry Andric ASAN_INTERCEPT_FUNC(pthread_create); 84668d75effSDimitry Andric #endif 84768d75effSDimitry Andric ASAN_INTERCEPT_FUNC(pthread_join); 84806c3fb27SDimitry Andric ASAN_INTERCEPT_FUNC(pthread_detach); 84906c3fb27SDimitry Andric ASAN_INTERCEPT_FUNC(pthread_exit); 85006c3fb27SDimitry Andric # endif 85106c3fb27SDimitry Andric 85206c3fb27SDimitry Andric # if ASAN_INTERCEPT_TIMEDJOIN 85306c3fb27SDimitry Andric ASAN_INTERCEPT_FUNC(pthread_timedjoin_np); 85406c3fb27SDimitry Andric #endif 85506c3fb27SDimitry Andric 85606c3fb27SDimitry Andric #if ASAN_INTERCEPT_TRYJOIN 85706c3fb27SDimitry Andric ASAN_INTERCEPT_FUNC(pthread_tryjoin_np); 85868d75effSDimitry Andric #endif 85968d75effSDimitry Andric 86068d75effSDimitry Andric // Intercept atexit function. 86168d75effSDimitry Andric #if ASAN_INTERCEPT___CXA_ATEXIT 86268d75effSDimitry Andric ASAN_INTERCEPT_FUNC(__cxa_atexit); 86368d75effSDimitry Andric #endif 86468d75effSDimitry Andric 86568d75effSDimitry Andric #if ASAN_INTERCEPT_ATEXIT 86668d75effSDimitry Andric ASAN_INTERCEPT_FUNC(atexit); 86768d75effSDimitry Andric #endif 86868d75effSDimitry Andric 86968d75effSDimitry Andric #if ASAN_INTERCEPT_PTHREAD_ATFORK 87068d75effSDimitry Andric ASAN_INTERCEPT_FUNC(pthread_atfork); 87168d75effSDimitry Andric #endif 87268d75effSDimitry Andric 87368d75effSDimitry Andric #if ASAN_INTERCEPT_VFORK 87468d75effSDimitry Andric ASAN_INTERCEPT_FUNC(vfork); 87568d75effSDimitry Andric #endif 87668d75effSDimitry Andric 87768d75effSDimitry Andric VReport(1, "AddressSanitizer: libc interceptors initialized\n"); 87868d75effSDimitry Andric } 87968d75effSDimitry Andric 880*0fca6ea1SDimitry Andric # if SANITIZER_WINDOWS 881*0fca6ea1SDimitry Andric # pragma pop_macro("strdup") 882*0fca6ea1SDimitry Andric # endif 883*0fca6ea1SDimitry Andric 88468d75effSDimitry Andric } // namespace __asan 88568d75effSDimitry Andric 88668d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA 887