Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / compiler-rt / lib / hwasan / hwasan_interceptors.cpp
blob0889831373a80396b2df2dfd3c6514f4f38e1e11
1 //===-- hwasan_interceptors.cpp -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of HWAddressSanitizer.
11 // Interceptors for standard library functions.
13 // FIXME: move as many interceptors as possible into
14 // sanitizer_common/sanitizer_common_interceptors.h
15 //===----------------------------------------------------------------------===//
17 #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
19 #include "hwasan.h"
20 #include "hwasan_allocator.h"
21 #include "hwasan_checks.h"
22 #include "hwasan_platform_interceptors.h"
23 #include "hwasan_thread.h"
24 #include "hwasan_thread_list.h"
25 #include "interception/interception.h"
26 #include "sanitizer_common/sanitizer_errno.h"
27 #include "sanitizer_common/sanitizer_linux.h"
28 #include "sanitizer_common/sanitizer_stackdepot.h"
30 #if !SANITIZER_FUCHSIA
32 using namespace __hwasan;
34 struct HWAsanInterceptorContext {
35 const char *interceptor_name;
38 # define ACCESS_MEMORY_RANGE(ctx, offset, size, access) \
39 do { \
40 __hwasan::CheckAddressSized<ErrorAction::Abort, access>((uptr)offset, \
41 size); \
42 } while (0)
44 # define HWASAN_READ_RANGE(ctx, offset, size) \
45 ACCESS_MEMORY_RANGE(ctx, offset, size, AccessType::Load)
46 # define HWASAN_WRITE_RANGE(ctx, offset, size) \
47 ACCESS_MEMORY_RANGE(ctx, offset, size, AccessType::Store)
49 # if !SANITIZER_APPLE
50 # define HWASAN_INTERCEPT_FUNC(name) \
51 do { \
52 if (!INTERCEPT_FUNCTION(name)) \
53 VReport(1, "HWAddressSanitizer: failed to intercept '%s'\n", #name); \
54 } while (0)
55 # define HWASAN_INTERCEPT_FUNC_VER(name, ver) \
56 do { \
57 if (!INTERCEPT_FUNCTION_VER(name, ver)) \
58 VReport(1, "HWAddressSanitizer: failed to intercept '%s@@%s'\n", \
59 #name, ver); \
60 } while (0)
61 # define HWASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \
62 do { \
63 if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \
64 VReport( \
65 1, "HWAddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \
66 #name, ver, #name); \
67 } while (0)
69 # else
70 // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
71 # define HWASAN_INTERCEPT_FUNC(name)
72 # endif // SANITIZER_APPLE
74 # if HWASAN_WITH_INTERCEPTORS
76 # define COMMON_SYSCALL_PRE_READ_RANGE(p, s) __hwasan_loadN((uptr)p, (uptr)s)
77 # define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
78 __hwasan_storeN((uptr)p, (uptr)s)
79 # define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
80 do { \
81 (void)(p); \
82 (void)(s); \
83 } while (false)
84 # define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
85 do { \
86 (void)(p); \
87 (void)(s); \
88 } while (false)
89 # include "sanitizer_common/sanitizer_common_syscalls.inc"
90 # include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
92 # define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
93 do { \
94 } while (false)
96 # define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
97 HWASAN_READ_RANGE(ctx, ptr, size)
99 # define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
100 HWAsanInterceptorContext _ctx = {#func}; \
101 ctx = (void *)&_ctx; \
102 do { \
103 (void)(ctx); \
104 (void)(func); \
105 } while (false)
107 # define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
108 do { \
109 (void)(ctx); \
110 (void)(path); \
111 } while (false)
113 # define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
114 do { \
115 (void)(ctx); \
116 (void)(fd); \
117 } while (false)
119 # define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
120 do { \
121 (void)(ctx); \
122 (void)(fd); \
123 } while (false)
125 # define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
126 do { \
127 (void)(ctx); \
128 (void)(fd); \
129 (void)(newfd); \
130 } while (false)
132 # define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
133 do { \
134 (void)(ctx); \
135 (void)(name); \
136 } while (false)
138 # define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
139 do { \
140 (void)(ctx); \
141 (void)(thread); \
142 (void)(name); \
143 } while (false)
145 # define COMMON_INTERCEPTOR_BLOCK_REAL(name) \
146 do { \
147 (void)(name); \
148 } while (false)
150 # define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \
151 do { \
152 (void)(ctx); \
153 (void)(to); \
154 (void)(from); \
155 (void)(size); \
156 } while (false)
158 # define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \
159 do { \
160 (void)(ctx); \
161 (void)(to); \
162 (void)(from); \
163 (void)(size); \
164 } while (false)
166 # define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \
167 do { \
168 (void)(ctx); \
169 (void)(block); \
170 (void)(c); \
171 (void)(size); \
172 } while (false)
174 # define COMMON_INTERCEPTOR_STRERROR() \
175 do { \
176 } while (false)
178 # define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
180 # define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!hwasan_inited)
182 // The main purpose of the mmap interceptor is to prevent the user from
183 // allocating on top of shadow pages.
185 // For compatibility, it does not tag pointers, nor does it allow
186 // MAP_FIXED in combination with a tagged pointer. (Since mmap itself
187 // will not return a tagged pointer, the tagged pointer must have come
188 // from elsewhere, such as the secondary allocator, which makes it a
189 // very odd usecase.)
190 template <class Mmap>
191 static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
192 int prot, int flags, int fd, OFF64_T offset) {
193 if (addr) {
194 if (flags & map_fixed) CHECK_EQ(addr, UntagPtr(addr));
196 addr = UntagPtr(addr);
198 SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
199 void *end_addr = (char *)addr + (rounded_length - 1);
200 if (addr && length &&
201 (!MemIsApp(reinterpret_cast<uptr>(addr)) ||
202 !MemIsApp(reinterpret_cast<uptr>(end_addr)))) {
203 // User requested an address that is incompatible with HWASan's
204 // memory layout. Use a different address if allowed, else fail.
205 if (flags & map_fixed) {
206 errno = errno_EINVAL;
207 return (void *)-1;
208 } else {
209 addr = nullptr;
212 void *res = real_mmap(addr, length, prot, flags, fd, offset);
213 if (length && res != (void *)-1) {
214 uptr beg = reinterpret_cast<uptr>(res);
215 DCHECK(IsAligned(beg, GetPageSize()));
216 if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
217 // Application has attempted to map more memory than is supported by
218 // HWASan. Act as if we ran out of memory.
219 internal_munmap(res, length);
220 errno = errno_ENOMEM;
221 return (void *)-1;
223 __hwasan::TagMemoryAligned(beg, rounded_length, 0);
226 return res;
229 template <class Munmap>
230 static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
231 // We should not tag if munmap fail, but it's to late to tag after
232 // real_munmap, as the pages could be mmaped by another thread.
233 uptr beg = reinterpret_cast<uptr>(addr);
234 if (length && IsAligned(beg, GetPageSize())) {
235 SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
236 // Protect from unmapping the shadow.
237 if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
238 errno = errno_EINVAL;
239 return -1;
241 __hwasan::TagMemoryAligned(beg, rounded_length, 0);
243 return real_munmap(addr, length);
246 # define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
247 fd, offset) \
248 do { \
249 (void)(ctx); \
250 return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \
251 } while (false)
253 # define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
254 do { \
255 (void)(ctx); \
256 return munmap_interceptor(REAL(munmap), addr, sz); \
257 } while (false)
259 # include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc"
260 # include "sanitizer_common/sanitizer_common_interceptors.inc"
262 struct ThreadStartArg {
263 __sanitizer_sigset_t starting_sigset_;
266 static void *HwasanThreadStartFunc(void *arg) {
267 __hwasan_thread_enter();
268 SetSigProcMask(&reinterpret_cast<ThreadStartArg *>(arg)->starting_sigset_,
269 nullptr);
270 InternalFree(arg);
271 auto self = GetThreadSelf();
272 auto args = hwasanThreadArgRetval().GetArgs(self);
273 void *retval = (*args.routine)(args.arg_retval);
274 hwasanThreadArgRetval().Finish(self, retval);
275 return retval;
278 extern "C" {
279 int pthread_attr_getdetachstate(void *attr, int *v);
282 INTERCEPTOR(int, pthread_create, void *thread, void *attr,
283 void *(*callback)(void *), void *param) {
284 EnsureMainThreadIDIsCorrect();
285 ScopedTaggingDisabler tagging_disabler;
286 bool detached = [attr]() {
287 int d = 0;
288 return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
289 }();
290 ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg));
291 ScopedBlockSignals block(&A->starting_sigset_);
292 // ASAN uses the same approach to disable leaks from pthread_create.
293 # if CAN_SANITIZE_LEAKS
294 __lsan::ScopedInterceptorDisabler lsan_disabler;
295 # endif
297 int result;
298 hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
299 result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A);
300 return result ? 0 : *(uptr *)(thread);
302 if (result != 0)
303 InternalFree(A);
304 return result;
307 INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
308 int result;
309 hwasanThreadArgRetval().Join((uptr)thread, [&]() {
310 result = REAL(pthread_join)(thread, retval);
311 return !result;
313 return result;
316 INTERCEPTOR(int, pthread_detach, void *thread) {
317 int result;
318 hwasanThreadArgRetval().Detach((uptr)thread, [&]() {
319 result = REAL(pthread_detach)(thread);
320 return !result;
322 return result;
325 INTERCEPTOR(int, pthread_exit, void *retval) {
326 hwasanThreadArgRetval().Finish(GetThreadSelf(), retval);
327 return REAL(pthread_exit)(retval);
330 # if SANITIZER_GLIBC
331 INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
332 int result;
333 hwasanThreadArgRetval().Join((uptr)thread, [&]() {
334 result = REAL(pthread_tryjoin_np)(thread, ret);
335 return !result;
337 return result;
340 INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
341 const struct timespec *abstime) {
342 int result;
343 hwasanThreadArgRetval().Join((uptr)thread, [&]() {
344 result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
345 return !result;
347 return result;
349 # endif
351 DEFINE_REAL_PTHREAD_FUNCTIONS
353 DEFINE_REAL(int, vfork)
354 DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
356 // Get and/or change the set of blocked signals.
357 extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
358 __hw_sigset_t *__restrict __oset);
359 # define SIG_BLOCK 0
360 # define SIG_SETMASK 2
361 extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
362 env[0].__magic = kHwJmpBufMagic;
363 env[0].__mask_was_saved =
364 (savemask &&
365 sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0);
366 return 0;
369 static void __attribute__((always_inline))
370 InternalLongjmp(__hw_register_buf env, int retval) {
371 # if defined(__aarch64__)
372 constexpr size_t kSpIndex = 13;
373 # elif defined(__x86_64__)
374 constexpr size_t kSpIndex = 6;
375 # elif SANITIZER_RISCV64
376 constexpr size_t kSpIndex = 13;
377 # endif
379 // Clear all memory tags on the stack between here and where we're going.
380 unsigned long long stack_pointer = env[kSpIndex];
381 // The stack pointer should never be tagged, so we don't need to clear the
382 // tag for this function call.
383 __hwasan_handle_longjmp((void *)stack_pointer);
385 // Run code for handling a longjmp.
386 // Need to use a register that isn't going to be loaded from the environment
387 // buffer -- hence why we need to specify the register to use.
388 // Must implement this ourselves, since we don't know the order of registers
389 // in different libc implementations and many implementations mangle the
390 // stack pointer so we can't use it without knowing the demangling scheme.
391 # if defined(__aarch64__)
392 register long int retval_tmp asm("x1") = retval;
393 register void *env_address asm("x0") = &env[0];
394 asm volatile(
395 "ldp x19, x20, [%0, #0<<3];"
396 "ldp x21, x22, [%0, #2<<3];"
397 "ldp x23, x24, [%0, #4<<3];"
398 "ldp x25, x26, [%0, #6<<3];"
399 "ldp x27, x28, [%0, #8<<3];"
400 "ldp x29, x30, [%0, #10<<3];"
401 "ldp d8, d9, [%0, #14<<3];"
402 "ldp d10, d11, [%0, #16<<3];"
403 "ldp d12, d13, [%0, #18<<3];"
404 "ldp d14, d15, [%0, #20<<3];"
405 "ldr x5, [%0, #13<<3];"
406 "mov sp, x5;"
407 // Return the value requested to return through arguments.
408 // This should be in x1 given what we requested above.
409 "cmp %1, #0;"
410 "mov x0, #1;"
411 "csel x0, %1, x0, ne;"
412 "br x30;"
413 : "+r"(env_address)
414 : "r"(retval_tmp));
415 # elif defined(__x86_64__)
416 register long int retval_tmp asm("%rsi") = retval;
417 register void *env_address asm("%rdi") = &env[0];
418 asm volatile(
419 // Restore registers.
420 "mov (0*8)(%0),%%rbx;"
421 "mov (1*8)(%0),%%rbp;"
422 "mov (2*8)(%0),%%r12;"
423 "mov (3*8)(%0),%%r13;"
424 "mov (4*8)(%0),%%r14;"
425 "mov (5*8)(%0),%%r15;"
426 "mov (6*8)(%0),%%rsp;"
427 "mov (7*8)(%0),%%rdx;"
428 // Return 1 if retval is 0.
429 "mov $1,%%rax;"
430 "test %1,%1;"
431 "cmovnz %1,%%rax;"
432 "jmp *%%rdx;" ::"r"(env_address),
433 "r"(retval_tmp));
434 # elif SANITIZER_RISCV64
435 register long int retval_tmp asm("x11") = retval;
436 register void *env_address asm("x10") = &env[0];
437 asm volatile(
438 "ld ra, 0<<3(%0);"
439 "ld s0, 1<<3(%0);"
440 "ld s1, 2<<3(%0);"
441 "ld s2, 3<<3(%0);"
442 "ld s3, 4<<3(%0);"
443 "ld s4, 5<<3(%0);"
444 "ld s5, 6<<3(%0);"
445 "ld s6, 7<<3(%0);"
446 "ld s7, 8<<3(%0);"
447 "ld s8, 9<<3(%0);"
448 "ld s9, 10<<3(%0);"
449 "ld s10, 11<<3(%0);"
450 "ld s11, 12<<3(%0);"
451 # if __riscv_float_abi_double
452 "fld fs0, 14<<3(%0);"
453 "fld fs1, 15<<3(%0);"
454 "fld fs2, 16<<3(%0);"
455 "fld fs3, 17<<3(%0);"
456 "fld fs4, 18<<3(%0);"
457 "fld fs5, 19<<3(%0);"
458 "fld fs6, 20<<3(%0);"
459 "fld fs7, 21<<3(%0);"
460 "fld fs8, 22<<3(%0);"
461 "fld fs9, 23<<3(%0);"
462 "fld fs10, 24<<3(%0);"
463 "fld fs11, 25<<3(%0);"
464 # elif __riscv_float_abi_soft
465 # else
466 # error "Unsupported case"
467 # endif
468 "ld a4, 13<<3(%0);"
469 "mv sp, a4;"
470 // Return the value requested to return through arguments.
471 // This should be in x11 given what we requested above.
472 "seqz a0, %1;"
473 "add a0, a0, %1;"
474 "ret;"
475 : "+r"(env_address)
476 : "r"(retval_tmp));
477 # endif
480 INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
481 if (env[0].__magic != kHwJmpBufMagic) {
482 Printf(
483 "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
484 "there is a bug in HWASan.\n");
485 return REAL(siglongjmp)(env, val);
488 if (env[0].__mask_was_saved)
489 // Restore the saved signal mask.
490 (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (__hw_sigset_t *)0);
491 InternalLongjmp(env[0].__jmpbuf, val);
494 // Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
495 // _setjmp on start_thread. Hence we have to intercept the longjmp on
496 // pthread_exit so the __hw_jmp_buf order matches.
497 INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
498 if (env[0].__magic != kHwJmpBufMagic)
499 return REAL(__libc_longjmp)(env, val);
500 InternalLongjmp(env[0].__jmpbuf, val);
503 INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
504 if (env[0].__magic != kHwJmpBufMagic) {
505 Printf(
506 "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
507 "there is a bug in HWASan.\n");
508 return REAL(longjmp)(env, val);
510 InternalLongjmp(env[0].__jmpbuf, val);
512 # undef SIG_BLOCK
513 # undef SIG_SETMASK
515 # endif // HWASAN_WITH_INTERCEPTORS
517 namespace __hwasan {
519 int OnExit() {
520 if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
521 __lsan::HasReportedLeaks()) {
522 return common_flags()->exitcode;
524 // FIXME: ask frontend whether we need to return failure.
525 return 0;
528 } // namespace __hwasan
530 namespace __hwasan {
532 void InitializeInterceptors() {
533 static int inited = 0;
534 CHECK_EQ(inited, 0);
536 # if HWASAN_WITH_INTERCEPTORS
537 InitializeCommonInterceptors();
539 (void)(read_iovec);
540 (void)(write_iovec);
542 # if defined(__linux__)
543 INTERCEPT_FUNCTION(__libc_longjmp);
544 INTERCEPT_FUNCTION(longjmp);
545 INTERCEPT_FUNCTION(siglongjmp);
546 INTERCEPT_FUNCTION(vfork);
547 # endif // __linux__
548 INTERCEPT_FUNCTION(pthread_create);
549 INTERCEPT_FUNCTION(pthread_join);
550 INTERCEPT_FUNCTION(pthread_detach);
551 INTERCEPT_FUNCTION(pthread_exit);
552 # if SANITIZER_GLIBC
553 INTERCEPT_FUNCTION(pthread_tryjoin_np);
554 INTERCEPT_FUNCTION(pthread_timedjoin_np);
555 # endif
556 # endif
558 inited = 1;
560 } // namespace __hwasan
562 #endif // #if !SANITIZER_FUCHSIA