aboutsummaryrefslogtreecommitdiff
path: root/lib/msan/msan_interceptors.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/msan/msan_interceptors.cc')
-rw-r--r--lib/msan/msan_interceptors.cc707
1 files changed, 523 insertions, 184 deletions
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 1bcf93db9440..15a8bec12f31 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -19,6 +19,8 @@
#include "msan.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_libc.h"
@@ -28,10 +30,15 @@
// ACHTUNG! No other system header includes in this file.
// Ideally, we should get rid of stdarg.h as well.
-extern "C" const int __msan_keep_going;
-
using namespace __msan;
+using __sanitizer::memory_order;
+using __sanitizer::atomic_load;
+using __sanitizer::atomic_store;
+using __sanitizer::atomic_uintptr_t;
+
+static unsigned g_thread_finalize_key;
+
// True if this is a nested interceptor.
static THREADLOCAL int in_interceptor_scope;
@@ -52,28 +59,30 @@ bool IsInInterceptorScope() {
} while (0)
// Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n) \
- do { \
- sptr offset = __msan_test_shadow(x, n); \
- if (__msan::IsInSymbolizer()) break; \
- if (offset >= 0 && __msan::flags()->report_umrs) { \
- GET_CALLER_PC_BP_SP; \
- (void) sp; \
- Printf("UMR in %s at offset %d inside [%p, +%d) \n", __FUNCTION__, \
- offset, x, n); \
- __msan::PrintWarningWithOrigin(pc, bp, \
- __msan_get_origin((char *) x + offset)); \
- if (!__msan_keep_going) { \
- Printf("Exiting\n"); \
- Die(); \
- } \
- } \
+#define CHECK_UNPOISONED_0(x, n) \
+ do { \
+ sptr offset = __msan_test_shadow(x, n); \
+ if (__msan::IsInSymbolizer()) break; \
+ if (offset >= 0 && __msan::flags()->report_umrs) { \
+ GET_CALLER_PC_BP_SP; \
+ (void) sp; \
+ Printf("UMR in %s at offset %d inside [%p, +%d) \n", __FUNCTION__, \
+ offset, x, n); \
+ __msan::PrintWarningWithOrigin(pc, bp, \
+ __msan_get_origin((char *)x + offset)); \
+ if (__msan::flags()->halt_on_error) { \
+ Printf("Exiting\n"); \
+ Die(); \
+ } \
+ } \
} while (0)
// Check that [x, x+n) range is unpoisoned unless we are in a nested
// interceptor.
-#define CHECK_UNPOISONED(x, n) \
- if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n);
+#define CHECK_UNPOISONED(x, n) \
+ do { \
+ if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
+ } while (0);
static void *fast_memset(void *ptr, int c, SIZE_T n);
static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
@@ -103,22 +112,22 @@ INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) {
return res;
}
-INTERCEPTOR(void *, readdir, void *a) {
- ENSURE_MSAN_INITED();
- void *res = REAL(readdir)(a);
- __msan_unpoison(res, __sanitizer::struct_dirent_sz);
- return res;
+INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
+ return __msan_memcpy(dest, src, n);
}
-INTERCEPTOR(void *, readdir64, void *a) {
- ENSURE_MSAN_INITED();
- void *res = REAL(readdir)(a);
- __msan_unpoison(res, __sanitizer::struct_dirent64_sz);
- return res;
+INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
+ return (char *)__msan_memcpy(dest, src, n) + n;
}
-INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
- return __msan_memcpy(dest, src, n);
+INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ void *res = REAL(memccpy)(dest, src, c, n);
+ CHECK(!res || (res >= dest && res <= (char *)dest + n));
+ SIZE_T sz = res ? (char *)res - (char *)dest : n;
+ CHECK_UNPOISONED(src, sz);
+ __msan_unpoison(dest, sz);
+ return res;
}
INTERCEPTOR(void *, memmove, void *dest, const void *src, SIZE_T n) {
@@ -129,6 +138,10 @@ INTERCEPTOR(void *, memset, void *s, int c, SIZE_T n) {
return __msan_memset(s, c, n);
}
+INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
+ return __msan_memmove(dest, src, n);
+}
+
INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_EQ(alignment & (alignment - 1), 0);
@@ -139,10 +152,35 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
return 0;
}
+INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ CHECK_EQ(boundary & (boundary - 1), 0);
+ void *ptr = MsanReallocate(&stack, 0, size, boundary, false);
+ return ptr;
+}
+
+INTERCEPTOR(void *, valloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ void *ptr = MsanReallocate(&stack, 0, size, GetPageSizeCached(), false);
+ return ptr;
+}
+
+INTERCEPTOR(void *, pvalloc, SIZE_T size) {
+ GET_MALLOC_STACK_TRACE;
+ uptr PageSize = GetPageSizeCached();
+ size = RoundUpTo(size, PageSize);
+ if (size == 0) {
+ // pvalloc(0) should allocate one page.
+ size = PageSize;
+ }
+ void *ptr = MsanReallocate(&stack, 0, size, PageSize, false);
+ return ptr;
+}
+
INTERCEPTOR(void, free, void *ptr) {
- ENSURE_MSAN_INITED();
+ GET_MALLOC_STACK_TRACE;
if (ptr == 0) return;
- MsanDeallocate(ptr);
+ MsanDeallocate(&stack, ptr);
}
INTERCEPTOR(SIZE_T, strlen, const char *s) {
@@ -181,6 +219,14 @@ INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { // NOLINT
return res;
}
+INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { // NOLINT
+ ENSURE_MSAN_INITED();
+ SIZE_T n = REAL(strlen)(src);
+ char *res = REAL(stpcpy)(dest, src); // NOLINT
+ __msan_copy_poison(dest, src, n + 1);
+ return res;
+}
+
INTERCEPTOR(char *, strdup, char *src) {
ENSURE_MSAN_INITED();
SIZE_T n = REAL(strlen)(src);
@@ -295,6 +341,26 @@ INTERCEPTOR(double, strtod, const char *nptr, char **endptr) { // NOLINT
return res;
}
+INTERCEPTOR(double, strtod_l, const char *nptr, char **endptr,
+ void *loc) { // NOLINT
+ ENSURE_MSAN_INITED();
+ double res = REAL(strtod_l)(nptr, endptr, loc); // NOLINT
+ if (!__msan_has_dynamic_component()) {
+ __msan_unpoison(endptr, sizeof(*endptr));
+ }
+ return res;
+}
+
+INTERCEPTOR(double, __strtod_l, const char *nptr, char **endptr,
+ void *loc) { // NOLINT
+ ENSURE_MSAN_INITED();
+ double res = REAL(__strtod_l)(nptr, endptr, loc); // NOLINT
+ if (!__msan_has_dynamic_component()) {
+ __msan_unpoison(endptr, sizeof(*endptr));
+ }
+ return res;
+}
+
INTERCEPTOR(float, strtof, const char *nptr, char **endptr) { // NOLINT
ENSURE_MSAN_INITED();
float res = REAL(strtof)(nptr, endptr); // NOLINT
@@ -304,6 +370,26 @@ INTERCEPTOR(float, strtof, const char *nptr, char **endptr) { // NOLINT
return res;
}
+INTERCEPTOR(float, strtof_l, const char *nptr, char **endptr,
+ void *loc) { // NOLINT
+ ENSURE_MSAN_INITED();
+ float res = REAL(strtof_l)(nptr, endptr, loc); // NOLINT
+ if (!__msan_has_dynamic_component()) {
+ __msan_unpoison(endptr, sizeof(*endptr));
+ }
+ return res;
+}
+
+INTERCEPTOR(float, __strtof_l, const char *nptr, char **endptr,
+ void *loc) { // NOLINT
+ ENSURE_MSAN_INITED();
+ float res = REAL(__strtof_l)(nptr, endptr, loc); // NOLINT
+ if (!__msan_has_dynamic_component()) {
+ __msan_unpoison(endptr, sizeof(*endptr));
+ }
+ return res;
+}
+
INTERCEPTOR(long double, strtold, const char *nptr, char **endptr) { // NOLINT
ENSURE_MSAN_INITED();
long double res = REAL(strtold)(nptr, endptr); // NOLINT
@@ -313,11 +399,50 @@ INTERCEPTOR(long double, strtold, const char *nptr, char **endptr) { // NOLINT
return res;
}
+INTERCEPTOR(long double, strtold_l, const char *nptr, char **endptr,
+ void *loc) { // NOLINT
+ ENSURE_MSAN_INITED();
+ long double res = REAL(strtold_l)(nptr, endptr, loc); // NOLINT
+ if (!__msan_has_dynamic_component()) {
+ __msan_unpoison(endptr, sizeof(*endptr));
+ }
+ return res;
+}
+
+INTERCEPTOR(long double, __strtold_l, const char *nptr, char **endptr,
+ void *loc) { // NOLINT
+ ENSURE_MSAN_INITED();
+ long double res = REAL(__strtold_l)(nptr, endptr, loc); // NOLINT
+ if (!__msan_has_dynamic_component()) {
+ __msan_unpoison(endptr, sizeof(*endptr));
+ }
+ return res;
+}
+
+INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(vasprintf)(strp, format, ap);
+ if (res >= 0 && !__msan_has_dynamic_component()) {
+ __msan_unpoison(strp, sizeof(*strp));
+ __msan_unpoison(*strp, res + 1);
+ }
+ return res;
+}
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) { // NOLINT
+ ENSURE_MSAN_INITED();
+ va_list ap;
+ va_start(ap, format);
+ int res = vasprintf(strp, format, ap); // NOLINT
+ va_end(ap);
+ return res;
+}
+
INTERCEPTOR(int, vsnprintf, char *str, uptr size,
const char *format, va_list ap) {
ENSURE_MSAN_INITED();
int res = REAL(vsnprintf)(str, size, format, ap);
- if (!__msan_has_dynamic_component()) {
+ if (res >= 0 && !__msan_has_dynamic_component()) {
__msan_unpoison(str, res + 1);
}
return res;
@@ -326,7 +451,7 @@ INTERCEPTOR(int, vsnprintf, char *str, uptr size,
INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
ENSURE_MSAN_INITED();
int res = REAL(vsprintf)(str, format, ap);
- if (!__msan_has_dynamic_component()) {
+ if (res >= 0 && !__msan_has_dynamic_component()) {
__msan_unpoison(str, res + 1);
}
return res;
@@ -335,7 +460,7 @@ INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
ENSURE_MSAN_INITED();
int res = REAL(vswprintf)(str, size, format, ap);
- if (!__msan_has_dynamic_component()) {
+ if (res >= 0 && !__msan_has_dynamic_component()) {
__msan_unpoison(str, 4 * (res + 1));
}
return res;
@@ -370,25 +495,24 @@ INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) {
// SIZE_T strftime(char *s, SIZE_T max, const char *format,const struct tm *tm);
INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format,
- void *tm) {
+ __sanitizer_tm *tm) {
ENSURE_MSAN_INITED();
SIZE_T res = REAL(strftime)(s, max, format, tm);
if (res) __msan_unpoison(s, res + 1);
return res;
}
-INTERCEPTOR(SIZE_T, wcstombs, void *dest, void *src, SIZE_T size) {
+INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
ENSURE_MSAN_INITED();
- SIZE_T res = REAL(wcstombs)(dest, src, size);
- if (res != (SIZE_T)-1) __msan_unpoison(dest, res + 1);
+ int res = REAL(mbtowc)(dest, src, n);
+ if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
return res;
}
-// SIZE_T mbstowcs(wchar_t *dest, const char *src, SIZE_T n);
-INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T n) {
+INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) {
ENSURE_MSAN_INITED();
- SIZE_T res = REAL(mbstowcs)(dest, src, n);
- if (res != (SIZE_T)-1) __msan_unpoison(dest, (res + 1) * sizeof(wchar_t));
+ SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
+ if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
return res;
}
@@ -422,6 +546,13 @@ INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
return res;
}
+INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+ ENSURE_MSAN_INITED();
+ wchar_t *res = REAL(wmempcpy)(dest, src, n);
+ __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+ return res;
+}
+
INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
CHECK(MEM_IS_APP(s));
ENSURE_MSAN_INITED();
@@ -450,28 +581,6 @@ INTERCEPTOR(double, wcstod, const wchar_t *nptr, wchar_t **endptr) {
return res;
}
-// #define UNSUPPORTED(name) \
-// INTERCEPTOR(void, name, void) { \
-// Printf("MSAN: Unsupported %s\n", __FUNCTION__); \
-// Die(); \
-// }
-
-// FIXME: intercept the following functions:
-// Note, they only matter when running without a dynamic tool.
-// UNSUPPORTED(wcscoll_l)
-// UNSUPPORTED(wcsnrtombs)
-// UNSUPPORTED(wcstol)
-// UNSUPPORTED(wcstoll)
-// UNSUPPORTED(wcstold)
-// UNSUPPORTED(wcstoul)
-// UNSUPPORTED(wcstoull)
-// UNSUPPORTED(wcsxfrm_l)
-// UNSUPPORTED(wcsdup)
-// UNSUPPORTED(wcsftime)
-// UNSUPPORTED(wcsstr)
-// UNSUPPORTED(wcsrchr)
-// UNSUPPORTED(wctob)
-
INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
ENSURE_MSAN_INITED();
int res = REAL(gettimeofday)(tv, tz);
@@ -502,6 +611,32 @@ INTERCEPTOR(char *, getenv, char *name) {
return res;
}
+extern char **environ;
+
+static void UnpoisonEnviron() {
+ char **envp = environ;
+ for (; *envp; ++envp) {
+ __msan_unpoison(envp, sizeof(*envp));
+ __msan_unpoison(*envp, REAL(strlen)(*envp) + 1);
+ }
+ // Trailing NULL pointer.
+ __msan_unpoison(envp, sizeof(*envp));
+}
+
+INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(setenv)(name, value, overwrite);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
+INTERCEPTOR(int, putenv, char *string) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(putenv)(string);
+ if (!res) UnpoisonEnviron();
+ return res;
+}
+
INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__fxstat)(magic, fd, buf);
@@ -518,6 +653,22 @@ INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) {
return res;
}
+INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+
+INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf,
+ int flags) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags);
+ if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+
INTERCEPTOR(int, __xstat, int magic, char *path, void *buf) {
ENSURE_MSAN_INITED();
int res = REAL(__xstat)(magic, path, buf);
@@ -592,22 +743,6 @@ INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) {
return res;
}
-INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
- ENSURE_MSAN_INITED();
- char *res = REAL(getcwd)(buf, size);
- if (res)
- __msan_unpoison(res, REAL(strlen)(res) + 1);
- return res;
-}
-
-INTERCEPTOR(char *, realpath, char *path, char *abspath) {
- ENSURE_MSAN_INITED();
- char *res = REAL(realpath)(path, abspath);
- if (res)
- __msan_unpoison(abspath, REAL(strlen)(abspath) + 1);
- return res;
-}
-
INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
if (msan_init_is_running)
return REAL(getrlimit)(resource, rlim);
@@ -628,38 +763,6 @@ INTERCEPTOR(int, getrlimit64, int resource, void *rlim) {
return res;
}
-INTERCEPTOR(int, statfs, const char *s, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(statfs)(s, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs_sz);
- return res;
-}
-
-INTERCEPTOR(int, fstatfs, int fd, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(fstatfs)(fd, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs_sz);
- return res;
-}
-
-INTERCEPTOR(int, statfs64, const char *s, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(statfs64)(s, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs64_sz);
- return res;
-}
-
-INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
- ENSURE_MSAN_INITED();
- int res = REAL(fstatfs64)(fd, buf);
- if (!res)
- __msan_unpoison(buf, __sanitizer::struct_statfs64_sz);
- return res;
-}
-
INTERCEPTOR(int, uname, void *utsname) {
ENSURE_MSAN_INITED();
int res = REAL(uname)(utsname);
@@ -710,35 +813,24 @@ INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
}
INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
- void *srcaddr, void *addrlen) {
+ void *srcaddr, int *addrlen) {
ENSURE_MSAN_INITED();
SIZE_T srcaddr_sz;
- if (srcaddr)
- srcaddr_sz = __sanitizer_get_socklen_t(addrlen);
+ if (srcaddr) srcaddr_sz = *addrlen;
SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
if (res > 0) {
__msan_unpoison(buf, res);
if (srcaddr) {
- SIZE_T sz = __sanitizer_get_socklen_t(addrlen);
+ SIZE_T sz = *addrlen;
__msan_unpoison(srcaddr, (sz < srcaddr_sz) ? sz : srcaddr_sz);
}
}
return res;
}
-INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct msghdr *msg, int flags) {
- ENSURE_MSAN_INITED();
- SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
- if (res > 0) {
- for (SIZE_T i = 0; i < __sanitizer_get_msghdr_iovlen(msg); ++i)
- __msan_unpoison(__sanitizer_get_msghdr_iov_iov_base(msg, i),
- __sanitizer_get_msghdr_iov_iov_len(msg, i));
- }
- return res;
-}
-
INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
- if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb))
+ return AllocatorReturnNull();
GET_MALLOC_STACK_TRACE;
if (!msan_inited) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
@@ -814,6 +906,13 @@ INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
return res;
}
+INTERCEPTOR(char *, dlerror) {
+ ENSURE_MSAN_INITED();
+ char *res = REAL(dlerror)();
+ if (res != 0) __msan_unpoison(res, REAL(strlen)(res) + 1);
+ return res;
+}
+
// dlopen() ultimately calls mmap() down inside the loader, which generally
// doesn't participate in dynamic symbol resolution. Therefore we won't
// intercept its calls to mmap, and we have to hook it here. The loader
@@ -828,7 +927,7 @@ INTERCEPTOR(void *, dlopen, const char *filename, int flag) {
if (!__msan_has_dynamic_component() && map) {
// If msandr didn't clear the shadow before the initializers ran, we do it
// ourselves afterwards.
- UnpoisonMappedDSO(map);
+ ForEachMappedRegion(map, __msan_unpoison);
}
return (void *)map;
}
@@ -848,7 +947,7 @@ static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
__msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
}
dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
- __msan_unpoison_param(3);
+ UnpoisonParam(3);
return cbdata->callback(info, size, cbdata->data);
}
@@ -872,22 +971,32 @@ INTERCEPTOR(int, getrusage, int who, void *usage) {
return res;
}
+// sigactions_mu guarantees atomicity of sigaction() and signal() calls.
+// Access to sigactions[] is gone with relaxed atomics to avoid data race with
+// the signal handler.
const int kMaxSignals = 1024;
-static uptr sigactions[kMaxSignals];
+static atomic_uintptr_t sigactions[kMaxSignals];
static StaticSpinMutex sigactions_mu;
static void SignalHandler(int signo) {
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(1);
+
typedef void (*signal_cb)(int x);
- signal_cb cb = (signal_cb)sigactions[signo];
+ signal_cb cb =
+ (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
cb(signo);
}
static void SignalAction(int signo, void *si, void *uc) {
- __msan_unpoison(si, __sanitizer::struct_sigaction_sz);
+ ScopedThreadLocalStateBackup stlsb;
+ UnpoisonParam(3);
+ __msan_unpoison(si, sizeof(__sanitizer_sigaction));
__msan_unpoison(uc, __sanitizer::ucontext_t_sz);
typedef void (*sigaction_cb)(int, void *, void *);
- sigaction_cb cb = (sigaction_cb)sigactions[signo];
+ sigaction_cb cb =
+ (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
cb(signo, si, uc);
}
@@ -900,25 +1009,25 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
if (flags()->wrap_signals) {
SpinMutexLock lock(&sigactions_mu);
CHECK_LT(signo, kMaxSignals);
- uptr old_cb = sigactions[signo];
+ uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed);
__sanitizer_sigaction new_act;
__sanitizer_sigaction *pnew_act = act ? &new_act : 0;
if (act) {
- internal_memcpy(pnew_act, act, __sanitizer::struct_sigaction_sz);
- uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(pnew_act);
- uptr new_cb =
- __sanitizer::__sanitizer_get_sigaction_sa_siginfo(pnew_act) ?
- (uptr)SignalAction : (uptr)SignalHandler;
+ internal_memcpy(pnew_act, act, sizeof(__sanitizer_sigaction));
+ uptr cb = (uptr)pnew_act->sa_sigaction;
+ uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
+ ? (uptr)SignalAction
+ : (uptr)SignalHandler;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- sigactions[signo] = cb;
- __sanitizer::__sanitizer_set_sigaction_sa_sigaction(pnew_act, new_cb);
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
+ pnew_act->sa_sigaction = (void (*)(int, void *, void *))new_cb;
}
}
res = REAL(sigaction)(signo, pnew_act, oldact);
if (res == 0 && oldact) {
- uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(oldact);
+ uptr cb = (uptr)oldact->sa_sigaction;
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- __sanitizer::__sanitizer_set_sigaction_sa_sigaction(oldact, old_cb);
+ oldact->sa_sigaction = (void (*)(int, void *, void *))old_cb;
}
}
} else {
@@ -926,7 +1035,7 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
}
if (res == 0 && oldact) {
- __msan_unpoison(oldact, __sanitizer::struct_sigaction_sz);
+ __msan_unpoison(oldact, sizeof(__sanitizer_sigaction));
}
return res;
}
@@ -937,7 +1046,7 @@ INTERCEPTOR(int, signal, int signo, uptr cb) {
CHECK_LT(signo, kMaxSignals);
SpinMutexLock lock(&sigactions_mu);
if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
- sigactions[signo] = cb;
+ atomic_store(&sigactions[signo], cb, memory_order_relaxed);
cb = (uptr) SignalHandler;
}
return REAL(signal)(signo, cb);
@@ -948,8 +1057,39 @@ INTERCEPTOR(int, signal, int signo, uptr cb) {
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
-extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
-extern "C" int pthread_attr_getstack(void *attr, uptr *stack, uptr *stacksize);
+extern "C" int pthread_setspecific(unsigned key, const void *v);
+extern "C" int pthread_yield();
+
+static void thread_finalize(void *v) {
+ uptr iter = (uptr)v;
+ if (iter > 1) {
+ if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+ Printf("MemorySanitizer: failed to set thread key\n");
+ Die();
+ }
+ return;
+ }
+ MsanAllocatorThreadFinish();
+}
+
+struct ThreadParam {
+ void* (*callback)(void *arg);
+ void *param;
+ atomic_uintptr_t done;
+};
+
+static void *MsanThreadStartFunc(void *arg) {
+ ThreadParam *p = (ThreadParam *)arg;
+ void* (*callback)(void *arg) = p->callback;
+ void *param = p->param;
+ if (pthread_setspecific(g_thread_finalize_key,
+ (void *)kPthreadDestructorIterations)) {
+ Printf("MemorySanitizer: failed to set thread key\n");
+ Die();
+ }
+ atomic_store(&p->done, 1, memory_order_release);
+ return callback(param);
+}
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
void * param) {
@@ -960,9 +1100,19 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
attr = &myattr;
}
- AdjustStackSizeLinux(attr, flags()->verbosity);
+ AdjustStackSizeLinux(attr);
+
+ ThreadParam p;
+ p.callback = callback;
+ p.param = param;
+ atomic_store(&p.done, 0, memory_order_relaxed);
+
+ int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, (void *)&p);
+ if (res == 0) {
+ while (atomic_load(&p.done, memory_order_acquire) != 1)
+ pthread_yield();
+ }
- int res = REAL(pthread_create)(th, attr, callback, param);
if (attr == &myattr)
pthread_attr_destroy(&myattr);
if (!res) {
@@ -971,37 +1121,177 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
return res;
}
+INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
+ void (*dtor)(void *value)) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_key_create)(key, dtor);
+ if (!res && key)
+ __msan_unpoison(key, sizeof(*key));
+ return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **retval) {
+ ENSURE_MSAN_INITED();
+ int res = REAL(pthread_join)(th, retval);
+ if (!res && retval)
+ __msan_unpoison(retval, sizeof(*retval));
+ return res;
+}
+
+extern char *tzname[2];
+
+INTERCEPTOR(void, tzset) {
+ ENSURE_MSAN_INITED();
+ REAL(tzset)();
+ if (tzname[0])
+ __msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
+ if (tzname[1])
+ __msan_unpoison(tzname[1], REAL(strlen)(tzname[1]) + 1);
+ return;
+}
+
+struct MSanAtExitRecord {
+ void (*func)(void *arg);
+ void *arg;
+};
+
+void MSanAtExitWrapper(void *arg) {
+ UnpoisonParam(1);
+ MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
+ r->func(r->arg);
+ InternalFree(r);
+}
+
+// Unpoison argument shadow for C++ module destructors.
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+ void *dso_handle) {
+ if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ ENSURE_MSAN_INITED();
+ MSanAtExitRecord *r =
+ (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
+ r->func = func;
+ r->arg = arg;
+ return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle);
+}
+
+DECLARE_REAL(int, shmctl, int shmid, int cmd, void *buf)
+
+INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
+ ENSURE_MSAN_INITED();
+ void *p = REAL(shmat)(shmid, shmaddr, shmflg);
+ if (p != (void *)-1) {
+ __sanitizer_shmid_ds ds;
+ int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds);
+ if (!res) {
+ __msan_unpoison(p, ds.shm_segsz);
+ }
+ }
+ return p;
+}
+
+// Linux kernel has a bug that leads to kernel deadlock if a process
+// maps TBs of memory and then calls mlock().
+static void MlockIsUnsupported() {
+ static atomic_uint8_t printed;
+ if (atomic_exchange(&printed, 1, memory_order_relaxed))
+ return;
+ if (common_flags()->verbosity > 0)
+ Printf("INFO: MemorySanitizer ignores mlock/mlockall/munlock/munlockall\n");
+}
+
+INTERCEPTOR(int, mlock, const void *addr, uptr len) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlock, const void *addr, uptr len) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, mlockall, int flags) {
+ MlockIsUnsupported();
+ return 0;
+}
+
+INTERCEPTOR(int, munlockall, void) {
+ MlockIsUnsupported();
+ return 0;
+}
+
struct MSanInterceptorContext {
bool in_interceptor_scope;
};
-// A version of CHECK_UNPOISED using a saved scope value. Used in common
+namespace __msan {
+
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
+} // namespace __msan
+
+extern "C" int *__errno_location(void);
+
+// A version of CHECK_UNPOISONED using a saved scope value. Used in common
// interceptors.
-#define CHECK_UNPOISONED_CTX(ctx, x, n) \
- if (!((MSanInterceptorContext *) ctx)->in_interceptor_scope) \
- CHECK_UNPOISONED_0(x, n);
+#define CHECK_UNPOISONED_CTX(ctx, x, n) \
+ do { \
+ if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
+ CHECK_UNPOISONED_0(x, n); \
+ } while (0)
+#define MSAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
+ common_flags()->verbosity > 0) \
+ Report("MemorySanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+
+#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+ UnpoisonParam(count)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
- CHECK_UNPOISONED_CTX(ctx, ptr, size);
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
- if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
- MSanInterceptorContext msan_ctx = { IsInInterceptorScope() }; \
- ctx = (void *)&msan_ctx; \
- InterceptorScope interceptor_scope; \
+ CHECK_UNPOISONED_CTX(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, ptr, size) \
+ __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+ if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
+ MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
+ ctx = (void *)&msan_ctx; \
+ (void)ctx; \
+ InterceptorScope interceptor_scope; \
+ __msan_unpoison(__errno_location(), sizeof(int)); /* NOLINT */ \
ENSURE_MSAN_INITED();
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
do { \
} while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+ do { \
+ } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+ do { \
+ } while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
- do { } while (false) // FIXME
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false) // FIXME
+#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
-#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
-#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
+ do { \
+ } while (false)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+ do { \
+ } while (false)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
@@ -1062,15 +1352,41 @@ void __msan_clear_and_unpoison(void *a, uptr size) {
fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
}
+u32 get_origin_if_poisoned(uptr a, uptr size) {
+ unsigned char *s = (unsigned char *)MEM_TO_SHADOW(a);
+ for (uptr i = 0; i < size; ++i)
+ if (s[i])
+ return *(u32 *)SHADOW_TO_ORIGIN((s + i) & ~3UL);
+ return 0;
+}
+
void __msan_copy_origin(void *dst, const void *src, uptr size) {
if (!__msan_get_track_origins()) return;
if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
- uptr d = MEM_TO_ORIGIN(dst);
- uptr s = MEM_TO_ORIGIN(src);
- uptr beg = d & ~3UL; // align down.
- uptr end = (d + size + 3) & ~3UL; // align up.
- s = s & ~3UL; // align down.
- fast_memcpy((void*)beg, (void*)s, end - beg);
+ uptr d = (uptr)dst;
+ uptr beg = d & ~3UL;
+ // Copy left unaligned origin if that memory is poisoned.
+ if (beg < d) {
+ u32 o = get_origin_if_poisoned(beg, d - beg);
+ if (o)
+ *(u32 *)MEM_TO_ORIGIN(beg) = o;
+ beg += 4;
+ }
+
+ uptr end = (d + size + 3) & ~3UL;
+ // Copy right unaligned origin if that memory is poisoned.
+ if (end > d + size) {
+ u32 o = get_origin_if_poisoned(d + size, end - d - size);
+ if (o)
+ *(u32 *)MEM_TO_ORIGIN(end - 4) = o;
+ end -= 4;
+ }
+
+ if (beg < end) {
+ // Align src up.
+ uptr s = ((uptr)src + 3) & ~3UL;
+ fast_memcpy((void*)MEM_TO_ORIGIN(beg), (void*)MEM_TO_ORIGIN(s), end - beg);
+ }
}
void __msan_copy_poison(void *dst, const void *src, uptr size) {
@@ -1119,6 +1435,9 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(mmap);
INTERCEPT_FUNCTION(mmap64);
INTERCEPT_FUNCTION(posix_memalign);
+ INTERCEPT_FUNCTION(memalign);
+ INTERCEPT_FUNCTION(valloc);
+ INTERCEPT_FUNCTION(pvalloc);
INTERCEPT_FUNCTION(malloc);
INTERCEPT_FUNCTION(calloc);
INTERCEPT_FUNCTION(realloc);
@@ -1126,15 +1445,18 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(fread);
INTERCEPT_FUNCTION(fread_unlocked);
INTERCEPT_FUNCTION(readlink);
- INTERCEPT_FUNCTION(readdir);
- INTERCEPT_FUNCTION(readdir64);
INTERCEPT_FUNCTION(memcpy);
+ INTERCEPT_FUNCTION(memccpy);
+ INTERCEPT_FUNCTION(mempcpy);
INTERCEPT_FUNCTION(memset);
INTERCEPT_FUNCTION(memmove);
+ INTERCEPT_FUNCTION(bcopy);
INTERCEPT_FUNCTION(wmemset);
INTERCEPT_FUNCTION(wmemcpy);
+ INTERCEPT_FUNCTION(wmempcpy);
INTERCEPT_FUNCTION(wmemmove);
INTERCEPT_FUNCTION(strcpy); // NOLINT
+ INTERCEPT_FUNCTION(stpcpy); // NOLINT
INTERCEPT_FUNCTION(strdup);
INTERCEPT_FUNCTION(__strdup);
INTERCEPT_FUNCTION(strndup);
@@ -1150,8 +1472,16 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(strtoul);
INTERCEPT_FUNCTION(strtoull);
INTERCEPT_FUNCTION(strtod);
+ INTERCEPT_FUNCTION(strtod_l);
+ INTERCEPT_FUNCTION(__strtod_l);
INTERCEPT_FUNCTION(strtof);
+ INTERCEPT_FUNCTION(strtof_l);
+ INTERCEPT_FUNCTION(__strtof_l);
INTERCEPT_FUNCTION(strtold);
+ INTERCEPT_FUNCTION(strtold_l);
+ INTERCEPT_FUNCTION(__strtold_l);
+ INTERCEPT_FUNCTION(vasprintf);
+ INTERCEPT_FUNCTION(asprintf);
INTERCEPT_FUNCTION(vsprintf);
INTERCEPT_FUNCTION(vsnprintf);
INTERCEPT_FUNCTION(vswprintf);
@@ -1159,20 +1489,24 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(snprintf);
INTERCEPT_FUNCTION(swprintf);
INTERCEPT_FUNCTION(strftime);
- INTERCEPT_FUNCTION(wcstombs);
- INTERCEPT_FUNCTION(mbstowcs);
+ INTERCEPT_FUNCTION(mbtowc);
+ INTERCEPT_FUNCTION(mbrtowc);
INTERCEPT_FUNCTION(wcslen);
INTERCEPT_FUNCTION(wcschr);
INTERCEPT_FUNCTION(wcscpy);
INTERCEPT_FUNCTION(wcscmp);
INTERCEPT_FUNCTION(wcstod);
INTERCEPT_FUNCTION(getenv);
+ INTERCEPT_FUNCTION(setenv);
+ INTERCEPT_FUNCTION(putenv);
INTERCEPT_FUNCTION(gettimeofday);
INTERCEPT_FUNCTION(fcvt);
INTERCEPT_FUNCTION(__fxstat);
+ INTERCEPT_FUNCTION(__fxstatat);
INTERCEPT_FUNCTION(__xstat);
INTERCEPT_FUNCTION(__lxstat);
INTERCEPT_FUNCTION(__fxstat64);
+ INTERCEPT_FUNCTION(__fxstatat64);
INTERCEPT_FUNCTION(__xstat64);
INTERCEPT_FUNCTION(__lxstat64);
INTERCEPT_FUNCTION(pipe);
@@ -1180,28 +1514,33 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(socketpair);
INTERCEPT_FUNCTION(fgets);
INTERCEPT_FUNCTION(fgets_unlocked);
- INTERCEPT_FUNCTION(getcwd);
- INTERCEPT_FUNCTION(realpath);
INTERCEPT_FUNCTION(getrlimit);
INTERCEPT_FUNCTION(getrlimit64);
- INTERCEPT_FUNCTION(statfs);
- INTERCEPT_FUNCTION(fstatfs);
- INTERCEPT_FUNCTION(statfs64);
- INTERCEPT_FUNCTION(fstatfs64);
INTERCEPT_FUNCTION(uname);
INTERCEPT_FUNCTION(gethostname);
INTERCEPT_FUNCTION(epoll_wait);
INTERCEPT_FUNCTION(epoll_pwait);
INTERCEPT_FUNCTION(recv);
INTERCEPT_FUNCTION(recvfrom);
- INTERCEPT_FUNCTION(recvmsg);
INTERCEPT_FUNCTION(dladdr);
+ INTERCEPT_FUNCTION(dlerror);
INTERCEPT_FUNCTION(dlopen);
INTERCEPT_FUNCTION(dl_iterate_phdr);
INTERCEPT_FUNCTION(getrusage);
INTERCEPT_FUNCTION(sigaction);
INTERCEPT_FUNCTION(signal);
INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_key_create);
+ INTERCEPT_FUNCTION(pthread_join);
+ INTERCEPT_FUNCTION(tzset);
+ INTERCEPT_FUNCTION(__cxa_atexit);
+ INTERCEPT_FUNCTION(shmat);
+
+ if (REAL(pthread_key_create)(&g_thread_finalize_key, &thread_finalize)) {
+ Printf("MemorySanitizer: failed to create thread key\n");
+ Die();
+ }
+
inited = 1;
}
} // namespace __msan