Skip to content

Commit 0c878b6

Browse files
committed
[msan] Re-exec with no ASLR if memory layout is incompatible on Linux
This ports the change from TSan (0784b1e). A key difference is that TSan initializes the allocator prior to CheckAndProtect, while MSan initializes the allocator afterwards; this slightly simplifies the MSan patch. Nonetheless, we need to check that the allocator layout is compatible with ASLR. Since the information is not readily available in msan.h, we duplicate the information from msan_allocator.cpp, and create a new MappingDesc::ALLOCATOR type. Testing notes: run 'sudo sysctl vm.mmap_rnd_bits=32; ninja check-msan' before and after this patch.
1 parent af2bf86 commit 0c878b6

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

compiler-rt/lib/msan/msan.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ void __msan_init() {
467467
__msan_clear_on_return();
468468
if (__msan_get_track_origins())
469469
VPrintf(1, "msan_track_origins\n");
470-
if (!InitShadow(__msan_get_track_origins())) {
470+
if (!InitShadowWithReExec(__msan_get_track_origins())) {
471471
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
472472
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
473473
Printf("FATAL: Disabling ASLR is known to cause this error.\n");

compiler-rt/lib/msan/msan.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ extern bool msan_init_is_running;
263263
extern int msan_report_count;
264264

265265
bool ProtectRange(uptr beg, uptr end);
266-
bool InitShadow(bool init_origins);
266+
bool InitShadowWithReExec(bool init_origins);
267267
char *GetProcSelfMaps();
268268
void InitializeInterceptors();
269269

compiler-rt/lib/msan/msan_linux.cpp

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
# include <signal.h>
2121
# include <stdio.h>
2222
# include <stdlib.h>
23+
# if SANITIZER_LINUX
24+
# include <sys/personality.h>
25+
# endif
2326
# include <sys/resource.h>
2427
# include <sys/time.h>
2528
# include <unistd.h>
@@ -43,11 +46,13 @@ void ReportMapRange(const char *descr, uptr beg, uptr size) {
4346
}
4447
}
4548

46-
static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
49+
static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {
4750
if (size > 0) {
4851
uptr end = beg + size - 1;
4952
if (!MemoryRangeIsAvailable(beg, end)) {
50-
Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end);
53+
if (verbose)
54+
Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg,
55+
end);
5156
return false;
5257
}
5358
}
@@ -106,7 +111,7 @@ static void CheckMemoryLayoutSanity() {
106111
}
107112
}
108113

109-
bool InitShadow(bool init_origins) {
114+
static bool InitShadow(bool init_origins, bool dry_run) {
110115
// Let user know mapping parameters first.
111116
VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));
112117
for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
@@ -116,8 +121,9 @@ bool InitShadow(bool init_origins) {
116121
CheckMemoryLayoutSanity();
117122

118123
if (!MEM_IS_APP(&__msan_init)) {
119-
Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
120-
reinterpret_cast<void *>(&__msan_init));
124+
if (!dry_run)
125+
Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
126+
reinterpret_cast<void *>(&__msan_init));
121127
return false;
122128
}
123129

@@ -142,28 +148,60 @@ bool InitShadow(bool init_origins) {
142148
CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
143149

144150
if (type == MappingDesc::ALLOCATOR &&
145-
!CheckMemoryRangeAvailability(start, size))
151+
!CheckMemoryRangeAvailability(start, size, !dry_run))
146152
return false;
147153
}
148154
if (map) {
149-
if (!CheckMemoryRangeAvailability(start, size))
155+
if (!CheckMemoryRangeAvailability(start, size, !dry_run))
150156
return false;
151-
if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
157+
if (!dry_run &&
158+
!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
152159
return false;
153-
if (common_flags()->use_madv_dontdump)
160+
if (!dry_run && common_flags()->use_madv_dontdump)
154161
DontDumpShadowMemory(start, size);
155162
}
156163
if (protect) {
157-
if (!CheckMemoryRangeAvailability(start, size))
164+
if (!CheckMemoryRangeAvailability(start, size, !dry_run))
158165
return false;
159-
if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
166+
if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))
160167
return false;
161168
}
162169
}
163170

164171
return true;
165172
}
166173

174+
bool InitShadowWithReExec(bool init_origins) {
175+
// Start with dry run: check layout is ok, but don't print warnings because
176+
// warning messages will cause tests to fail (even if we successfully re-exec
177+
// after the warning).
178+
bool success = InitShadow(__msan_get_track_origins(), true);
179+
if (!success) {
180+
# if SANITIZER_LINUX
181+
// Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.
182+
int old_personality = personality(0xffffffff);
183+
bool aslr_on =
184+
(old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
185+
186+
if (aslr_on) {
187+
VReport(1,
188+
"WARNING: MemorySanitizer: memory layout is incompatible, "
189+
"possibly due to high-entropy ASLR.\n"
190+
"Re-execing with fixed virtual address space.\n"
191+
"N.B. reducing ASLR entropy is preferable.\n");
192+
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
193+
ReExec();
194+
}
195+
# endif
196+
}
197+
198+
// The earlier dry run didn't actually map or protect anything. Run again in
199+
// non-dry run mode.
200+
success = InitShadow(__msan_get_track_origins(), false);
201+
202+
return success;
203+
}
204+
167205
static void MsanAtExit(void) {
168206
if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
169207
ReportStats();

0 commit comments

Comments
 (0)