1*7c3d14c8STreehugger Robot //===-- asan_interceptors.cc ----------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of AddressSanitizer, an address sanity checker.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Intercept various libc functions.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot
15*7c3d14c8STreehugger Robot #include "asan_interceptors.h"
16*7c3d14c8STreehugger Robot #include "asan_allocator.h"
17*7c3d14c8STreehugger Robot #include "asan_internal.h"
18*7c3d14c8STreehugger Robot #include "asan_mapping.h"
19*7c3d14c8STreehugger Robot #include "asan_poisoning.h"
20*7c3d14c8STreehugger Robot #include "asan_report.h"
21*7c3d14c8STreehugger Robot #include "asan_stack.h"
22*7c3d14c8STreehugger Robot #include "asan_stats.h"
23*7c3d14c8STreehugger Robot #include "asan_suppressions.h"
24*7c3d14c8STreehugger Robot #include "lsan/lsan_common.h"
25*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_libc.h"
26*7c3d14c8STreehugger Robot
27*7c3d14c8STreehugger Robot #if SANITIZER_POSIX
28*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_posix.h"
29*7c3d14c8STreehugger Robot #endif
30*7c3d14c8STreehugger Robot
31*7c3d14c8STreehugger Robot #if defined(__i386) && SANITIZER_LINUX
32*7c3d14c8STreehugger Robot #define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
33*7c3d14c8STreehugger Robot #elif defined(__mips__) && SANITIZER_LINUX
34*7c3d14c8STreehugger Robot #define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
35*7c3d14c8STreehugger Robot #endif
36*7c3d14c8STreehugger Robot
37*7c3d14c8STreehugger Robot namespace __asan {
38*7c3d14c8STreehugger Robot
39*7c3d14c8STreehugger Robot // Return true if we can quickly decide that the region is unpoisoned.
QuickCheckForUnpoisonedRegion(uptr beg,uptr size)40*7c3d14c8STreehugger Robot static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
41*7c3d14c8STreehugger Robot if (size == 0) return true;
42*7c3d14c8STreehugger Robot if (size <= 32)
43*7c3d14c8STreehugger Robot return !AddressIsPoisoned(beg) &&
44*7c3d14c8STreehugger Robot !AddressIsPoisoned(beg + size - 1) &&
45*7c3d14c8STreehugger Robot !AddressIsPoisoned(beg + size / 2);
46*7c3d14c8STreehugger Robot return false;
47*7c3d14c8STreehugger Robot }
48*7c3d14c8STreehugger Robot
49*7c3d14c8STreehugger Robot struct AsanInterceptorContext {
50*7c3d14c8STreehugger Robot const char *interceptor_name;
51*7c3d14c8STreehugger Robot };
52*7c3d14c8STreehugger Robot
53*7c3d14c8STreehugger Robot // We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
54*7c3d14c8STreehugger Robot // and ASAN_WRITE_RANGE as macro instead of function so
55*7c3d14c8STreehugger Robot // that no extra frames are created, and stack trace contains
56*7c3d14c8STreehugger Robot // relevant information only.
57*7c3d14c8STreehugger Robot // We check all shadow bytes.
58*7c3d14c8STreehugger Robot #define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
59*7c3d14c8STreehugger Robot uptr __offset = (uptr)(offset); \
60*7c3d14c8STreehugger Robot uptr __size = (uptr)(size); \
61*7c3d14c8STreehugger Robot uptr __bad = 0; \
62*7c3d14c8STreehugger Robot if (__offset > __offset + __size) { \
63*7c3d14c8STreehugger Robot GET_STACK_TRACE_FATAL_HERE; \
64*7c3d14c8STreehugger Robot ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
65*7c3d14c8STreehugger Robot } \
66*7c3d14c8STreehugger Robot if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
67*7c3d14c8STreehugger Robot (__bad = __asan_region_is_poisoned(__offset, __size))) { \
68*7c3d14c8STreehugger Robot AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
69*7c3d14c8STreehugger Robot bool suppressed = false; \
70*7c3d14c8STreehugger Robot if (_ctx) { \
71*7c3d14c8STreehugger Robot suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
72*7c3d14c8STreehugger Robot if (!suppressed && HaveStackTraceBasedSuppressions()) { \
73*7c3d14c8STreehugger Robot GET_STACK_TRACE_FATAL_HERE; \
74*7c3d14c8STreehugger Robot suppressed = IsStackTraceSuppressed(&stack); \
75*7c3d14c8STreehugger Robot } \
76*7c3d14c8STreehugger Robot } \
77*7c3d14c8STreehugger Robot if (!suppressed) { \
78*7c3d14c8STreehugger Robot GET_CURRENT_PC_BP_SP; \
79*7c3d14c8STreehugger Robot ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
80*7c3d14c8STreehugger Robot } \
81*7c3d14c8STreehugger Robot } \
82*7c3d14c8STreehugger Robot } while (0)
83*7c3d14c8STreehugger Robot
84*7c3d14c8STreehugger Robot #define ASAN_READ_RANGE(ctx, offset, size) \
85*7c3d14c8STreehugger Robot ACCESS_MEMORY_RANGE(ctx, offset, size, false)
86*7c3d14c8STreehugger Robot #define ASAN_WRITE_RANGE(ctx, offset, size) \
87*7c3d14c8STreehugger Robot ACCESS_MEMORY_RANGE(ctx, offset, size, true)
88*7c3d14c8STreehugger Robot
89*7c3d14c8STreehugger Robot #define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
90*7c3d14c8STreehugger Robot ASAN_READ_RANGE((ctx), (s), \
91*7c3d14c8STreehugger Robot common_flags()->strict_string_checks ? (len) + 1 : (n))
92*7c3d14c8STreehugger Robot
93*7c3d14c8STreehugger Robot #define ASAN_READ_STRING(ctx, s, n) \
94*7c3d14c8STreehugger Robot ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
95*7c3d14c8STreehugger Robot
96*7c3d14c8STreehugger Robot // Behavior of functions like "memcpy" or "strcpy" is undefined
97*7c3d14c8STreehugger Robot // if memory intervals overlap. We report error in this case.
98*7c3d14c8STreehugger Robot // Macro is used to avoid creation of new frames.
RangesOverlap(const char * offset1,uptr length1,const char * offset2,uptr length2)99*7c3d14c8STreehugger Robot static inline bool RangesOverlap(const char *offset1, uptr length1,
100*7c3d14c8STreehugger Robot const char *offset2, uptr length2) {
101*7c3d14c8STreehugger Robot return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
102*7c3d14c8STreehugger Robot }
103*7c3d14c8STreehugger Robot #define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
104*7c3d14c8STreehugger Robot const char *offset1 = (const char*)_offset1; \
105*7c3d14c8STreehugger Robot const char *offset2 = (const char*)_offset2; \
106*7c3d14c8STreehugger Robot if (RangesOverlap(offset1, length1, offset2, length2)) { \
107*7c3d14c8STreehugger Robot GET_STACK_TRACE_FATAL_HERE; \
108*7c3d14c8STreehugger Robot ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
109*7c3d14c8STreehugger Robot offset2, length2, &stack); \
110*7c3d14c8STreehugger Robot } \
111*7c3d14c8STreehugger Robot } while (0)
112*7c3d14c8STreehugger Robot
MaybeRealStrnlen(const char * s,uptr maxlen)113*7c3d14c8STreehugger Robot static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
114*7c3d14c8STreehugger Robot #if SANITIZER_INTERCEPT_STRNLEN
115*7c3d14c8STreehugger Robot if (REAL(strnlen)) {
116*7c3d14c8STreehugger Robot return REAL(strnlen)(s, maxlen);
117*7c3d14c8STreehugger Robot }
118*7c3d14c8STreehugger Robot #endif
119*7c3d14c8STreehugger Robot return internal_strnlen(s, maxlen);
120*7c3d14c8STreehugger Robot }
121*7c3d14c8STreehugger Robot
SetThreadName(const char * name)122*7c3d14c8STreehugger Robot void SetThreadName(const char *name) {
123*7c3d14c8STreehugger Robot AsanThread *t = GetCurrentThread();
124*7c3d14c8STreehugger Robot if (t)
125*7c3d14c8STreehugger Robot asanThreadRegistry().SetThreadName(t->tid(), name);
126*7c3d14c8STreehugger Robot }
127*7c3d14c8STreehugger Robot
OnExit()128*7c3d14c8STreehugger Robot int OnExit() {
129*7c3d14c8STreehugger Robot // FIXME: ask frontend whether we need to return failure.
130*7c3d14c8STreehugger Robot return 0;
131*7c3d14c8STreehugger Robot }
132*7c3d14c8STreehugger Robot
133*7c3d14c8STreehugger Robot } // namespace __asan
134*7c3d14c8STreehugger Robot
135*7c3d14c8STreehugger Robot // ---------------------- Wrappers ---------------- {{{1
136*7c3d14c8STreehugger Robot using namespace __asan; // NOLINT
137*7c3d14c8STreehugger Robot
138*7c3d14c8STreehugger Robot DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
139*7c3d14c8STreehugger Robot DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
140*7c3d14c8STreehugger Robot
141*7c3d14c8STreehugger Robot #define ASAN_INTERCEPTOR_ENTER(ctx, func) \
142*7c3d14c8STreehugger Robot AsanInterceptorContext _ctx = {#func}; \
143*7c3d14c8STreehugger Robot ctx = (void *)&_ctx; \
144*7c3d14c8STreehugger Robot (void) ctx; \
145*7c3d14c8STreehugger Robot
146*7c3d14c8STreehugger Robot #define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
147*7c3d14c8STreehugger Robot #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
148*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC_VER(name, ver)
149*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
150*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, ptr, size)
151*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
152*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, ptr, size)
153*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
154*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, func); \
155*7c3d14c8STreehugger Robot do { \
156*7c3d14c8STreehugger Robot if (asan_init_is_running) \
157*7c3d14c8STreehugger Robot return REAL(func)(__VA_ARGS__); \
158*7c3d14c8STreehugger Robot if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
159*7c3d14c8STreehugger Robot return REAL(func)(__VA_ARGS__); \
160*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED(); \
161*7c3d14c8STreehugger Robot } while (false)
162*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
163*7c3d14c8STreehugger Robot do { \
164*7c3d14c8STreehugger Robot } while (false)
165*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
166*7c3d14c8STreehugger Robot do { \
167*7c3d14c8STreehugger Robot } while (false)
168*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
169*7c3d14c8STreehugger Robot do { \
170*7c3d14c8STreehugger Robot } while (false)
171*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
172*7c3d14c8STreehugger Robot do { \
173*7c3d14c8STreehugger Robot } while (false)
174*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
175*7c3d14c8STreehugger Robot // Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
176*7c3d14c8STreehugger Robot // But asan does not remember UserId's for threads (pthread_t);
177*7c3d14c8STreehugger Robot // and remembers all ever existed threads, so the linear search by UserId
178*7c3d14c8STreehugger Robot // can be slow.
179*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
180*7c3d14c8STreehugger Robot do { \
181*7c3d14c8STreehugger Robot } while (false)
182*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
183*7c3d14c8STreehugger Robot // Strict init-order checking is dlopen-hostile:
184*7c3d14c8STreehugger Robot // https://github.com/google/sanitizers/issues/178
185*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
186*7c3d14c8STreehugger Robot if (flags()->strict_init_order) { \
187*7c3d14c8STreehugger Robot StopInitOrderChecking(); \
188*7c3d14c8STreehugger Robot }
189*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
190*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
191*7c3d14c8STreehugger Robot CoverageUpdateMapping()
192*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping()
193*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
194*7c3d14c8STreehugger Robot #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
195*7c3d14c8STreehugger Robot if (AsanThread *t = GetCurrentThread()) { \
196*7c3d14c8STreehugger Robot *begin = t->tls_begin(); \
197*7c3d14c8STreehugger Robot *end = t->tls_end(); \
198*7c3d14c8STreehugger Robot } else { \
199*7c3d14c8STreehugger Robot *begin = *end = 0; \
200*7c3d14c8STreehugger Robot }
201*7c3d14c8STreehugger Robot // Asan needs custom handling of these:
202*7c3d14c8STreehugger Robot #undef SANITIZER_INTERCEPT_MEMSET
203*7c3d14c8STreehugger Robot #undef SANITIZER_INTERCEPT_MEMMOVE
204*7c3d14c8STreehugger Robot #undef SANITIZER_INTERCEPT_MEMCPY
205*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common_interceptors.inc"
206*7c3d14c8STreehugger Robot
207*7c3d14c8STreehugger Robot // Syscall interceptors don't have contexts, we don't support suppressions
208*7c3d14c8STreehugger Robot // for them.
209*7c3d14c8STreehugger Robot #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
210*7c3d14c8STreehugger Robot #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
211*7c3d14c8STreehugger Robot #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
212*7c3d14c8STreehugger Robot do { \
213*7c3d14c8STreehugger Robot (void)(p); \
214*7c3d14c8STreehugger Robot (void)(s); \
215*7c3d14c8STreehugger Robot } while (false)
216*7c3d14c8STreehugger Robot #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
217*7c3d14c8STreehugger Robot do { \
218*7c3d14c8STreehugger Robot (void)(p); \
219*7c3d14c8STreehugger Robot (void)(s); \
220*7c3d14c8STreehugger Robot } while (false)
221*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common_syscalls.inc"
222*7c3d14c8STreehugger Robot
223*7c3d14c8STreehugger Robot struct ThreadStartParam {
224*7c3d14c8STreehugger Robot atomic_uintptr_t t;
225*7c3d14c8STreehugger Robot atomic_uintptr_t is_registered;
226*7c3d14c8STreehugger Robot };
227*7c3d14c8STreehugger Robot
228*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_PTHREAD_CREATE
asan_thread_start(void * arg)229*7c3d14c8STreehugger Robot static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
230*7c3d14c8STreehugger Robot ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
231*7c3d14c8STreehugger Robot AsanThread *t = nullptr;
232*7c3d14c8STreehugger Robot while ((t = reinterpret_cast<AsanThread *>(
233*7c3d14c8STreehugger Robot atomic_load(¶m->t, memory_order_acquire))) == nullptr)
234*7c3d14c8STreehugger Robot internal_sched_yield();
235*7c3d14c8STreehugger Robot SetCurrentThread(t);
236*7c3d14c8STreehugger Robot return t->ThreadStart(GetTid(), ¶m->is_registered);
237*7c3d14c8STreehugger Robot }
238*7c3d14c8STreehugger Robot
INTERCEPTOR(int,pthread_create,void * thread,void * attr,void * (* start_routine)(void *),void * arg)239*7c3d14c8STreehugger Robot INTERCEPTOR(int, pthread_create, void *thread,
240*7c3d14c8STreehugger Robot void *attr, void *(*start_routine)(void*), void *arg) {
241*7c3d14c8STreehugger Robot EnsureMainThreadIDIsCorrect();
242*7c3d14c8STreehugger Robot // Strict init-order checking is thread-hostile.
243*7c3d14c8STreehugger Robot if (flags()->strict_init_order)
244*7c3d14c8STreehugger Robot StopInitOrderChecking();
245*7c3d14c8STreehugger Robot GET_STACK_TRACE_THREAD;
246*7c3d14c8STreehugger Robot int detached = 0;
247*7c3d14c8STreehugger Robot if (attr)
248*7c3d14c8STreehugger Robot REAL(pthread_attr_getdetachstate)(attr, &detached);
249*7c3d14c8STreehugger Robot ThreadStartParam param;
250*7c3d14c8STreehugger Robot atomic_store(¶m.t, 0, memory_order_relaxed);
251*7c3d14c8STreehugger Robot atomic_store(¶m.is_registered, 0, memory_order_relaxed);
252*7c3d14c8STreehugger Robot int result;
253*7c3d14c8STreehugger Robot {
254*7c3d14c8STreehugger Robot // Ignore all allocations made by pthread_create: thread stack/TLS may be
255*7c3d14c8STreehugger Robot // stored by pthread for future reuse even after thread destruction, and
256*7c3d14c8STreehugger Robot // the linked list it's stored in doesn't even hold valid pointers to the
257*7c3d14c8STreehugger Robot // objects, the latter are calculated by obscure pointer arithmetic.
258*7c3d14c8STreehugger Robot #if CAN_SANITIZE_LEAKS
259*7c3d14c8STreehugger Robot __lsan::ScopedInterceptorDisabler disabler;
260*7c3d14c8STreehugger Robot #endif
261*7c3d14c8STreehugger Robot result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
262*7c3d14c8STreehugger Robot }
263*7c3d14c8STreehugger Robot if (result == 0) {
264*7c3d14c8STreehugger Robot u32 current_tid = GetCurrentTidOrInvalid();
265*7c3d14c8STreehugger Robot AsanThread *t =
266*7c3d14c8STreehugger Robot AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
267*7c3d14c8STreehugger Robot atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
268*7c3d14c8STreehugger Robot // Wait until the AsanThread object is initialized and the ThreadRegistry
269*7c3d14c8STreehugger Robot // entry is in "started" state. One reason for this is that after this
270*7c3d14c8STreehugger Robot // interceptor exits, the child thread's stack may be the only thing holding
271*7c3d14c8STreehugger Robot // the |arg| pointer. This may cause LSan to report a leak if leak checking
272*7c3d14c8STreehugger Robot // happens at a point when the interceptor has already exited, but the stack
273*7c3d14c8STreehugger Robot // range for the child thread is not yet known.
274*7c3d14c8STreehugger Robot while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
275*7c3d14c8STreehugger Robot internal_sched_yield();
276*7c3d14c8STreehugger Robot }
277*7c3d14c8STreehugger Robot return result;
278*7c3d14c8STreehugger Robot }
279*7c3d14c8STreehugger Robot
INTERCEPTOR(int,pthread_join,void * t,void ** arg)280*7c3d14c8STreehugger Robot INTERCEPTOR(int, pthread_join, void *t, void **arg) {
281*7c3d14c8STreehugger Robot return real_pthread_join(t, arg);
282*7c3d14c8STreehugger Robot }
283*7c3d14c8STreehugger Robot
284*7c3d14c8STreehugger Robot DEFINE_REAL_PTHREAD_FUNCTIONS
285*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT_PTHREAD_CREATE
286*7c3d14c8STreehugger Robot
287*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
288*7c3d14c8STreehugger Robot
289*7c3d14c8STreehugger Robot #if SANITIZER_ANDROID
INTERCEPTOR(void *,bsd_signal,int signum,void * handler)290*7c3d14c8STreehugger Robot INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
291*7c3d14c8STreehugger Robot if (!IsHandledDeadlySignal(signum) ||
292*7c3d14c8STreehugger Robot common_flags()->allow_user_segv_handler) {
293*7c3d14c8STreehugger Robot return REAL(bsd_signal)(signum, handler);
294*7c3d14c8STreehugger Robot }
295*7c3d14c8STreehugger Robot return 0;
296*7c3d14c8STreehugger Robot }
297*7c3d14c8STreehugger Robot #endif
298*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,signal,int signum,void * handler)299*7c3d14c8STreehugger Robot INTERCEPTOR(void*, signal, int signum, void *handler) {
300*7c3d14c8STreehugger Robot if (!IsHandledDeadlySignal(signum) ||
301*7c3d14c8STreehugger Robot common_flags()->allow_user_segv_handler) {
302*7c3d14c8STreehugger Robot return REAL(signal)(signum, handler);
303*7c3d14c8STreehugger Robot }
304*7c3d14c8STreehugger Robot return nullptr;
305*7c3d14c8STreehugger Robot }
306*7c3d14c8STreehugger Robot
INTERCEPTOR(int,sigaction,int signum,const struct sigaction * act,struct sigaction * oldact)307*7c3d14c8STreehugger Robot INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
308*7c3d14c8STreehugger Robot struct sigaction *oldact) {
309*7c3d14c8STreehugger Robot if (!IsHandledDeadlySignal(signum) ||
310*7c3d14c8STreehugger Robot common_flags()->allow_user_segv_handler) {
311*7c3d14c8STreehugger Robot return REAL(sigaction)(signum, act, oldact);
312*7c3d14c8STreehugger Robot }
313*7c3d14c8STreehugger Robot return 0;
314*7c3d14c8STreehugger Robot }
315*7c3d14c8STreehugger Robot
316*7c3d14c8STreehugger Robot namespace __sanitizer {
real_sigaction(int signum,const void * act,void * oldact)317*7c3d14c8STreehugger Robot int real_sigaction(int signum, const void *act, void *oldact) {
318*7c3d14c8STreehugger Robot return REAL(sigaction)(signum, (const struct sigaction *)act,
319*7c3d14c8STreehugger Robot (struct sigaction *)oldact);
320*7c3d14c8STreehugger Robot }
321*7c3d14c8STreehugger Robot } // namespace __sanitizer
322*7c3d14c8STreehugger Robot
323*7c3d14c8STreehugger Robot #elif SANITIZER_POSIX
324*7c3d14c8STreehugger Robot // We need to have defined REAL(sigaction) on posix systems.
325*7c3d14c8STreehugger Robot DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
326*7c3d14c8STreehugger Robot struct sigaction *oldact)
327*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
328*7c3d14c8STreehugger Robot
329*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_SWAPCONTEXT
ClearShadowMemoryForContextStack(uptr stack,uptr ssize)330*7c3d14c8STreehugger Robot static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
331*7c3d14c8STreehugger Robot // Align to page size.
332*7c3d14c8STreehugger Robot uptr PageSize = GetPageSizeCached();
333*7c3d14c8STreehugger Robot uptr bottom = stack & ~(PageSize - 1);
334*7c3d14c8STreehugger Robot ssize += stack - bottom;
335*7c3d14c8STreehugger Robot ssize = RoundUpTo(ssize, PageSize);
336*7c3d14c8STreehugger Robot static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb
337*7c3d14c8STreehugger Robot if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) {
338*7c3d14c8STreehugger Robot PoisonShadow(bottom, ssize, 0);
339*7c3d14c8STreehugger Robot }
340*7c3d14c8STreehugger Robot }
341*7c3d14c8STreehugger Robot
INTERCEPTOR(int,swapcontext,struct ucontext_t * oucp,struct ucontext_t * ucp)342*7c3d14c8STreehugger Robot INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
343*7c3d14c8STreehugger Robot struct ucontext_t *ucp) {
344*7c3d14c8STreehugger Robot static bool reported_warning = false;
345*7c3d14c8STreehugger Robot if (!reported_warning) {
346*7c3d14c8STreehugger Robot Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
347*7c3d14c8STreehugger Robot "functions and may produce false positives in some cases!\n");
348*7c3d14c8STreehugger Robot reported_warning = true;
349*7c3d14c8STreehugger Robot }
350*7c3d14c8STreehugger Robot // Clear shadow memory for new context (it may share stack
351*7c3d14c8STreehugger Robot // with current context).
352*7c3d14c8STreehugger Robot uptr stack, ssize;
353*7c3d14c8STreehugger Robot ReadContextStack(ucp, &stack, &ssize);
354*7c3d14c8STreehugger Robot ClearShadowMemoryForContextStack(stack, ssize);
355*7c3d14c8STreehugger Robot int res = REAL(swapcontext)(oucp, ucp);
356*7c3d14c8STreehugger Robot // swapcontext technically does not return, but program may swap context to
357*7c3d14c8STreehugger Robot // "oucp" later, that would look as if swapcontext() returned 0.
358*7c3d14c8STreehugger Robot // We need to clear shadow for ucp once again, as it may be in arbitrary
359*7c3d14c8STreehugger Robot // state.
360*7c3d14c8STreehugger Robot ClearShadowMemoryForContextStack(stack, ssize);
361*7c3d14c8STreehugger Robot return res;
362*7c3d14c8STreehugger Robot }
363*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT_SWAPCONTEXT
364*7c3d14c8STreehugger Robot
INTERCEPTOR(void,longjmp,void * env,int val)365*7c3d14c8STreehugger Robot INTERCEPTOR(void, longjmp, void *env, int val) {
366*7c3d14c8STreehugger Robot __asan_handle_no_return();
367*7c3d14c8STreehugger Robot REAL(longjmp)(env, val);
368*7c3d14c8STreehugger Robot }
369*7c3d14c8STreehugger Robot
370*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT__LONGJMP
INTERCEPTOR(void,_longjmp,void * env,int val)371*7c3d14c8STreehugger Robot INTERCEPTOR(void, _longjmp, void *env, int val) {
372*7c3d14c8STreehugger Robot __asan_handle_no_return();
373*7c3d14c8STreehugger Robot REAL(_longjmp)(env, val);
374*7c3d14c8STreehugger Robot }
375*7c3d14c8STreehugger Robot #endif
376*7c3d14c8STreehugger Robot
377*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_SIGLONGJMP
INTERCEPTOR(void,siglongjmp,void * env,int val)378*7c3d14c8STreehugger Robot INTERCEPTOR(void, siglongjmp, void *env, int val) {
379*7c3d14c8STreehugger Robot __asan_handle_no_return();
380*7c3d14c8STreehugger Robot REAL(siglongjmp)(env, val);
381*7c3d14c8STreehugger Robot }
382*7c3d14c8STreehugger Robot #endif
383*7c3d14c8STreehugger Robot
384*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT___CXA_THROW
INTERCEPTOR(void,__cxa_throw,void * a,void * b,void * c)385*7c3d14c8STreehugger Robot INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
386*7c3d14c8STreehugger Robot CHECK(REAL(__cxa_throw));
387*7c3d14c8STreehugger Robot __asan_handle_no_return();
388*7c3d14c8STreehugger Robot REAL(__cxa_throw)(a, b, c);
389*7c3d14c8STreehugger Robot }
390*7c3d14c8STreehugger Robot #endif
391*7c3d14c8STreehugger Robot
392*7c3d14c8STreehugger Robot // memcpy is called during __asan_init() from the internals of printf(...).
393*7c3d14c8STreehugger Robot // We do not treat memcpy with to==from as a bug.
394*7c3d14c8STreehugger Robot // See http://llvm.org/bugs/show_bug.cgi?id=11763.
395*7c3d14c8STreehugger Robot #define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
396*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
397*7c3d14c8STreehugger Robot if (asan_init_is_running) { \
398*7c3d14c8STreehugger Robot return REAL(memcpy)(to, from, size); \
399*7c3d14c8STreehugger Robot } \
400*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED(); \
401*7c3d14c8STreehugger Robot if (flags()->replace_intrin) { \
402*7c3d14c8STreehugger Robot if (to != from) { \
403*7c3d14c8STreehugger Robot CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
404*7c3d14c8STreehugger Robot } \
405*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, from, size); \
406*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, to, size); \
407*7c3d14c8STreehugger Robot } \
408*7c3d14c8STreehugger Robot return REAL(memcpy)(to, from, size); \
409*7c3d14c8STreehugger Robot } while (0)
410*7c3d14c8STreehugger Robot
411*7c3d14c8STreehugger Robot
__asan_memcpy(void * to,const void * from,uptr size)412*7c3d14c8STreehugger Robot void *__asan_memcpy(void *to, const void *from, uptr size) {
413*7c3d14c8STreehugger Robot ASAN_MEMCPY_IMPL(nullptr, to, from, size);
414*7c3d14c8STreehugger Robot }
415*7c3d14c8STreehugger Robot
416*7c3d14c8STreehugger Robot // memset is called inside Printf.
417*7c3d14c8STreehugger Robot #define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
418*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
419*7c3d14c8STreehugger Robot if (asan_init_is_running) { \
420*7c3d14c8STreehugger Robot return REAL(memset)(block, c, size); \
421*7c3d14c8STreehugger Robot } \
422*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED(); \
423*7c3d14c8STreehugger Robot if (flags()->replace_intrin) { \
424*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, block, size); \
425*7c3d14c8STreehugger Robot } \
426*7c3d14c8STreehugger Robot return REAL(memset)(block, c, size); \
427*7c3d14c8STreehugger Robot } while (0)
428*7c3d14c8STreehugger Robot
__asan_memset(void * block,int c,uptr size)429*7c3d14c8STreehugger Robot void *__asan_memset(void *block, int c, uptr size) {
430*7c3d14c8STreehugger Robot ASAN_MEMSET_IMPL(nullptr, block, c, size);
431*7c3d14c8STreehugger Robot }
432*7c3d14c8STreehugger Robot
433*7c3d14c8STreehugger Robot #define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
434*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) \
435*7c3d14c8STreehugger Robot return internal_memmove(to, from, size); \
436*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED(); \
437*7c3d14c8STreehugger Robot if (flags()->replace_intrin) { \
438*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, from, size); \
439*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, to, size); \
440*7c3d14c8STreehugger Robot } \
441*7c3d14c8STreehugger Robot return internal_memmove(to, from, size); \
442*7c3d14c8STreehugger Robot } while (0)
443*7c3d14c8STreehugger Robot
__asan_memmove(void * to,const void * from,uptr size)444*7c3d14c8STreehugger Robot void *__asan_memmove(void *to, const void *from, uptr size) {
445*7c3d14c8STreehugger Robot ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
446*7c3d14c8STreehugger Robot }
447*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,memmove,void * to,const void * from,uptr size)448*7c3d14c8STreehugger Robot INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
449*7c3d14c8STreehugger Robot void *ctx;
450*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, memmove);
451*7c3d14c8STreehugger Robot ASAN_MEMMOVE_IMPL(ctx, to, from, size);
452*7c3d14c8STreehugger Robot }
453*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,memcpy,void * to,const void * from,uptr size)454*7c3d14c8STreehugger Robot INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
455*7c3d14c8STreehugger Robot void *ctx;
456*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
457*7c3d14c8STreehugger Robot #if !SANITIZER_MAC
458*7c3d14c8STreehugger Robot ASAN_MEMCPY_IMPL(ctx, to, from, size);
459*7c3d14c8STreehugger Robot #else
460*7c3d14c8STreehugger Robot // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
461*7c3d14c8STreehugger Robot // with WRAP(memcpy). As a result, false positives are reported for memmove()
462*7c3d14c8STreehugger Robot // calls. If we just disable error reporting with
463*7c3d14c8STreehugger Robot // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
464*7c3d14c8STreehugger Robot // internal_memcpy(), which may lead to crashes, see
465*7c3d14c8STreehugger Robot // http://llvm.org/bugs/show_bug.cgi?id=16362.
466*7c3d14c8STreehugger Robot ASAN_MEMMOVE_IMPL(ctx, to, from, size);
467*7c3d14c8STreehugger Robot #endif // !SANITIZER_MAC
468*7c3d14c8STreehugger Robot }
469*7c3d14c8STreehugger Robot
INTERCEPTOR(void *,memset,void * block,int c,uptr size)470*7c3d14c8STreehugger Robot INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
471*7c3d14c8STreehugger Robot void *ctx;
472*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, memset);
473*7c3d14c8STreehugger Robot ASAN_MEMSET_IMPL(ctx, block, c, size);
474*7c3d14c8STreehugger Robot }
475*7c3d14c8STreehugger Robot
476*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_INDEX
477*7c3d14c8STreehugger Robot # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
478*7c3d14c8STreehugger Robot INTERCEPTOR(char*, index, const char *string, int c)
479*7c3d14c8STreehugger Robot ALIAS(WRAPPER_NAME(strchr));
480*7c3d14c8STreehugger Robot # else
481*7c3d14c8STreehugger Robot # if SANITIZER_MAC
482*7c3d14c8STreehugger Robot DECLARE_REAL(char*, index, const char *string, int c)
483*7c3d14c8STreehugger Robot OVERRIDE_FUNCTION(index, strchr);
484*7c3d14c8STreehugger Robot # else
DEFINE_REAL(char *,index,const char * string,int c)485*7c3d14c8STreehugger Robot DEFINE_REAL(char*, index, const char *string, int c)
486*7c3d14c8STreehugger Robot # endif
487*7c3d14c8STreehugger Robot # endif
488*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT_INDEX
489*7c3d14c8STreehugger Robot
490*7c3d14c8STreehugger Robot // For both strcat() and strncat() we need to check the validity of |to|
491*7c3d14c8STreehugger Robot // argument irrespective of the |from| length.
492*7c3d14c8STreehugger Robot INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
493*7c3d14c8STreehugger Robot void *ctx;
494*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
495*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
496*7c3d14c8STreehugger Robot if (flags()->replace_str) {
497*7c3d14c8STreehugger Robot uptr from_length = REAL(strlen)(from);
498*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, from, from_length + 1);
499*7c3d14c8STreehugger Robot uptr to_length = REAL(strlen)(to);
500*7c3d14c8STreehugger Robot ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
501*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
502*7c3d14c8STreehugger Robot // If the copying actually happens, the |from| string should not overlap
503*7c3d14c8STreehugger Robot // with the resulting string starting at |to|, which has a length of
504*7c3d14c8STreehugger Robot // to_length + from_length + 1.
505*7c3d14c8STreehugger Robot if (from_length > 0) {
506*7c3d14c8STreehugger Robot CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1,
507*7c3d14c8STreehugger Robot from, from_length + 1);
508*7c3d14c8STreehugger Robot }
509*7c3d14c8STreehugger Robot }
510*7c3d14c8STreehugger Robot return REAL(strcat)(to, from); // NOLINT
511*7c3d14c8STreehugger Robot }
512*7c3d14c8STreehugger Robot
INTERCEPTOR(char *,strncat,char * to,const char * from,uptr size)513*7c3d14c8STreehugger Robot INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
514*7c3d14c8STreehugger Robot void *ctx;
515*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strncat);
516*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
517*7c3d14c8STreehugger Robot if (flags()->replace_str) {
518*7c3d14c8STreehugger Robot uptr from_length = MaybeRealStrnlen(from, size);
519*7c3d14c8STreehugger Robot uptr copy_length = Min(size, from_length + 1);
520*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, from, copy_length);
521*7c3d14c8STreehugger Robot uptr to_length = REAL(strlen)(to);
522*7c3d14c8STreehugger Robot ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
523*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
524*7c3d14c8STreehugger Robot if (from_length > 0) {
525*7c3d14c8STreehugger Robot CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
526*7c3d14c8STreehugger Robot from, copy_length);
527*7c3d14c8STreehugger Robot }
528*7c3d14c8STreehugger Robot }
529*7c3d14c8STreehugger Robot return REAL(strncat)(to, from, size);
530*7c3d14c8STreehugger Robot }
531*7c3d14c8STreehugger Robot
INTERCEPTOR(char *,strcpy,char * to,const char * from)532*7c3d14c8STreehugger Robot INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
533*7c3d14c8STreehugger Robot void *ctx;
534*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
535*7c3d14c8STreehugger Robot #if SANITIZER_MAC
536*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
537*7c3d14c8STreehugger Robot #endif
538*7c3d14c8STreehugger Robot // strcpy is called from malloc_default_purgeable_zone()
539*7c3d14c8STreehugger Robot // in __asan::ReplaceSystemAlloc() on Mac.
540*7c3d14c8STreehugger Robot if (asan_init_is_running) {
541*7c3d14c8STreehugger Robot return REAL(strcpy)(to, from); // NOLINT
542*7c3d14c8STreehugger Robot }
543*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
544*7c3d14c8STreehugger Robot if (flags()->replace_str) {
545*7c3d14c8STreehugger Robot uptr from_size = REAL(strlen)(from) + 1;
546*7c3d14c8STreehugger Robot CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
547*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, from, from_size);
548*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, to, from_size);
549*7c3d14c8STreehugger Robot }
550*7c3d14c8STreehugger Robot return REAL(strcpy)(to, from); // NOLINT
551*7c3d14c8STreehugger Robot }
552*7c3d14c8STreehugger Robot
INTERCEPTOR(char *,strdup,const char * s)553*7c3d14c8STreehugger Robot INTERCEPTOR(char*, strdup, const char *s) {
554*7c3d14c8STreehugger Robot void *ctx;
555*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strdup);
556*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return internal_strdup(s);
557*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
558*7c3d14c8STreehugger Robot uptr length = REAL(strlen)(s);
559*7c3d14c8STreehugger Robot if (flags()->replace_str) {
560*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, s, length + 1);
561*7c3d14c8STreehugger Robot }
562*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
563*7c3d14c8STreehugger Robot void *new_mem = asan_malloc(length + 1, &stack);
564*7c3d14c8STreehugger Robot REAL(memcpy)(new_mem, s, length + 1);
565*7c3d14c8STreehugger Robot return reinterpret_cast<char*>(new_mem);
566*7c3d14c8STreehugger Robot }
567*7c3d14c8STreehugger Robot
568*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT___STRDUP
INTERCEPTOR(char *,__strdup,const char * s)569*7c3d14c8STreehugger Robot INTERCEPTOR(char*, __strdup, const char *s) {
570*7c3d14c8STreehugger Robot void *ctx;
571*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strdup);
572*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return internal_strdup(s);
573*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
574*7c3d14c8STreehugger Robot uptr length = REAL(strlen)(s);
575*7c3d14c8STreehugger Robot if (flags()->replace_str) {
576*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, s, length + 1);
577*7c3d14c8STreehugger Robot }
578*7c3d14c8STreehugger Robot GET_STACK_TRACE_MALLOC;
579*7c3d14c8STreehugger Robot void *new_mem = asan_malloc(length + 1, &stack);
580*7c3d14c8STreehugger Robot REAL(memcpy)(new_mem, s, length + 1);
581*7c3d14c8STreehugger Robot return reinterpret_cast<char*>(new_mem);
582*7c3d14c8STreehugger Robot }
583*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT___STRDUP
584*7c3d14c8STreehugger Robot
INTERCEPTOR(SIZE_T,wcslen,const wchar_t * s)585*7c3d14c8STreehugger Robot INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
586*7c3d14c8STreehugger Robot void *ctx;
587*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
588*7c3d14c8STreehugger Robot SIZE_T length = REAL(wcslen)(s);
589*7c3d14c8STreehugger Robot if (!asan_init_is_running) {
590*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
591*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
592*7c3d14c8STreehugger Robot }
593*7c3d14c8STreehugger Robot return length;
594*7c3d14c8STreehugger Robot }
595*7c3d14c8STreehugger Robot
INTERCEPTOR(char *,strncpy,char * to,const char * from,uptr size)596*7c3d14c8STreehugger Robot INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
597*7c3d14c8STreehugger Robot void *ctx;
598*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
599*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
600*7c3d14c8STreehugger Robot if (flags()->replace_str) {
601*7c3d14c8STreehugger Robot uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
602*7c3d14c8STreehugger Robot CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
603*7c3d14c8STreehugger Robot ASAN_READ_RANGE(ctx, from, from_size);
604*7c3d14c8STreehugger Robot ASAN_WRITE_RANGE(ctx, to, size);
605*7c3d14c8STreehugger Robot }
606*7c3d14c8STreehugger Robot return REAL(strncpy)(to, from, size);
607*7c3d14c8STreehugger Robot }
608*7c3d14c8STreehugger Robot
INTERCEPTOR(long,strtol,const char * nptr,char ** endptr,int base)609*7c3d14c8STreehugger Robot INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
610*7c3d14c8STreehugger Robot char **endptr, int base) {
611*7c3d14c8STreehugger Robot void *ctx;
612*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strtol);
613*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
614*7c3d14c8STreehugger Robot if (!flags()->replace_str) {
615*7c3d14c8STreehugger Robot return REAL(strtol)(nptr, endptr, base);
616*7c3d14c8STreehugger Robot }
617*7c3d14c8STreehugger Robot char *real_endptr;
618*7c3d14c8STreehugger Robot long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
619*7c3d14c8STreehugger Robot StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
620*7c3d14c8STreehugger Robot return result;
621*7c3d14c8STreehugger Robot }
622*7c3d14c8STreehugger Robot
INTERCEPTOR(int,atoi,const char * nptr)623*7c3d14c8STreehugger Robot INTERCEPTOR(int, atoi, const char *nptr) {
624*7c3d14c8STreehugger Robot void *ctx;
625*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, atoi);
626*7c3d14c8STreehugger Robot #if SANITIZER_MAC
627*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
628*7c3d14c8STreehugger Robot #endif
629*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
630*7c3d14c8STreehugger Robot if (!flags()->replace_str) {
631*7c3d14c8STreehugger Robot return REAL(atoi)(nptr);
632*7c3d14c8STreehugger Robot }
633*7c3d14c8STreehugger Robot char *real_endptr;
634*7c3d14c8STreehugger Robot // "man atoi" tells that behavior of atoi(nptr) is the same as
635*7c3d14c8STreehugger Robot // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
636*7c3d14c8STreehugger Robot // parsed integer can't be stored in *long* type (even if it's
637*7c3d14c8STreehugger Robot // different from int). So, we just imitate this behavior.
638*7c3d14c8STreehugger Robot int result = REAL(strtol)(nptr, &real_endptr, 10);
639*7c3d14c8STreehugger Robot FixRealStrtolEndptr(nptr, &real_endptr);
640*7c3d14c8STreehugger Robot ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
641*7c3d14c8STreehugger Robot return result;
642*7c3d14c8STreehugger Robot }
643*7c3d14c8STreehugger Robot
INTERCEPTOR(long,atol,const char * nptr)644*7c3d14c8STreehugger Robot INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
645*7c3d14c8STreehugger Robot void *ctx;
646*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, atol);
647*7c3d14c8STreehugger Robot #if SANITIZER_MAC
648*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
649*7c3d14c8STreehugger Robot #endif
650*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
651*7c3d14c8STreehugger Robot if (!flags()->replace_str) {
652*7c3d14c8STreehugger Robot return REAL(atol)(nptr);
653*7c3d14c8STreehugger Robot }
654*7c3d14c8STreehugger Robot char *real_endptr;
655*7c3d14c8STreehugger Robot long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
656*7c3d14c8STreehugger Robot FixRealStrtolEndptr(nptr, &real_endptr);
657*7c3d14c8STreehugger Robot ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
658*7c3d14c8STreehugger Robot return result;
659*7c3d14c8STreehugger Robot }
660*7c3d14c8STreehugger Robot
661*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
INTERCEPTOR(long long,strtoll,const char * nptr,char ** endptr,int base)662*7c3d14c8STreehugger Robot INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
663*7c3d14c8STreehugger Robot char **endptr, int base) {
664*7c3d14c8STreehugger Robot void *ctx;
665*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
666*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
667*7c3d14c8STreehugger Robot if (!flags()->replace_str) {
668*7c3d14c8STreehugger Robot return REAL(strtoll)(nptr, endptr, base);
669*7c3d14c8STreehugger Robot }
670*7c3d14c8STreehugger Robot char *real_endptr;
671*7c3d14c8STreehugger Robot long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
672*7c3d14c8STreehugger Robot StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
673*7c3d14c8STreehugger Robot return result;
674*7c3d14c8STreehugger Robot }
675*7c3d14c8STreehugger Robot
INTERCEPTOR(long long,atoll,const char * nptr)676*7c3d14c8STreehugger Robot INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
677*7c3d14c8STreehugger Robot void *ctx;
678*7c3d14c8STreehugger Robot ASAN_INTERCEPTOR_ENTER(ctx, atoll);
679*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
680*7c3d14c8STreehugger Robot if (!flags()->replace_str) {
681*7c3d14c8STreehugger Robot return REAL(atoll)(nptr);
682*7c3d14c8STreehugger Robot }
683*7c3d14c8STreehugger Robot char *real_endptr;
684*7c3d14c8STreehugger Robot long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
685*7c3d14c8STreehugger Robot FixRealStrtolEndptr(nptr, &real_endptr);
686*7c3d14c8STreehugger Robot ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
687*7c3d14c8STreehugger Robot return result;
688*7c3d14c8STreehugger Robot }
689*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
690*7c3d14c8STreehugger Robot
691*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT___CXA_ATEXIT
AtCxaAtexit(void * unused)692*7c3d14c8STreehugger Robot static void AtCxaAtexit(void *unused) {
693*7c3d14c8STreehugger Robot (void)unused;
694*7c3d14c8STreehugger Robot StopInitOrderChecking();
695*7c3d14c8STreehugger Robot }
696*7c3d14c8STreehugger Robot
INTERCEPTOR(int,__cxa_atexit,void (* func)(void *),void * arg,void * dso_handle)697*7c3d14c8STreehugger Robot INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
698*7c3d14c8STreehugger Robot void *dso_handle) {
699*7c3d14c8STreehugger Robot #if SANITIZER_MAC
700*7c3d14c8STreehugger Robot if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
701*7c3d14c8STreehugger Robot #endif
702*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
703*7c3d14c8STreehugger Robot int res = REAL(__cxa_atexit)(func, arg, dso_handle);
704*7c3d14c8STreehugger Robot REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
705*7c3d14c8STreehugger Robot return res;
706*7c3d14c8STreehugger Robot }
707*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT___CXA_ATEXIT
708*7c3d14c8STreehugger Robot
709*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_FORK
INTERCEPTOR(int,fork,void)710*7c3d14c8STreehugger Robot INTERCEPTOR(int, fork, void) {
711*7c3d14c8STreehugger Robot ENSURE_ASAN_INITED();
712*7c3d14c8STreehugger Robot if (common_flags()->coverage) CovBeforeFork();
713*7c3d14c8STreehugger Robot int pid = REAL(fork)();
714*7c3d14c8STreehugger Robot if (common_flags()->coverage) CovAfterFork(pid);
715*7c3d14c8STreehugger Robot return pid;
716*7c3d14c8STreehugger Robot }
717*7c3d14c8STreehugger Robot #endif // ASAN_INTERCEPT_FORK
718*7c3d14c8STreehugger Robot
719*7c3d14c8STreehugger Robot // ---------------------- InitializeAsanInterceptors ---------------- {{{1
720*7c3d14c8STreehugger Robot namespace __asan {
InitializeAsanInterceptors()721*7c3d14c8STreehugger Robot void InitializeAsanInterceptors() {
722*7c3d14c8STreehugger Robot static bool was_called_once;
723*7c3d14c8STreehugger Robot CHECK(was_called_once == false);
724*7c3d14c8STreehugger Robot was_called_once = true;
725*7c3d14c8STreehugger Robot InitializeCommonInterceptors();
726*7c3d14c8STreehugger Robot
727*7c3d14c8STreehugger Robot // Intercept mem* functions.
728*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(memcpy);
729*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(memset);
730*7c3d14c8STreehugger Robot if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
731*7c3d14c8STreehugger Robot // In asan, REAL(memmove) is not used, but it is used in msan.
732*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(memmove);
733*7c3d14c8STreehugger Robot }
734*7c3d14c8STreehugger Robot CHECK(REAL(memcpy));
735*7c3d14c8STreehugger Robot
736*7c3d14c8STreehugger Robot // Intercept str* functions.
737*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strcat); // NOLINT
738*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
739*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(wcslen);
740*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strncat);
741*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strncpy);
742*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strdup);
743*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT___STRDUP
744*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(__strdup);
745*7c3d14c8STreehugger Robot #endif
746*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
747*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(index);
748*7c3d14c8STreehugger Robot #endif
749*7c3d14c8STreehugger Robot
750*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(atoi);
751*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(atol);
752*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strtol);
753*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
754*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(atoll);
755*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(strtoll);
756*7c3d14c8STreehugger Robot #endif
757*7c3d14c8STreehugger Robot
758*7c3d14c8STreehugger Robot // Intecept signal- and jump-related functions.
759*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(longjmp);
760*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
761*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(sigaction);
762*7c3d14c8STreehugger Robot #if SANITIZER_ANDROID
763*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(bsd_signal);
764*7c3d14c8STreehugger Robot #endif
765*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(signal);
766*7c3d14c8STreehugger Robot #endif
767*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_SWAPCONTEXT
768*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(swapcontext);
769*7c3d14c8STreehugger Robot #endif
770*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT__LONGJMP
771*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(_longjmp);
772*7c3d14c8STreehugger Robot #endif
773*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_SIGLONGJMP
774*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(siglongjmp);
775*7c3d14c8STreehugger Robot #endif
776*7c3d14c8STreehugger Robot
777*7c3d14c8STreehugger Robot // Intercept exception handling functions.
778*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT___CXA_THROW
779*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(__cxa_throw);
780*7c3d14c8STreehugger Robot #endif
781*7c3d14c8STreehugger Robot
782*7c3d14c8STreehugger Robot // Intercept threading-related functions
783*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_PTHREAD_CREATE
784*7c3d14c8STreehugger Robot #if defined(ASAN_PTHREAD_CREATE_VERSION)
785*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
786*7c3d14c8STreehugger Robot #else
787*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(pthread_create);
788*7c3d14c8STreehugger Robot #endif
789*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(pthread_join);
790*7c3d14c8STreehugger Robot #endif
791*7c3d14c8STreehugger Robot
792*7c3d14c8STreehugger Robot // Intercept atexit function.
793*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT___CXA_ATEXIT
794*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(__cxa_atexit);
795*7c3d14c8STreehugger Robot #endif
796*7c3d14c8STreehugger Robot
797*7c3d14c8STreehugger Robot #if ASAN_INTERCEPT_FORK
798*7c3d14c8STreehugger Robot ASAN_INTERCEPT_FUNC(fork);
799*7c3d14c8STreehugger Robot #endif
800*7c3d14c8STreehugger Robot
801*7c3d14c8STreehugger Robot InitializePlatformInterceptors();
802*7c3d14c8STreehugger Robot
803*7c3d14c8STreehugger Robot VReport(1, "AddressSanitizer: libc interceptors initialized\n");
804*7c3d14c8STreehugger Robot }
805*7c3d14c8STreehugger Robot
806*7c3d14c8STreehugger Robot } // namespace __asan
807