Skip to content

Commit 4deda57

Browse files
committed
[DFSan] Handle mmap() calls before interceptors are installed.
InitializeInterceptors() calls dlsym(), which calls calloc(). Depending on the allocator implementation, calloc() may invoke mmap(), which results in a segfault since REAL(mmap) is still being resolved. We fix this by doing a direct syscall if interceptors haven't been fully resolved yet. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D86168
1 parent e264548 commit 4deda57

File tree

2 files changed

+51
-6
lines changed

2 files changed

+51
-6
lines changed

compiler-rt/lib/dfsan/dfsan_interceptors.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,48 @@
1111
// Interceptors for standard library functions.
1212
//===----------------------------------------------------------------------===//
1313

14+
#include <sys/syscall.h>
15+
#include <unistd.h>
16+
1417
#include "dfsan/dfsan.h"
1518
#include "interception/interception.h"
1619
#include "sanitizer_common/sanitizer_common.h"
1720

1821
using namespace __sanitizer;
1922

23+
static bool interceptors_initialized;
24+
2025
INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
2126
int fd, OFF_T offset) {
22-
void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
23-
if (res != (void*)-1)
27+
void *res;
28+
29+
// interceptors_initialized is set to true during preinit_array, when we're
30+
// single-threaded. So we don't need to worry about accessing it atomically.
31+
if (!interceptors_initialized)
32+
res = (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
33+
else
34+
res = REAL(mmap)(addr, length, prot, flags, fd, offset);
35+
36+
if (res != (void *)-1)
2437
dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
2538
return res;
2639
}
2740

2841
INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
2942
int fd, OFF64_T offset) {
3043
void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
31-
if (res != (void*)-1)
44+
if (res != (void *)-1)
3245
dfsan_set_label(0, res, RoundUpTo(length, GetPageSize()));
3346
return res;
3447
}
3548

3649
namespace __dfsan {
3750
void InitializeInterceptors() {
38-
static int inited = 0;
39-
CHECK_EQ(inited, 0);
51+
CHECK(!interceptors_initialized);
4052

4153
INTERCEPT_FUNCTION(mmap);
4254
INTERCEPT_FUNCTION(mmap64);
43-
inited = 1;
55+
56+
interceptors_initialized = true;
4457
}
4558
} // namespace __dfsan

compiler-rt/test/dfsan/interceptors.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_dfsan -fno-sanitize=dataflow -DCALLOC -c %s -o %t-calloc.o
2+
// RUN: %clang_dfsan %s %t-calloc.o -o %t
3+
// RUN: %run %t
4+
//
5+
// Tests that calling mmap() during during dfsan initialization works.
6+
7+
#include <assert.h>
8+
#include <sanitizer/dfsan_interface.h>
9+
#include <string.h>
10+
#include <sys/mman.h>
11+
#include <unistd.h>
12+
13+
#ifdef CALLOC
14+
15+
// dfsan_init() installs interceptors via dlysm(), which calls calloc().
16+
// Calling mmap() from here should work even if interceptors haven't been fully
17+
// set up yet.
18+
void *calloc(size_t Num, size_t Size) {
19+
size_t PageSize = getpagesize();
20+
Size = Size * Num;
21+
Size = (Size + PageSize - 1) & ~(PageSize - 1); // Round up to PageSize.
22+
void *Ret = mmap(NULL, Size, PROT_READ | PROT_WRITE,
23+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
24+
assert(Ret != MAP_FAILED);
25+
return Ret;
26+
}
27+
28+
#else
29+
30+
int main() { return 0; }
31+
32+
#endif // CALLOC

0 commit comments

Comments
 (0)