diff options
Diffstat (limited to 'compiler-rt')
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc | 10 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interceptors.cc | 12 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_platform.h | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc | 24 |
4 files changed, 46 insertions, 1 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 9e43e8d146f..1668bb0fa84 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -25,6 +25,7 @@ // COMMON_INTERCEPTOR_MUTEX_UNLOCK // COMMON_INTERCEPTOR_MUTEX_REPAIR // COMMON_INTERCEPTOR_SET_PTHREAD_NAME +// COMMON_INTERCEPTOR_HANDLE_RECVMSG //===----------------------------------------------------------------------===// #include "interception/interception.h" #include "sanitizer_platform_interceptors.h" @@ -55,6 +56,10 @@ #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {} #endif +#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG +#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg)) +#endif + #if SANITIZER_INTERCEPT_STRCMP static inline int CharCmpX(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; @@ -1402,7 +1407,10 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, SSIZE_T res = REAL(recvmsg)(fd, msg, flags); if (res >= 0) { if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); - if (msg) write_msghdr(ctx, msg, res); + if (msg) { + write_msghdr(ctx, msg, res); + COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg); + } } return res; } diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index 18637b591b2..f02b97d71b8 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -1834,6 +1834,14 @@ struct TsanInterceptorContext { const uptr pc; }; +static void HandleRecvmsg(ThreadState *thr, uptr pc, + __sanitizer_msghdr *msg) { + int fds[64]; + int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds)); + for (int i = 0; i < cnt; i++) + FdEventCreate(thr, pc, fds[i]); +} + #include "sanitizer_common/sanitizer_platform_interceptors.h" // Causes interceptor recursion (getpwuid_r() calls fopen()) #undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS @@ -1900,6 +1908,10 @@ struct TsanInterceptorContext { MutexRepair(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) +#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ + HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, msg) + #include "sanitizer_common/sanitizer_common_interceptors.inc" #define TSAN_SYSCALL() \ diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h index 32e22ba6043..8377767156f 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform.h +++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -162,6 +162,7 @@ void internal_start_thread(void(*func)(void*), void *arg); // Guesses with high probability, may yield both false positives and negatives. bool IsGlobalVar(uptr addr); int ExtractResolvFDs(void *state, int *fds, int nfd); +int ExtractRecvmsgFDs(void *msg, int *fds, int nfd); } // namespace __tsan diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc index 906b5dc73be..282b2982fdd 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc @@ -34,6 +34,7 @@ #include <sys/mman.h> #include <sys/prctl.h> #include <sys/syscall.h> +#include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> #include <sys/resource.h> @@ -347,6 +348,9 @@ bool IsGlobalVar(uptr addr) { } #ifndef TSAN_GO +// Extract file descriptors passed to glibc internal __res_iclose function. +// This is required to properly "close" the fds, because we do not see internal +// closes within glibc. The code is a pure hack. int ExtractResolvFDs(void *state, int *fds, int nfd) { int cnt = 0; __res_state *statp = (__res_state*)state; @@ -356,6 +360,26 @@ int ExtractResolvFDs(void *state, int *fds, int nfd) { } return cnt; } + +// Extract file descriptors passed via UNIX domain sockets. +// This is requried to properly handle "open" of these fds. +// see 'man recvmsg' and 'man 3 cmsg'. +int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) { + int res = 0; + msghdr *msg = (msghdr*)msgp; + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); + for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) + continue; + int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]); + for (int i = 0; i < n; i++) { + fds[res++] = ((int*)CMSG_DATA(cmsg))[i]; + if (res == nfd) + return res; + } + } + return res; +} #endif |

