xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/safestack/safestack_platform.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- safestack_platform.h ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements platform specific parts of SafeStack runtime.
10*0fca6ea1SDimitry Andric // Don't use equivalent functionality from sanitizer_common to avoid dragging
11*0fca6ea1SDimitry Andric // a large codebase into security sensitive code.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #ifndef SAFESTACK_PLATFORM_H
160b57cec5SDimitry Andric #define SAFESTACK_PLATFORM_H
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "safestack_util.h"
190b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include <dlfcn.h>
22*0fca6ea1SDimitry Andric #include <errno.h>
230b57cec5SDimitry Andric #include <stdint.h>
240b57cec5SDimitry Andric #include <stdio.h>
250b57cec5SDimitry Andric #include <stdlib.h>
260b57cec5SDimitry Andric #include <sys/mman.h>
270b57cec5SDimitry Andric #include <sys/syscall.h>
280b57cec5SDimitry Andric #include <sys/types.h>
290b57cec5SDimitry Andric #include <unistd.h>
300b57cec5SDimitry Andric 
31*0fca6ea1SDimitry Andric #if !(SANITIZER_NETBSD || SANITIZER_FREEBSD || SANITIZER_LINUX || \
32*0fca6ea1SDimitry Andric       SANITIZER_SOLARIS)
330b57cec5SDimitry Andric #  error "Support for your platform has not been implemented"
340b57cec5SDimitry Andric #endif
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #if SANITIZER_NETBSD
370b57cec5SDimitry Andric #include <lwp.h>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric extern "C" void *__mmap(void *, size_t, int, int, int, int, off_t);
400b57cec5SDimitry Andric #endif
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric #if SANITIZER_FREEBSD
430b57cec5SDimitry Andric #include <sys/thr.h>
440b57cec5SDimitry Andric #endif
450b57cec5SDimitry Andric 
46*0fca6ea1SDimitry Andric #if SANITIZER_SOLARIS
47*0fca6ea1SDimitry Andric #  include <thread.h>
48*0fca6ea1SDimitry Andric #endif
49*0fca6ea1SDimitry Andric 
50*0fca6ea1SDimitry Andric // Keep in sync with sanitizer_linux.cpp.
51*0fca6ea1SDimitry Andric //
52*0fca6ea1SDimitry Andric // Are we using 32-bit or 64-bit Linux syscalls?
53*0fca6ea1SDimitry Andric // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
54*0fca6ea1SDimitry Andric // but it still needs to use 64-bit syscalls.
55*0fca6ea1SDimitry Andric #if SANITIZER_LINUX &&                                \
56*0fca6ea1SDimitry Andric     (defined(__x86_64__) || defined(__powerpc64__) || \
57*0fca6ea1SDimitry Andric      SANITIZER_WORDSIZE == 64 || (defined(__mips__) && _MIPS_SIM == _ABIN32))
58*0fca6ea1SDimitry Andric #  define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
59*0fca6ea1SDimitry Andric #else
60*0fca6ea1SDimitry Andric #  define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
61*0fca6ea1SDimitry Andric #endif
62*0fca6ea1SDimitry Andric 
630b57cec5SDimitry Andric namespace safestack {
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric #if SANITIZER_NETBSD
660b57cec5SDimitry Andric static void *GetRealLibcAddress(const char *symbol) {
670b57cec5SDimitry Andric   void *real = dlsym(RTLD_NEXT, symbol);
680b57cec5SDimitry Andric   if (!real)
690b57cec5SDimitry Andric     real = dlsym(RTLD_DEFAULT, symbol);
700b57cec5SDimitry Andric   if (!real) {
710b57cec5SDimitry Andric     fprintf(stderr, "safestack GetRealLibcAddress failed for symbol=%s",
720b57cec5SDimitry Andric             symbol);
730b57cec5SDimitry Andric     abort();
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric   return real;
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric #define _REAL(func, ...) real##_##func(__VA_ARGS__)
790b57cec5SDimitry Andric #define DEFINE__REAL(ret_type, func, ...)                              \
800b57cec5SDimitry Andric   static ret_type (*real_##func)(__VA_ARGS__) = NULL;                  \
810b57cec5SDimitry Andric   if (!real_##func) {                                                  \
820b57cec5SDimitry Andric     real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \
830b57cec5SDimitry Andric   }                                                                    \
840b57cec5SDimitry Andric   SFS_CHECK(real_##func);
850b57cec5SDimitry Andric #endif
860b57cec5SDimitry Andric 
87*0fca6ea1SDimitry Andric #if SANITIZER_SOLARIS
88*0fca6ea1SDimitry Andric #  define _REAL(func) _##func
89*0fca6ea1SDimitry Andric #  define DEFINE__REAL(ret_type, func, ...) \
90*0fca6ea1SDimitry Andric     extern "C" ret_type _REAL(func)(__VA_ARGS__)
91*0fca6ea1SDimitry Andric 
92*0fca6ea1SDimitry Andric #  if !defined(_LP64) && _FILE_OFFSET_BITS == 64
93*0fca6ea1SDimitry Andric #    define _REAL64(func) _##func##64
94*0fca6ea1SDimitry Andric #  else
95*0fca6ea1SDimitry Andric #    define _REAL64(func) _REAL(func)
96*0fca6ea1SDimitry Andric #  endif
97*0fca6ea1SDimitry Andric #  define DEFINE__REAL64(ret_type, func, ...) \
98*0fca6ea1SDimitry Andric     extern "C" ret_type _REAL64(func)(__VA_ARGS__)
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric DEFINE__REAL64(void *, mmap, void *a, size_t b, int c, int d, int e, off_t f);
101*0fca6ea1SDimitry Andric DEFINE__REAL(int, munmap, void *a, size_t b);
102*0fca6ea1SDimitry Andric DEFINE__REAL(int, mprotect, void *a, size_t b, int c);
103*0fca6ea1SDimitry Andric #endif
104*0fca6ea1SDimitry Andric 
1050b57cec5SDimitry Andric using ThreadId = uint64_t;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric inline ThreadId GetTid() {
1080b57cec5SDimitry Andric #if SANITIZER_NETBSD
1090b57cec5SDimitry Andric   DEFINE__REAL(int, _lwp_self);
1100b57cec5SDimitry Andric   return _REAL(_lwp_self);
1110b57cec5SDimitry Andric #elif SANITIZER_FREEBSD
1120b57cec5SDimitry Andric   long Tid;
1130b57cec5SDimitry Andric   thr_self(&Tid);
1140b57cec5SDimitry Andric   return Tid;
115*0fca6ea1SDimitry Andric #elif SANITIZER_SOLARIS
116*0fca6ea1SDimitry Andric   return thr_self();
1170b57cec5SDimitry Andric #else
1180b57cec5SDimitry Andric   return syscall(SYS_gettid);
1190b57cec5SDimitry Andric #endif
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric inline int TgKill(pid_t pid, ThreadId tid, int sig) {
1230b57cec5SDimitry Andric #if SANITIZER_NETBSD
1240b57cec5SDimitry Andric   DEFINE__REAL(int, _lwp_kill, int a, int b);
1250b57cec5SDimitry Andric   (void)pid;
1260b57cec5SDimitry Andric   return _REAL(_lwp_kill, tid, sig);
127*0fca6ea1SDimitry Andric #elif SANITIZER_SOLARIS
128*0fca6ea1SDimitry Andric   (void)pid;
129*0fca6ea1SDimitry Andric   errno = thr_kill(tid, sig);
130*0fca6ea1SDimitry Andric   // TgKill is expected to return -1 on error, not an errno.
131*0fca6ea1SDimitry Andric   return errno != 0 ? -1 : 0;
1320b57cec5SDimitry Andric #elif SANITIZER_FREEBSD
1330b57cec5SDimitry Andric   return syscall(SYS_thr_kill2, pid, tid, sig);
1340b57cec5SDimitry Andric #else
135*0fca6ea1SDimitry Andric   // tid is pid_t (int), not ThreadId (uint64_t).
136*0fca6ea1SDimitry Andric   return syscall(SYS_tgkill, pid, (pid_t)tid, sig);
1370b57cec5SDimitry Andric #endif
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric inline void *Mmap(void *addr, size_t length, int prot, int flags, int fd,
1410b57cec5SDimitry Andric                   off_t offset) {
1420b57cec5SDimitry Andric #if SANITIZER_NETBSD
1430b57cec5SDimitry Andric   return __mmap(addr, length, prot, flags, fd, 0, offset);
14481ad6265SDimitry Andric #elif SANITIZER_FREEBSD && (defined(__aarch64__) || defined(__x86_64__))
1450b57cec5SDimitry Andric   return (void *)__syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
146*0fca6ea1SDimitry Andric #elif SANITIZER_FREEBSD && (defined(__i386__))
1470b57cec5SDimitry Andric   return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
148*0fca6ea1SDimitry Andric #elif SANITIZER_SOLARIS
149*0fca6ea1SDimitry Andric   return _REAL64(mmap)(addr, length, prot, flags, fd, offset);
150*0fca6ea1SDimitry Andric #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
151*0fca6ea1SDimitry Andric   return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
152*0fca6ea1SDimitry Andric #else
153*0fca6ea1SDimitry Andric   // mmap2 specifies file offset in 4096-byte units.
154*0fca6ea1SDimitry Andric   SFS_CHECK(IsAligned(offset, 4096));
155*0fca6ea1SDimitry Andric   return (void *)syscall(SYS_mmap2, addr, length, prot, flags, fd,
156*0fca6ea1SDimitry Andric                          offset / 4096);
1570b57cec5SDimitry Andric #endif
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric inline int Munmap(void *addr, size_t length) {
1610b57cec5SDimitry Andric #if SANITIZER_NETBSD
1620b57cec5SDimitry Andric   DEFINE__REAL(int, munmap, void *a, size_t b);
1630b57cec5SDimitry Andric   return _REAL(munmap, addr, length);
164*0fca6ea1SDimitry Andric #elif SANITIZER_SOLARIS
165*0fca6ea1SDimitry Andric   return _REAL(munmap)(addr, length);
1660b57cec5SDimitry Andric #else
1670b57cec5SDimitry Andric   return syscall(SYS_munmap, addr, length);
1680b57cec5SDimitry Andric #endif
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric inline int Mprotect(void *addr, size_t length, int prot) {
1720b57cec5SDimitry Andric #if SANITIZER_NETBSD
1730b57cec5SDimitry Andric   DEFINE__REAL(int, mprotect, void *a, size_t b, int c);
1740b57cec5SDimitry Andric   return _REAL(mprotect, addr, length, prot);
175*0fca6ea1SDimitry Andric #elif SANITIZER_SOLARIS
176*0fca6ea1SDimitry Andric   return _REAL(mprotect)(addr, length, prot);
1770b57cec5SDimitry Andric #else
1780b57cec5SDimitry Andric   return syscall(SYS_mprotect, addr, length, prot);
1790b57cec5SDimitry Andric #endif
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric }  // namespace safestack
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric #endif  // SAFESTACK_PLATFORM_H
185