msan.cpp
msan_allocator.cpp
msan_chained_origin_depot.cpp
+ msan_dl.cpp
msan_interceptors.cpp
msan_linux.cpp
msan_report.cpp
msan.h
msan_allocator.h
msan_chained_origin_depot.h
+ msan_dl.h
msan_flags.h
msan_flags.inc
msan_interface_internal.h
--- /dev/null
+//===-- msan_dl.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Helper functions for unpoisoning results of dladdr and dladdr1.
+//===----------------------------------------------------------------------===//
+
+#include "msan_dl.h"
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <link.h>
+
+#include "msan_poisoning.h"
+
+namespace __msan {
+
+void UnpoisonDllAddrInfo(void *info) {
+ Dl_info *ptr = (Dl_info *)(info);
+ __msan_unpoison(ptr, sizeof(*ptr));
+ if (ptr->dli_fname)
+ __msan_unpoison(ptr->dli_fname, internal_strlen(ptr->dli_fname) + 1);
+ if (ptr->dli_sname)
+ __msan_unpoison(ptr->dli_sname, internal_strlen(ptr->dli_sname) + 1);
+}
+
+void UnpoisonDllAddr1ExtraInfo(void **extra_info, int flags) {
+ if (flags == RTLD_DL_SYMENT) {
+ __msan_unpoison(extra_info, sizeof(void *));
+
+ const ElfW(Sym) *s = *((const ElfW(Sym) **)(extra_info));
+ __msan_unpoison(s, sizeof(ElfW(Sym)));
+ } else if (flags == RTLD_DL_LINKMAP) {
+ __msan_unpoison(extra_info, sizeof(void *));
+
+ struct link_map *map = *((struct link_map **)(extra_info));
+
+ // Walk forward
+ for (auto *ptr = map; ptr; ptr = ptr->l_next) {
+ __msan_unpoison(ptr, sizeof(struct link_map));
+ if (ptr->l_name)
+ __msan_unpoison(ptr->l_name, internal_strlen(ptr->l_name) + 1);
+ }
+
+ if (!map) return;
+
+ // Walk backward
+ for (auto *ptr = map->l_prev; ptr; ptr = ptr->l_prev) {
+ __msan_unpoison(ptr, sizeof(struct link_map));
+ if (ptr->l_name)
+ __msan_unpoison(ptr->l_name, internal_strlen(ptr->l_name) + 1);
+ }
+ }
+}
+
+} // namespace __msan
--- /dev/null
+//===-- msan_dl.h ---------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemorySanitizer.
+//
+// Helper functions for unpoisoning results of dladdr and dladdr1.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_DL_H
+#define MSAN_DL_H
+
+#include "msan.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __msan {
+
+void UnpoisonDllAddrInfo(void *info);
+// void UnpoisonDllAddrInfo(Dl_info *info);
+void UnpoisonDllAddr1ExtraInfo(void **extra_info, int flags);
+
+} // namespace __msan
+
+#endif // MSAN_DL_H
#include "interception/interception.h"
#include "msan.h"
#include "msan_chained_origin_depot.h"
+#include "msan_dl.h"
#include "msan_origin.h"
#include "msan_poisoning.h"
#include "msan_report.h"
return res;
}
-struct dlinfo {
- char *dli_fname;
- void *dli_fbase;
- char *dli_sname;
- void *dli_saddr;
-};
-
-INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
+INTERCEPTOR(int, dladdr, void *addr, void *info) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, dladdr, addr, info);
int res = REAL(dladdr)(addr, info);
+ if (res != 0)
+ UnpoisonDllAddrInfo(info);
+ return res;
+}
+
+INTERCEPTOR(int, dladdr1, void *addr, void *info, void **extra_info,
+ int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, dladdr1, addr, info, extra_info, flags);
+ int res = REAL(dladdr1)(addr, info, extra_info, flags);
if (res != 0) {
- __msan_unpoison(info, sizeof(*info));
- if (info->dli_fname)
- __msan_unpoison(info->dli_fname, internal_strlen(info->dli_fname) + 1);
- if (info->dli_sname)
- __msan_unpoison(info->dli_sname, internal_strlen(info->dli_sname) + 1);
+ UnpoisonDllAddrInfo(info);
+ UnpoisonDllAddr1ExtraInfo(extra_info, flags);
}
return res;
}
MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
INTERCEPT_FUNCTION(strsignal);
INTERCEPT_FUNCTION(dladdr);
+ INTERCEPT_FUNCTION(dladdr1);
INTERCEPT_FUNCTION(dlerror);
INTERCEPT_FUNCTION(dl_iterate_phdr);
INTERCEPT_FUNCTION(getrusage);
--- /dev/null
+/* RUN: %clang_msan -g %s -o %t
+ RUN: %clang_msan -g %s -DBUILD_SO -fPIC -o %t-so.so -shared
+ RUN: %run %t 2>&1 | FileCheck %s
+
+ REQUIRES: glibc{{.*}}
+*/
+
+#define _GNU_SOURCE
+
+#ifndef BUILD_SO
+#include <assert.h>
+#include <dlfcn.h>
+#include <elf.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef volatile long *(* get_t)();
+get_t GetTls;
+
+int main(int argc, char *argv[]) {
+ char path[4096];
+ snprintf(path, sizeof(path), "%s-so.so", argv[0]);
+ int i;
+
+ void *handle = dlopen(path, RTLD_LAZY);
+ if (!handle) fprintf(stderr, "%s\n", dlerror());
+ assert(handle != 0);
+ GetTls = (get_t)dlsym(handle, "GetTls");
+ assert(dlerror() == 0);
+
+ {
+ printf("Testing RTLD_DL_LINKMAP\n");
+ fflush(stdout);
+
+ Dl_info info;
+ struct link_map *map_ptr;
+ int ret = dladdr1(GetTls, &info, (void**)(&map_ptr), RTLD_DL_LINKMAP);
+ assert(ret != 0);
+ printf("fname: %s\n", info.dli_fname);
+ printf("fbase: %p\n", info.dli_fbase);
+ printf("sname: %s\n", info.dli_sname);
+ // CHECK: sname: GetTls
+ printf("saddr: %p\n", info.dli_saddr);
+
+ assert(map_ptr != NULL);
+ printf("map_ptr: %p\n", map_ptr);
+ fflush(stdout);
+
+ // Find the start of the link map
+ while(map_ptr->l_prev != NULL) {
+ fflush(stdout);
+ map_ptr = map_ptr->l_prev;
+ }
+
+ fflush(stdout);
+ while(map_ptr != NULL) {
+ assert(map_ptr->l_name != NULL);
+ printf("0x%lx: '%s', %p\n", map_ptr->l_addr, map_ptr->l_name, map_ptr->l_ld);
+ fflush(stdout);
+ map_ptr = map_ptr->l_next;
+ }
+ // CHECK: libc.so
+ // CHECK: dladdr1_test
+ }
+
+ // Test RTLD_DL_SYMENT
+
+ {
+ printf("Testing RTLD_DL_SYMENT\n");
+ fflush(stdout);
+
+ Dl_info info;
+ ElfW(Sym) *sym;
+ int ret = dladdr1(GetTls, &info, (void**)(&sym), RTLD_DL_SYMENT);
+ assert(ret != 0);
+ printf("fname: %s\n", info.dli_fname);
+ printf("fbase: %p\n", info.dli_fbase);
+ printf("sname: %s\n", info.dli_sname);
+ // CHECK: sname: GetTls
+ printf("saddr: %p\n", info.dli_saddr);
+
+ printf("sym: %d %d %d %d %lu %lu\n",
+ sym->st_name, sym->st_info, sym->st_other,
+ sym->st_shndx, sym->st_value, sym->st_size);
+ // CHECK: sym:
+ }
+ return 0;
+}
+#else // BUILD_SO
+long var;
+long *GetTls() {
+ return &var;
+}
+#endif