Skip to content

Commit 9095d5c

Browse files
committed
Reland '[msan] Intercept dladdr1, and refactor dladdr'
Relanding with #if SANITIZER_GLIBC to avoid breaking FreeBSD. Also incorporates Arthur's BUILD.gn fix (thanks!) from https://reviews.llvm.org/rGc1e283851772ba494113311405d48cfb883751d1 Original commit message: This patch adds an msan interceptor for dladdr1 (with support for RTLD_DL_LINKMAP and RTLD_DL_SYMENT) and an accompanying test. It also adds a helper file, msan_dl.cpp, that contains UnpoisonDllAddrInfo (refactored out of the dladdr interceptor) and UnpoisonDllAddr1ExtraInfo. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D154272
1 parent 4a63264 commit 9095d5c

File tree

6 files changed

+214
-13
lines changed

6 files changed

+214
-13
lines changed

compiler-rt/lib/msan/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(MSAN_RTL_SOURCES
55
msan.cpp
66
msan_allocator.cpp
77
msan_chained_origin_depot.cpp
8+
msan_dl.cpp
89
msan_interceptors.cpp
910
msan_linux.cpp
1011
msan_report.cpp
@@ -20,6 +21,7 @@ set(MSAN_RTL_HEADERS
2021
msan.h
2122
msan_allocator.h
2223
msan_chained_origin_depot.h
24+
msan_dl.h
2325
msan_flags.h
2426
msan_flags.inc
2527
msan_interface_internal.h

compiler-rt/lib/msan/msan_dl.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===-- msan_dl.cpp -------------------------------------------------------===//
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+
// This file is a part of MemorySanitizer.
10+
//
11+
// Helper functions for unpoisoning results of dladdr and dladdr1.
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "msan_dl.h"
15+
16+
#include <dlfcn.h>
17+
#include <elf.h>
18+
#include <link.h>
19+
20+
#include "msan_poisoning.h"
21+
22+
namespace __msan {
23+
24+
void UnpoisonDllAddrInfo(void *info) {
25+
Dl_info *ptr = (Dl_info *)(info);
26+
__msan_unpoison(ptr, sizeof(*ptr));
27+
if (ptr->dli_fname)
28+
__msan_unpoison(ptr->dli_fname, internal_strlen(ptr->dli_fname) + 1);
29+
if (ptr->dli_sname)
30+
__msan_unpoison(ptr->dli_sname, internal_strlen(ptr->dli_sname) + 1);
31+
}
32+
33+
#if SANITIZER_GLIBC
34+
void UnpoisonDllAddr1ExtraInfo(void **extra_info, int flags) {
35+
if (flags == RTLD_DL_SYMENT) {
36+
__msan_unpoison(extra_info, sizeof(void *));
37+
38+
const ElfW(Sym) *s = (const ElfW(Sym) *)*((const ElfW(Sym) **)(extra_info));
39+
__msan_unpoison(s, sizeof(ElfW(Sym)));
40+
} else if (flags == RTLD_DL_LINKMAP) {
41+
__msan_unpoison(extra_info, sizeof(void *));
42+
43+
struct link_map *map = *((struct link_map **)(extra_info));
44+
45+
// Walk forward
46+
for (auto *ptr = map; ptr; ptr = ptr->l_next) {
47+
__msan_unpoison(ptr, sizeof(struct link_map));
48+
if (ptr->l_name)
49+
__msan_unpoison(ptr->l_name, internal_strlen(ptr->l_name) + 1);
50+
}
51+
52+
if (!map)
53+
return;
54+
55+
// Walk backward
56+
for (auto *ptr = map->l_prev; ptr; ptr = ptr->l_prev) {
57+
__msan_unpoison(ptr, sizeof(struct link_map));
58+
if (ptr->l_name)
59+
__msan_unpoison(ptr->l_name, internal_strlen(ptr->l_name) + 1);
60+
}
61+
}
62+
}
63+
#endif
64+
65+
} // namespace __msan

compiler-rt/lib/msan/msan_dl.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===-- msan_dl.h ---------------------------------------------------------===//
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+
// This file is a part of MemorySanitizer.
10+
//
11+
// Helper functions for unpoisoning results of dladdr and dladdr1.
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef MSAN_DL_H
15+
#define MSAN_DL_H
16+
17+
#include "msan.h"
18+
#include "sanitizer_common/sanitizer_common.h"
19+
20+
namespace __msan {
21+
22+
void UnpoisonDllAddrInfo(void *info);
23+
24+
#if SANITIZER_GLIBC
25+
void UnpoisonDllAddr1ExtraInfo(void **extra_info, int flags);
26+
#endif
27+
28+
} // namespace __msan
29+
30+
#endif // MSAN_DL_H

compiler-rt/lib/msan/msan_interceptors.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "interception/interception.h"
2020
#include "msan.h"
2121
#include "msan_chained_origin_depot.h"
22+
#include "msan_dl.h"
2223
#include "msan_origin.h"
2324
#include "msan_poisoning.h"
2425
#include "msan_report.h"
@@ -1520,26 +1521,31 @@ INTERCEPTOR(const char *, strsignal, int sig) {
15201521
return res;
15211522
}
15221523

1523-
struct dlinfo {
1524-
char *dli_fname;
1525-
void *dli_fbase;
1526-
char *dli_sname;
1527-
void *dli_saddr;
1528-
};
1529-
1530-
INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) {
1524+
INTERCEPTOR(int, dladdr, void *addr, void *info) {
15311525
void *ctx;
15321526
COMMON_INTERCEPTOR_ENTER(ctx, dladdr, addr, info);
15331527
int res = REAL(dladdr)(addr, info);
1528+
if (res != 0)
1529+
UnpoisonDllAddrInfo(info);
1530+
return res;
1531+
}
1532+
1533+
#if SANITIZER_GLIBC
1534+
INTERCEPTOR(int, dladdr1, void *addr, void *info, void **extra_info,
1535+
int flags) {
1536+
void *ctx;
1537+
COMMON_INTERCEPTOR_ENTER(ctx, dladdr1, addr, info, extra_info, flags);
1538+
int res = REAL(dladdr1)(addr, info, extra_info, flags);
15341539
if (res != 0) {
1535-
__msan_unpoison(info, sizeof(*info));
1536-
if (info->dli_fname)
1537-
__msan_unpoison(info->dli_fname, internal_strlen(info->dli_fname) + 1);
1538-
if (info->dli_sname)
1539-
__msan_unpoison(info->dli_sname, internal_strlen(info->dli_sname) + 1);
1540+
UnpoisonDllAddrInfo(info);
1541+
UnpoisonDllAddr1ExtraInfo(extra_info, flags);
15401542
}
15411543
return res;
15421544
}
1545+
# define MSAN_MAYBE_INTERCEPT_DLADDR1 MSAN_INTERCEPT_FUNC(dladdr1)
1546+
#else
1547+
#define MSAN_MAYBE_INTERCEPT_DLADDR1
1548+
#endif
15431549

15441550
INTERCEPTOR(char *, dlerror, int fake) {
15451551
void *ctx;
@@ -1788,6 +1794,7 @@ void InitializeInterceptors() {
17881794
MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
17891795
INTERCEPT_FUNCTION(strsignal);
17901796
INTERCEPT_FUNCTION(dladdr);
1797+
MSAN_MAYBE_INTERCEPT_DLADDR1;
17911798
INTERCEPT_FUNCTION(dlerror);
17921799
INTERCEPT_FUNCTION(dl_iterate_phdr);
17931800
INTERCEPT_FUNCTION(getrusage);

compiler-rt/test/msan/dladdr1_test.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* RUN: %clang_msan -g %s -o %t
2+
RUN: %clang_msan -g %s -DBUILD_SO -fPIC -o %t-so.so -shared
3+
RUN: %run %t 2>&1 | FileCheck %s
4+
5+
REQUIRES: glibc{{.*}}
6+
*/
7+
8+
#define _GNU_SOURCE
9+
10+
#ifndef BUILD_SO
11+
#include <assert.h>
12+
#include <dlfcn.h>
13+
#include <elf.h>
14+
#include <link.h>
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
18+
typedef volatile long *(* get_t)();
19+
get_t GetTls;
20+
21+
int main(int argc, char *argv[]) {
22+
char path[4096];
23+
snprintf(path, sizeof(path), "%s-so.so", argv[0]);
24+
int i;
25+
26+
void *handle = dlopen(path, RTLD_LAZY);
27+
if (!handle) fprintf(stderr, "%s\n", dlerror());
28+
assert(handle != 0);
29+
GetTls = (get_t)dlsym(handle, "GetTls");
30+
assert(dlerror() == 0);
31+
32+
{
33+
printf("Testing RTLD_DL_LINKMAP\n");
34+
fflush(stdout);
35+
36+
Dl_info info;
37+
struct link_map *map_ptr;
38+
int ret = dladdr1(GetTls, &info, (void**)(&map_ptr), RTLD_DL_LINKMAP);
39+
assert(ret != 0);
40+
printf("fname: %s\n", info.dli_fname);
41+
printf("fbase: %p\n", info.dli_fbase);
42+
printf("sname: %s\n", info.dli_sname);
43+
// CHECK: sname: GetTls
44+
printf("saddr: %p\n", info.dli_saddr);
45+
46+
assert(map_ptr != NULL);
47+
printf("map_ptr: %p\n", map_ptr);
48+
fflush(stdout);
49+
50+
// Find the start of the link map
51+
while(map_ptr->l_prev != NULL) {
52+
fflush(stdout);
53+
map_ptr = map_ptr->l_prev;
54+
}
55+
56+
fflush(stdout);
57+
while(map_ptr != NULL) {
58+
assert(map_ptr->l_name != NULL);
59+
printf("0x%lx: '%s', %p\n", map_ptr->l_addr, map_ptr->l_name, map_ptr->l_ld);
60+
fflush(stdout);
61+
map_ptr = map_ptr->l_next;
62+
}
63+
// CHECK: libc.so
64+
// CHECK: dladdr1_test
65+
}
66+
67+
// Test RTLD_DL_SYMENT
68+
69+
{
70+
printf("Testing RTLD_DL_SYMENT\n");
71+
fflush(stdout);
72+
73+
Dl_info info;
74+
ElfW(Sym) *sym;
75+
int ret = dladdr1(GetTls, &info, (void**)(&sym), RTLD_DL_SYMENT);
76+
assert(ret != 0);
77+
printf("fname: %s\n", info.dli_fname);
78+
printf("fbase: %p\n", info.dli_fbase);
79+
printf("sname: %s\n", info.dli_sname);
80+
// CHECK: sname: GetTls
81+
printf("saddr: %p\n", info.dli_saddr);
82+
83+
printf("sym: %d %d %d %d %lu %lu\n",
84+
sym->st_name, sym->st_info, sym->st_other,
85+
sym->st_shndx, sym->st_value, sym->st_size);
86+
// CHECK: sym:
87+
}
88+
return 0;
89+
}
90+
#else // BUILD_SO
91+
long var;
92+
long *GetTls() {
93+
return &var;
94+
}
95+
#endif

llvm/utils/gn/secondary/compiler-rt/lib/msan/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ static_library("msan") {
2525
"msan_allocator.h",
2626
"msan_chained_origin_depot.cpp",
2727
"msan_chained_origin_depot.h",
28+
"msan_dl.cpp",
29+
"msan_dl.h",
2830
"msan_flags.h",
2931
"msan_flags.inc",
3032
"msan_interceptors.cpp",

0 commit comments

Comments
 (0)