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