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-exception
6//
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 are
32// really defined to replace libc functions.
33#if !SANITIZER_FUCHSIA
34
35# if SANITIZER_POSIX
36# include "sanitizer_common/sanitizer_posix.h"
37# endif
38
39# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \
40 ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
41# include <unwind.h>
42# endif
43
44# if defined(__i386) && SANITIZER_LINUX
45# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
46# elif defined(__mips__) && SANITIZER_LINUX
47# define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
48# endif
49
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_STRNLEN
61 if (static_cast<bool>(REAL(strnlen)))
62 return REAL(strnlen)(s, maxlen);
63# endif
64 return internal_strnlen(s, maxlen);
65}
66
67static inline uptr MaybeRealWcsnlen(const wchar_t* s, uptr maxlen) {
68# if SANITIZER_INTERCEPT_WCSNLEN
69 if (static_cast<bool>(REAL(wcsnlen)))
70 return REAL(wcsnlen)(s, maxlen);
71# endif
72 return internal_wcsnlen(s, maxlen);
73}
74
75void SetThreadName(const char* name) {
76 AsanThread* t = GetCurrentThread();
77 if (t)
78 asanThreadRegistry().SetThreadName(tid: 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# if SANITIZER_POSIX
91static inline bool RangeOverlaps(uptr beg, uptr end_excl, uptr seg_beg,
92 uptr seg_end_incl) {
93 if (!seg_beg && !seg_end_incl)
94 return false;
95 uptr seg_end_excl = seg_end_incl + 1;
96 return beg < seg_end_excl && end_excl > seg_beg;
97}
98
99static inline bool IntersectsShadow(uptr beg, uptr end_excl) {
100 // Check shadow regions
101 if (RangeOverlaps(beg, end_excl, kLowShadowBeg, kLowShadowEnd))
102 return true;
103 if (kMidShadowBeg &&
104 RangeOverlaps(beg, end_excl, kMidShadowBeg, kMidShadowEnd))
105 return true;
106 if (RangeOverlaps(beg, end_excl, kHighShadowBeg, kHighShadowEnd))
107 return true;
108 return false;
109}
110# endif // SANITIZER_POSIX
111
112} // namespace __asan
113
114// ---------------------- Wrappers ---------------- {{{1
115using namespace __asan;
116
117DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, usize)
118DECLARE_REAL_AND_INTERCEPTOR(void, free, void*)
119
120# define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
121 ASAN_INTERCEPT_FUNC_VER(name, ver)
122# define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
123 ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
124# define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
125 ASAN_WRITE_RANGE(ctx, ptr, size)
126# define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
127 ASAN_READ_RANGE(ctx, ptr, size)
128# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
129 ASAN_INTERCEPTOR_ENTER(ctx, func); \
130 do { \
131 if constexpr (SANITIZER_APPLE) { \
132 if (UNLIKELY(!AsanInited())) \
133 return REAL(func)(__VA_ARGS__); \
134 } else { \
135 if (!TryAsanInitFromRtl()) \
136 return REAL(func)(__VA_ARGS__); \
137 } \
138 } while (false)
139# define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
140 do { \
141 } while (false)
142# define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
143 do { \
144 } while (false)
145# define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
146 do { \
147 } while (false)
148# define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
149 do { \
150 } while (false)
151# define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
152// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
153// But asan does not remember UserId's for threads (pthread_t);
154// and remembers all ever existed threads, so the linear search by UserId
155// can be slow.
156# define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
157 do { \
158 } while (false)
159# define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
160// Strict init-order checking is dlopen-hostile:
161// https://github.com/google/sanitizers/issues/178
162# define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
163 ({ \
164 if (flags()->strict_init_order) \
165 StopInitOrderChecking(); \
166 OnDlOpen(filename, flag); \
167 REAL(dlopen)(filename, flag); \
168 })
169# define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
170# define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
171# define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
172# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())
173# define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
174 if (AsanThread* t = GetCurrentThread()) { \
175 *begin = t->tls_begin(); \
176 *end = t->tls_end(); \
177 } else { \
178 *begin = *end = 0; \
179 }
180
181# if SANITIZER_INTERCEPT_MMAP
182template <class Mmap>
183static void* mmap_interceptor(Mmap real_mmap, void* addr, SIZE_T length,
184 int prot, int flags, int fd, OFF64_T offset) {
185# if SANITIZER_POSIX
186 if (length == 0)
187 return real_mmap(addr, length, prot, flags, fd, offset);
188 const uptr start = reinterpret_cast<uptr>(addr);
189 uptr end_excl;
190 if (UNLIKELY(__builtin_add_overflow(start, static_cast<uptr>(length),
191 &end_excl))) {
192 errno = errno_EINVAL;
193 return (void*)-1;
194 }
195 if (flags & map_fixed) {
196 // TODO: shadow gap may need to be checked
197 if (__asan::IntersectsShadow(beg: start, end_excl)) {
198 errno = errno_EINVAL;
199 return (void*)-1;
200 }
201 }
202# endif // SANITIZER_POSIX
203
204 void* res = real_mmap(addr, length, prot, flags, fd, offset);
205 if (length && res != (void*)-1) {
206 const uptr beg = reinterpret_cast<uptr>(res);
207 DCHECK(IsAligned(beg, GetPageSize()));
208 SIZE_T rounded_length = RoundUpTo(size: length, boundary: GetPageSize());
209 // Only unpoison shadow if it's an ASAN managed address.
210 if (AddrIsInMem(a: beg) && AddrIsInMem(a: beg + rounded_length - 1))
211 PoisonShadow(addr: beg, size: RoundUpTo(size: length, boundary: GetPageSize()), value: 0);
212 }
213 return res;
214}
215
216template <class Munmap>
217static int munmap_interceptor(Munmap real_munmap, void* addr, SIZE_T length) {
218 const uptr start = reinterpret_cast<uptr>(addr);
219
220# if SANITIZER_POSIX
221 if (length == 0)
222 return real_munmap(addr, length);
223
224 uptr end_excl;
225 if (UNLIKELY(__builtin_add_overflow(start, static_cast<uptr>(length),
226 &end_excl))) {
227 errno = errno_EINVAL;
228 return -1;
229 }
230 // TODO: shadow gap may need to be checked
231 if (__asan::IntersectsShadow(beg: start, end_excl)) {
232 errno = errno_EINVAL;
233 return -1;
234 }
235# endif // SANITIZER_POSIX
236
237 // We should not tag if munmap fail, but it's to late to tag after
238 // real_munmap, as the pages could be mmaped by another thread.
239 if (length && IsAligned(a: start, alignment: GetPageSize())) {
240 SIZE_T rounded_length = RoundUpTo(size: length, boundary: GetPageSize());
241 // Protect from unmapping the shadow.
242 if (AddrIsInMem(a: start) && AddrIsInMem(a: start + rounded_length - 1))
243 PoisonShadow(addr: start, size: rounded_length, value: 0);
244 }
245 return real_munmap(addr, length);
246}
247# endif // SANITIZER_INTERCEPT_MMAP
248
249# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
250 fd, offset) \
251 do { \
252 (void)(ctx); \
253 return mmap_interceptor(REAL(mmap), addr, length, prot, flags, fd, \
254 offset); \
255 } while (false)
256
257# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
258 do { \
259 (void)(ctx); \
260 return munmap_interceptor(REAL(munmap), addr, length); \
261 } while (false)
262
263# if CAN_SANITIZE_LEAKS
264# define COMMON_INTERCEPTOR_STRERROR() \
265 __lsan::ScopedInterceptorDisabler disabler
266# endif
267
268# define SIGNAL_INTERCEPTOR_ENTER() \
269 do { \
270 AsanInitFromRtl(); \
271 } while (false)
272
273# include "sanitizer_common/sanitizer_common_interceptors.inc"
274# include "sanitizer_common/sanitizer_signal_interceptors.inc"
275
276// Syscall interceptors don't have contexts, we don't support suppressions
277// for them.
278# define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
279# define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
280# define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
281 do { \
282 (void)(p); \
283 (void)(s); \
284 } while (false)
285# define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
286 do { \
287 (void)(p); \
288 (void)(s); \
289 } while (false)
290# include "sanitizer_common/sanitizer_common_syscalls.inc"
291# include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
292
293# if ASAN_INTERCEPT_PTHREAD_CREATE
294static thread_return_t THREAD_CALLING_CONV asan_thread_start(void* arg) {
295 AsanThread* t = (AsanThread*)arg;
296 SetCurrentThread(t);
297 auto self = GetThreadSelf();
298 auto args = asanThreadArgRetval().GetArgs(thread: self);
299 t->ThreadStart(os_id: GetTid());
300
301# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
302 SANITIZER_SOLARIS
303 __sanitizer_sigset_t sigset;
304 t->GetStartData(data&: sigset);
305 SetSigProcMask(set: &sigset, oldset: nullptr);
306# endif
307
308 thread_return_t retval = (*args.routine)(args.arg_retval);
309 asanThreadArgRetval().Finish(thread: self, retval);
310 return retval;
311}
312
313INTERCEPTOR(int, pthread_create, void* thread, void* attr,
314 void* (*start_routine)(void*), void* arg) {
315 EnsureMainThreadIDIsCorrect();
316 // Strict init-order checking is thread-hostile.
317 if (flags()->strict_init_order)
318 StopInitOrderChecking();
319 GET_STACK_TRACE_THREAD;
320 bool detached = [attr]() {
321 int d = 0;
322 return attr && !REAL(pthread_attr_getdetachstate)(attr, &d) &&
323 IsStateDetached(state: d);
324 }();
325
326 u32 current_tid = GetCurrentTidOrInvalid();
327
328 __sanitizer_sigset_t sigset = {};
329# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
330 SANITIZER_SOLARIS
331 ScopedBlockSignals block(&sigset);
332# endif
333
334 AsanThread* t = AsanThread::Create(data: sigset, parent_tid: current_tid, stack: &stack, detached);
335
336 int result;
337 {
338 // Ignore all allocations made by pthread_create: thread stack/TLS may be
339 // stored by pthread for future reuse even after thread destruction, and
340 // the linked list it's stored in doesn't even hold valid pointers to the
341 // objects, the latter are calculated by obscure pointer arithmetic.
342# if CAN_SANITIZE_LEAKS
343 __lsan::ScopedInterceptorDisabler disabler;
344# endif
345 asanThreadArgRetval().Create(detached, args: {.routine: start_routine, .arg_retval: arg}, fn: [&]() -> uptr {
346 result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
347// AIX pthread_t is unsigned int.
348# if SANITIZER_AIX
349 return result ? 0 : *(unsigned*)(thread);
350# else
351 return result ? 0 : *(uptr*)(thread);
352# endif
353 });
354 }
355 if (result != 0) {
356 // If the thread didn't start delete the AsanThread to avoid leaking it.
357 // Note AsanThreadContexts never get destroyed so the AsanThreadContext
358 // that was just created for the AsanThread is wasted.
359 t->Destroy();
360 }
361 return result;
362}
363
364INTERCEPTOR(int, pthread_join, void* thread, void** retval) {
365 int result;
366 asanThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() {
367 result = REAL(pthread_join)(thread, retval);
368 return !result;
369 });
370 return result;
371}
372
373INTERCEPTOR(int, pthread_detach, void* thread) {
374 int result;
375 asanThreadArgRetval().Detach(thread: (uptr)thread, fn: [&]() {
376 result = REAL(pthread_detach)(thread);
377 return !result;
378 });
379 return result;
380}
381
382INTERCEPTOR(void, pthread_exit, void* retval) {
383 asanThreadArgRetval().Finish(thread: GetThreadSelf(), retval);
384 REAL(pthread_exit)(retval);
385}
386
387# if ASAN_INTERCEPT_TRYJOIN
388INTERCEPTOR(int, pthread_tryjoin_np, void* thread, void** ret) {
389 int result;
390 asanThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() {
391 result = REAL(pthread_tryjoin_np)(thread, ret);
392 return !result;
393 });
394 return result;
395}
396# endif
397
398# if ASAN_INTERCEPT_TIMEDJOIN
399INTERCEPTOR(int, pthread_timedjoin_np, void* thread, void** ret,
400 const struct timespec* abstime) {
401 int result;
402 asanThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() {
403 result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
404 return !result;
405 });
406 return result;
407}
408# endif
409
410DEFINE_INTERNAL_PTHREAD_FUNCTIONS
411# endif // ASAN_INTERCEPT_PTHREAD_CREATE
412
413# if ASAN_INTERCEPT_SWAPCONTEXT
414static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
415 // Only clear if we know the stack. This should be true only for contexts
416 // created with makecontext().
417 if (!ssize)
418 return;
419 // Align to page size.
420 uptr PageSize = GetPageSizeCached();
421 uptr bottom = RoundDownTo(x: stack, boundary: PageSize);
422 if (!AddrIsInMem(a: bottom))
423 return;
424 ssize += stack - bottom;
425 ssize = RoundUpTo(size: ssize, boundary: PageSize);
426 PoisonShadow(addr: bottom, size: ssize, value: 0);
427}
428
429// Since Solaris 10/SPARC, ucp->uc_stack.ss_sp refers to the stack base address
430// as on other targets. For binary compatibility, the new version uses a
431// different external name, so we intercept that.
432# if SANITIZER_SOLARIS && defined(__sparc__)
433INTERCEPTOR(void, __makecontext_v2, struct ucontext_t* ucp, void (*func)(),
434 int argc, ...) {
435# else
436INTERCEPTOR(void, makecontext, struct ucontext_t* ucp, void (*func)(), int argc,
437 ...) {
438# endif
439 va_list ap;
440 uptr args[64];
441 // We don't know a better way to forward ... into REAL function. We can
442 // increase args size if necessary.
443 CHECK_LE(argc, ARRAY_SIZE(args));
444 internal_memset(s: args, c: 0, n: sizeof(args));
445 va_start(ap, argc);
446 for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
447 va_end(ap);
448
449# define ENUMERATE_ARRAY_4(start) \
450 args[start], args[start + 1], args[start + 2], args[start + 3]
451# define ENUMERATE_ARRAY_16(start) \
452 ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
453 ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
454# define ENUMERATE_ARRAY_64() \
455 ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
456 ENUMERATE_ARRAY_16(48)
457
458# if SANITIZER_SOLARIS && defined(__sparc__)
459 REAL(__makecontext_v2)
460# else
461 REAL(makecontext)
462# endif
463 ((struct ucontext_t*)ucp, func, argc, ENUMERATE_ARRAY_64());
464
465# undef ENUMERATE_ARRAY_4
466# undef ENUMERATE_ARRAY_16
467# undef ENUMERATE_ARRAY_64
468
469 // Sign the stack so we can identify it for unpoisoning.
470 SignContextStack(context: ucp);
471}
472
473INTERCEPTOR(int, swapcontext, struct ucontext_t* oucp, struct ucontext_t* ucp) {
474 static bool reported_warning = false;
475 if (!reported_warning) {
476 Report(
477 format: "WARNING: ASan doesn't fully support makecontext/swapcontext "
478 "functions and may produce false positives in some cases!\n");
479 reported_warning = true;
480 }
481 // Clear shadow memory for new context (it may share stack
482 // with current context).
483 uptr stack, ssize;
484 ReadContextStack(context: ucp, stack: &stack, ssize: &ssize);
485 ClearShadowMemoryForContextStack(stack, ssize);
486
487# if __has_attribute(__indirect_return__) && \
488 (defined(__x86_64__) || defined(__i386__))
489 int (*real_swapcontext)(struct ucontext_t*, struct ucontext_t*)
490 __attribute__((__indirect_return__)) = REAL(swapcontext);
491 int res = real_swapcontext(oucp, ucp);
492# else
493 int res = REAL(swapcontext)(oucp, ucp);
494# endif
495 // swapcontext technically does not return, but program may swap context to
496 // "oucp" later, that would look as if swapcontext() returned 0.
497 // We need to clear shadow for ucp once again, as it may be in arbitrary
498 // state.
499 ClearShadowMemoryForContextStack(stack, ssize);
500 return res;
501}
502# endif // ASAN_INTERCEPT_SWAPCONTEXT
503
504# if SANITIZER_NETBSD
505# define longjmp __longjmp14
506# define siglongjmp __siglongjmp14
507# endif
508
509# if ASAN_INTERCEPT_LONGJMP
510INTERCEPTOR(void, longjmp, void* env, int val) {
511 __asan_handle_no_return();
512 REAL(longjmp)(env, val);
513}
514# endif
515
516# if ASAN_INTERCEPT__LONGJMP
517INTERCEPTOR(void, _longjmp, void* env, int val) {
518 __asan_handle_no_return();
519 REAL(_longjmp)(env, val);
520}
521# endif
522
523# if ASAN_INTERCEPT___LONGJMP_CHK
524INTERCEPTOR(void, __longjmp_chk, void* env, int val) {
525 __asan_handle_no_return();
526 REAL(__longjmp_chk)(env, val);
527}
528# endif
529
530# if ASAN_INTERCEPT_SIGLONGJMP
531INTERCEPTOR(void, siglongjmp, void* env, int val) {
532 __asan_handle_no_return();
533 REAL(siglongjmp)(env, val);
534}
535# endif
536
537# if ASAN_INTERCEPT___CXA_THROW
538INTERCEPTOR(void, __cxa_throw, void* a, void* b, void* c) {
539 CHECK(REAL(__cxa_throw));
540 __asan_handle_no_return();
541 REAL(__cxa_throw)(a, b, c);
542}
543# endif
544
545# if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
546INTERCEPTOR(void, __cxa_rethrow_primary_exception, void* a) {
547 CHECK(REAL(__cxa_rethrow_primary_exception));
548 __asan_handle_no_return();
549 REAL(__cxa_rethrow_primary_exception)(a);
550}
551# endif
552
553# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
554INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException,
555 _Unwind_Exception* object) {
556 CHECK(REAL(_Unwind_RaiseException));
557 __asan_handle_no_return();
558 return REAL(_Unwind_RaiseException)(object);
559}
560# endif
561
562# if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION
563INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException,
564 _Unwind_Exception* object) {
565 CHECK(REAL(_Unwind_SjLj_RaiseException));
566 __asan_handle_no_return();
567 return REAL(_Unwind_SjLj_RaiseException)(object);
568}
569# endif
570
571# if ASAN_INTERCEPT_INDEX
572# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
573INTERCEPTOR(char*, index, const char* string, int c)
574ALIAS(WRAP(strchr));
575# else
576# if SANITIZER_APPLE
577DECLARE_REAL(char*, index, const char* string, int c)
578OVERRIDE_FUNCTION(index, strchr);
579# else
580DEFINE_REAL(char*, index, const char* string, int c)
581# endif
582# endif
583# endif // ASAN_INTERCEPT_INDEX
584
585// For both strcat() and strncat() we need to check the validity of |to|
586// argument irrespective of the |from| length.
587INTERCEPTOR(char*, strcat, char* to, const char* from) {
588 void* ctx;
589 ASAN_INTERCEPTOR_ENTER(ctx, strcat);
590 AsanInitFromRtl();
591 if (flags()->replace_str) {
592 uptr from_length = internal_strlen(s: from);
593 ASAN_READ_RANGE(ctx, from, from_length + 1);
594 uptr to_length = internal_strlen(s: to);
595 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
596 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
597 // If the copying actually happens, the |from| string should not overlap
598 // with the resulting string starting at |to|, which has a length of
599 // to_length + from_length + 1.
600 if (from_length > 0) {
601 CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from,
602 from_length + 1);
603 }
604 }
605 return REAL(strcat)(to, from);
606}
607
608INTERCEPTOR(char*, strncat, char* to, const char* from, usize size) {
609 void* ctx;
610 ASAN_INTERCEPTOR_ENTER(ctx, strncat);
611 AsanInitFromRtl();
612 if (flags()->replace_str) {
613 uptr from_length = MaybeRealStrnlen(s: from, maxlen: size);
614 uptr copy_length = Min<uptr>(a: size, b: from_length + 1);
615 ASAN_READ_RANGE(ctx, from, copy_length);
616 uptr to_length = internal_strlen(s: to);
617 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
618 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
619 if (from_length > 0) {
620 CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1, from,
621 copy_length);
622 }
623 }
624 return REAL(strncat)(to, from, size);
625}
626
627INTERCEPTOR(char*, strcpy, char* to, const char* from) {
628 void* ctx;
629 ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
630 if constexpr (SANITIZER_APPLE) {
631 // strcpy is called from malloc_default_purgeable_zone()
632 // in __asan::ReplaceSystemAlloc() on Mac.
633 if (UNLIKELY(!AsanInited()))
634 return REAL(strcpy)(to, from);
635 } else {
636 if (!TryAsanInitFromRtl())
637 return REAL(strcpy)(to, from);
638 }
639
640 if (flags()->replace_str) {
641 uptr from_size = internal_strlen(s: from) + 1;
642 CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
643 ASAN_READ_RANGE(ctx, from, from_size);
644 ASAN_WRITE_RANGE(ctx, to, from_size);
645 }
646 return REAL(strcpy)(to, from);
647}
648
649INTERCEPTOR(wchar_t*, wcscpy, wchar_t* to, const wchar_t* from) {
650 void* ctx;
651 ASAN_INTERCEPTOR_ENTER(ctx, wcscpy);
652 if (!TryAsanInitFromRtl())
653 return REAL(wcscpy)(to, from);
654 if (flags()->replace_str) {
655 uptr size = (internal_wcslen(s: from) + 1) * sizeof(wchar_t);
656 CHECK_RANGES_OVERLAP("wcscpy", to, size, from, size);
657 ASAN_READ_RANGE(ctx, from, size);
658 ASAN_WRITE_RANGE(ctx, to, size);
659 }
660 return REAL(wcscpy)(to, from);
661}
662
663// Windows doesn't always define the strdup identifier,
664// and when it does it's a macro defined to either _strdup
665// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so
666// we want to intercept that. push/pop_macro are used to avoid problems
667// if this file ends up including <string.h> in the future.
668# if SANITIZER_WINDOWS
669# pragma push_macro("strdup")
670# undef strdup
671# define strdup _strdup
672# endif
673
674INTERCEPTOR(char*, strdup, const char* s) {
675 void* ctx;
676 ASAN_INTERCEPTOR_ENTER(ctx, strdup);
677 // Allowing null input is Windows-specific
678 if (SANITIZER_WINDOWS && UNLIKELY(!s))
679 return nullptr;
680 if (UNLIKELY(!TryAsanInitFromRtl()))
681 return internal_strdup(s);
682 uptr length = internal_strlen(s);
683 if (flags()->replace_str) {
684 ASAN_READ_RANGE(ctx, s, length + 1);
685 }
686 GET_STACK_TRACE_MALLOC;
687 void* new_mem = asan_malloc(size: length + 1, stack: &stack);
688 if (new_mem) {
689 REAL(memcpy)(new_mem, s, length + 1);
690 }
691 return reinterpret_cast<char*>(new_mem);
692}
693
694# if ASAN_INTERCEPT___STRDUP
695INTERCEPTOR(char*, __strdup, const char* s) {
696 void* ctx;
697 ASAN_INTERCEPTOR_ENTER(ctx, strdup);
698 if (UNLIKELY(!TryAsanInitFromRtl()))
699 return internal_strdup(s);
700 uptr length = internal_strlen(s);
701 if (flags()->replace_str) {
702 ASAN_READ_RANGE(ctx, s, length + 1);
703 }
704 GET_STACK_TRACE_MALLOC;
705 void* new_mem = asan_malloc(size: length + 1, stack: &stack);
706 if (new_mem) {
707 REAL(memcpy)(new_mem, s, length + 1);
708 }
709 return reinterpret_cast<char*>(new_mem);
710}
711# endif // ASAN_INTERCEPT___STRDUP
712
713INTERCEPTOR(char*, strncpy, char* to, const char* from, usize size) {
714 void* ctx;
715 ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
716 AsanInitFromRtl();
717 if (flags()->replace_str) {
718 uptr from_size = Min<uptr>(a: size, b: MaybeRealStrnlen(s: from, maxlen: size) + 1);
719 CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
720 ASAN_READ_RANGE(ctx, from, from_size);
721 ASAN_WRITE_RANGE(ctx, to, size);
722 }
723 return REAL(strncpy)(to, from, size);
724}
725
726INTERCEPTOR(wchar_t*, wcsncpy, wchar_t* to, const wchar_t* from, uptr size) {
727 void* ctx;
728 ASAN_INTERCEPTOR_ENTER(ctx, wcsncpy);
729 AsanInitFromRtl();
730 if (flags()->replace_str) {
731 uptr from_size =
732 Min(a: size, b: MaybeRealWcsnlen(s: from, maxlen: size) + 1) * sizeof(wchar_t);
733 CHECK_RANGES_OVERLAP("wcsncpy", to, from_size, from, from_size);
734 ASAN_READ_RANGE(ctx, from, from_size);
735 ASAN_WRITE_RANGE(ctx, to, size * sizeof(wchar_t));
736 }
737 return REAL(wcsncpy)(to, from, size);
738}
739
740template <typename Fn>
741static ALWAYS_INLINE auto StrtolImpl(void* ctx, Fn real, const char* nptr,
742 char** endptr, int base)
743 -> decltype(real(nullptr, nullptr, 0)) {
744 if (!flags()->replace_str)
745 return real(nptr, endptr, base);
746 char* real_endptr;
747 auto res = real(nptr, &real_endptr, base);
748 StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
749 return res;
750}
751
752# define INTERCEPTOR_STRTO_BASE(ret_type, func) \
753 INTERCEPTOR(ret_type, func, const char* nptr, char** endptr, int base) { \
754 void* ctx; \
755 ASAN_INTERCEPTOR_ENTER(ctx, func); \
756 AsanInitFromRtl(); \
757 return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \
758 }
759
760INTERCEPTOR_STRTO_BASE(long long, strtoll)
761
762# if SANITIZER_WINDOWS
763INTERCEPTOR(long, strtol, const char* nptr, char** endptr, int base) {
764 // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead,
765 // call REAL(strtoll) and do the range check ourselves.
766 COMPILER_CHECK(sizeof(long) == sizeof(u32));
767
768 void* ctx;
769 ASAN_INTERCEPTOR_ENTER(ctx, strtol);
770 AsanInitFromRtl();
771
772 long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base);
773
774 if (result > INT32_MAX) {
775 errno = errno_ERANGE;
776 return INT32_MAX;
777 }
778 if (result < INT32_MIN) {
779 errno = errno_ERANGE;
780 return INT32_MIN;
781 }
782 return (long)result;
783}
784# else
785INTERCEPTOR_STRTO_BASE(long, strtol)
786# endif
787
788# if SANITIZER_GLIBC
789INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)
790INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
791# endif
792
793INTERCEPTOR(int, atoi, const char* nptr) {
794 void* ctx;
795 ASAN_INTERCEPTOR_ENTER(ctx, atoi);
796 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
797 return REAL(atoi)(nptr);
798 AsanInitFromRtl();
799 if (!flags()->replace_str) {
800 return REAL(atoi)(nptr);
801 }
802 char* real_endptr;
803 // "man atoi" tells that behavior of atoi(nptr) is the same as
804 // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
805 // parsed integer can't be stored in *long* type (even if it's
806 // different from int). So, we just imitate this behavior.
807 int result = REAL(strtol)(nptr, &real_endptr, 10);
808 FixRealStrtolEndptr(nptr, endptr: &real_endptr);
809 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
810 return result;
811}
812
813INTERCEPTOR(long, atol, const char* nptr) {
814 void* ctx;
815 ASAN_INTERCEPTOR_ENTER(ctx, atol);
816 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
817 return REAL(atol)(nptr);
818 AsanInitFromRtl();
819 if (!flags()->replace_str) {
820 return REAL(atol)(nptr);
821 }
822 char* real_endptr;
823 long result = REAL(strtol)(nptr, &real_endptr, 10);
824 FixRealStrtolEndptr(nptr, endptr: &real_endptr);
825 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
826 return result;
827}
828
829INTERCEPTOR(long long, atoll, const char* nptr) {
830 void* ctx;
831 ASAN_INTERCEPTOR_ENTER(ctx, atoll);
832 AsanInitFromRtl();
833 if (!flags()->replace_str) {
834 return REAL(atoll)(nptr);
835 }
836 char* real_endptr;
837 long long result = REAL(strtoll)(nptr, &real_endptr, 10);
838 FixRealStrtolEndptr(nptr, endptr: &real_endptr);
839 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
840 return result;
841}
842
843# if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT
844static void AtCxaAtexit(void* unused) {
845 (void)unused;
846 StopInitOrderChecking();
847}
848# endif
849
850# if ASAN_INTERCEPT___CXA_ATEXIT
851INTERCEPTOR(int, __cxa_atexit, void (*func)(void*), void* arg,
852 void* dso_handle) {
853 if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
854 return REAL(__cxa_atexit)(func, arg, dso_handle);
855 AsanInitFromRtl();
856# if CAN_SANITIZE_LEAKS
857 __lsan::ScopedInterceptorDisabler disabler;
858# endif
859 int res = REAL(__cxa_atexit)(func, arg, dso_handle);
860 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
861 return res;
862}
863# endif // ASAN_INTERCEPT___CXA_ATEXIT
864
865# if ASAN_INTERCEPT_ATEXIT
866INTERCEPTOR(int, atexit, void (*func)()) {
867 AsanInitFromRtl();
868# if CAN_SANITIZE_LEAKS
869 __lsan::ScopedInterceptorDisabler disabler;
870# endif
871 // Avoid calling real atexit as it is unreachable on at least on Linux.
872 int res = REAL(__cxa_atexit)((void (*)(void* a))func, nullptr, nullptr);
873 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
874 return res;
875}
876# endif
877
878# if ASAN_INTERCEPT_PTHREAD_ATFORK
879extern "C" {
880extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
881 void (*child)());
882}
883
884INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
885 void (*child)()) {
886# if CAN_SANITIZE_LEAKS
887 __lsan::ScopedInterceptorDisabler disabler;
888# endif
889 // REAL(pthread_atfork) cannot be called due to symbol indirections at least
890 // on NetBSD
891 return _pthread_atfork(prepare, parent, child);
892}
893# endif
894
895# if ASAN_INTERCEPT_VFORK
896DEFINE_REAL(int, vfork, )
897DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork, )
898# endif
899
900// ---------------------- InitializeAsanInterceptors ---------------- {{{1
901namespace __asan {
902void InitializeAsanInterceptors() {
903 static bool was_called_once;
904 CHECK(!was_called_once);
905 was_called_once = true;
906 InitializePlatformInterceptors();
907 InitializeCommonInterceptors();
908 InitializeSignalInterceptors();
909
910 // Intercept str* functions.
911 ASAN_INTERCEPT_FUNC(strcat);
912 ASAN_INTERCEPT_FUNC(strcpy);
913 ASAN_INTERCEPT_FUNC(strncat);
914 ASAN_INTERCEPT_FUNC(strncpy);
915 ASAN_INTERCEPT_FUNC(strdup);
916
917 // Intercept wcs* functions.
918 ASAN_INTERCEPT_FUNC(wcscpy);
919 ASAN_INTERCEPT_FUNC(wcsncpy);
920
921# if ASAN_INTERCEPT___STRDUP
922 ASAN_INTERCEPT_FUNC(__strdup);
923# endif
924# if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
925 ASAN_INTERCEPT_FUNC(index);
926# endif
927
928 ASAN_INTERCEPT_FUNC(atoi);
929 ASAN_INTERCEPT_FUNC(atol);
930 ASAN_INTERCEPT_FUNC(atoll);
931 ASAN_INTERCEPT_FUNC(strtol);
932 ASAN_INTERCEPT_FUNC(strtoll);
933# if SANITIZER_GLIBC
934 ASAN_INTERCEPT_FUNC(__isoc23_strtol);
935 ASAN_INTERCEPT_FUNC(__isoc23_strtoll);
936# endif
937
938 // Intercept jump-related functions.
939# if ASAN_INTERCEPT_LONGJMP
940 ASAN_INTERCEPT_FUNC(longjmp);
941# endif
942
943# if ASAN_INTERCEPT_SWAPCONTEXT
944 ASAN_INTERCEPT_FUNC(swapcontext);
945 // See the makecontext interceptor above for an explanation.
946# if SANITIZER_SOLARIS && defined(__sparc__)
947 ASAN_INTERCEPT_FUNC(__makecontext_v2);
948# else
949 ASAN_INTERCEPT_FUNC(makecontext);
950# endif
951# endif
952# if ASAN_INTERCEPT__LONGJMP
953 ASAN_INTERCEPT_FUNC(_longjmp);
954# endif
955# if ASAN_INTERCEPT___LONGJMP_CHK
956 ASAN_INTERCEPT_FUNC(__longjmp_chk);
957# endif
958# if ASAN_INTERCEPT_SIGLONGJMP
959 ASAN_INTERCEPT_FUNC(siglongjmp);
960# endif
961
962 // Intercept exception handling functions.
963# if ASAN_INTERCEPT___CXA_THROW
964 ASAN_INTERCEPT_FUNC(__cxa_throw);
965# endif
966# if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION
967 ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception);
968# endif
969 // Indirectly intercept std::rethrow_exception.
970# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
971 ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);
972# endif
973 // Indirectly intercept std::rethrow_exception.
974# if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION
975 ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);
976# endif
977
978 // Intercept threading-related functions
979# if ASAN_INTERCEPT_PTHREAD_CREATE
980// TODO: this should probably have an unversioned fallback for newer arches?
981# if defined(ASAN_PTHREAD_CREATE_VERSION)
982 ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
983# else
984 ASAN_INTERCEPT_FUNC(pthread_create);
985# endif
986 ASAN_INTERCEPT_FUNC(pthread_join);
987 ASAN_INTERCEPT_FUNC(pthread_detach);
988 ASAN_INTERCEPT_FUNC(pthread_exit);
989# endif
990
991# if ASAN_INTERCEPT_TIMEDJOIN
992 ASAN_INTERCEPT_FUNC(pthread_timedjoin_np);
993# endif
994
995# if ASAN_INTERCEPT_TRYJOIN
996 ASAN_INTERCEPT_FUNC(pthread_tryjoin_np);
997# endif
998
999 // Intercept atexit function.
1000# if ASAN_INTERCEPT___CXA_ATEXIT
1001 ASAN_INTERCEPT_FUNC(__cxa_atexit);
1002# endif
1003
1004# if ASAN_INTERCEPT_ATEXIT
1005 ASAN_INTERCEPT_FUNC(atexit);
1006# endif
1007
1008# if ASAN_INTERCEPT_PTHREAD_ATFORK
1009 ASAN_INTERCEPT_FUNC(pthread_atfork);
1010# endif
1011
1012# if ASAN_INTERCEPT_VFORK
1013 ASAN_INTERCEPT_FUNC(vfork);
1014# endif
1015
1016 VReport(1, "AddressSanitizer: libc interceptors initialized\n");
1017}
1018
1019# if SANITIZER_WINDOWS
1020# pragma pop_macro("strdup")
1021# endif
1022
1023} // namespace __asan
1024
1025#endif // !SANITIZER_FUCHSIA
1026