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 || \ 58 (defined(__mips__) && defined(_ABIN32) && _MIPS_SIM == _ABIN32)) 59 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 60 #else 61 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 62 #endif 63 64 namespace safestack { 65 66 #if SANITIZER_NETBSD 67 static void *GetRealLibcAddress(const char *symbol) { 68 void *real = dlsym(RTLD_NEXT, symbol); 69 if (!real) 70 real = dlsym(RTLD_DEFAULT, symbol); 71 if (!real) { 72 fprintf(stderr, "safestack GetRealLibcAddress failed for symbol=%s", 73 symbol); 74 abort(); 75 } 76 return real; 77 } 78 79 #define _REAL(func, ...) real##_##func(__VA_ARGS__) 80 #define DEFINE__REAL(ret_type, func, ...) \ 81 static ret_type (*real_##func)(__VA_ARGS__) = NULL; \ 82 if (!real_##func) { \ 83 real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \ 84 } \ 85 SFS_CHECK(real_##func); 86 #endif 87 88 #if SANITIZER_SOLARIS 89 # define _REAL(func) _##func 90 # define DEFINE__REAL(ret_type, func, ...) \ 91 extern "C" ret_type _REAL(func)(__VA_ARGS__) 92 93 # if !defined(_LP64) && _FILE_OFFSET_BITS == 64 94 # define _REAL64(func) _##func##64 95 # else 96 # define _REAL64(func) _REAL(func) 97 # endif 98 # define DEFINE__REAL64(ret_type, func, ...) \ 99 extern "C" ret_type _REAL64(func)(__VA_ARGS__) 100 101 DEFINE__REAL64(void *, mmap, void *a, size_t b, int c, int d, int e, off_t f); 102 DEFINE__REAL(int, munmap, void *a, size_t b); 103 DEFINE__REAL(int, mprotect, void *a, size_t b, int c); 104 #endif 105 106 using ThreadId = uint64_t; 107 108 inline ThreadId GetTid() { 109 #if SANITIZER_NETBSD 110 DEFINE__REAL(int, _lwp_self); 111 return _REAL(_lwp_self); 112 #elif SANITIZER_FREEBSD 113 long Tid; 114 thr_self(&Tid); 115 return Tid; 116 #elif SANITIZER_SOLARIS 117 return thr_self(); 118 #else 119 return syscall(SYS_gettid); 120 #endif 121 } 122 123 inline int TgKill(pid_t pid, ThreadId tid, int sig) { 124 #if SANITIZER_NETBSD 125 DEFINE__REAL(int, _lwp_kill, int a, int b); 126 (void)pid; 127 return _REAL(_lwp_kill, tid, sig); 128 #elif SANITIZER_SOLARIS 129 (void)pid; 130 errno = thr_kill(tid, sig); 131 // TgKill is expected to return -1 on error, not an errno. 132 return errno != 0 ? -1 : 0; 133 #elif SANITIZER_FREEBSD 134 return syscall(SYS_thr_kill2, pid, tid, sig); 135 #else 136 // tid is pid_t (int), not ThreadId (uint64_t). 137 return syscall(SYS_tgkill, pid, (pid_t)tid, sig); 138 #endif 139 } 140 141 inline void *Mmap(void *addr, size_t length, int prot, int flags, int fd, 142 off_t offset) { 143 #if SANITIZER_NETBSD 144 return __mmap(addr, length, prot, flags, fd, 0, offset); 145 #elif SANITIZER_FREEBSD && (defined(__aarch64__) || defined(__x86_64__)) 146 return (void *)__syscall(SYS_mmap, addr, length, prot, flags, fd, offset); 147 #elif SANITIZER_FREEBSD && (defined(__i386__)) 148 return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); 149 #elif SANITIZER_SOLARIS 150 return _REAL64(mmap)(addr, length, prot, flags, fd, offset); 151 #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS 152 return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); 153 #else 154 // mmap2 specifies file offset in 4096-byte units. 155 SFS_CHECK(IsAligned(offset, 4096)); 156 return (void *)syscall(SYS_mmap2, addr, length, prot, flags, fd, 157 offset / 4096); 158 #endif 159 } 160 161 inline int Munmap(void *addr, size_t length) { 162 #if SANITIZER_NETBSD 163 DEFINE__REAL(int, munmap, void *a, size_t b); 164 return _REAL(munmap, addr, length); 165 #elif SANITIZER_SOLARIS 166 return _REAL(munmap)(addr, length); 167 #else 168 return syscall(SYS_munmap, addr, length); 169 #endif 170 } 171 172 inline int Mprotect(void *addr, size_t length, int prot) { 173 #if SANITIZER_NETBSD 174 DEFINE__REAL(int, mprotect, void *a, size_t b, int c); 175 return _REAL(mprotect, addr, length, prot); 176 #elif SANITIZER_SOLARIS 177 return _REAL(mprotect)(addr, length, prot); 178 #else 179 return syscall(SYS_mprotect, addr, length, prot); 180 #endif 181 } 182 183 } // namespace safestack 184 185 #endif // SAFESTACK_PLATFORM_H 186