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, uptr) |
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 neccecary. |
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, uptr 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(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 | if (UNLIKELY(!TryAsanInitFromRtl())) |
588 | return internal_strdup(s); |
589 | uptr length = internal_strlen(s); |
590 | if (flags()->replace_str) { |
591 | ASAN_READ_RANGE(ctx, s, length + 1); |
592 | } |
593 | GET_STACK_TRACE_MALLOC; |
594 | void *new_mem = asan_malloc(size: length + 1, stack: &stack); |
595 | if (new_mem) { |
596 | REAL(memcpy)(new_mem, s, length + 1); |
597 | } |
598 | return reinterpret_cast<char*>(new_mem); |
599 | } |
600 | |
601 | # if ASAN_INTERCEPT___STRDUP |
602 | INTERCEPTOR(char*, __strdup, const char *s) { |
603 | void *ctx; |
604 | ASAN_INTERCEPTOR_ENTER(ctx, strdup); |
605 | if (UNLIKELY(!TryAsanInitFromRtl())) |
606 | return internal_strdup(s); |
607 | uptr length = internal_strlen(s); |
608 | if (flags()->replace_str) { |
609 | ASAN_READ_RANGE(ctx, s, length + 1); |
610 | } |
611 | GET_STACK_TRACE_MALLOC; |
612 | void *new_mem = asan_malloc(size: length + 1, stack: &stack); |
613 | if (new_mem) { |
614 | REAL(memcpy)(new_mem, s, length + 1); |
615 | } |
616 | return reinterpret_cast<char*>(new_mem); |
617 | } |
618 | #endif // ASAN_INTERCEPT___STRDUP |
619 | |
620 | INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { |
621 | void *ctx; |
622 | ASAN_INTERCEPTOR_ENTER(ctx, strncpy); |
623 | AsanInitFromRtl(); |
624 | if (flags()->replace_str) { |
625 | uptr from_size = Min(a: size, b: MaybeRealStrnlen(s: from, maxlen: size) + 1); |
626 | CHECK_RANGES_OVERLAP("strncpy" , to, from_size, from, from_size); |
627 | ASAN_READ_RANGE(ctx, from, from_size); |
628 | ASAN_WRITE_RANGE(ctx, to, size); |
629 | } |
630 | return REAL(strncpy)(to, from, size); |
631 | } |
632 | |
633 | template <typename Fn> |
634 | static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, |
635 | char **endptr, int base) |
636 | -> decltype(real(nullptr, nullptr, 0)) { |
637 | if (!flags()->replace_str) |
638 | return real(nptr, endptr, base); |
639 | char *real_endptr; |
640 | auto res = real(nptr, &real_endptr, base); |
641 | StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); |
642 | return res; |
643 | } |
644 | |
645 | # define INTERCEPTOR_STRTO_BASE(ret_type, func) \ |
646 | INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \ |
647 | void *ctx; \ |
648 | ASAN_INTERCEPTOR_ENTER(ctx, func); \ |
649 | AsanInitFromRtl(); \ |
650 | return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \ |
651 | } |
652 | |
653 | INTERCEPTOR_STRTO_BASE(long, strtol) |
654 | INTERCEPTOR_STRTO_BASE(long long, strtoll) |
655 | |
656 | # if SANITIZER_GLIBC |
657 | INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol) |
658 | INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll) |
659 | # endif |
660 | |
661 | INTERCEPTOR(int, atoi, const char *nptr) { |
662 | void *ctx; |
663 | ASAN_INTERCEPTOR_ENTER(ctx, atoi); |
664 | if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) |
665 | return REAL(atoi)(nptr); |
666 | AsanInitFromRtl(); |
667 | if (!flags()->replace_str) { |
668 | return REAL(atoi)(nptr); |
669 | } |
670 | char *real_endptr; |
671 | // "man atoi" tells that behavior of atoi(nptr) is the same as |
672 | // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the |
673 | // parsed integer can't be stored in *long* type (even if it's |
674 | // different from int). So, we just imitate this behavior. |
675 | int result = REAL(strtol)(nptr, &real_endptr, 10); |
676 | FixRealStrtolEndptr(nptr, endptr: &real_endptr); |
677 | ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); |
678 | return result; |
679 | } |
680 | |
681 | INTERCEPTOR(long, atol, const char *nptr) { |
682 | void *ctx; |
683 | ASAN_INTERCEPTOR_ENTER(ctx, atol); |
684 | if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) |
685 | return REAL(atol)(nptr); |
686 | AsanInitFromRtl(); |
687 | if (!flags()->replace_str) { |
688 | return REAL(atol)(nptr); |
689 | } |
690 | char *real_endptr; |
691 | long result = REAL(strtol)(nptr, &real_endptr, 10); |
692 | FixRealStrtolEndptr(nptr, endptr: &real_endptr); |
693 | ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); |
694 | return result; |
695 | } |
696 | |
697 | INTERCEPTOR(long long, atoll, const char *nptr) { |
698 | void *ctx; |
699 | ASAN_INTERCEPTOR_ENTER(ctx, atoll); |
700 | AsanInitFromRtl(); |
701 | if (!flags()->replace_str) { |
702 | return REAL(atoll)(nptr); |
703 | } |
704 | char *real_endptr; |
705 | long long result = REAL(strtoll)(nptr, &real_endptr, 10); |
706 | FixRealStrtolEndptr(nptr, endptr: &real_endptr); |
707 | ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); |
708 | return result; |
709 | } |
710 | |
711 | #if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT |
712 | static void AtCxaAtexit(void *unused) { |
713 | (void)unused; |
714 | StopInitOrderChecking(); |
715 | } |
716 | #endif |
717 | |
718 | #if ASAN_INTERCEPT___CXA_ATEXIT |
719 | INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, |
720 | void *dso_handle) { |
721 | if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) |
722 | return REAL(__cxa_atexit)(func, arg, dso_handle); |
723 | AsanInitFromRtl(); |
724 | # if CAN_SANITIZE_LEAKS |
725 | __lsan::ScopedInterceptorDisabler disabler; |
726 | #endif |
727 | int res = REAL(__cxa_atexit)(func, arg, dso_handle); |
728 | REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); |
729 | return res; |
730 | } |
731 | #endif // ASAN_INTERCEPT___CXA_ATEXIT |
732 | |
733 | #if ASAN_INTERCEPT_ATEXIT |
734 | INTERCEPTOR(int, atexit, void (*func)()) { |
735 | AsanInitFromRtl(); |
736 | # if CAN_SANITIZE_LEAKS |
737 | __lsan::ScopedInterceptorDisabler disabler; |
738 | #endif |
739 | // Avoid calling real atexit as it is unreachable on at least on Linux. |
740 | int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr); |
741 | REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); |
742 | return res; |
743 | } |
744 | #endif |
745 | |
746 | #if ASAN_INTERCEPT_PTHREAD_ATFORK |
747 | extern "C" { |
748 | extern int _pthread_atfork(void (*prepare)(), void (*parent)(), |
749 | void (*child)()); |
750 | } |
751 | |
752 | INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), |
753 | void (*child)()) { |
754 | #if CAN_SANITIZE_LEAKS |
755 | __lsan::ScopedInterceptorDisabler disabler; |
756 | #endif |
757 | // REAL(pthread_atfork) cannot be called due to symbol indirections at least |
758 | // on NetBSD |
759 | return _pthread_atfork(prepare, parent, child); |
760 | } |
761 | #endif |
762 | |
763 | #if ASAN_INTERCEPT_VFORK |
764 | DEFINE_REAL(int, vfork,) |
765 | DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) |
766 | #endif |
767 | |
768 | // ---------------------- InitializeAsanInterceptors ---------------- {{{1 |
769 | namespace __asan { |
770 | void InitializeAsanInterceptors() { |
771 | static bool was_called_once; |
772 | CHECK(!was_called_once); |
773 | was_called_once = true; |
774 | InitializePlatformInterceptors(); |
775 | InitializeCommonInterceptors(); |
776 | InitializeSignalInterceptors(); |
777 | |
778 | // Intercept str* functions. |
779 | ASAN_INTERCEPT_FUNC(strcat); |
780 | ASAN_INTERCEPT_FUNC(strcpy); |
781 | ASAN_INTERCEPT_FUNC(strncat); |
782 | ASAN_INTERCEPT_FUNC(strncpy); |
783 | ASAN_INTERCEPT_FUNC(strdup); |
784 | # if ASAN_INTERCEPT___STRDUP |
785 | ASAN_INTERCEPT_FUNC(__strdup); |
786 | #endif |
787 | #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX |
788 | ASAN_INTERCEPT_FUNC(index); |
789 | #endif |
790 | |
791 | ASAN_INTERCEPT_FUNC(atoi); |
792 | ASAN_INTERCEPT_FUNC(atol); |
793 | ASAN_INTERCEPT_FUNC(atoll); |
794 | ASAN_INTERCEPT_FUNC(strtol); |
795 | ASAN_INTERCEPT_FUNC(strtoll); |
796 | # if SANITIZER_GLIBC |
797 | ASAN_INTERCEPT_FUNC(__isoc23_strtol); |
798 | ASAN_INTERCEPT_FUNC(__isoc23_strtoll); |
799 | # endif |
800 | |
801 | // Intecept jump-related functions. |
802 | ASAN_INTERCEPT_FUNC(longjmp); |
803 | |
804 | # if ASAN_INTERCEPT_SWAPCONTEXT |
805 | ASAN_INTERCEPT_FUNC(swapcontext); |
806 | // See the makecontext interceptor above for an explanation. |
807 | # if SANITIZER_SOLARIS && defined(__sparc__) |
808 | ASAN_INTERCEPT_FUNC(__makecontext_v2); |
809 | # else |
810 | ASAN_INTERCEPT_FUNC(makecontext); |
811 | # endif |
812 | # endif |
813 | # if ASAN_INTERCEPT__LONGJMP |
814 | ASAN_INTERCEPT_FUNC(_longjmp); |
815 | #endif |
816 | #if ASAN_INTERCEPT___LONGJMP_CHK |
817 | ASAN_INTERCEPT_FUNC(__longjmp_chk); |
818 | #endif |
819 | #if ASAN_INTERCEPT_SIGLONGJMP |
820 | ASAN_INTERCEPT_FUNC(siglongjmp); |
821 | #endif |
822 | |
823 | // Intercept exception handling functions. |
824 | #if ASAN_INTERCEPT___CXA_THROW |
825 | ASAN_INTERCEPT_FUNC(__cxa_throw); |
826 | #endif |
827 | #if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION |
828 | ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception); |
829 | #endif |
830 | // Indirectly intercept std::rethrow_exception. |
831 | #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION |
832 | ASAN_INTERCEPT_FUNC(_Unwind_RaiseException); |
833 | #endif |
834 | // Indirectly intercept std::rethrow_exception. |
835 | #if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION |
836 | ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException); |
837 | #endif |
838 | |
839 | // Intercept threading-related functions |
840 | #if ASAN_INTERCEPT_PTHREAD_CREATE |
841 | // TODO: this should probably have an unversioned fallback for newer arches? |
842 | #if defined(ASAN_PTHREAD_CREATE_VERSION) |
843 | ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION); |
844 | #else |
845 | ASAN_INTERCEPT_FUNC(pthread_create); |
846 | #endif |
847 | ASAN_INTERCEPT_FUNC(pthread_join); |
848 | ASAN_INTERCEPT_FUNC(pthread_detach); |
849 | ASAN_INTERCEPT_FUNC(pthread_exit); |
850 | # endif |
851 | |
852 | # if ASAN_INTERCEPT_TIMEDJOIN |
853 | ASAN_INTERCEPT_FUNC(pthread_timedjoin_np); |
854 | #endif |
855 | |
856 | #if ASAN_INTERCEPT_TRYJOIN |
857 | ASAN_INTERCEPT_FUNC(pthread_tryjoin_np); |
858 | #endif |
859 | |
860 | // Intercept atexit function. |
861 | #if ASAN_INTERCEPT___CXA_ATEXIT |
862 | ASAN_INTERCEPT_FUNC(__cxa_atexit); |
863 | #endif |
864 | |
865 | #if ASAN_INTERCEPT_ATEXIT |
866 | ASAN_INTERCEPT_FUNC(atexit); |
867 | #endif |
868 | |
869 | #if ASAN_INTERCEPT_PTHREAD_ATFORK |
870 | ASAN_INTERCEPT_FUNC(pthread_atfork); |
871 | #endif |
872 | |
873 | #if ASAN_INTERCEPT_VFORK |
874 | ASAN_INTERCEPT_FUNC(vfork); |
875 | #endif |
876 | |
877 | VReport(1, "AddressSanitizer: libc interceptors initialized\n" ); |
878 | } |
879 | |
880 | # if SANITIZER_WINDOWS |
881 | # pragma pop_macro("strdup") |
882 | # endif |
883 | |
884 | } // namespace __asan |
885 | |
886 | #endif // !SANITIZER_FUCHSIA |
887 | |