955 lines · cpp
1//===-- asan_interceptors.cpp ---------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of AddressSanitizer, an address sanity checker.10//11// Intercept various libc functions.12//===----------------------------------------------------------------------===//13 14#include "asan_interceptors.h"15 16#include "asan_allocator.h"17#include "asan_internal.h"18#include "asan_mapping.h"19#include "asan_poisoning.h"20#include "asan_report.h"21#include "asan_stack.h"22#include "asan_stats.h"23#include "asan_suppressions.h"24#include "asan_thread.h"25#include "lsan/lsan_common.h"26#include "sanitizer_common/sanitizer_errno.h"27#include "sanitizer_common/sanitizer_internal_defs.h"28#include "sanitizer_common/sanitizer_libc.h"29 30// There is no general interception at all on Fuchsia.31// Only the functions in asan_interceptors_memintrinsics.cpp are32// really defined to replace libc functions.33#if !SANITIZER_FUCHSIA34 35# if SANITIZER_POSIX36# include "sanitizer_common/sanitizer_posix.h"37# endif38 39# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \40 ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION41# include <unwind.h>42# endif43 44# if defined(__i386) && SANITIZER_LINUX45# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"46# elif defined(__mips__) && SANITIZER_LINUX47# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"48# endif49 50namespace __asan {51 52#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \53 ASAN_READ_RANGE((ctx), (s), \54 common_flags()->strict_string_checks ? (len) + 1 : (n))55 56# define ASAN_READ_STRING(ctx, s, n) \57 ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n))58 59static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {60#if SANITIZER_INTERCEPT_STRNLEN61 if (static_cast<bool>(REAL(strnlen)))62 return REAL(strnlen)(s, maxlen);63# endif64 return internal_strnlen(s, maxlen);65}66 67static inline uptr MaybeRealWcsnlen(const wchar_t* s, uptr maxlen) {68# if SANITIZER_INTERCEPT_WCSNLEN69 if (static_cast<bool>(REAL(wcsnlen)))70 return REAL(wcsnlen)(s, maxlen);71# endif72 return internal_wcsnlen(s, maxlen);73}74 75void SetThreadName(const char *name) {76 AsanThread *t = GetCurrentThread();77 if (t)78 asanThreadRegistry().SetThreadName(t->tid(), name);79}80 81int OnExit() {82 if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&83 __lsan::HasReportedLeaks()) {84 return common_flags()->exitcode;85 }86 // FIXME: ask frontend whether we need to return failure.87 return 0;88}89 90} // namespace __asan91 92// ---------------------- Wrappers ---------------- {{{193using namespace __asan;94 95DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize)96DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)97 98#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \99 ASAN_INTERCEPT_FUNC_VER(name, ver)100#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \101 ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)102#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \103 ASAN_WRITE_RANGE(ctx, ptr, size)104#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \105 ASAN_READ_RANGE(ctx, ptr, size)106# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \107 ASAN_INTERCEPTOR_ENTER(ctx, func); \108 do { \109 if constexpr (SANITIZER_APPLE) { \110 if (UNLIKELY(!AsanInited())) \111 return REAL(func)(__VA_ARGS__); \112 } else { \113 if (!TryAsanInitFromRtl()) \114 return REAL(func)(__VA_ARGS__); \115 } \116 } while (false)117#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \118 do { \119 } while (false)120#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \121 do { \122 } while (false)123#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \124 do { \125 } while (false)126#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \127 do { \128 } while (false)129#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)130// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)131// But asan does not remember UserId's for threads (pthread_t);132// and remembers all ever existed threads, so the linear search by UserId133// can be slow.134#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \135 do { \136 } while (false)137#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)138// Strict init-order checking is dlopen-hostile:139// https://github.com/google/sanitizers/issues/178140# define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \141 ({ \142 if (flags()->strict_init_order) \143 StopInitOrderChecking(); \144 CheckNoDeepBind(filename, flag); \145 REAL(dlopen)(filename, flag); \146 })147# define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()148# define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)149# define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()150# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())151# define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \152 if (AsanThread *t = GetCurrentThread()) { \153 *begin = t->tls_begin(); \154 *end = t->tls_end(); \155 } else { \156 *begin = *end = 0; \157 }158 159template <class Mmap>160static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,161 int prot, int flags, int fd, OFF64_T offset) {162 void *res = real_mmap(addr, length, prot, flags, fd, offset);163 if (length && res != (void *)-1) {164 const uptr beg = reinterpret_cast<uptr>(res);165 DCHECK(IsAligned(beg, GetPageSize()));166 SIZE_T rounded_length = RoundUpTo(length, GetPageSize());167 // Only unpoison shadow if it's an ASAN managed address.168 if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))169 PoisonShadow(beg, RoundUpTo(length, GetPageSize()), 0);170 }171 return res;172}173 174template <class Munmap>175static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {176 // We should not tag if munmap fail, but it's to late to tag after177 // real_munmap, as the pages could be mmaped by another thread.178 const uptr beg = reinterpret_cast<uptr>(addr);179 if (length && IsAligned(beg, GetPageSize())) {180 SIZE_T rounded_length = RoundUpTo(length, GetPageSize());181 // Protect from unmapping the shadow.182 if (AddrIsInMem(beg) && AddrIsInMem(beg + rounded_length - 1))183 PoisonShadow(beg, rounded_length, 0);184 }185 return real_munmap(addr, length);186}187 188# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \189 fd, offset) \190 do { \191 (void)(ctx); \192 return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \193 } while (false)194 195# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \196 do { \197 (void)(ctx); \198 return munmap_interceptor(REAL(munmap), addr, sz); \199 } while (false)200 201#if CAN_SANITIZE_LEAKS202#define COMMON_INTERCEPTOR_STRERROR() \203 __lsan::ScopedInterceptorDisabler disabler204#endif205 206# define SIGNAL_INTERCEPTOR_ENTER() \207 do { \208 AsanInitFromRtl(); \209 } while (false)210 211# include "sanitizer_common/sanitizer_common_interceptors.inc"212# include "sanitizer_common/sanitizer_signal_interceptors.inc"213 214// Syscall interceptors don't have contexts, we don't support suppressions215// for them.216#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)217#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)218#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \219 do { \220 (void)(p); \221 (void)(s); \222 } while (false)223#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \224 do { \225 (void)(p); \226 (void)(s); \227 } while (false)228#include "sanitizer_common/sanitizer_common_syscalls.inc"229#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"230 231#if ASAN_INTERCEPT_PTHREAD_CREATE232static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {233 AsanThread *t = (AsanThread *)arg;234 SetCurrentThread(t);235 auto self = GetThreadSelf();236 auto args = asanThreadArgRetval().GetArgs(self);237 t->ThreadStart(GetTid());238 239# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \240 SANITIZER_SOLARIS241 __sanitizer_sigset_t sigset;242 t->GetStartData(sigset);243 SetSigProcMask(&sigset, nullptr);244# endif245 246 thread_return_t retval = (*args.routine)(args.arg_retval);247 asanThreadArgRetval().Finish(self, retval);248 return retval;249}250 251INTERCEPTOR(int, pthread_create, void *thread, void *attr,252 void *(*start_routine)(void *), void *arg) {253 EnsureMainThreadIDIsCorrect();254 // Strict init-order checking is thread-hostile.255 if (flags()->strict_init_order)256 StopInitOrderChecking();257 GET_STACK_TRACE_THREAD;258 bool detached = [attr]() {259 int d = 0;260 return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) &&261 IsStateDetached(d);262 }();263 264 u32 current_tid = GetCurrentTidOrInvalid();265 266 __sanitizer_sigset_t sigset = {};267# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \268 SANITIZER_SOLARIS269 ScopedBlockSignals block(&sigset);270# endif271 272 AsanThread *t = AsanThread::Create(sigset, current_tid, &stack, detached);273 274 int result;275 {276 // Ignore all allocations made by pthread_create: thread stack/TLS may be277 // stored by pthread for future reuse even after thread destruction, and278 // the linked list it's stored in doesn't even hold valid pointers to the279 // objects, the latter are calculated by obscure pointer arithmetic.280# if CAN_SANITIZE_LEAKS281 __lsan::ScopedInterceptorDisabler disabler;282# endif283 asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr {284 result = REAL(pthread_create)(thread, attr, asan_thread_start, t);285 return result ? 0 : *(uptr *)(thread);286 });287 }288 if (result != 0) {289 // If the thread didn't start delete the AsanThread to avoid leaking it.290 // Note AsanThreadContexts never get destroyed so the AsanThreadContext291 // that was just created for the AsanThread is wasted.292 t->Destroy();293 }294 return result;295}296 297INTERCEPTOR(int, pthread_join, void *thread, void **retval) {298 int result;299 asanThreadArgRetval().Join((uptr)thread, [&]() {300 result = REAL(pthread_join)(thread, retval);301 return !result;302 });303 return result;304}305 306INTERCEPTOR(int, pthread_detach, void *thread) {307 int result;308 asanThreadArgRetval().Detach((uptr)thread, [&]() {309 result = REAL(pthread_detach)(thread);310 return !result;311 });312 return result;313}314 315INTERCEPTOR(void, pthread_exit, void *retval) {316 asanThreadArgRetval().Finish(GetThreadSelf(), retval);317 REAL(pthread_exit)(retval);318}319 320# if ASAN_INTERCEPT_TRYJOIN321INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {322 int result;323 asanThreadArgRetval().Join((uptr)thread, [&]() {324 result = REAL(pthread_tryjoin_np)(thread, ret);325 return !result;326 });327 return result;328}329# endif330 331# if ASAN_INTERCEPT_TIMEDJOIN332INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,333 const struct timespec *abstime) {334 int result;335 asanThreadArgRetval().Join((uptr)thread, [&]() {336 result = REAL(pthread_timedjoin_np)(thread, ret, abstime);337 return !result;338 });339 return result;340}341# endif342 343DEFINE_INTERNAL_PTHREAD_FUNCTIONS344#endif // ASAN_INTERCEPT_PTHREAD_CREATE345 346#if ASAN_INTERCEPT_SWAPCONTEXT347static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {348 // Only clear if we know the stack. This should be true only for contexts349 // created with makecontext().350 if (!ssize)351 return;352 // Align to page size.353 uptr PageSize = GetPageSizeCached();354 uptr bottom = RoundDownTo(stack, PageSize);355 if (!AddrIsInMem(bottom))356 return;357 ssize += stack - bottom;358 ssize = RoundUpTo(ssize, PageSize);359 PoisonShadow(bottom, ssize, 0);360}361 362// Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address363// as on other targets. For binary compatibility, the new version uses a364// different external name, so we intercept that.365# if SANITIZER_SOLARIS && defined(__sparc__)366INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(),367 int argc, ...) {368# else369INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,370 ...) {371# endif372 va_list ap;373 uptr args[64];374 // We don't know a better way to forward ... into REAL function. We can375 // increase args size if necessary.376 CHECK_LE(argc, ARRAY_SIZE(args));377 internal_memset(args, 0, sizeof(args));378 va_start(ap, argc);379 for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);380 va_end(ap);381 382# define ENUMERATE_ARRAY_4(start) \383 args[start], args[start + 1], args[start + 2], args[start + 3]384# define ENUMERATE_ARRAY_16(start) \385 ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \386 ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)387# define ENUMERATE_ARRAY_64() \388 ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \389 ENUMERATE_ARRAY_16(48)390 391# if SANITIZER_SOLARIS && defined(__sparc__)392 REAL(__makecontext_v2)393# else394 REAL(makecontext)395# endif396 ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());397 398# undef ENUMERATE_ARRAY_4399# undef ENUMERATE_ARRAY_16400# undef ENUMERATE_ARRAY_64401 402 // Sign the stack so we can identify it for unpoisoning.403 SignContextStack(ucp);404}405 406INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,407 struct ucontext_t *ucp) {408 static bool reported_warning = false;409 if (!reported_warning) {410 Report("WARNING: ASan doesn't fully support makecontext/swapcontext "411 "functions and may produce false positives in some cases!\n");412 reported_warning = true;413 }414 // Clear shadow memory for new context (it may share stack415 // with current context).416 uptr stack, ssize;417 ReadContextStack(ucp, &stack, &ssize);418 ClearShadowMemoryForContextStack(stack, ssize);419 420# if __has_attribute(__indirect_return__) && \421 (defined(__x86_64__) || defined(__i386__))422 int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)423 __attribute__((__indirect_return__)) = REAL(swapcontext);424 int res = real_swapcontext(oucp, ucp);425# else426 int res = REAL(swapcontext)(oucp, ucp);427# endif428 // swapcontext technically does not return, but program may swap context to429 // "oucp" later, that would look as if swapcontext() returned 0.430 // We need to clear shadow for ucp once again, as it may be in arbitrary431 // state.432 ClearShadowMemoryForContextStack(stack, ssize);433 return res;434}435#endif // ASAN_INTERCEPT_SWAPCONTEXT436 437#if SANITIZER_NETBSD438#define longjmp __longjmp14439#define siglongjmp __siglongjmp14440#endif441 442INTERCEPTOR(void, longjmp, void *env, int val) {443 __asan_handle_no_return();444 REAL(longjmp)(env, val);445}446 447#if ASAN_INTERCEPT__LONGJMP448INTERCEPTOR(void, _longjmp, void *env, int val) {449 __asan_handle_no_return();450 REAL(_longjmp)(env, val);451}452#endif453 454#if ASAN_INTERCEPT___LONGJMP_CHK455INTERCEPTOR(void, __longjmp_chk, void *env, int val) {456 __asan_handle_no_return();457 REAL(__longjmp_chk)(env, val);458}459#endif460 461#if ASAN_INTERCEPT_SIGLONGJMP462INTERCEPTOR(void, siglongjmp, void *env, int val) {463 __asan_handle_no_return();464 REAL(siglongjmp)(env, val);465}466#endif467 468#if ASAN_INTERCEPT___CXA_THROW469INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {470 CHECK(REAL(__cxa_throw));471 __asan_handle_no_return();472 REAL(__cxa_throw)(a, b, c);473}474#endif475 476#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION477INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) {478 CHECK(REAL(__cxa_rethrow_primary_exception));479 __asan_handle_no_return();480 REAL(__cxa_rethrow_primary_exception)(a);481}482#endif483 484#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION485INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,486 _Unwind_Exception *object) {487 CHECK(REAL(_Unwind_RaiseException));488 __asan_handle_no_return();489 return REAL(_Unwind_RaiseException)(object);490}491#endif492 493#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION494INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,495 _Unwind_Exception *object) {496 CHECK(REAL(_Unwind_SjLj_RaiseException));497 __asan_handle_no_return();498 return REAL(_Unwind_SjLj_RaiseException)(object);499}500#endif501 502#if ASAN_INTERCEPT_INDEX503# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX504INTERCEPTOR(char*, index, const char *string, int c)505 ALIAS(WRAP(strchr));506# else507# if SANITIZER_APPLE508DECLARE_REAL(char*, index, const char *string, int c)509OVERRIDE_FUNCTION(index, strchr);510# else511DEFINE_REAL(char*, index, const char *string, int c)512# endif513# endif514#endif // ASAN_INTERCEPT_INDEX515 516// For both strcat() and strncat() we need to check the validity of |to|517// argument irrespective of the |from| length.518 INTERCEPTOR(char *, strcat, char *to, const char *from) {519 void *ctx;520 ASAN_INTERCEPTOR_ENTER(ctx, strcat);521 AsanInitFromRtl();522 if (flags()->replace_str) {523 uptr from_length = internal_strlen(from);524 ASAN_READ_RANGE(ctx, from, from_length + 1);525 uptr to_length = internal_strlen(to);526 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);527 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);528 // If the copying actually happens, the |from| string should not overlap529 // with the resulting string starting at |to|, which has a length of530 // to_length + from_length + 1.531 if (from_length > 0) {532 CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,533 from_length + 1);534 }535 }536 return REAL(strcat)(to, from);537 }538 539INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) {540 void *ctx;541 ASAN_INTERCEPTOR_ENTER(ctx, strncat);542 AsanInitFromRtl();543 if (flags()->replace_str) {544 uptr from_length = MaybeRealStrnlen(from, size);545 uptr copy_length = Min<uptr>(size, from_length + 1);546 ASAN_READ_RANGE(ctx, from, copy_length);547 uptr to_length = internal_strlen(to);548 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);549 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);550 if (from_length > 0) {551 CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,552 from, copy_length);553 }554 }555 return REAL(strncat)(to, from, size);556}557 558INTERCEPTOR(char *, strcpy, char *to, const char *from) {559 void *ctx;560 ASAN_INTERCEPTOR_ENTER(ctx, strcpy);561 if constexpr (SANITIZER_APPLE) {562 // strcpy is called from malloc_default_purgeable_zone()563 // in __asan::ReplaceSystemAlloc() on Mac.564 if (UNLIKELY(!AsanInited()))565 return REAL(strcpy)(to, from);566 } else {567 if (!TryAsanInitFromRtl())568 return REAL(strcpy)(to, from);569 }570 571 if (flags()->replace_str) {572 uptr from_size = internal_strlen(from) + 1;573 CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);574 ASAN_READ_RANGE(ctx, from, from_size);575 ASAN_WRITE_RANGE(ctx, to, from_size);576 }577 return REAL(strcpy)(to, from);578}579 580INTERCEPTOR(wchar_t*, wcscpy, wchar_t* to, const wchar_t* from) {581 void* ctx;582 ASAN_INTERCEPTOR_ENTER(ctx, wcscpy);583 if (!TryAsanInitFromRtl())584 return REAL(wcscpy)(to, from);585 if (flags()->replace_str) {586 uptr size = (internal_wcslen(from) + 1) * sizeof(wchar_t);587 CHECK_RANGES_OVERLAP("wcscpy", to, size, from, size);588 ASAN_READ_RANGE(ctx, from, size);589 ASAN_WRITE_RANGE(ctx, to, size);590 }591 return REAL(wcscpy)(to, from);592}593 594// Windows doesn't always define the strdup identifier,595// and when it does it's a macro defined to either _strdup596// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so597// we want to intercept that. push/pop_macro are used to avoid problems598// if this file ends up including <string.h> in the future.599# if SANITIZER_WINDOWS600# pragma push_macro("strdup")601# undef strdup602# define strdup _strdup603# endif604 605INTERCEPTOR(char*, strdup, const char *s) {606 void *ctx;607 ASAN_INTERCEPTOR_ENTER(ctx, strdup);608 // Allowing null input is Windows-specific609 if (SANITIZER_WINDOWS && UNLIKELY(!s))610 return nullptr;611 if (UNLIKELY(!TryAsanInitFromRtl()))612 return internal_strdup(s);613 uptr length = internal_strlen(s);614 if (flags()->replace_str) {615 ASAN_READ_RANGE(ctx, s, length + 1);616 }617 GET_STACK_TRACE_MALLOC;618 void *new_mem = asan_malloc(length + 1, &stack);619 if (new_mem) {620 REAL(memcpy)(new_mem, s, length + 1);621 }622 return reinterpret_cast<char*>(new_mem);623}624 625# if ASAN_INTERCEPT___STRDUP626INTERCEPTOR(char*, __strdup, const char *s) {627 void *ctx;628 ASAN_INTERCEPTOR_ENTER(ctx, strdup);629 if (UNLIKELY(!TryAsanInitFromRtl()))630 return internal_strdup(s);631 uptr length = internal_strlen(s);632 if (flags()->replace_str) {633 ASAN_READ_RANGE(ctx, s, length + 1);634 }635 GET_STACK_TRACE_MALLOC;636 void *new_mem = asan_malloc(length + 1, &stack);637 if (new_mem) {638 REAL(memcpy)(new_mem, s, length + 1);639 }640 return reinterpret_cast<char*>(new_mem);641}642#endif // ASAN_INTERCEPT___STRDUP643 644INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) {645 void *ctx;646 ASAN_INTERCEPTOR_ENTER(ctx, strncpy);647 AsanInitFromRtl();648 if (flags()->replace_str) {649 uptr from_size = Min<uptr>(size, MaybeRealStrnlen(from, size) + 1);650 CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);651 ASAN_READ_RANGE(ctx, from, from_size);652 ASAN_WRITE_RANGE(ctx, to, size);653 }654 return REAL(strncpy)(to, from, size);655}656 657INTERCEPTOR(wchar_t*, wcsncpy, wchar_t* to, const wchar_t* from, uptr size) {658 void* ctx;659 ASAN_INTERCEPTOR_ENTER(ctx, wcsncpy);660 AsanInitFromRtl();661 if (flags()->replace_str) {662 uptr from_size =663 Min(size, MaybeRealWcsnlen(from, size) + 1) * sizeof(wchar_t);664 CHECK_RANGES_OVERLAP("wcsncpy", to, from_size, from, from_size);665 ASAN_READ_RANGE(ctx, from, from_size);666 ASAN_WRITE_RANGE(ctx, to, size * sizeof(wchar_t));667 }668 return REAL(wcsncpy)(to, from, size);669}670 671template <typename Fn>672static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,673 char **endptr, int base)674 -> decltype(real(nullptr, nullptr, 0)) {675 if (!flags()->replace_str)676 return real(nptr, endptr, base);677 char *real_endptr;678 auto res = real(nptr, &real_endptr, base);679 StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);680 return res;681}682 683# define INTERCEPTOR_STRTO_BASE(ret_type, func) \684 INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \685 void *ctx; \686 ASAN_INTERCEPTOR_ENTER(ctx, func); \687 AsanInitFromRtl(); \688 return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \689 }690 691INTERCEPTOR_STRTO_BASE(long long, strtoll)692 693# if SANITIZER_WINDOWS694INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) {695 // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead,696 // call REAL(strtoll) and do the range check ourselves.697 COMPILER_CHECK(sizeof(long) == sizeof(u32));698 699 void *ctx;700 ASAN_INTERCEPTOR_ENTER(ctx, strtol);701 AsanInitFromRtl();702 703 long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base);704 705 if (result > INT32_MAX) {706 errno = errno_ERANGE;707 return INT32_MAX;708 }709 if (result < INT32_MIN) {710 errno = errno_ERANGE;711 return INT32_MIN;712 }713 return (long)result;714}715# else716INTERCEPTOR_STRTO_BASE(long, strtol)717# endif718 719# if SANITIZER_GLIBC720INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)721INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)722# endif723 724INTERCEPTOR(int, atoi, const char *nptr) {725 void *ctx;726 ASAN_INTERCEPTOR_ENTER(ctx, atoi);727 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))728 return REAL(atoi)(nptr);729 AsanInitFromRtl();730 if (!flags()->replace_str) {731 return REAL(atoi)(nptr);732 }733 char *real_endptr;734 // "man atoi" tells that behavior of atoi(nptr) is the same as735 // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the736 // parsed integer can't be stored in *long* type (even if it's737 // different from int). So, we just imitate this behavior.738 int result = REAL(strtol)(nptr, &real_endptr, 10);739 FixRealStrtolEndptr(nptr, &real_endptr);740 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);741 return result;742}743 744INTERCEPTOR(long, atol, const char *nptr) {745 void *ctx;746 ASAN_INTERCEPTOR_ENTER(ctx, atol);747 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))748 return REAL(atol)(nptr);749 AsanInitFromRtl();750 if (!flags()->replace_str) {751 return REAL(atol)(nptr);752 }753 char *real_endptr;754 long result = REAL(strtol)(nptr, &real_endptr, 10);755 FixRealStrtolEndptr(nptr, &real_endptr);756 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);757 return result;758}759 760INTERCEPTOR(long long, atoll, const char *nptr) {761 void *ctx;762 ASAN_INTERCEPTOR_ENTER(ctx, atoll);763 AsanInitFromRtl();764 if (!flags()->replace_str) {765 return REAL(atoll)(nptr);766 }767 char *real_endptr;768 long long result = REAL(strtoll)(nptr, &real_endptr, 10);769 FixRealStrtolEndptr(nptr, &real_endptr);770 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);771 return result;772}773 774#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT775static void AtCxaAtexit(void *unused) {776 (void)unused;777 StopInitOrderChecking();778}779#endif780 781#if ASAN_INTERCEPT___CXA_ATEXIT782INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,783 void *dso_handle) {784 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))785 return REAL(__cxa_atexit)(func, arg, dso_handle);786 AsanInitFromRtl();787# if CAN_SANITIZE_LEAKS788 __lsan::ScopedInterceptorDisabler disabler;789#endif790 int res = REAL(__cxa_atexit)(func, arg, dso_handle);791 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);792 return res;793}794#endif // ASAN_INTERCEPT___CXA_ATEXIT795 796#if ASAN_INTERCEPT_ATEXIT797INTERCEPTOR(int, atexit, void (*func)()) {798 AsanInitFromRtl();799# if CAN_SANITIZE_LEAKS800 __lsan::ScopedInterceptorDisabler disabler;801#endif802 // Avoid calling real atexit as it is unreachable on at least on Linux.803 int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr);804 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);805 return res;806}807#endif808 809#if ASAN_INTERCEPT_PTHREAD_ATFORK810extern "C" {811extern int _pthread_atfork(void (*prepare)(), void (*parent)(),812 void (*child)());813}814 815INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),816 void (*child)()) {817#if CAN_SANITIZE_LEAKS818 __lsan::ScopedInterceptorDisabler disabler;819#endif820 // REAL(pthread_atfork) cannot be called due to symbol indirections at least821 // on NetBSD822 return _pthread_atfork(prepare, parent, child);823}824#endif825 826#if ASAN_INTERCEPT_VFORK827DEFINE_REAL(int, vfork,)828DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)829#endif830 831// ---------------------- InitializeAsanInterceptors ---------------- {{{1832namespace __asan {833void InitializeAsanInterceptors() {834 static bool was_called_once;835 CHECK(!was_called_once);836 was_called_once = true;837 InitializePlatformInterceptors();838 InitializeCommonInterceptors();839 InitializeSignalInterceptors();840 841 // Intercept str* functions.842 ASAN_INTERCEPT_FUNC(strcat);843 ASAN_INTERCEPT_FUNC(strcpy);844 ASAN_INTERCEPT_FUNC(strncat);845 ASAN_INTERCEPT_FUNC(strncpy);846 ASAN_INTERCEPT_FUNC(strdup);847 848 // Intercept wcs* functions.849 ASAN_INTERCEPT_FUNC(wcscpy);850 ASAN_INTERCEPT_FUNC(wcsncpy);851 852# if ASAN_INTERCEPT___STRDUP853 ASAN_INTERCEPT_FUNC(__strdup);854#endif855#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX856 ASAN_INTERCEPT_FUNC(index);857#endif858 859 ASAN_INTERCEPT_FUNC(atoi);860 ASAN_INTERCEPT_FUNC(atol);861 ASAN_INTERCEPT_FUNC(atoll);862 ASAN_INTERCEPT_FUNC(strtol);863 ASAN_INTERCEPT_FUNC(strtoll);864# if SANITIZER_GLIBC865 ASAN_INTERCEPT_FUNC(__isoc23_strtol);866 ASAN_INTERCEPT_FUNC(__isoc23_strtoll);867# endif868 869 // Intercept jump-related functions.870 ASAN_INTERCEPT_FUNC(longjmp);871 872# if ASAN_INTERCEPT_SWAPCONTEXT873 ASAN_INTERCEPT_FUNC(swapcontext);874 // See the makecontext interceptor above for an explanation.875# if SANITIZER_SOLARIS && defined(__sparc__)876 ASAN_INTERCEPT_FUNC(__makecontext_v2);877# else878 ASAN_INTERCEPT_FUNC(makecontext);879# endif880# endif881# if ASAN_INTERCEPT__LONGJMP882 ASAN_INTERCEPT_FUNC(_longjmp);883#endif884#if ASAN_INTERCEPT___LONGJMP_CHK885 ASAN_INTERCEPT_FUNC(__longjmp_chk);886#endif887#if ASAN_INTERCEPT_SIGLONGJMP888 ASAN_INTERCEPT_FUNC(siglongjmp);889#endif890 891 // Intercept exception handling functions.892#if ASAN_INTERCEPT___CXA_THROW893 ASAN_INTERCEPT_FUNC(__cxa_throw);894#endif895#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION896 ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);897#endif898 // Indirectly intercept std::rethrow_exception.899#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION900 ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);901#endif902 // Indirectly intercept std::rethrow_exception.903#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION904 ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);905#endif906 907 // Intercept threading-related functions908#if ASAN_INTERCEPT_PTHREAD_CREATE909// TODO: this should probably have an unversioned fallback for newer arches?910#if defined(ASAN_PTHREAD_CREATE_VERSION)911 ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);912#else913 ASAN_INTERCEPT_FUNC(pthread_create);914#endif915 ASAN_INTERCEPT_FUNC(pthread_join);916 ASAN_INTERCEPT_FUNC(pthread_detach);917 ASAN_INTERCEPT_FUNC(pthread_exit);918# endif919 920# if ASAN_INTERCEPT_TIMEDJOIN921 ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);922#endif923 924#if ASAN_INTERCEPT_TRYJOIN925 ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);926#endif927 928 // Intercept atexit function.929#if ASAN_INTERCEPT___CXA_ATEXIT930 ASAN_INTERCEPT_FUNC(__cxa_atexit);931#endif932 933#if ASAN_INTERCEPT_ATEXIT934 ASAN_INTERCEPT_FUNC(atexit);935#endif936 937#if ASAN_INTERCEPT_PTHREAD_ATFORK938 ASAN_INTERCEPT_FUNC(pthread_atfork);939#endif940 941#if ASAN_INTERCEPT_VFORK942 ASAN_INTERCEPT_FUNC(vfork);943#endif944 945 VReport(1, "AddressSanitizer: libc interceptors initialized\n");946}947 948# if SANITIZER_WINDOWS949# pragma pop_macro("strdup")950# endif951 952} // namespace __asan953 954#endif // !SANITIZER_FUCHSIA955