xref: /freebsd/contrib/llvm-project/compiler-rt/lib/safestack/safestack_platform.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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