xref: /openbsd-src/gnu/llvm/compiler-rt/lib/hwasan/hwasan_interceptors.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
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