13cab2bb3Spatrick //===-- hwasan_interceptors.cpp -------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of HWAddressSanitizer.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Interceptors for standard library functions.
123cab2bb3Spatrick //
133cab2bb3Spatrick // FIXME: move as many interceptors as possible into
143cab2bb3Spatrick // sanitizer_common/sanitizer_common_interceptors.h
153cab2bb3Spatrick //===----------------------------------------------------------------------===//
163cab2bb3Spatrick
173cab2bb3Spatrick #include "interception/interception.h"
183cab2bb3Spatrick #include "hwasan.h"
193cab2bb3Spatrick #include "hwasan_thread.h"
203cab2bb3Spatrick #include "sanitizer_common/sanitizer_stackdepot.h"
213cab2bb3Spatrick
22d89ec533Spatrick #if !SANITIZER_FUCHSIA
233cab2bb3Spatrick
243cab2bb3Spatrick using namespace __hwasan;
253cab2bb3Spatrick
263cab2bb3Spatrick #if HWASAN_WITH_INTERCEPTORS
273cab2bb3Spatrick
283cab2bb3Spatrick struct ThreadStartArg {
293cab2bb3Spatrick thread_callback_t callback;
303cab2bb3Spatrick void *param;
313cab2bb3Spatrick };
323cab2bb3Spatrick
HwasanThreadStartFunc(void * arg)333cab2bb3Spatrick static void *HwasanThreadStartFunc(void *arg) {
343cab2bb3Spatrick __hwasan_thread_enter();
353cab2bb3Spatrick ThreadStartArg A = *reinterpret_cast<ThreadStartArg*>(arg);
363cab2bb3Spatrick UnmapOrDie(arg, GetPageSizeCached());
373cab2bb3Spatrick return A.callback(A.param);
383cab2bb3Spatrick }
393cab2bb3Spatrick
INTERCEPTOR(int,pthread_create,void * th,void * attr,void * (* callback)(void *),void * param)403cab2bb3Spatrick INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
413cab2bb3Spatrick void * param) {
423cab2bb3Spatrick ScopedTaggingDisabler disabler;
433cab2bb3Spatrick ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
443cab2bb3Spatrick GetPageSizeCached(), "pthread_create"));
453cab2bb3Spatrick *A = {callback, param};
46d89ec533Spatrick int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
473cab2bb3Spatrick return res;
483cab2bb3Spatrick }
493cab2bb3Spatrick
INTERCEPTOR(int,pthread_join,void * t,void ** arg)50*810390e3Srobert INTERCEPTOR(int, pthread_join, void *t, void **arg) {
51*810390e3Srobert return REAL(pthread_join)(t, arg);
52*810390e3Srobert }
53*810390e3Srobert
54*810390e3Srobert DEFINE_REAL_PTHREAD_FUNCTIONS
55*810390e3Srobert
563cab2bb3Spatrick DEFINE_REAL(int, vfork)
573cab2bb3Spatrick DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
583cab2bb3Spatrick
593cab2bb3Spatrick // Get and/or change the set of blocked signals.
603cab2bb3Spatrick extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
613cab2bb3Spatrick __hw_sigset_t *__restrict __oset);
623cab2bb3Spatrick #define SIG_BLOCK 0
633cab2bb3Spatrick #define SIG_SETMASK 2
__sigjmp_save(__hw_sigjmp_buf env,int savemask)643cab2bb3Spatrick extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
65*810390e3Srobert env[0].__magic = kHwJmpBufMagic;
663cab2bb3Spatrick env[0].__mask_was_saved =
673cab2bb3Spatrick (savemask && sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0,
683cab2bb3Spatrick &env[0].__saved_mask) == 0);
693cab2bb3Spatrick return 0;
703cab2bb3Spatrick }
713cab2bb3Spatrick
723cab2bb3Spatrick static void __attribute__((always_inline))
InternalLongjmp(__hw_register_buf env,int retval)733cab2bb3Spatrick InternalLongjmp(__hw_register_buf env, int retval) {
74*810390e3Srobert # if defined(__aarch64__)
75*810390e3Srobert constexpr size_t kSpIndex = 13;
76*810390e3Srobert # elif defined(__x86_64__)
77*810390e3Srobert constexpr size_t kSpIndex = 6;
78*810390e3Srobert # elif SANITIZER_RISCV64
79*810390e3Srobert constexpr size_t kSpIndex = 13;
80*810390e3Srobert # endif
81*810390e3Srobert
823cab2bb3Spatrick // Clear all memory tags on the stack between here and where we're going.
83*810390e3Srobert unsigned long long stack_pointer = env[kSpIndex];
843cab2bb3Spatrick // The stack pointer should never be tagged, so we don't need to clear the
853cab2bb3Spatrick // tag for this function call.
863cab2bb3Spatrick __hwasan_handle_longjmp((void *)stack_pointer);
873cab2bb3Spatrick
883cab2bb3Spatrick // Run code for handling a longjmp.
893cab2bb3Spatrick // Need to use a register that isn't going to be loaded from the environment
903cab2bb3Spatrick // buffer -- hence why we need to specify the register to use.
913cab2bb3Spatrick // Must implement this ourselves, since we don't know the order of registers
923cab2bb3Spatrick // in different libc implementations and many implementations mangle the
933cab2bb3Spatrick // stack pointer so we can't use it without knowing the demangling scheme.
94*810390e3Srobert # if defined(__aarch64__)
953cab2bb3Spatrick register long int retval_tmp asm("x1") = retval;
963cab2bb3Spatrick register void *env_address asm("x0") = &env[0];
973cab2bb3Spatrick asm volatile("ldp x19, x20, [%0, #0<<3];"
983cab2bb3Spatrick "ldp x21, x22, [%0, #2<<3];"
993cab2bb3Spatrick "ldp x23, x24, [%0, #4<<3];"
1003cab2bb3Spatrick "ldp x25, x26, [%0, #6<<3];"
1013cab2bb3Spatrick "ldp x27, x28, [%0, #8<<3];"
1023cab2bb3Spatrick "ldp x29, x30, [%0, #10<<3];"
1033cab2bb3Spatrick "ldp d8, d9, [%0, #14<<3];"
1043cab2bb3Spatrick "ldp d10, d11, [%0, #16<<3];"
1053cab2bb3Spatrick "ldp d12, d13, [%0, #18<<3];"
1063cab2bb3Spatrick "ldp d14, d15, [%0, #20<<3];"
1073cab2bb3Spatrick "ldr x5, [%0, #13<<3];"
1083cab2bb3Spatrick "mov sp, x5;"
1093cab2bb3Spatrick // Return the value requested to return through arguments.
1103cab2bb3Spatrick // This should be in x1 given what we requested above.
1113cab2bb3Spatrick "cmp %1, #0;"
1123cab2bb3Spatrick "mov x0, #1;"
1133cab2bb3Spatrick "csel x0, %1, x0, ne;"
1143cab2bb3Spatrick "br x30;"
1153cab2bb3Spatrick : "+r"(env_address)
1163cab2bb3Spatrick : "r"(retval_tmp));
117*810390e3Srobert # elif defined(__x86_64__)
118*810390e3Srobert register long int retval_tmp asm("%rsi") = retval;
119*810390e3Srobert register void *env_address asm("%rdi") = &env[0];
120*810390e3Srobert asm volatile(
121*810390e3Srobert // Restore registers.
122*810390e3Srobert "mov (0*8)(%0),%%rbx;"
123*810390e3Srobert "mov (1*8)(%0),%%rbp;"
124*810390e3Srobert "mov (2*8)(%0),%%r12;"
125*810390e3Srobert "mov (3*8)(%0),%%r13;"
126*810390e3Srobert "mov (4*8)(%0),%%r14;"
127*810390e3Srobert "mov (5*8)(%0),%%r15;"
128*810390e3Srobert "mov (6*8)(%0),%%rsp;"
129*810390e3Srobert "mov (7*8)(%0),%%rdx;"
130*810390e3Srobert // Return 1 if retval is 0.
131*810390e3Srobert "mov $1,%%rax;"
132*810390e3Srobert "test %1,%1;"
133*810390e3Srobert "cmovnz %1,%%rax;"
134*810390e3Srobert "jmp *%%rdx;" ::"r"(env_address),
135*810390e3Srobert "r"(retval_tmp));
136*810390e3Srobert # elif SANITIZER_RISCV64
137*810390e3Srobert register long int retval_tmp asm("x11") = retval;
138*810390e3Srobert register void *env_address asm("x10") = &env[0];
139*810390e3Srobert asm volatile(
140*810390e3Srobert "ld ra, 0<<3(%0);"
141*810390e3Srobert "ld s0, 1<<3(%0);"
142*810390e3Srobert "ld s1, 2<<3(%0);"
143*810390e3Srobert "ld s2, 3<<3(%0);"
144*810390e3Srobert "ld s3, 4<<3(%0);"
145*810390e3Srobert "ld s4, 5<<3(%0);"
146*810390e3Srobert "ld s5, 6<<3(%0);"
147*810390e3Srobert "ld s6, 7<<3(%0);"
148*810390e3Srobert "ld s7, 8<<3(%0);"
149*810390e3Srobert "ld s8, 9<<3(%0);"
150*810390e3Srobert "ld s9, 10<<3(%0);"
151*810390e3Srobert "ld s10, 11<<3(%0);"
152*810390e3Srobert "ld s11, 12<<3(%0);"
153*810390e3Srobert # if __riscv_float_abi_double
154*810390e3Srobert "fld fs0, 14<<3(%0);"
155*810390e3Srobert "fld fs1, 15<<3(%0);"
156*810390e3Srobert "fld fs2, 16<<3(%0);"
157*810390e3Srobert "fld fs3, 17<<3(%0);"
158*810390e3Srobert "fld fs4, 18<<3(%0);"
159*810390e3Srobert "fld fs5, 19<<3(%0);"
160*810390e3Srobert "fld fs6, 20<<3(%0);"
161*810390e3Srobert "fld fs7, 21<<3(%0);"
162*810390e3Srobert "fld fs8, 22<<3(%0);"
163*810390e3Srobert "fld fs9, 23<<3(%0);"
164*810390e3Srobert "fld fs10, 24<<3(%0);"
165*810390e3Srobert "fld fs11, 25<<3(%0);"
166*810390e3Srobert # elif __riscv_float_abi_soft
167*810390e3Srobert # else
168*810390e3Srobert # error "Unsupported case"
169*810390e3Srobert # endif
170*810390e3Srobert "ld a4, 13<<3(%0);"
171*810390e3Srobert "mv sp, a4;"
172*810390e3Srobert // Return the value requested to return through arguments.
173*810390e3Srobert // This should be in x11 given what we requested above.
174*810390e3Srobert "seqz a0, %1;"
175*810390e3Srobert "add a0, a0, %1;"
176*810390e3Srobert "ret;"
177*810390e3Srobert : "+r"(env_address)
178*810390e3Srobert : "r"(retval_tmp));
179*810390e3Srobert # endif
1803cab2bb3Spatrick }
1813cab2bb3Spatrick
INTERCEPTOR(void,siglongjmp,__hw_sigjmp_buf env,int val)1823cab2bb3Spatrick INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
183*810390e3Srobert if (env[0].__magic != kHwJmpBufMagic) {
184*810390e3Srobert Printf(
185*810390e3Srobert "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
186*810390e3Srobert "there is a bug in HWASan.\n");
187*810390e3Srobert return REAL(siglongjmp)(env, val);
188*810390e3Srobert }
189*810390e3Srobert
1903cab2bb3Spatrick if (env[0].__mask_was_saved)
1913cab2bb3Spatrick // Restore the saved signal mask.
1923cab2bb3Spatrick (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask,
1933cab2bb3Spatrick (__hw_sigset_t *)0);
1943cab2bb3Spatrick InternalLongjmp(env[0].__jmpbuf, val);
1953cab2bb3Spatrick }
1963cab2bb3Spatrick
1973cab2bb3Spatrick // Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
1983cab2bb3Spatrick // _setjmp on start_thread. Hence we have to intercept the longjmp on
1993cab2bb3Spatrick // pthread_exit so the __hw_jmp_buf order matches.
INTERCEPTOR(void,__libc_longjmp,__hw_jmp_buf env,int val)2003cab2bb3Spatrick INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
201*810390e3Srobert if (env[0].__magic != kHwJmpBufMagic)
202*810390e3Srobert return REAL(__libc_longjmp)(env, val);
2033cab2bb3Spatrick InternalLongjmp(env[0].__jmpbuf, val);
2043cab2bb3Spatrick }
2053cab2bb3Spatrick
INTERCEPTOR(void,longjmp,__hw_jmp_buf env,int val)2063cab2bb3Spatrick INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
207*810390e3Srobert if (env[0].__magic != kHwJmpBufMagic) {
208*810390e3Srobert Printf(
209*810390e3Srobert "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
210*810390e3Srobert "there is a bug in HWASan.\n");
211*810390e3Srobert return REAL(longjmp)(env, val);
212*810390e3Srobert }
2133cab2bb3Spatrick InternalLongjmp(env[0].__jmpbuf, val);
2143cab2bb3Spatrick }
2153cab2bb3Spatrick #undef SIG_BLOCK
2163cab2bb3Spatrick #undef SIG_SETMASK
2173cab2bb3Spatrick
218*810390e3Srobert # endif // HWASAN_WITH_INTERCEPTORS
2193cab2bb3Spatrick
2203cab2bb3Spatrick namespace __hwasan {
2213cab2bb3Spatrick
OnExit()2223cab2bb3Spatrick int OnExit() {
223*810390e3Srobert if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
224*810390e3Srobert __lsan::HasReportedLeaks()) {
225*810390e3Srobert return common_flags()->exitcode;
226*810390e3Srobert }
2273cab2bb3Spatrick // FIXME: ask frontend whether we need to return failure.
2283cab2bb3Spatrick return 0;
2293cab2bb3Spatrick }
2303cab2bb3Spatrick
2313cab2bb3Spatrick } // namespace __hwasan
2323cab2bb3Spatrick
2333cab2bb3Spatrick namespace __hwasan {
2343cab2bb3Spatrick
InitializeInterceptors()2353cab2bb3Spatrick void InitializeInterceptors() {
2363cab2bb3Spatrick static int inited = 0;
2373cab2bb3Spatrick CHECK_EQ(inited, 0);
2383cab2bb3Spatrick
2393cab2bb3Spatrick #if HWASAN_WITH_INTERCEPTORS
2403cab2bb3Spatrick #if defined(__linux__)
241*810390e3Srobert INTERCEPT_FUNCTION(__libc_longjmp);
242*810390e3Srobert INTERCEPT_FUNCTION(longjmp);
243*810390e3Srobert INTERCEPT_FUNCTION(siglongjmp);
2443cab2bb3Spatrick INTERCEPT_FUNCTION(vfork);
2453cab2bb3Spatrick #endif // __linux__
2463cab2bb3Spatrick INTERCEPT_FUNCTION(pthread_create);
247*810390e3Srobert INTERCEPT_FUNCTION(pthread_join);
2483cab2bb3Spatrick # endif
2493cab2bb3Spatrick
2503cab2bb3Spatrick inited = 1;
2513cab2bb3Spatrick }
2523cab2bb3Spatrick } // namespace __hwasan
253d89ec533Spatrick
254d89ec533Spatrick #endif // #if !SANITIZER_FUCHSIA
255