1 //===-- hwasan_interceptors.cc --------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of HWAddressSanitizer.
12 // Interceptors for standard library functions.
14 // FIXME: move as many interceptors as possible into
15 // sanitizer_common/sanitizer_common_interceptors.h
16 //===----------------------------------------------------------------------===//
18 #include "interception/interception.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"
38 // ACHTUNG! No other system header includes in this file.
39 // Ideally, we should get rid of stdarg.h as well.
41 using namespace __hwasan;
43 using __sanitizer::memory_order;
44 using __sanitizer::atomic_load;
45 using __sanitizer::atomic_store;
46 using __sanitizer::atomic_uintptr_t;
48 bool IsInInterceptorScope() {
49 Thread *t = GetCurrentThread();
50 return t && t->InInterceptorScope();
53 struct InterceptorScope {
55 Thread *t = GetCurrentThread();
57 t->EnterInterceptorScope();
60 Thread *t = GetCurrentThread();
62 t->LeaveInterceptorScope();
66 static uptr allocated_for_dlsym;
67 static const uptr kDlsymAllocPoolSize = 1024;
68 static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
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);
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);
83 #define ENSURE_HWASAN_INITED() do { \
84 CHECK(!hwasan_init_is_running); \
85 if (!hwasan_inited) { \
91 int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) {
92 GET_MALLOC_STACK_TRACE;
94 int res = hwasan_posix_memalign(memptr, alignment, size, &stack);
98 void * __sanitizer_memalign(uptr alignment, uptr size) {
99 GET_MALLOC_STACK_TRACE;
100 return hwasan_memalign(alignment, size, &stack);
103 void * __sanitizer_aligned_alloc(uptr alignment, uptr size) {
104 GET_MALLOC_STACK_TRACE;
105 return hwasan_aligned_alloc(alignment, size, &stack);
108 void * __sanitizer___libc_memalign(uptr alignment, uptr size) {
109 GET_MALLOC_STACK_TRACE;
110 void *ptr = hwasan_memalign(alignment, size, &stack);
112 DTLS_on_libc_memalign(ptr, size);
116 void * __sanitizer_valloc(uptr size) {
117 GET_MALLOC_STACK_TRACE;
118 return hwasan_valloc(size, &stack);
121 void * __sanitizer_pvalloc(uptr size) {
122 GET_MALLOC_STACK_TRACE;
123 return hwasan_pvalloc(size, &stack);
126 void __sanitizer_free(void *ptr) {
127 GET_MALLOC_STACK_TRACE;
128 if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
129 hwasan_free(ptr, &stack);
132 void __sanitizer_cfree(void *ptr) {
133 GET_MALLOC_STACK_TRACE;
134 if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
135 hwasan_free(ptr, &stack);
138 uptr __sanitizer_malloc_usable_size(const void *ptr) {
139 return __sanitizer_get_allocated_size(ptr);
142 struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() {
143 __sanitizer_struct_mallinfo sret;
144 internal_memset(&sret, 0, sizeof(sret));
148 int __sanitizer_mallopt(int cmd, int value) {
152 void __sanitizer_malloc_stats(void) {
153 // FIXME: implement, but don't call REAL(malloc_stats)!
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);
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);
170 if (UNLIKELY(!hwasan_inited)) {
171 new_ptr = AllocateFromLocalPool(copy_size);
174 new_ptr = hwasan_malloc(copy_size, &stack);
176 internal_memcpy(new_ptr, ptr, copy_size);
179 return hwasan_realloc(ptr, size, &stack);
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);
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)
199 INTERCEPTOR_ALIAS(int, posix_memalign, void **memptr, SIZE_T alignment,
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);
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);
218 #endif // HWASAN_WITH_INTERCEPTORS
221 #if HWASAN_WITH_INTERCEPTORS && !defined(__aarch64__)
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),
231 static void BeforeFork() {
235 static void AfterFork() {
236 StackDepotUnlockAll();
239 INTERCEPTOR(int, fork, void) {
240 ENSURE_HWASAN_INITED();
242 int pid = REAL(fork)();
248 struct HwasanInterceptorContext {
249 bool in_interceptor_scope;
255 // FIXME: ask frontend whether we need to return failure.
259 } // namespace __hwasan
263 void InitializeInterceptors() {
264 static int inited = 0;
267 INTERCEPT_FUNCTION(fork);
269 #if HWASAN_WITH_INTERCEPTORS
270 #if !defined(__aarch64__)
271 INTERCEPT_FUNCTION(pthread_create);
273 INTERCEPT_FUNCTION(realloc);
274 INTERCEPT_FUNCTION(free);
279 } // namespace __hwasan