1 //===-- safestack_platform.h ----------------------------------------------===// 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 implements platform specific parts of SafeStack runtime. 10 // Don't use equivalent functionality from sanitizer_common to avoid dragging 11 // a large codebase into security sensitive code. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef SAFESTACK_PLATFORM_H 16 #define SAFESTACK_PLATFORM_H 17 18 #include "safestack_util.h" 19 #include "sanitizer_common/sanitizer_platform.h" 20 21 #include <dlfcn.h> 22 #include <errno.h> 23 #include <stdint.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <sys/mman.h> 27 #include <sys/syscall.h> 28 #include <sys/types.h> 29 #include <unistd.h> 30 31 #if !(SANITIZER_NETBSD || SANITIZER_FREEBSD || SANITIZER_LINUX || \ 32 SANITIZER_SOLARIS) 33 # error "Support for your platform has not been implemented" 34 #endif 35 36 #if SANITIZER_NETBSD 37 #include <lwp.h> 38 39 extern "C" void *__mmap(void *, size_t, int, int, int, int, off_t); 40 #endif 41 42 #if SANITIZER_FREEBSD 43 #include <sys/thr.h> 44 #endif 45 46 #if SANITIZER_SOLARIS 47 # include <thread.h> 48 #endif 49 50 // Keep in sync with sanitizer_linux.cpp. 51 // 52 // Are we using 32-bit or 64-bit Linux syscalls? 53 // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 54 // but it still needs to use 64-bit syscalls. 55 #if SANITIZER_LINUX && \ 56 (defined(__x86_64__) || defined(__powerpc64__) || \ 57 SANITIZER_WORDSIZE == 64 || (defined(__mips__) && _MIPS_SIM == _ABIN32)) 58 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 59 #else 60 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 61 #endif 62 63 namespace safestack { 64 65 #if SANITIZER_NETBSD 66 static void *GetRealLibcAddress(const char *symbol) { 67 void *real = dlsym(RTLD_NEXT, symbol); 68 if (!real) 69 real = dlsym(RTLD_DEFAULT, symbol); 70 if (!real) { 71 fprintf(stderr, "safestack GetRealLibcAddress failed for symbol=%s", 72 symbol); 73 abort(); 74 } 75 return real; 76 } 77 78 #define _REAL(func, ...) real##_##func(__VA_ARGS__) 79 #define DEFINE__REAL(ret_type, func, ...) \ 80 static ret_type (*real_##func)(__VA_ARGS__) = NULL; \ 81 if (!real_##func) { \ 82 real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \ 83 } \ 84 SFS_CHECK(real_##func); 85 #endif 86 87 #if SANITIZER_SOLARIS 88 # define _REAL(func) _##func 89 # define DEFINE__REAL(ret_type, func, ...) \ 90 extern "C" ret_type _REAL(func)(__VA_ARGS__) 91 92 # if !defined(_LP64) && _FILE_OFFSET_BITS == 64 93 # define _REAL64(func) _##func##64 94 # else 95 # define _REAL64(func) _REAL(func) 96 # endif 97 # define DEFINE__REAL64(ret_type, func, ...) \ 98 extern "C" ret_type _REAL64(func)(__VA_ARGS__) 99 100 DEFINE__REAL64(void *, mmap, void *a, size_t b, int c, int d, int e, off_t f); 101 DEFINE__REAL(int, munmap, void *a, size_t b); 102 DEFINE__REAL(int, mprotect, void *a, size_t b, int c); 103 #endif 104 105 using ThreadId = uint64_t; 106 107 inline ThreadId GetTid() { 108 #if SANITIZER_NETBSD 109 DEFINE__REAL(int, _lwp_self); 110 return _REAL(_lwp_self); 111 #elif SANITIZER_FREEBSD 112 long Tid; 113 thr_self(&Tid); 114 return Tid; 115 #elif SANITIZER_SOLARIS 116 return thr_self(); 117 #else 118 return syscall(SYS_gettid); 119 #endif 120 } 121 122 inline int TgKill(pid_t pid, ThreadId tid, int sig) { 123 #if SANITIZER_NETBSD 124 DEFINE__REAL(int, _lwp_kill, int a, int b); 125 (void)pid; 126 return _REAL(_lwp_kill, tid, sig); 127 #elif SANITIZER_SOLARIS 128 (void)pid; 129 errno = thr_kill(tid, sig); 130 // TgKill is expected to return -1 on error, not an errno. 131 return errno != 0 ? -1 : 0; 132 #elif SANITIZER_FREEBSD 133 return syscall(SYS_thr_kill2, pid, tid, sig); 134 #else 135 // tid is pid_t (int), not ThreadId (uint64_t). 136 return syscall(SYS_tgkill, pid, (pid_t)tid, sig); 137 #endif 138 } 139 140 inline void *Mmap(void *addr, size_t length, int prot, int flags, int fd, 141 off_t offset) { 142 #if SANITIZER_NETBSD 143 return __mmap(addr, length, prot, flags, fd, 0, offset); 144 #elif SANITIZER_FREEBSD && (defined(__aarch64__) || defined(__x86_64__)) 145 return (void *)__syscall(SYS_mmap, addr, length, prot, flags, fd, offset); 146 #elif SANITIZER_FREEBSD && (defined(__i386__)) 147 return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); 148 #elif SANITIZER_SOLARIS 149 return _REAL64(mmap)(addr, length, prot, flags, fd, offset); 150 #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS 151 return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); 152 #else 153 // mmap2 specifies file offset in 4096-byte units. 154 SFS_CHECK(IsAligned(offset, 4096)); 155 return (void *)syscall(SYS_mmap2, addr, length, prot, flags, fd, 156 offset / 4096); 157 #endif 158 } 159 160 inline int Munmap(void *addr, size_t length) { 161 #if SANITIZER_NETBSD 162 DEFINE__REAL(int, munmap, void *a, size_t b); 163 return _REAL(munmap, addr, length); 164 #elif SANITIZER_SOLARIS 165 return _REAL(munmap)(addr, length); 166 #else 167 return syscall(SYS_munmap, addr, length); 168 #endif 169 } 170 171 inline int Mprotect(void *addr, size_t length, int prot) { 172 #if SANITIZER_NETBSD 173 DEFINE__REAL(int, mprotect, void *a, size_t b, int c); 174 return _REAL(mprotect, addr, length, prot); 175 #elif SANITIZER_SOLARIS 176 return _REAL(mprotect)(addr, length, prot); 177 #else 178 return syscall(SYS_mprotect, addr, length, prot); 179 #endif 180 } 181 182 } // namespace safestack 183 184 #endif // SAFESTACK_PLATFORM_H 185