Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c2a5703

Browse files
thurstondtstellar
authored andcommitted
[msan] Re-exec with no ASLR if memory layout is incompatible on Linux (llvm#85142)
This ports the change from TSan (llvm@0784b1e). Testing notes: run 'sudo sysctl vm.mmap_rnd_bits=32; ninja check-msan' before and after this patch. N.B. aggressive ASLR may also cause the app to overlap with the allocator region; for MSan, this was fixed in llvm@af2bf86 (cherry picked from commit 58f7251)
1 parent b74f615 commit c2a5703

File tree

3 files changed

+50
-14
lines changed

3 files changed

+50
-14
lines changed

compiler-rt/lib/msan/msan.cpp

+1-1
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

+1-1
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

+48-12
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

@@ -141,29 +147,59 @@ bool InitShadow(bool init_origins) {
141147
if (!map && !protect) {
142148
CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
143149

144-
if (type == MappingDesc::ALLOCATOR &&
145-
!CheckMemoryRangeAvailability(start, size))
150+
if (dry_run && type == MappingDesc::ALLOCATOR &&
151+
!CheckMemoryRangeAvailability(start, size, !dry_run))
146152
return false;
147153
}
148154
if (map) {
149-
if (!CheckMemoryRangeAvailability(start, size))
155+
if (dry_run && !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 (dry_run && !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+
return success && InitShadow(__msan_get_track_origins(), false);
201+
}
202+
167203
static void MsanAtExit(void) {
168204
if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
169205
ReportStats();

0 commit comments

Comments
 (0)