libstdc++: Use variable template to fix -fconcepts-ts error [PR113366]
[official-gcc.git] / libsanitizer / hwasan / hwasan_interceptors.cpp
blobd9237cf9b8e3bf982cf213123ef22e73ec027c9e
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_mapping.h"
23 #include "hwasan_platform_interceptors.h"
24 #include "hwasan_thread.h"
25 #include "hwasan_thread_list.h"
26 #include "interception/interception.h"
27 #include "sanitizer_common/sanitizer_errno.h"
28 #include "sanitizer_common/sanitizer_linux.h"
29 #include "sanitizer_common/sanitizer_stackdepot.h"
31 #if !SANITIZER_FUCHSIA
33 using namespace __hwasan;
35 struct HWAsanInterceptorContext {
36 const char *interceptor_name;
39 # define ACCESS_MEMORY_RANGE(ctx, offset, size, access) \
40 do { \
41 __hwasan::CheckAddressSized<ErrorAction::Abort, access>((uptr)offset, \
42 size); \
43 } while (0)
45 # define HWASAN_READ_RANGE(ctx, offset, size) \
46 ACCESS_MEMORY_RANGE(ctx, offset, size, AccessType::Load)
47 # define HWASAN_WRITE_RANGE(ctx, offset, size) \
48 ACCESS_MEMORY_RANGE(ctx, offset, size, AccessType::Store)
50 # if !SANITIZER_APPLE
51 # define HWASAN_INTERCEPT_FUNC(name) \
52 do { \
53 if (!INTERCEPT_FUNCTION(name)) \
54 VReport(1, "HWAddressSanitizer: failed to intercept '%s'\n", #name); \
55 } while (0)
56 # define HWASAN_INTERCEPT_FUNC_VER(name, ver) \
57 do { \
58 if (!INTERCEPT_FUNCTION_VER(name, ver)) \
59 VReport(1, "HWAddressSanitizer: failed to intercept '%s@@%s'\n", \
60 #name, ver); \
61 } while (0)
62 # define HWASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \
63 do { \
64 if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \
65 VReport( \
66 1, "HWAddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \
67 #name, ver, #name); \
68 } while (0)
70 # else
71 // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
72 # define HWASAN_INTERCEPT_FUNC(name)
73 # endif // SANITIZER_APPLE
75 # if HWASAN_WITH_INTERCEPTORS
77 # define COMMON_SYSCALL_PRE_READ_RANGE(p, s) __hwasan_loadN((uptr)p, (uptr)s)
78 # define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
79 __hwasan_storeN((uptr)p, (uptr)s)
80 # define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
81 do { \
82 (void)(p); \
83 (void)(s); \
84 } while (false)
85 # define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
86 do { \
87 (void)(p); \
88 (void)(s); \
89 } while (false)
90 # include "sanitizer_common/sanitizer_common_syscalls.inc"
91 # include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
93 # define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
94 HWASAN_WRITE_RANGE(ctx, ptr, size)
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_MEMSET_IMPL(ctx, dst, v, size) \
152 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
153 return internal_memset(dst, v, size); \
154 COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
155 if (MemIsApp(UntagAddr(reinterpret_cast<uptr>(dst))) && \
156 common_flags()->intercept_intrin) \
157 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
158 return REAL(memset)(dst, v, size); \
161 # define COMMON_INTERCEPTOR_STRERROR() \
162 do { \
163 } while (false)
165 # define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
167 # define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!hwasan_inited)
169 // The main purpose of the mmap interceptor is to prevent the user from
170 // allocating on top of shadow pages.
172 // For compatibility, it does not tag pointers, nor does it allow
173 // MAP_FIXED in combination with a tagged pointer. (Since mmap itself
174 // will not return a tagged pointer, the tagged pointer must have come
175 // from elsewhere, such as the secondary allocator, which makes it a
176 // very odd usecase.)
177 template <class Mmap>
178 static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
179 int prot, int flags, int fd, OFF64_T offset) {
180 if (addr) {
181 if (flags & map_fixed) CHECK_EQ(addr, UntagPtr(addr));
183 addr = UntagPtr(addr);
185 SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
186 void *end_addr = (char *)addr + (rounded_length - 1);
187 if (addr && length &&
188 (!MemIsApp(reinterpret_cast<uptr>(addr)) ||
189 !MemIsApp(reinterpret_cast<uptr>(end_addr)))) {
190 // User requested an address that is incompatible with HWASan's
191 // memory layout. Use a different address if allowed, else fail.
192 if (flags & map_fixed) {
193 errno = errno_EINVAL;
194 return (void *)-1;
195 } else {
196 addr = nullptr;
199 void *res = real_mmap(addr, length, prot, flags, fd, offset);
200 if (length && res != (void *)-1) {
201 uptr beg = reinterpret_cast<uptr>(res);
202 DCHECK(IsAligned(beg, GetPageSize()));
203 if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
204 // Application has attempted to map more memory than is supported by
205 // HWASan. Act as if we ran out of memory.
206 internal_munmap(res, length);
207 errno = errno_ENOMEM;
208 return (void *)-1;
210 __hwasan::TagMemoryAligned(beg, rounded_length, 0);
213 return res;
216 template <class Munmap>
217 static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
218 // We should not tag if munmap fail, but it's to late to tag after
219 // real_munmap, as the pages could be mmaped by another thread.
220 uptr beg = reinterpret_cast<uptr>(addr);
221 if (length && IsAligned(beg, GetPageSize())) {
222 SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
223 // Protect from unmapping the shadow.
224 if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
225 errno = errno_EINVAL;
226 return -1;
228 __hwasan::TagMemoryAligned(beg, rounded_length, 0);
230 return real_munmap(addr, length);
233 # define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
234 fd, offset) \
235 do { \
236 (void)(ctx); \
237 return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \
238 } while (false)
240 # define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
241 do { \
242 (void)(ctx); \
243 return munmap_interceptor(REAL(munmap), addr, sz); \
244 } while (false)
246 # include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc"
247 # include "sanitizer_common/sanitizer_common_interceptors.inc"
249 struct ThreadStartArg {
250 __sanitizer_sigset_t starting_sigset_;
253 static void *HwasanThreadStartFunc(void *arg) {
254 __hwasan_thread_enter();
255 SetSigProcMask(&reinterpret_cast<ThreadStartArg *>(arg)->starting_sigset_,
256 nullptr);
257 InternalFree(arg);
258 auto self = GetThreadSelf();
259 auto args = hwasanThreadArgRetval().GetArgs(self);
260 void *retval = (*args.routine)(args.arg_retval);
261 hwasanThreadArgRetval().Finish(self, retval);
262 return retval;
265 extern "C" {
266 int pthread_attr_getdetachstate(void *attr, int *v);
269 INTERCEPTOR(int, pthread_create, void *thread, void *attr,
270 void *(*callback)(void *), void *param) {
271 EnsureMainThreadIDIsCorrect();
272 ScopedTaggingDisabler tagging_disabler;
273 bool detached = [attr]() {
274 int d = 0;
275 return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
276 }();
277 ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg));
278 ScopedBlockSignals block(&A->starting_sigset_);
279 // ASAN uses the same approach to disable leaks from pthread_create.
280 # if CAN_SANITIZE_LEAKS
281 __lsan::ScopedInterceptorDisabler lsan_disabler;
282 # endif
284 int result;
285 hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
286 result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A);
287 return result ? 0 : *(uptr *)(thread);
289 if (result != 0)
290 InternalFree(A);
291 return result;
294 INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
295 int result;
296 hwasanThreadArgRetval().Join((uptr)thread, [&]() {
297 result = REAL(pthread_join)(thread, retval);
298 return !result;
300 return result;
303 INTERCEPTOR(int, pthread_detach, void *thread) {
304 int result;
305 hwasanThreadArgRetval().Detach((uptr)thread, [&]() {
306 result = REAL(pthread_detach)(thread);
307 return !result;
309 return result;
312 INTERCEPTOR(void, pthread_exit, void *retval) {
313 hwasanThreadArgRetval().Finish(GetThreadSelf(), retval);
314 REAL(pthread_exit)(retval);
317 # if SANITIZER_GLIBC
318 INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
319 int result;
320 hwasanThreadArgRetval().Join((uptr)thread, [&]() {
321 result = REAL(pthread_tryjoin_np)(thread, ret);
322 return !result;
324 return result;
327 INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
328 const struct timespec *abstime) {
329 int result;
330 hwasanThreadArgRetval().Join((uptr)thread, [&]() {
331 result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
332 return !result;
334 return result;
336 # endif
338 DEFINE_REAL_PTHREAD_FUNCTIONS
340 DEFINE_REAL(int, vfork)
341 DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
343 // Get and/or change the set of blocked signals.
344 extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
345 __hw_sigset_t *__restrict __oset);
346 # define SIG_BLOCK 0
347 # define SIG_SETMASK 2
348 extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
349 env[0].__magic = kHwJmpBufMagic;
350 env[0].__mask_was_saved =
351 (savemask &&
352 sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0);
353 return 0;
356 static void __attribute__((always_inline))
357 InternalLongjmp(__hw_register_buf env, int retval) {
358 # if defined(__aarch64__)
359 constexpr size_t kSpIndex = 13;
360 # elif defined(__x86_64__)
361 constexpr size_t kSpIndex = 6;
362 # elif SANITIZER_RISCV64
363 constexpr size_t kSpIndex = 13;
364 # endif
366 // Clear all memory tags on the stack between here and where we're going.
367 unsigned long long stack_pointer = env[kSpIndex];
368 // The stack pointer should never be tagged, so we don't need to clear the
369 // tag for this function call.
370 __hwasan_handle_longjmp((void *)stack_pointer);
372 // Run code for handling a longjmp.
373 // Need to use a register that isn't going to be loaded from the environment
374 // buffer -- hence why we need to specify the register to use.
375 // Must implement this ourselves, since we don't know the order of registers
376 // in different libc implementations and many implementations mangle the
377 // stack pointer so we can't use it without knowing the demangling scheme.
378 # if defined(__aarch64__)
379 register long int retval_tmp asm("x1") = retval;
380 register void *env_address asm("x0") = &env[0];
381 asm volatile(
382 "ldp x19, x20, [%0, #0<<3];"
383 "ldp x21, x22, [%0, #2<<3];"
384 "ldp x23, x24, [%0, #4<<3];"
385 "ldp x25, x26, [%0, #6<<3];"
386 "ldp x27, x28, [%0, #8<<3];"
387 "ldp x29, x30, [%0, #10<<3];"
388 "ldp d8, d9, [%0, #14<<3];"
389 "ldp d10, d11, [%0, #16<<3];"
390 "ldp d12, d13, [%0, #18<<3];"
391 "ldp d14, d15, [%0, #20<<3];"
392 "ldr x5, [%0, #13<<3];"
393 "mov sp, x5;"
394 // Return the value requested to return through arguments.
395 // This should be in x1 given what we requested above.
396 "cmp %1, #0;"
397 "mov x0, #1;"
398 "csel x0, %1, x0, ne;"
399 "br x30;"
400 : "+r"(env_address)
401 : "r"(retval_tmp));
402 # elif defined(__x86_64__)
403 register long int retval_tmp asm("%rsi") = retval;
404 register void *env_address asm("%rdi") = &env[0];
405 asm volatile(
406 // Restore registers.
407 "mov (0*8)(%0),%%rbx;"
408 "mov (1*8)(%0),%%rbp;"
409 "mov (2*8)(%0),%%r12;"
410 "mov (3*8)(%0),%%r13;"
411 "mov (4*8)(%0),%%r14;"
412 "mov (5*8)(%0),%%r15;"
413 "mov (6*8)(%0),%%rsp;"
414 "mov (7*8)(%0),%%rdx;"
415 // Return 1 if retval is 0.
416 "mov $1,%%rax;"
417 "test %1,%1;"
418 "cmovnz %1,%%rax;"
419 "jmp *%%rdx;" ::"r"(env_address),
420 "r"(retval_tmp));
421 # elif SANITIZER_RISCV64
422 register long int retval_tmp asm("x11") = retval;
423 register void *env_address asm("x10") = &env[0];
424 asm volatile(
425 "ld ra, 0<<3(%0);"
426 "ld s0, 1<<3(%0);"
427 "ld s1, 2<<3(%0);"
428 "ld s2, 3<<3(%0);"
429 "ld s3, 4<<3(%0);"
430 "ld s4, 5<<3(%0);"
431 "ld s5, 6<<3(%0);"
432 "ld s6, 7<<3(%0);"
433 "ld s7, 8<<3(%0);"
434 "ld s8, 9<<3(%0);"
435 "ld s9, 10<<3(%0);"
436 "ld s10, 11<<3(%0);"
437 "ld s11, 12<<3(%0);"
438 # if __riscv_float_abi_double
439 "fld fs0, 14<<3(%0);"
440 "fld fs1, 15<<3(%0);"
441 "fld fs2, 16<<3(%0);"
442 "fld fs3, 17<<3(%0);"
443 "fld fs4, 18<<3(%0);"
444 "fld fs5, 19<<3(%0);"
445 "fld fs6, 20<<3(%0);"
446 "fld fs7, 21<<3(%0);"
447 "fld fs8, 22<<3(%0);"
448 "fld fs9, 23<<3(%0);"
449 "fld fs10, 24<<3(%0);"
450 "fld fs11, 25<<3(%0);"
451 # elif __riscv_float_abi_soft
452 # else
453 # error "Unsupported case"
454 # endif
455 "ld a4, 13<<3(%0);"
456 "mv sp, a4;"
457 // Return the value requested to return through arguments.
458 // This should be in x11 given what we requested above.
459 "seqz a0, %1;"
460 "add a0, a0, %1;"
461 "ret;"
462 : "+r"(env_address)
463 : "r"(retval_tmp));
464 # endif
467 INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
468 if (env[0].__magic != kHwJmpBufMagic) {
469 Printf(
470 "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
471 "there is a bug in HWASan.\n");
472 return REAL(siglongjmp)(env, val);
475 if (env[0].__mask_was_saved)
476 // Restore the saved signal mask.
477 (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (__hw_sigset_t *)0);
478 InternalLongjmp(env[0].__jmpbuf, val);
481 // Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
482 // _setjmp on start_thread. Hence we have to intercept the longjmp on
483 // pthread_exit so the __hw_jmp_buf order matches.
484 INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
485 if (env[0].__magic != kHwJmpBufMagic)
486 return REAL(__libc_longjmp)(env, val);
487 InternalLongjmp(env[0].__jmpbuf, val);
490 INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
491 if (env[0].__magic != kHwJmpBufMagic) {
492 Printf(
493 "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
494 "there is a bug in HWASan.\n");
495 return REAL(longjmp)(env, val);
497 InternalLongjmp(env[0].__jmpbuf, val);
499 # undef SIG_BLOCK
500 # undef SIG_SETMASK
502 # endif // HWASAN_WITH_INTERCEPTORS
504 namespace __hwasan {
506 int OnExit() {
507 if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
508 __lsan::HasReportedLeaks()) {
509 return common_flags()->exitcode;
511 // FIXME: ask frontend whether we need to return failure.
512 return 0;
515 } // namespace __hwasan
517 namespace __hwasan {
519 void InitializeInterceptors() {
520 static int inited = 0;
521 CHECK_EQ(inited, 0);
523 # if HWASAN_WITH_INTERCEPTORS
524 InitializeCommonInterceptors();
526 (void)(read_iovec);
527 (void)(write_iovec);
529 # if defined(__linux__)
530 INTERCEPT_FUNCTION(__libc_longjmp);
531 INTERCEPT_FUNCTION(longjmp);
532 INTERCEPT_FUNCTION(siglongjmp);
533 INTERCEPT_FUNCTION(vfork);
534 # endif // __linux__
535 INTERCEPT_FUNCTION(pthread_create);
536 INTERCEPT_FUNCTION(pthread_join);
537 INTERCEPT_FUNCTION(pthread_detach);
538 INTERCEPT_FUNCTION(pthread_exit);
539 # if SANITIZER_GLIBC
540 INTERCEPT_FUNCTION(pthread_tryjoin_np);
541 INTERCEPT_FUNCTION(pthread_timedjoin_np);
542 # endif
543 # endif
545 inited = 1;
547 } // namespace __hwasan
549 #endif // #if !SANITIZER_FUCHSIA