]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/hwasan/hwasan_interceptors.cc
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / hwasan / hwasan_interceptors.cc
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
48 bool IsInInterceptorScope() {
49   Thread *t = GetCurrentThread();
50   return t && t->InInterceptorScope();
51 }
52
53 struct InterceptorScope {
54   InterceptorScope() {
55     Thread *t = GetCurrentThread();
56     if (t)
57       t->EnterInterceptorScope();
58   }
59   ~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
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
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
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
98 void * __sanitizer_memalign(uptr alignment, uptr size) {
99   GET_MALLOC_STACK_TRACE;
100   return hwasan_memalign(alignment, size, &stack);
101 }
102
103 void * __sanitizer_aligned_alloc(uptr alignment, uptr size) {
104   GET_MALLOC_STACK_TRACE;
105   return hwasan_aligned_alloc(alignment, size, &stack);
106 }
107
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
116 void * __sanitizer_valloc(uptr size) {
117   GET_MALLOC_STACK_TRACE;
118   return hwasan_valloc(size, &stack);
119 }
120
121 void * __sanitizer_pvalloc(uptr size) {
122   GET_MALLOC_STACK_TRACE;
123   return hwasan_pvalloc(size, &stack);
124 }
125
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
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
138 uptr __sanitizer_malloc_usable_size(const void *ptr) {
139   return __sanitizer_get_allocated_size(ptr);
140 }
141
142 struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() {
143   __sanitizer_struct_mallinfo sret;
144   internal_memset(&sret, 0, sizeof(sret));
145   return sret;
146 }
147
148 int __sanitizer_mallopt(int cmd, int value) {
149   return 0;
150 }
151
152 void __sanitizer_malloc_stats(void) {
153   // FIXME: implement, but don't call REAL(malloc_stats)!
154 }
155
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
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
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__)
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
231 static void BeforeFork() {
232   StackDepotLockAll();
233 }
234
235 static void AfterFork() {
236   StackDepotUnlockAll();
237 }
238
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
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
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