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