1 | //===--- rtsan_interceptors.cpp - Realtime Sanitizer ------------*- C++ -*-===// |
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 | //===----------------------------------------------------------------------===// |
10 | |
11 | #include "rtsan/rtsan_interceptors.h" |
12 | |
13 | #include "interception/interception.h" |
14 | #include "sanitizer_common/sanitizer_allocator_dlsym.h" |
15 | #include "sanitizer_common/sanitizer_allocator_internal.h" |
16 | #include "sanitizer_common/sanitizer_platform.h" |
17 | #include "sanitizer_common/sanitizer_platform_interceptors.h" |
18 | |
19 | #include "interception/interception.h" |
20 | #include "rtsan/rtsan.h" |
21 | #include "rtsan/rtsan_context.h" |
22 | |
23 | #if SANITIZER_APPLE |
24 | |
25 | #if TARGET_OS_MAC |
26 | // On MacOS OSSpinLockLock is deprecated and no longer present in the headers, |
27 | // but the symbol still exists on the system. Forward declare here so we |
28 | // don't get compilation errors. |
29 | #include <stdint.h> |
30 | extern "C" { |
31 | typedef int32_t OSSpinLock; |
32 | void OSSpinLockLock(volatile OSSpinLock *__lock); |
33 | } |
34 | #endif |
35 | |
36 | #include <libkern/OSAtomic.h> |
37 | #include <os/lock.h> |
38 | #endif |
39 | |
40 | #if SANITIZER_INTERCEPT_MEMALIGN || SANITIZER_INTERCEPT_PVALLOC |
41 | #include <malloc.h> |
42 | #endif |
43 | |
44 | #include <fcntl.h> |
45 | #include <pthread.h> |
46 | #include <stdarg.h> |
47 | #include <stdio.h> |
48 | #include <sys/socket.h> |
49 | #include <time.h> |
50 | #include <unistd.h> |
51 | |
52 | using namespace __sanitizer; |
53 | |
54 | using __rtsan::rtsan_init_is_running; |
55 | using __rtsan::rtsan_initialized; |
56 | |
57 | namespace { |
58 | struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { |
59 | static bool UseImpl() { return !rtsan_initialized; } |
60 | }; |
61 | } // namespace |
62 | |
63 | void ExpectNotRealtime(const char *intercepted_function_name) { |
64 | __rtsan::GetContextForThisThread().ExpectNotRealtime( |
65 | intercepted_function_name); |
66 | } |
67 | |
68 | // Filesystem |
69 | |
70 | INTERCEPTOR(int, open, const char *path, int oflag, ...) { |
71 | // TODO Establish whether we should intercept here if the flag contains |
72 | // O_NONBLOCK |
73 | ExpectNotRealtime(intercepted_function_name: "open" ); |
74 | |
75 | va_list args; |
76 | va_start(args, oflag); |
77 | const mode_t mode = va_arg(args, int); |
78 | va_end(args); |
79 | |
80 | const int result = REAL(open)(path, oflag, mode); |
81 | return result; |
82 | } |
83 | |
84 | INTERCEPTOR(int, openat, int fd, const char *path, int oflag, ...) { |
85 | // TODO Establish whether we should intercept here if the flag contains |
86 | // O_NONBLOCK |
87 | ExpectNotRealtime(intercepted_function_name: "openat" ); |
88 | |
89 | va_list args; |
90 | va_start(args, oflag); |
91 | mode_t mode = va_arg(args, int); |
92 | va_end(args); |
93 | |
94 | const int result = REAL(openat)(fd, path, oflag, mode); |
95 | return result; |
96 | } |
97 | |
98 | INTERCEPTOR(int, creat, const char *path, mode_t mode) { |
99 | // TODO Establish whether we should intercept here if the flag contains |
100 | // O_NONBLOCK |
101 | ExpectNotRealtime(intercepted_function_name: "creat" ); |
102 | const int result = REAL(creat)(path, mode); |
103 | return result; |
104 | } |
105 | |
106 | INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) { |
107 | ExpectNotRealtime(intercepted_function_name: "fcntl" ); |
108 | |
109 | va_list args; |
110 | va_start(args, cmd); |
111 | |
112 | // Following precedent here. The linux source (fcntl.c, do_fcntl) accepts the |
113 | // final argument in a variable that will hold the largest of the possible |
114 | // argument types (pointers and ints are typical in fcntl) It is then assumed |
115 | // that the implementation of fcntl will cast it properly depending on cmd. |
116 | // |
117 | // This is also similar to what is done in |
118 | // sanitizer_common/sanitizer_common_syscalls.inc |
119 | const unsigned long arg = va_arg(args, unsigned long); |
120 | int result = REAL(fcntl)(filedes, cmd, arg); |
121 | |
122 | va_end(args); |
123 | |
124 | return result; |
125 | } |
126 | |
127 | INTERCEPTOR(int, close, int filedes) { |
128 | ExpectNotRealtime(intercepted_function_name: "close" ); |
129 | return REAL(close)(filedes); |
130 | } |
131 | |
132 | INTERCEPTOR(FILE *, fopen, const char *path, const char *mode) { |
133 | ExpectNotRealtime(intercepted_function_name: "fopen" ); |
134 | return REAL(fopen)(path, mode); |
135 | } |
136 | |
137 | INTERCEPTOR(size_t, fread, void *ptr, size_t size, size_t nitems, |
138 | FILE *stream) { |
139 | ExpectNotRealtime(intercepted_function_name: "fread" ); |
140 | return REAL(fread)(ptr, size, nitems, stream); |
141 | } |
142 | |
143 | INTERCEPTOR(size_t, fwrite, const void *ptr, size_t size, size_t nitems, |
144 | FILE *stream) { |
145 | ExpectNotRealtime(intercepted_function_name: "fwrite" ); |
146 | return REAL(fwrite)(ptr, size, nitems, stream); |
147 | } |
148 | |
149 | INTERCEPTOR(int, fclose, FILE *stream) { |
150 | ExpectNotRealtime(intercepted_function_name: "fclose" ); |
151 | return REAL(fclose)(stream); |
152 | } |
153 | |
154 | INTERCEPTOR(int, fputs, const char *s, FILE *stream) { |
155 | ExpectNotRealtime(intercepted_function_name: "fputs" ); |
156 | return REAL(fputs)(s, stream); |
157 | } |
158 | |
159 | // Streams |
160 | INTERCEPTOR(int, puts, const char *s) { |
161 | ExpectNotRealtime(intercepted_function_name: "puts" ); |
162 | return REAL(puts)(s); |
163 | } |
164 | |
165 | // Concurrency |
166 | #if SANITIZER_APPLE |
167 | #pragma clang diagnostic push |
168 | // OSSpinLockLock is deprecated, but still in use in libc++ |
169 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
170 | INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) { |
171 | ExpectNotRealtime("OSSpinLockLock" ); |
172 | return REAL(OSSpinLockLock)(lock); |
173 | } |
174 | #pragma clang diagnostic pop |
175 | |
176 | INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) { |
177 | ExpectNotRealtime("os_unfair_lock_lock" ); |
178 | return REAL(os_unfair_lock_lock)(lock); |
179 | } |
180 | #elif SANITIZER_LINUX |
181 | INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *spinlock) { |
182 | ExpectNotRealtime(intercepted_function_name: "pthread_spin_lock" ); |
183 | return REAL(pthread_spin_lock)(spinlock); |
184 | } |
185 | #endif |
186 | |
187 | INTERCEPTOR(int, pthread_create, pthread_t *thread, const pthread_attr_t *attr, |
188 | void *(*start_routine)(void *), void *arg) { |
189 | ExpectNotRealtime(intercepted_function_name: "pthread_create" ); |
190 | return REAL(pthread_create)(thread, attr, start_routine, arg); |
191 | } |
192 | |
193 | INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *mutex) { |
194 | ExpectNotRealtime(intercepted_function_name: "pthread_mutex_lock" ); |
195 | return REAL(pthread_mutex_lock)(mutex); |
196 | } |
197 | |
198 | INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *mutex) { |
199 | ExpectNotRealtime(intercepted_function_name: "pthread_mutex_unlock" ); |
200 | return REAL(pthread_mutex_unlock)(mutex); |
201 | } |
202 | |
203 | INTERCEPTOR(int, pthread_join, pthread_t thread, void **value_ptr) { |
204 | ExpectNotRealtime(intercepted_function_name: "pthread_join" ); |
205 | return REAL(pthread_join)(thread, value_ptr); |
206 | } |
207 | |
208 | INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *cond) { |
209 | ExpectNotRealtime(intercepted_function_name: "pthread_cond_signal" ); |
210 | return REAL(pthread_cond_signal)(cond); |
211 | } |
212 | |
213 | INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *cond) { |
214 | ExpectNotRealtime(intercepted_function_name: "pthread_cond_broadcast" ); |
215 | return REAL(pthread_cond_broadcast)(cond); |
216 | } |
217 | |
218 | INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *cond, |
219 | pthread_mutex_t *mutex) { |
220 | ExpectNotRealtime(intercepted_function_name: "pthread_cond_wait" ); |
221 | return REAL(pthread_cond_wait)(cond, mutex); |
222 | } |
223 | |
224 | INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *cond, |
225 | pthread_mutex_t *mutex, const timespec *ts) { |
226 | ExpectNotRealtime(intercepted_function_name: "pthread_cond_timedwait" ); |
227 | return REAL(pthread_cond_timedwait)(cond, mutex, ts); |
228 | } |
229 | |
230 | INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *lock) { |
231 | ExpectNotRealtime(intercepted_function_name: "pthread_rwlock_rdlock" ); |
232 | return REAL(pthread_rwlock_rdlock)(lock); |
233 | } |
234 | |
235 | INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *lock) { |
236 | ExpectNotRealtime(intercepted_function_name: "pthread_rwlock_unlock" ); |
237 | return REAL(pthread_rwlock_unlock)(lock); |
238 | } |
239 | |
240 | INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *lock) { |
241 | ExpectNotRealtime(intercepted_function_name: "pthread_rwlock_wrlock" ); |
242 | return REAL(pthread_rwlock_wrlock)(lock); |
243 | } |
244 | |
245 | // Sleeping |
246 | |
247 | INTERCEPTOR(unsigned int, sleep, unsigned int s) { |
248 | ExpectNotRealtime(intercepted_function_name: "sleep" ); |
249 | return REAL(sleep)(s); |
250 | } |
251 | |
252 | INTERCEPTOR(int, usleep, useconds_t u) { |
253 | ExpectNotRealtime(intercepted_function_name: "usleep" ); |
254 | return REAL(usleep)(u); |
255 | } |
256 | |
257 | INTERCEPTOR(int, nanosleep, const struct timespec *rqtp, |
258 | struct timespec *rmtp) { |
259 | ExpectNotRealtime(intercepted_function_name: "nanosleep" ); |
260 | return REAL(nanosleep)(rqtp, rmtp); |
261 | } |
262 | |
263 | // Memory |
264 | |
265 | INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) { |
266 | if (DlsymAlloc::Use()) |
267 | return DlsymAlloc::Callocate(nmemb: num, size); |
268 | |
269 | ExpectNotRealtime(intercepted_function_name: "calloc" ); |
270 | return REAL(calloc)(num, size); |
271 | } |
272 | |
273 | INTERCEPTOR(void, free, void *ptr) { |
274 | if (DlsymAlloc::PointerIsMine(ptr)) |
275 | return DlsymAlloc::Free(ptr); |
276 | |
277 | if (ptr != NULL) { |
278 | ExpectNotRealtime(intercepted_function_name: "free" ); |
279 | } |
280 | return REAL(free)(ptr); |
281 | } |
282 | |
283 | INTERCEPTOR(void *, malloc, SIZE_T size) { |
284 | if (DlsymAlloc::Use()) |
285 | return DlsymAlloc::Allocate(size_in_bytes: size); |
286 | |
287 | ExpectNotRealtime(intercepted_function_name: "malloc" ); |
288 | return REAL(malloc)(size); |
289 | } |
290 | |
291 | INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { |
292 | if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) |
293 | return DlsymAlloc::Realloc(ptr, new_size: size); |
294 | |
295 | ExpectNotRealtime(intercepted_function_name: "realloc" ); |
296 | return REAL(realloc)(ptr, size); |
297 | } |
298 | |
299 | INTERCEPTOR(void *, reallocf, void *ptr, SIZE_T size) { |
300 | ExpectNotRealtime(intercepted_function_name: "reallocf" ); |
301 | return REAL(reallocf)(ptr, size); |
302 | } |
303 | |
304 | INTERCEPTOR(void *, valloc, SIZE_T size) { |
305 | ExpectNotRealtime(intercepted_function_name: "valloc" ); |
306 | return REAL(valloc)(size); |
307 | } |
308 | |
309 | #if SANITIZER_INTERCEPT_ALIGNED_ALLOC |
310 | INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { |
311 | ExpectNotRealtime(intercepted_function_name: "aligned_alloc" ); |
312 | return REAL(aligned_alloc)(alignment, size); |
313 | } |
314 | #define RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) |
315 | #else |
316 | #define RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC |
317 | #endif |
318 | |
319 | INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) { |
320 | ExpectNotRealtime(intercepted_function_name: "posix_memalign" ); |
321 | return REAL(posix_memalign)(memptr, alignment, size); |
322 | } |
323 | |
324 | #if SANITIZER_INTERCEPT_MEMALIGN |
325 | INTERCEPTOR(void *, memalign, size_t alignment, size_t size) { |
326 | ExpectNotRealtime(intercepted_function_name: "memalign" ); |
327 | return REAL(memalign)(alignment, size); |
328 | } |
329 | #endif |
330 | |
331 | #if SANITIZER_INTERCEPT_PVALLOC |
332 | INTERCEPTOR(void *, pvalloc, size_t size) { |
333 | ExpectNotRealtime(intercepted_function_name: "pvalloc" ); |
334 | return REAL(pvalloc)(size); |
335 | } |
336 | #endif |
337 | |
338 | // Sockets |
339 | INTERCEPTOR(int, socket, int domain, int type, int protocol) { |
340 | ExpectNotRealtime(intercepted_function_name: "socket" ); |
341 | return REAL(socket)(domain, type, protocol); |
342 | } |
343 | |
344 | INTERCEPTOR(ssize_t, send, int sockfd, const void *buf, size_t len, int flags) { |
345 | ExpectNotRealtime(intercepted_function_name: "send" ); |
346 | return REAL(send)(sockfd, buf, len, flags); |
347 | } |
348 | |
349 | INTERCEPTOR(ssize_t, sendmsg, int socket, const struct msghdr *message, |
350 | int flags) { |
351 | ExpectNotRealtime(intercepted_function_name: "sendmsg" ); |
352 | return REAL(sendmsg)(socket, message, flags); |
353 | } |
354 | |
355 | INTERCEPTOR(ssize_t, sendto, int socket, const void *buffer, size_t length, |
356 | int flags, const struct sockaddr *dest_addr, socklen_t dest_len) { |
357 | ExpectNotRealtime(intercepted_function_name: "sendto" ); |
358 | return REAL(sendto)(socket, buffer, length, flags, dest_addr, dest_len); |
359 | } |
360 | |
361 | INTERCEPTOR(ssize_t, recv, int socket, void *buffer, size_t length, int flags) { |
362 | ExpectNotRealtime(intercepted_function_name: "recv" ); |
363 | return REAL(recv)(socket, buffer, length, flags); |
364 | } |
365 | |
366 | INTERCEPTOR(ssize_t, recvfrom, int socket, void *buffer, size_t length, |
367 | int flags, struct sockaddr *address, socklen_t *address_len) { |
368 | ExpectNotRealtime(intercepted_function_name: "recvfrom" ); |
369 | return REAL(recvfrom)(socket, buffer, length, flags, address, address_len); |
370 | } |
371 | |
372 | INTERCEPTOR(ssize_t, recvmsg, int socket, struct msghdr *message, int flags) { |
373 | ExpectNotRealtime(intercepted_function_name: "recvmsg" ); |
374 | return REAL(recvmsg)(socket, message, flags); |
375 | } |
376 | |
377 | INTERCEPTOR(int, shutdown, int socket, int how) { |
378 | ExpectNotRealtime(intercepted_function_name: "shutdown" ); |
379 | return REAL(shutdown)(socket, how); |
380 | } |
381 | |
382 | // Preinit |
383 | void __rtsan::InitializeInterceptors() { |
384 | INTERCEPT_FUNCTION(calloc); |
385 | INTERCEPT_FUNCTION(free); |
386 | INTERCEPT_FUNCTION(malloc); |
387 | INTERCEPT_FUNCTION(realloc); |
388 | INTERCEPT_FUNCTION(reallocf); |
389 | INTERCEPT_FUNCTION(valloc); |
390 | RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC; |
391 | INTERCEPT_FUNCTION(posix_memalign); |
392 | #if SANITIZER_INTERCEPT_MEMALIGN |
393 | INTERCEPT_FUNCTION(memalign); |
394 | #endif |
395 | #if SANITIZER_INTERCEPT_PVALLOC |
396 | INTERCEPT_FUNCTION(pvalloc); |
397 | #endif |
398 | |
399 | INTERCEPT_FUNCTION(open); |
400 | INTERCEPT_FUNCTION(openat); |
401 | INTERCEPT_FUNCTION(close); |
402 | INTERCEPT_FUNCTION(fopen); |
403 | INTERCEPT_FUNCTION(fread); |
404 | INTERCEPT_FUNCTION(fwrite); |
405 | INTERCEPT_FUNCTION(fclose); |
406 | INTERCEPT_FUNCTION(fcntl); |
407 | INTERCEPT_FUNCTION(creat); |
408 | INTERCEPT_FUNCTION(puts); |
409 | INTERCEPT_FUNCTION(fputs); |
410 | |
411 | #if SANITIZER_APPLE |
412 | INTERCEPT_FUNCTION(OSSpinLockLock); |
413 | INTERCEPT_FUNCTION(os_unfair_lock_lock); |
414 | #elif SANITIZER_LINUX |
415 | INTERCEPT_FUNCTION(pthread_spin_lock); |
416 | #endif |
417 | |
418 | INTERCEPT_FUNCTION(pthread_create); |
419 | INTERCEPT_FUNCTION(pthread_mutex_lock); |
420 | INTERCEPT_FUNCTION(pthread_mutex_unlock); |
421 | INTERCEPT_FUNCTION(pthread_join); |
422 | INTERCEPT_FUNCTION(pthread_cond_signal); |
423 | INTERCEPT_FUNCTION(pthread_cond_broadcast); |
424 | INTERCEPT_FUNCTION(pthread_cond_wait); |
425 | INTERCEPT_FUNCTION(pthread_cond_timedwait); |
426 | INTERCEPT_FUNCTION(pthread_rwlock_rdlock); |
427 | INTERCEPT_FUNCTION(pthread_rwlock_unlock); |
428 | INTERCEPT_FUNCTION(pthread_rwlock_wrlock); |
429 | |
430 | INTERCEPT_FUNCTION(sleep); |
431 | INTERCEPT_FUNCTION(usleep); |
432 | INTERCEPT_FUNCTION(nanosleep); |
433 | |
434 | INTERCEPT_FUNCTION(socket); |
435 | INTERCEPT_FUNCTION(send); |
436 | INTERCEPT_FUNCTION(sendmsg); |
437 | INTERCEPT_FUNCTION(sendto); |
438 | INTERCEPT_FUNCTION(recv); |
439 | INTERCEPT_FUNCTION(recvmsg); |
440 | INTERCEPT_FUNCTION(recvfrom); |
441 | INTERCEPT_FUNCTION(shutdown); |
442 | } |
443 | |