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