1 //===-- hwasan_interceptors.cc --------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of HWAddressSanitizer.
11 //
12 // Interceptors for standard library functions.
13 //
14 // FIXME: move as many interceptors as possible into
15 // sanitizer_common/sanitizer_common_interceptors.h
16 //===----------------------------------------------------------------------===//
17
18 #include "interception/interception.h"
19 #include "hwasan.h"
20 #include "hwasan_allocator.h"
21 #include "hwasan_mapping.h"
22 #include "hwasan_thread.h"
23 #include "hwasan_poisoning.h"
24 #include "hwasan_report.h"
25 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
26 #include "sanitizer_common/sanitizer_allocator.h"
27 #include "sanitizer_common/sanitizer_allocator_interface.h"
28 #include "sanitizer_common/sanitizer_allocator_internal.h"
29 #include "sanitizer_common/sanitizer_atomic.h"
30 #include "sanitizer_common/sanitizer_common.h"
31 #include "sanitizer_common/sanitizer_errno.h"
32 #include "sanitizer_common/sanitizer_stackdepot.h"
33 #include "sanitizer_common/sanitizer_libc.h"
34 #include "sanitizer_common/sanitizer_linux.h"
35 #include "sanitizer_common/sanitizer_tls_get_addr.h"
36
37 #include <stdarg.h>
38 // ACHTUNG! No other system header includes in this file.
39 // Ideally, we should get rid of stdarg.h as well.
40
41 using namespace __hwasan;
42
43 using __sanitizer::memory_order;
44 using __sanitizer::atomic_load;
45 using __sanitizer::atomic_store;
46 using __sanitizer::atomic_uintptr_t;
47
IsInInterceptorScope()48 bool IsInInterceptorScope() {
49 Thread *t = GetCurrentThread();
50 return t && t->InInterceptorScope();
51 }
52
53 struct InterceptorScope {
InterceptorScopeInterceptorScope54 InterceptorScope() {
55 Thread *t = GetCurrentThread();
56 if (t)
57 t->EnterInterceptorScope();
58 }
~InterceptorScopeInterceptorScope59 ~InterceptorScope() {
60 Thread *t = GetCurrentThread();
61 if (t)
62 t->LeaveInterceptorScope();
63 }
64 };
65
66 static uptr allocated_for_dlsym;
67 static const uptr kDlsymAllocPoolSize = 1024;
68 static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
69
IsInDlsymAllocPool(const void * ptr)70 static bool IsInDlsymAllocPool(const void *ptr) {
71 uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
72 return off < sizeof(alloc_memory_for_dlsym);
73 }
74
AllocateFromLocalPool(uptr size_in_bytes)75 static void *AllocateFromLocalPool(uptr size_in_bytes) {
76 uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
77 void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym];
78 allocated_for_dlsym += size_in_words;
79 CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
80 return mem;
81 }
82
83 #define ENSURE_HWASAN_INITED() do { \
84 CHECK(!hwasan_init_is_running); \
85 if (!hwasan_inited) { \
86 __hwasan_init(); \
87 } \
88 } while (0)
89
90
__sanitizer_posix_memalign(void ** memptr,uptr alignment,uptr size)91 int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) {
92 GET_MALLOC_STACK_TRACE;
93 CHECK_NE(memptr, 0);
94 int res = hwasan_posix_memalign(memptr, alignment, size, &stack);
95 return res;
96 }
97
__sanitizer_memalign(uptr alignment,uptr size)98 void * __sanitizer_memalign(uptr alignment, uptr size) {
99 GET_MALLOC_STACK_TRACE;
100 return hwasan_memalign(alignment, size, &stack);
101 }
102
__sanitizer_aligned_alloc(uptr alignment,uptr size)103 void * __sanitizer_aligned_alloc(uptr alignment, uptr size) {
104 GET_MALLOC_STACK_TRACE;
105 return hwasan_aligned_alloc(alignment, size, &stack);
106 }
107
__sanitizer___libc_memalign(uptr alignment,uptr size)108 void * __sanitizer___libc_memalign(uptr alignment, uptr size) {
109 GET_MALLOC_STACK_TRACE;
110 void *ptr = hwasan_memalign(alignment, size, &stack);
111 if (ptr)
112 DTLS_on_libc_memalign(ptr, size);
113 return ptr;
114 }
115
__sanitizer_valloc(uptr size)116 void * __sanitizer_valloc(uptr size) {
117 GET_MALLOC_STACK_TRACE;
118 return hwasan_valloc(size, &stack);
119 }
120
__sanitizer_pvalloc(uptr size)121 void * __sanitizer_pvalloc(uptr size) {
122 GET_MALLOC_STACK_TRACE;
123 return hwasan_pvalloc(size, &stack);
124 }
125
__sanitizer_free(void * ptr)126 void __sanitizer_free(void *ptr) {
127 GET_MALLOC_STACK_TRACE;
128 if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
129 hwasan_free(ptr, &stack);
130 }
131
__sanitizer_cfree(void * ptr)132 void __sanitizer_cfree(void *ptr) {
133 GET_MALLOC_STACK_TRACE;
134 if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
135 hwasan_free(ptr, &stack);
136 }
137
__sanitizer_malloc_usable_size(const void * ptr)138 uptr __sanitizer_malloc_usable_size(const void *ptr) {
139 return __sanitizer_get_allocated_size(ptr);
140 }
141
__sanitizer_mallinfo()142 struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() {
143 __sanitizer_struct_mallinfo sret;
144 internal_memset(&sret, 0, sizeof(sret));
145 return sret;
146 }
147
__sanitizer_mallopt(int cmd,int value)148 int __sanitizer_mallopt(int cmd, int value) {
149 return 0;
150 }
151
__sanitizer_malloc_stats(void)152 void __sanitizer_malloc_stats(void) {
153 // FIXME: implement, but don't call REAL(malloc_stats)!
154 }
155
__sanitizer_calloc(uptr nmemb,uptr size)156 void * __sanitizer_calloc(uptr nmemb, uptr size) {
157 GET_MALLOC_STACK_TRACE;
158 if (UNLIKELY(!hwasan_inited))
159 // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
160 return AllocateFromLocalPool(nmemb * size);
161 return hwasan_calloc(nmemb, size, &stack);
162 }
163
__sanitizer_realloc(void * ptr,uptr size)164 void * __sanitizer_realloc(void *ptr, uptr size) {
165 GET_MALLOC_STACK_TRACE;
166 if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
167 uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
168 uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
169 void *new_ptr;
170 if (UNLIKELY(!hwasan_inited)) {
171 new_ptr = AllocateFromLocalPool(copy_size);
172 } else {
173 copy_size = size;
174 new_ptr = hwasan_malloc(copy_size, &stack);
175 }
176 internal_memcpy(new_ptr, ptr, copy_size);
177 return new_ptr;
178 }
179 return hwasan_realloc(ptr, size, &stack);
180 }
181
__sanitizer_malloc(uptr size)182 void * __sanitizer_malloc(uptr size) {
183 GET_MALLOC_STACK_TRACE;
184 if (UNLIKELY(!hwasan_init_is_running))
185 ENSURE_HWASAN_INITED();
186 if (UNLIKELY(!hwasan_inited))
187 // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
188 return AllocateFromLocalPool(size);
189 return hwasan_malloc(size, &stack);
190 }
191
192 #if HWASAN_WITH_INTERCEPTORS
193 #define INTERCEPTOR_ALIAS(RET, FN, ARGS...) \
194 extern "C" SANITIZER_INTERFACE_ATTRIBUTE RET WRAP(FN)(ARGS) \
195 ALIAS("__sanitizer_" #FN); \
196 extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE RET FN( \
197 ARGS) ALIAS("__sanitizer_" #FN)
198
199 INTERCEPTOR_ALIAS(int, posix_memalign, void **memptr, SIZE_T alignment,
200 SIZE_T size);
201 INTERCEPTOR_ALIAS(void *, aligned_alloc, SIZE_T alignment, SIZE_T size);
202 INTERCEPTOR_ALIAS(void *, __libc_memalign, SIZE_T alignment, SIZE_T size);
203 INTERCEPTOR_ALIAS(void *, valloc, SIZE_T size);
204 INTERCEPTOR_ALIAS(void, free, void *ptr);
205 INTERCEPTOR_ALIAS(uptr, malloc_usable_size, const void *ptr);
206 INTERCEPTOR_ALIAS(void *, calloc, SIZE_T nmemb, SIZE_T size);
207 INTERCEPTOR_ALIAS(void *, realloc, void *ptr, SIZE_T size);
208 INTERCEPTOR_ALIAS(void *, malloc, SIZE_T size);
209
210 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
211 INTERCEPTOR_ALIAS(void *, memalign, SIZE_T alignment, SIZE_T size);
212 INTERCEPTOR_ALIAS(void *, pvalloc, SIZE_T size);
213 INTERCEPTOR_ALIAS(void, cfree, void *ptr);
214 INTERCEPTOR_ALIAS(__sanitizer_struct_mallinfo, mallinfo);
215 INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value);
216 INTERCEPTOR_ALIAS(void, malloc_stats, void);
217 #endif
218 #endif // HWASAN_WITH_INTERCEPTORS
219
220
221 #if HWASAN_WITH_INTERCEPTORS && !defined(__aarch64__)
INTERCEPTOR(int,pthread_create,void * th,void * attr,void * (* callback)(void *),void * param)222 INTERCEPTOR(int, pthread_create, void *th, void *attr,
223 void *(*callback)(void *), void *param) {
224 ScopedTaggingDisabler disabler;
225 int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
226 callback, param);
227 return res;
228 }
229 #endif
230
BeforeFork()231 static void BeforeFork() {
232 StackDepotLockAll();
233 }
234
AfterFork()235 static void AfterFork() {
236 StackDepotUnlockAll();
237 }
238
INTERCEPTOR(int,fork,void)239 INTERCEPTOR(int, fork, void) {
240 ENSURE_HWASAN_INITED();
241 BeforeFork();
242 int pid = REAL(fork)();
243 AfterFork();
244 return pid;
245 }
246
247
248 struct HwasanInterceptorContext {
249 bool in_interceptor_scope;
250 };
251
252 namespace __hwasan {
253
OnExit()254 int OnExit() {
255 // FIXME: ask frontend whether we need to return failure.
256 return 0;
257 }
258
259 } // namespace __hwasan
260
261 namespace __hwasan {
262
InitializeInterceptors()263 void InitializeInterceptors() {
264 static int inited = 0;
265 CHECK_EQ(inited, 0);
266
267 INTERCEPT_FUNCTION(fork);
268
269 #if HWASAN_WITH_INTERCEPTORS
270 #if !defined(__aarch64__)
271 INTERCEPT_FUNCTION(pthread_create);
272 #endif
273 INTERCEPT_FUNCTION(realloc);
274 INTERCEPT_FUNCTION(free);
275 #endif
276
277 inited = 1;
278 }
279 } // namespace __hwasan
280