[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 "