summaryrefslogtreecommitdiff
path: root/lib/msandr/msandr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/msandr/msandr.cc')
-rw-r--r--lib/msandr/msandr.cc91
1 files changed, 72 insertions, 19 deletions
diff --git a/lib/msandr/msandr.cc b/lib/msandr/msandr.cc
index 235a1eddd..fee9834de 100644
--- a/lib/msandr/msandr.cc
+++ b/lib/msandr/msandr.cc
@@ -37,6 +37,7 @@
#include <drsyscall.h>
#include <sys/mman.h>
+#include <sys/syscall.h> /* for SYS_mmap */
#include <algorithm>
#include <string>
@@ -103,6 +104,17 @@ ModuleData::ModuleData(const module_data_t *info)
int(*__msan_get_retval_tls_offset)();
int(*__msan_get_param_tls_offset)();
+void (*__msan_unpoison)(void *base, size_t size);
+bool (*__msan_is_in_loader)();
+
+static generic_func_t LookupCallback(module_data_t *app, const char *name) {
+ generic_func_t callback = dr_get_proc_address(app->handle, name);
+ if (callback == NULL) {
+ dr_printf("Couldn't find `%s` in %s\n", name, app->full_path);
+ CHECK(callback);
+ }
+ return callback;
+}
void InitializeMSanCallbacks() {
module_data_t *app = dr_lookup_module_by_name(dr_get_application_name());
@@ -113,25 +125,18 @@ void InitializeMSanCallbacks() {
}
g_app_path = app->full_path;
- const char *callback_name = "__msan_get_retval_tls_offset";
- __msan_get_retval_tls_offset =
- (int(*)()) dr_get_proc_address(app->handle, callback_name);
- if (__msan_get_retval_tls_offset == NULL) {
- dr_printf("Couldn't find `%s` in %s\n", callback_name, app->full_path);
- CHECK(__msan_get_retval_tls_offset);
- }
+ __msan_get_retval_tls_offset = (int (*)())
+ LookupCallback(app, "__msan_get_retval_tls_offset");
+ __msan_get_param_tls_offset = (int (*)())
+ LookupCallback(app, "__msan_get_param_tls_offset");
+ __msan_unpoison = (void(*)(void *, size_t))
+ LookupCallback(app, "__msan_unpoison");
+ __msan_is_in_loader = (bool (*)())
+ LookupCallback(app, "__msan_is_in_loader");
- callback_name = "__msan_get_param_tls_offset";
- __msan_get_param_tls_offset =
- (int(*)()) dr_get_proc_address(app->handle, callback_name);
- if (__msan_get_param_tls_offset == NULL) {
- dr_printf("Couldn't find `%s` in %s\n", callback_name, app->full_path);
- CHECK(__msan_get_param_tls_offset);
- }
+ dr_free_module_data(app);
}
-#define MEM_TO_SHADOW(mem) ((mem) & ~0x400000000000ULL)
-
// FIXME: Handle absolute addresses and PC-relative addresses.
// FIXME: Handle TLS accesses via FS or GS. DR assumes all other segments have
// a zero base anyway.
@@ -520,7 +525,7 @@ bool drsys_iter_memarg_cb(drsys_arg_t *arg, void *user_data) {
if (arg->pre)
return true;
- if (arg->mode != DRSYS_PARAM_OUT)
+ if (!TESTANY(DRSYS_PARAM_OUT, arg->mode))
return true;
size_t sz = arg->size;
@@ -538,8 +543,19 @@ bool drsys_iter_memarg_cb(drsys_arg_t *arg, void *user_data) {
(unsigned long long)(sz & 0xFFFFFFFF));
}
- void *p = (void *)MEM_TO_SHADOW((ptr_uint_t) arg->start_addr);
- memset(p, 0, sz);
+ if (VERBOSITY > 0) {
+ drmf_status_t res;
+ drsys_syscall_t *syscall = (drsys_syscall_t *)user_data;
+ const char *name;
+ res = drsys_syscall_name(syscall, &name);
+ dr_printf("drsyscall: syscall '%s' arg %d wrote range [%p, %p)\n",
+ name, arg->ordinal, arg->start_addr,
+ (char *)arg->start_addr + sz);
+ }
+
+ // We don't switch to the app context because __msan_unpoison() doesn't need
+ // TLS segments.
+ __msan_unpoison(arg->start_addr, sz);
return true; /* keep going */
}
@@ -576,6 +592,19 @@ bool event_pre_syscall(void *drcontext, int sysnum) {
return true;
}
+static bool IsInLoader(void *drcontext) {
+ // TODO: This segment swap is inefficient. DR should just let us query the
+ // app segment base, which it has. Alternatively, if we disable
+ // -mangle_app_seg, then we won't need the swap.
+ bool need_swap = !dr_using_app_state(drcontext);
+ if (need_swap)
+ dr_switch_to_app_state(drcontext);
+ bool is_in_loader = __msan_is_in_loader();
+ if (need_swap)
+ dr_switch_to_dr_state(drcontext);
+ return is_in_loader;
+}
+
void event_post_syscall(void *drcontext, int sysnum) {
drsys_syscall_t *syscall;
drsys_sysnum_t sysnum_full;
@@ -598,6 +627,30 @@ void event_post_syscall(void *drcontext, int sysnum) {
drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, (void *)syscall);
CHECK(res == DRMF_SUCCESS);
}
+
+ // Our normal mmap interceptor can't intercept calls from the loader itself.
+ // This means we don't clear the shadow for calls to dlopen. For now, we
+ // solve this by intercepting mmap from ld.so here, but ideally we'd have a
+ // solution that doesn't rely on msandr.
+ //
+ // Be careful not to intercept maps done by the msan rtl. Otherwise we end up
+ // unpoisoning vast regions of memory and OOMing.
+ // TODO: __msan_unpoison() could "flush" large regions of memory like tsan
+ // does instead of doing a large memset. However, we need the memory to be
+ // zeroed, where as tsan does not, so plain madvise is not enough.
+ if (success && (sysnum == SYS_mmap IF_NOT_X64(|| sysnum == SYS_mmap2))) {
+ if (IsInLoader(drcontext)) {
+ app_pc base = (app_pc)dr_syscall_get_result(drcontext);
+ ptr_uint_t size;
+ drmf_status_t res = drsys_pre_syscall_arg(drcontext, 1, &size);
+ CHECK(res == DRMF_SUCCESS);
+ if (VERBOSITY > 0)
+ dr_printf("unpoisoning for dlopen: [%p-%p]\n", base, base + size);
+ // We don't switch to the app context because __msan_unpoison() doesn't
+ // need TLS segments.
+ __msan_unpoison(base, size);
+ }
+ }
}
} // namespace