[scudo] Return nullptr if a remap fails on linux. (#200537) Add a check if a fixed address mmap doesn't return the expected address. Allow a remap call to fail if the mmap fails and returns a nullptr to the caller. Fix a place where if remap fails in the secondary, it didn't do anything. Now it will unmap the original entry on failure. GitOrigin-RevId: adcd285fc4047759e4014d6568d80bb64589aded
diff --git a/mem_map_linux.cpp b/mem_map_linux.cpp index b34bef5..2a5e8b5 100644 --- a/mem_map_linux.cpp +++ b/mem_map_linux.cpp
@@ -68,6 +68,10 @@ reportMapError(errno == ENOMEM ? Size : 0); return nullptr; } + + if (Addr && reinterpret_cast<uptr>(P) != Addr) + reportMapFixedError(reinterpret_cast<uptr>(P), Addr); + #if SCUDO_ANDROID if (Name) prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, P, Size, Name); @@ -108,9 +112,7 @@ bool MemMapLinux::remapImpl(uptr Addr, uptr Size, const char *Name, uptr Flags) { void *P = mmapWrapper(Addr, Size, Name, Flags); - if (reinterpret_cast<uptr>(P) != Addr) - reportMapError(); - return true; + return reinterpret_cast<uptr>(P) == Addr; } void MemMapLinux::setMemoryPermissionImpl(uptr Addr, uptr Size, uptr Flags) {
diff --git a/report_linux.cpp b/report_linux.cpp index 432f6a0..b790b99 100644 --- a/report_linux.cpp +++ b/report_linux.cpp
@@ -33,6 +33,14 @@ reportRawError(Error.data()); } +void NORETURN reportMapFixedError(uptr ExpectedAddr, uptr RequestedAddr) { + ScopedString Error; + Error.append("Scudo ERROR: internal map failure using fixed address " + "(expected: 0x%zx requested: 0x%zx)\n", + ExpectedAddr, RequestedAddr); + reportRawError(Error.data()); +} + void NORETURN reportUnmapError(uptr Addr, uptr Size) { ScopedString Error; Error.append("Scudo ERROR: internal unmap failure (error desc=%s) Addr 0x%zx "
diff --git a/report_linux.h b/report_linux.h index aa0bb24..ffbd50f 100644 --- a/report_linux.h +++ b/report_linux.h
@@ -21,6 +21,10 @@ // hold the requested size on an out-of-memory error, 0 otherwise. void NORETURN reportMapError(uptr SizeIfOOM = 0); +// Report a fatal error when a map call using a fixed address doesn't +// return the requested address. +void NORETURN reportMapFixedError(uptr ExpectedAddr, uptr RequestedAddr); + // Report a fatal error when an unmap call fails. void NORETURN reportUnmapError(uptr Addr, uptr Size);
diff --git a/secondary.h b/secondary.h index cce8f47..a689ea9 100644 --- a/secondary.h +++ b/secondary.h
@@ -306,8 +306,13 @@ // Fuchsia does not support replacing mappings by creating a new mapping // on top so we just do the two syscalls there. Entry.Time = 0; - mapSecondary<Config>(Options, Entry.CommitBase, Entry.CommitSize, - Entry.CommitBase, MAP_NOACCESS, Entry.MemMap); + if (!mapSecondary<Config>(Options, Entry.CommitBase, Entry.CommitSize, + Entry.CommitBase, MAP_NOACCESS, + Entry.MemMap)) { + // A mmap failed, unmap and return. + unmapCallBack(Entry.MemMap); + return; + } } else { Entry.MemMap.setMemoryPermission(Entry.CommitBase, Entry.CommitSize, MAP_NOACCESS);
diff --git a/tests/report_test.cpp b/tests/report_test.cpp index e69291c..e69f5dc 100644 --- a/tests/report_test.cpp +++ b/tests/report_test.cpp
@@ -105,6 +105,9 @@ EXPECT_DEATH(scudo::reportMapError(1024U), "Scudo ERROR:.*internal map failure \\(error desc=.*\\) " "requesting 1KB"); + EXPECT_DEATH(scudo::reportMapFixedError(0x1000U, 0x2000U), + "Scudo ERROR:.*internal map failure using fixed address " + "\\(expected: 0x1000 requested: 0x2000\\)"); errno = ENOMEM; EXPECT_DEATH(scudo::reportUnmapError(0x1000U, 100U), "Scudo ERROR:.*internal unmap failure \\(error desc=.*\\) Addr "