xref: /freebsd/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.cpp (revision 56b17de1e8360fe131d425de20b5e75ff3ea897c)
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("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("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("creat");
102   const int result = REAL(creat)(path, mode);
103   return result;
104 }
105 
106 INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) {
107   ExpectNotRealtime("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("close");
129   return REAL(close)(filedes);
130 }
131 
132 INTERCEPTOR(FILE *, fopen, const char *path, const char *mode) {
133   ExpectNotRealtime("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("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("fwrite");
146   return REAL(fwrite)(ptr, size, nitems, stream);
147 }
148 
149 INTERCEPTOR(int, fclose, FILE *stream) {
150   ExpectNotRealtime("fclose");
151   return REAL(fclose)(stream);
152 }
153 
154 INTERCEPTOR(int, fputs, const char *s, FILE *stream) {
155   ExpectNotRealtime("fputs");
156   return REAL(fputs)(s, stream);
157 }
158 
159 // Streams
160 INTERCEPTOR(int, puts, const char *s) {
161   ExpectNotRealtime("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("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("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("pthread_mutex_lock");
195   return REAL(pthread_mutex_lock)(mutex);
196 }
197 
198 INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *mutex) {
199   ExpectNotRealtime("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("pthread_join");
205   return REAL(pthread_join)(thread, value_ptr);
206 }
207 
208 INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *cond) {
209   ExpectNotRealtime("pthread_cond_signal");
210   return REAL(pthread_cond_signal)(cond);
211 }
212 
213 INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *cond) {
214   ExpectNotRealtime("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("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("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("pthread_rwlock_rdlock");
232   return REAL(pthread_rwlock_rdlock)(lock);
233 }
234 
235 INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *lock) {
236   ExpectNotRealtime("pthread_rwlock_unlock");
237   return REAL(pthread_rwlock_unlock)(lock);
238 }
239 
240 INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *lock) {
241   ExpectNotRealtime("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("sleep");
249   return REAL(sleep)(s);
250 }
251 
252 INTERCEPTOR(int, usleep, useconds_t u) {
253   ExpectNotRealtime("usleep");
254   return REAL(usleep)(u);
255 }
256 
257 INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
258             struct timespec *rmtp) {
259   ExpectNotRealtime("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(num, size);
268 
269   ExpectNotRealtime("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("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);
286 
287   ExpectNotRealtime("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, size);
294 
295   ExpectNotRealtime("realloc");
296   return REAL(realloc)(ptr, size);
297 }
298 
299 INTERCEPTOR(void *, reallocf, void *ptr, SIZE_T size) {
300   ExpectNotRealtime("reallocf");
301   return REAL(reallocf)(ptr, size);
302 }
303 
304 INTERCEPTOR(void *, valloc, SIZE_T size) {
305   ExpectNotRealtime("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("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("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("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("pvalloc");
334   return REAL(pvalloc)(size);
335 }
336 #endif
337 
338 // Sockets
339 INTERCEPTOR(int, socket, int domain, int type, int protocol) {
340   ExpectNotRealtime("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("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("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("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("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("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("recvmsg");
374   return REAL(recvmsg)(socket, message, flags);
375 }
376 
377 INTERCEPTOR(int, shutdown, int socket, int how) {
378   ExpectNotRealtime("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