]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/hwasan/hwasan_interceptors.cc
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
[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_thread.h"
21 #include "hwasan_poisoning.h"
22 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
23 #include "sanitizer_common/sanitizer_allocator.h"
24 #include "sanitizer_common/sanitizer_allocator_interface.h"
25 #include "sanitizer_common/sanitizer_allocator_internal.h"
26 #include "sanitizer_common/sanitizer_atomic.h"
27 #include "sanitizer_common/sanitizer_common.h"
28 #include "sanitizer_common/sanitizer_errno.h"
29 #include "sanitizer_common/sanitizer_stackdepot.h"
30 #include "sanitizer_common/sanitizer_libc.h"
31 #include "sanitizer_common/sanitizer_linux.h"
32 #include "sanitizer_common/sanitizer_tls_get_addr.h"
33
34 #include <stdarg.h>
35 // ACHTUNG! No other system header includes in this file.
36 // Ideally, we should get rid of stdarg.h as well.
37
38 using namespace __hwasan;
39
40 using __sanitizer::memory_order;
41 using __sanitizer::atomic_load;
42 using __sanitizer::atomic_store;
43 using __sanitizer::atomic_uintptr_t;
44
45 DECLARE_REAL(SIZE_T, strlen, const char *s)
46 DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
47 DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
48 DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
49
50 bool IsInInterceptorScope() {
51   HwasanThread *t = GetCurrentThread();
52   return t && t->InInterceptorScope();
53 }
54
55 struct InterceptorScope {
56   InterceptorScope() {
57     HwasanThread *t = GetCurrentThread();
58     if (t)
59       t->EnterInterceptorScope();
60   }
61   ~InterceptorScope() {
62     HwasanThread *t = GetCurrentThread();
63     if (t)
64       t->LeaveInterceptorScope();
65   }
66 };
67
68 static uptr allocated_for_dlsym;
69 static const uptr kDlsymAllocPoolSize = 1024;
70 static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
71
72 static bool IsInDlsymAllocPool(const void *ptr) {
73   uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
74   return off < sizeof(alloc_memory_for_dlsym);
75 }
76
77 static void *AllocateFromLocalPool(uptr size_in_bytes) {
78   uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
79   void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym];
80   allocated_for_dlsym += size_in_words;
81   CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
82   return mem;
83 }
84
85 #define ENSURE_HWASAN_INITED() do { \
86   CHECK(!hwasan_init_is_running); \
87   if (!hwasan_inited) { \
88     __hwasan_init(); \
89   } \
90 } while (0)
91
92
93
94 #define HWASAN_READ_RANGE(ctx, offset, size) \
95   CHECK_UNPOISONED(offset, size)
96 #define HWASAN_WRITE_RANGE(ctx, offset, size) \
97   CHECK_UNPOISONED(offset, size)
98
99
100
101 // Check that [x, x+n) range is unpoisoned.
102 #define CHECK_UNPOISONED_0(x, n)                                       \
103   do {                                                                 \
104     sptr __offset = __hwasan_test_shadow(x, n);                         \
105     if (__hwasan::IsInSymbolizer()) break;                              \
106     if (__offset >= 0) {                                               \
107       GET_CALLER_PC_BP_SP;                                             \
108       (void)sp;                                                        \
109       ReportInvalidAccessInsideAddressRange(__func__, x, n, __offset); \
110       __hwasan::PrintWarning(pc, bp);                                   \
111       if (__hwasan::flags()->halt_on_error) {                           \
112         Printf("Exiting\n");                                           \
113         Die();                                                         \
114       }                                                                \
115     }                                                                  \
116   } while (0)
117
118 // Check that [x, x+n) range is unpoisoned unless we are in a nested
119 // interceptor.
120 #define CHECK_UNPOISONED(x, n)                             \
121   do {                                                     \
122     if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
123   } while (0)
124
125 #define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n)               \
126   CHECK_UNPOISONED((x),                                         \
127     common_flags()->strict_string_checks ? (len) + 1 : (n) )
128
129
130 INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
131   GET_MALLOC_STACK_TRACE;
132   CHECK_NE(memptr, 0);
133   int res = hwasan_posix_memalign(memptr, alignment, size, &stack);
134   return res;
135 }
136
137 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
138 INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) {
139   GET_MALLOC_STACK_TRACE;
140   return hwasan_memalign(alignment, size, &stack);
141 }
142 #define HWASAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
143 #else
144 #define HWASAN_MAYBE_INTERCEPT_MEMALIGN
145 #endif
146
147 INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
148   GET_MALLOC_STACK_TRACE;
149   return hwasan_aligned_alloc(alignment, size, &stack);
150 }
151
152 INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
153   GET_MALLOC_STACK_TRACE;
154   void *ptr = hwasan_memalign(alignment, size, &stack);
155   if (ptr)
156     DTLS_on_libc_memalign(ptr, size);
157   return ptr;
158 }
159
160 INTERCEPTOR(void *, valloc, SIZE_T size) {
161   GET_MALLOC_STACK_TRACE;
162   return hwasan_valloc(size, &stack);
163 }
164
165 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
166 INTERCEPTOR(void *, pvalloc, SIZE_T size) {
167   GET_MALLOC_STACK_TRACE;
168   return hwasan_pvalloc(size, &stack);
169 }
170 #define HWASAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
171 #else
172 #define HWASAN_MAYBE_INTERCEPT_PVALLOC
173 #endif
174
175 INTERCEPTOR(void, free, void *ptr) {
176   GET_MALLOC_STACK_TRACE;
177   if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
178   HwasanDeallocate(&stack, ptr);
179 }
180
181 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
182 INTERCEPTOR(void, cfree, void *ptr) {
183   GET_MALLOC_STACK_TRACE;
184   if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
185   HwasanDeallocate(&stack, ptr);
186 }
187 #define HWASAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
188 #else
189 #define HWASAN_MAYBE_INTERCEPT_CFREE
190 #endif
191
192 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
193   return __sanitizer_get_allocated_size(ptr);
194 }
195
196 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
197 // This function actually returns a struct by value, but we can't unpoison a
198 // temporary! The following is equivalent on all supported platforms but
199 // aarch64 (which uses a different register for sret value).  We have a test
200 // to confirm that.
201 INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
202 #ifdef __aarch64__
203   uptr r8;
204   asm volatile("mov %0,x8" : "=r" (r8));
205   sret = reinterpret_cast<__sanitizer_mallinfo*>(r8);
206 #endif
207   REAL(memset)(sret, 0, sizeof(*sret));
208 }
209 #define HWASAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
210 #else
211 #define HWASAN_MAYBE_INTERCEPT_MALLINFO
212 #endif
213
214 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
215 INTERCEPTOR(int, mallopt, int cmd, int value) {
216   return -1;
217 }
218 #define HWASAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
219 #else
220 #define HWASAN_MAYBE_INTERCEPT_MALLOPT
221 #endif
222
223 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
224 INTERCEPTOR(void, malloc_stats, void) {
225   // FIXME: implement, but don't call REAL(malloc_stats)!
226 }
227 #define HWASAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
228 #else
229 #define HWASAN_MAYBE_INTERCEPT_MALLOC_STATS
230 #endif
231
232
233 INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
234   GET_MALLOC_STACK_TRACE;
235   if (UNLIKELY(!hwasan_inited))
236     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
237     return AllocateFromLocalPool(nmemb * size);
238   return hwasan_calloc(nmemb, size, &stack);
239 }
240
241 INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
242   GET_MALLOC_STACK_TRACE;
243   if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
244     uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
245     uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
246     void *new_ptr;
247     if (UNLIKELY(!hwasan_inited)) {
248       new_ptr = AllocateFromLocalPool(copy_size);
249     } else {
250       copy_size = size;
251       new_ptr = hwasan_malloc(copy_size, &stack);
252     }
253     internal_memcpy(new_ptr, ptr, copy_size);
254     return new_ptr;
255   }
256   return hwasan_realloc(ptr, size, &stack);
257 }
258
259 INTERCEPTOR(void *, malloc, SIZE_T size) {
260   GET_MALLOC_STACK_TRACE;
261   if (UNLIKELY(!hwasan_inited))
262     // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
263     return AllocateFromLocalPool(size);
264   return hwasan_malloc(size, &stack);
265 }
266
267
268 INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
269             int fd, OFF_T offset) {
270   if (hwasan_init_is_running)
271     return REAL(mmap)(addr, length, prot, flags, fd, offset);
272   ENSURE_HWASAN_INITED();
273   if (addr && !MEM_IS_APP(addr)) {
274     if (flags & map_fixed) {
275       errno = errno_EINVAL;
276       return (void *)-1;
277     } else {
278       addr = nullptr;
279     }
280   }
281   void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
282   return res;
283 }
284
285 #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
286 INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
287             int fd, OFF64_T offset) {
288   ENSURE_HWASAN_INITED();
289   if (addr && !MEM_IS_APP(addr)) {
290     if (flags & map_fixed) {
291       errno = errno_EINVAL;
292       return (void *)-1;
293     } else {
294       addr = nullptr;
295     }
296   }
297   void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
298   return res;
299 }
300 #define HWASAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64)
301 #else
302 #define HWASAN_MAYBE_INTERCEPT_MMAP64
303 #endif
304
305 extern "C" int pthread_attr_init(void *attr);
306 extern "C" int pthread_attr_destroy(void *attr);
307
308 static void *HwasanThreadStartFunc(void *arg) {
309   HwasanThread *t = (HwasanThread *)arg;
310   SetCurrentThread(t);
311   return t->ThreadStart();
312 }
313
314 INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
315             void * param) {
316   ENSURE_HWASAN_INITED(); // for GetTlsSize()
317   __sanitizer_pthread_attr_t myattr;
318   if (!attr) {
319     pthread_attr_init(&myattr);
320     attr = &myattr;
321   }
322
323   AdjustStackSize(attr);
324
325   HwasanThread *t = HwasanThread::Create(callback, param);
326
327   int res = REAL(pthread_create)(th, attr, HwasanThreadStartFunc, t);
328
329   if (attr == &myattr)
330     pthread_attr_destroy(&myattr);
331   return res;
332 }
333
334 static void BeforeFork() {
335   StackDepotLockAll();
336 }
337
338 static void AfterFork() {
339   StackDepotUnlockAll();
340 }
341
342 INTERCEPTOR(int, fork, void) {
343   ENSURE_HWASAN_INITED();
344   BeforeFork();
345   int pid = REAL(fork)();
346   AfterFork();
347   return pid;
348 }
349
350
351 struct HwasanInterceptorContext {
352   bool in_interceptor_scope;
353 };
354
355 namespace __hwasan {
356
357 int OnExit() {
358   // FIXME: ask frontend whether we need to return failure.
359   return 0;
360 }
361
362 } // namespace __hwasan
363
364 // A version of CHECK_UNPOISONED using a saved scope value. Used in common
365 // interceptors.
366 #define CHECK_UNPOISONED_CTX(ctx, x, n)                         \
367   do {                                                          \
368     if (!((HwasanInterceptorContext *)ctx)->in_interceptor_scope) \
369       CHECK_UNPOISONED_0(x, n);                                 \
370   } while (0)
371
372 #define HWASAN_INTERCEPT_FUNC(name)                                       \
373   do {                                                                  \
374     if ((!INTERCEPT_FUNCTION(name) || !REAL(name)))                     \
375       VReport(1, "HWAddressSanitizer: failed to intercept '" #name "'\n"); \
376   } while (0)
377
378 #define HWASAN_INTERCEPT_FUNC_VER(name, ver)                                    \
379   do {                                                                        \
380     if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name)))                  \
381       VReport(                                                                \
382           1, "HWAddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \
383   } while (0)
384
385 #define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
386 #define COMMON_INTERCEPT_FUNCTION_VER(name, ver)                          \
387   HWASAN_INTERCEPT_FUNC_VER(name, ver)
388 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
389   CHECK_UNPOISONED_CTX(ctx, ptr, size)
390 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
391   CHECK_UNPOISONED_CTX(ctx, ptr, size)
392 #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
393   HWASAN_WRITE_RANGE(ctx, ptr, size)
394 #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)                  \
395   if (hwasan_init_is_running) return REAL(func)(__VA_ARGS__);       \
396   ENSURE_HWASAN_INITED();                                           \
397   HwasanInterceptorContext hwasan_ctx = {IsInInterceptorScope()};     \
398   ctx = (void *)&hwasan_ctx;                                        \
399   (void)ctx;                                                      \
400   InterceptorScope interceptor_scope;
401 #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
402   do {                                            \
403   } while (false)
404 #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
405   do {                                         \
406   } while (false)
407 #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
408   do {                                         \
409   } while (false)
410 #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
411   do {                                                      \
412   } while (false)
413 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
414   do {                                                \
415   } while (false)  // FIXME
416 #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
417   do {                                                         \
418   } while (false)  // FIXME
419 #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
420 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
421
422 #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end)                           \
423   if (HwasanThread *t = GetCurrentThread()) {                                    \
424     *begin = t->tls_begin();                                                   \
425     *end = t->tls_end();                                                       \
426   } else {                                                                     \
427     *begin = *end = 0;                                                         \
428   }
429
430 #include "sanitizer_common/sanitizer_platform_interceptors.h"
431 #include "sanitizer_common/sanitizer_common_interceptors.inc"
432 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
433
434 #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
435 #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
436   do {                                       \
437     (void)(p);                               \
438     (void)(s);                               \
439   } while (false)
440 #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
441   do {                                       \
442     (void)(p);                               \
443     (void)(s);                               \
444   } while (false)
445 #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
446   do {                                        \
447     (void)(p);                                \
448     (void)(s);                                \
449   } while (false)
450 #include "sanitizer_common/sanitizer_common_syscalls.inc"
451
452
453
454 namespace __hwasan {
455
456 void InitializeInterceptors() {
457   static int inited = 0;
458   CHECK_EQ(inited, 0);
459   InitializeCommonInterceptors();
460   InitializeSignalInterceptors();
461
462   INTERCEPT_FUNCTION(mmap);
463   HWASAN_MAYBE_INTERCEPT_MMAP64;
464   INTERCEPT_FUNCTION(posix_memalign);
465   HWASAN_MAYBE_INTERCEPT_MEMALIGN;
466   INTERCEPT_FUNCTION(__libc_memalign);
467   INTERCEPT_FUNCTION(valloc);
468   HWASAN_MAYBE_INTERCEPT_PVALLOC;
469   INTERCEPT_FUNCTION(malloc);
470   INTERCEPT_FUNCTION(calloc);
471   INTERCEPT_FUNCTION(realloc);
472   INTERCEPT_FUNCTION(free);
473   HWASAN_MAYBE_INTERCEPT_CFREE;
474   INTERCEPT_FUNCTION(malloc_usable_size);
475   HWASAN_MAYBE_INTERCEPT_MALLINFO;
476   HWASAN_MAYBE_INTERCEPT_MALLOPT;
477   HWASAN_MAYBE_INTERCEPT_MALLOC_STATS;
478   INTERCEPT_FUNCTION(pthread_create);
479   INTERCEPT_FUNCTION(fork);
480
481   inited = 1;
482 }
483 } // namespace __hwasan