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. 10 // 11 // Interceptors for standard library functions. 12 // 13 // FIXME: move as many interceptors as possible into 14 // sanitizer_common/sanitizer_common_interceptors.h 15 //===----------------------------------------------------------------------===// 16 17 #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS 18 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" 29 30 #if !SANITIZER_FUCHSIA 31 32 using namespace __hwasan; 33 34 # if !SANITIZER_APPLE 35 # define HWASAN_INTERCEPT_FUNC(name) \ 36 do { \ 37 if (!INTERCEPT_FUNCTION(name)) \ 38 VReport(1, "HWAddressSanitizer: failed to intercept '%s'\n", #name); \ 39 } while (0) 40 # define HWASAN_INTERCEPT_FUNC_VER(name, ver) \ 41 do { \ 42 if (!INTERCEPT_FUNCTION_VER(name, ver)) \ 43 VReport(1, "HWAddressSanitizer: failed to intercept '%s@@%s'\n", \ 44 #name, ver); \ 45 } while (0) 46 # define HWASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \ 47 do { \ 48 if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \ 49 VReport( \ 50 1, "HWAddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \ 51 #name, ver, #name); \ 52 } while (0) 53 54 # else 55 // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. 56 # define HWASAN_INTERCEPT_FUNC(name) 57 # endif // SANITIZER_APPLE 58 59 # if HWASAN_WITH_INTERCEPTORS 60 61 # define COMMON_SYSCALL_PRE_READ_RANGE(p, s) __hwasan_loadN((uptr)p, (uptr)s) 62 # define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ 63 __hwasan_storeN((uptr)p, (uptr)s) 64 # define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ 65 do { \ 66 (void)(p); \ 67 (void)(s); \ 68 } while (false) 69 # define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ 70 do { \ 71 (void)(p); \ 72 (void)(s); \ 73 } while (false) 74 # include "sanitizer_common/sanitizer_common_syscalls.inc" 75 # include "sanitizer_common/sanitizer_syscalls_netbsd.inc" 76 77 # define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ 78 do { \ 79 } while (false) 80 81 # define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ 82 do { \ 83 (void)(ctx); \ 84 (void)(ptr); \ 85 (void)(size); \ 86 } while (false) 87 88 # define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ 89 do { \ 90 (void)(ctx); \ 91 (void)(func); \ 92 } while (false) 93 94 # define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ 95 do { \ 96 (void)(ctx); \ 97 (void)(path); \ 98 } while (false) 99 100 # define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ 101 do { \ 102 (void)(ctx); \ 103 (void)(fd); \ 104 } while (false) 105 106 # define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ 107 do { \ 108 (void)(ctx); \ 109 (void)(fd); \ 110 } while (false) 111 112 # define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ 113 do { \ 114 (void)(ctx); \ 115 (void)(fd); \ 116 (void)(newfd); \ 117 } while (false) 118 119 # define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ 120 do { \ 121 (void)(ctx); \ 122 (void)(name); \ 123 } while (false) 124 125 # define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ 126 do { \ 127 (void)(ctx); \ 128 (void)(thread); \ 129 (void)(name); \ 130 } while (false) 131 132 # define COMMON_INTERCEPTOR_BLOCK_REAL(name) \ 133 do { \ 134 (void)(name); \ 135 } while (false) 136 137 # define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \ 138 do { \ 139 (void)(ctx); \ 140 (void)(to); \ 141 (void)(from); \ 142 (void)(size); \ 143 } while (false) 144 145 # define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \ 146 do { \ 147 (void)(ctx); \ 148 (void)(to); \ 149 (void)(from); \ 150 (void)(size); \ 151 } while (false) 152 153 # define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \ 154 do { \ 155 (void)(ctx); \ 156 (void)(block); \ 157 (void)(c); \ 158 (void)(size); \ 159 } while (false) 160 161 # define COMMON_INTERCEPTOR_STRERROR() \ 162 do { \ 163 } while (false) 164 165 # define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name) 166 167 # define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!hwasan_inited) 168 169 // The main purpose of the mmap interceptor is to prevent the user from 170 // allocating on top of shadow pages. 171 // 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)); 182 183 addr = UntagPtr(addr); 184 } 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; 197 } 198 } 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; 209 } 210 __hwasan::TagMemoryAligned(beg, rounded_length, 0); 211 } 212 213 return res; 214 } 215 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; 227 } 228 __hwasan::TagMemoryAligned(beg, rounded_length, 0); 229 } 230 return real_munmap(addr, length); 231 } 232 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) 239 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) 245 246 # include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc" 247 # include "sanitizer_common/sanitizer_common_interceptors.inc" 248 249 struct ThreadStartArg { 250 __sanitizer_sigset_t starting_sigset_; 251 }; 252 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; 263 } 264 265 extern "C" { 266 int pthread_attr_getdetachstate(void *attr, int *v); 267 } 268 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 283 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); 288 }); 289 if (result != 0) 290 InternalFree(A); 291 return result; 292 } 293 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; 299 }); 300 return result; 301 } 302 303 INTERCEPTOR(int, pthread_detach, void *thread) { 304 int result; 305 hwasanThreadArgRetval().Detach((uptr)thread, [&]() { 306 result = REAL(pthread_detach)(thread); 307 return !result; 308 }); 309 return result; 310 } 311 312 INTERCEPTOR(int, pthread_exit, void *retval) { 313 hwasanThreadArgRetval().Finish(GetThreadSelf(), retval); 314 return REAL(pthread_exit)(retval); 315 } 316 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; 323 }); 324 return result; 325 } 326 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; 333 }); 334 return result; 335 } 336 # endif 337 338 DEFINE_REAL_PTHREAD_FUNCTIONS 339 340 DEFINE_REAL(int, vfork) 341 DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) 342 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; 354 } 355 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 365 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); 371 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 465 } 466 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); 473 } 474 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); 479 } 480 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); 488 } 489 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); 496 } 497 InternalLongjmp(env[0].__jmpbuf, val); 498 } 499 # undef SIG_BLOCK 500 # undef SIG_SETMASK 501 502 # endif // HWASAN_WITH_INTERCEPTORS 503 504 namespace __hwasan { 505 506 int OnExit() { 507 if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks && 508 __lsan::HasReportedLeaks()) { 509 return common_flags()->exitcode; 510 } 511 // FIXME: ask frontend whether we need to return failure. 512 return 0; 513 } 514 515 } // namespace __hwasan 516 517 namespace __hwasan { 518 519 void InitializeInterceptors() { 520 static int inited = 0; 521 CHECK_EQ(inited, 0); 522 523 InitializeCommonInterceptors(); 524 525 (void)(read_iovec); 526 (void)(write_iovec); 527 528 # if HWASAN_WITH_INTERCEPTORS 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 544 545 inited = 1; 546 } 547 } // namespace __hwasan 548 549 #endif // #if !SANITIZER_FUCHSIA 550