mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 18:26:37 +00:00
[msan] Re-exec with no ASLR if memory layout is incompatible on Linux (#85142)
This ports the change from TSan (0784b1eefa
). 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 inaf2bf86a37
This commit is contained in:
parent
9ecc72f399
commit
58f7251820
@ -467,7 +467,7 @@ void __msan_init() {
|
||||
__msan_clear_on_return();
|
||||
if (__msan_get_track_origins())
|
||||
VPrintf(1, "msan_track_origins\n");
|
||||
if (!InitShadow(__msan_get_track_origins())) {
|
||||
if (!InitShadowWithReExec(__msan_get_track_origins())) {
|
||||
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
|
||||
Printf("FATAL: Disabling ASLR is known to cause this error.\n");
|
||||
|
@ -263,7 +263,7 @@ extern bool msan_init_is_running;
|
||||
extern int msan_report_count;
|
||||
|
||||
bool ProtectRange(uptr beg, uptr end);
|
||||
bool InitShadow(bool init_origins);
|
||||
bool InitShadowWithReExec(bool init_origins);
|
||||
char *GetProcSelfMaps();
|
||||
void InitializeInterceptors();
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
# include <signal.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# if SANITIZER_LINUX
|
||||
# include <sys/personality.h>
|
||||
# endif
|
||||
# include <sys/resource.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
@ -43,11 +46,13 @@ void ReportMapRange(const char *descr, uptr beg, uptr size) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
|
||||
static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {
|
||||
if (size > 0) {
|
||||
uptr end = beg + size - 1;
|
||||
if (!MemoryRangeIsAvailable(beg, end)) {
|
||||
Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end);
|
||||
if (verbose)
|
||||
Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg,
|
||||
end);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -106,7 +111,7 @@ static void CheckMemoryLayoutSanity() {
|
||||
}
|
||||
}
|
||||
|
||||
bool InitShadow(bool init_origins) {
|
||||
static bool InitShadow(bool init_origins, bool dry_run) {
|
||||
// Let user know mapping parameters first.
|
||||
VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));
|
||||
for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
|
||||
@ -116,8 +121,9 @@ bool InitShadow(bool init_origins) {
|
||||
CheckMemoryLayoutSanity();
|
||||
|
||||
if (!MEM_IS_APP(&__msan_init)) {
|
||||
Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
|
||||
reinterpret_cast<void *>(&__msan_init));
|
||||
if (!dry_run)
|
||||
Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
|
||||
reinterpret_cast<void *>(&__msan_init));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -141,22 +147,23 @@ bool InitShadow(bool init_origins) {
|
||||
if (!map && !protect) {
|
||||
CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
|
||||
|
||||
if (type == MappingDesc::ALLOCATOR &&
|
||||
!CheckMemoryRangeAvailability(start, size))
|
||||
if (dry_run && type == MappingDesc::ALLOCATOR &&
|
||||
!CheckMemoryRangeAvailability(start, size, !dry_run))
|
||||
return false;
|
||||
}
|
||||
if (map) {
|
||||
if (!CheckMemoryRangeAvailability(start, size))
|
||||
if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
|
||||
return false;
|
||||
if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
|
||||
if (!dry_run &&
|
||||
!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
|
||||
return false;
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
if (!dry_run && common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(start, size);
|
||||
}
|
||||
if (protect) {
|
||||
if (!CheckMemoryRangeAvailability(start, size))
|
||||
if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
|
||||
return false;
|
||||
if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
|
||||
if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -164,6 +171,35 @@ bool InitShadow(bool init_origins) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitShadowWithReExec(bool init_origins) {
|
||||
// Start with dry run: check layout is ok, but don't print warnings because
|
||||
// warning messages will cause tests to fail (even if we successfully re-exec
|
||||
// after the warning).
|
||||
bool success = InitShadow(__msan_get_track_origins(), true);
|
||||
if (!success) {
|
||||
# if SANITIZER_LINUX
|
||||
// Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.
|
||||
int old_personality = personality(0xffffffff);
|
||||
bool aslr_on =
|
||||
(old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
|
||||
|
||||
if (aslr_on) {
|
||||
VReport(1,
|
||||
"WARNING: MemorySanitizer: memory layout is incompatible, "
|
||||
"possibly due to high-entropy ASLR.\n"
|
||||
"Re-execing with fixed virtual address space.\n"
|
||||
"N.B. reducing ASLR entropy is preferable.\n");
|
||||
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
|
||||
ReExec();
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
// The earlier dry run didn't actually map or protect anything. Run again in
|
||||
// non-dry run mode.
|
||||
return success && InitShadow(__msan_get_track_origins(), false);
|
||||
}
|
||||
|
||||
static void MsanAtExit(void) {
|
||||
if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
|
||||
ReportStats();
|
||||
|
Loading…
x
Reference in New Issue
Block a user