[compiler-rt] [tsan] Fix ASLR edge case, and improve diagnostics (PR #97125)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 28 17:08:14 PDT 2024


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/97125

>From 4d54427724583aded98ec69bf928dd453c2c63f9 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 28 Jun 2024 23:46:54 +0000
Subject: [PATCH 1/2] [tsan] Fix ASLR edge case, and improve diagnostics

In extremely rare cases (estimated 1 in 3 million), minor allocations that happen after
InitializePlatformEarly() - when the memory layout is checked for
compatibility - may result in the memory layout unexpectedly being incompatible in InitializePlatform().
We fix this by adding another memory layout check (and opportunity to
re-exec without ASLR) in InitializePlatform().

To improve future debuggability, this patch also dumps the process map
if the memory layout is unexpectedly incompatible.
---
 .../lib/tsan/rtl/tsan_platform_linux.cpp      | 27 ++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
index c723dba556ed2..6c138ba5ee882 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
@@ -215,7 +215,7 @@ void InitializeShadowMemoryPlatform() {
 #endif  // #if !SANITIZER_GO
 
 #  if !SANITIZER_GO
-static void ReExecIfNeeded() {
+static void ReExecIfNeeded(bool ignore_heap) {
   // Go maps shadow memory lazily and works fine with limited address space.
   // Unlimited stack is not a problem as well, because the executable
   // is not compiled with -pie.
@@ -266,7 +266,7 @@ static void ReExecIfNeeded() {
 
   if (reexec) {
     // Don't check the address space since we're going to re-exec anyway.
-  } else if (!CheckAndProtect(false, false, false)) {
+  } else if (!CheckAndProtect(false, ignore_heap, false)) {
     // ASLR personality check.
     // N.B. 'personality' is sometimes forbidden by sandboxes, so we only call
     // this as a last resort (when the memory mapping is incompatible and TSan
@@ -290,10 +290,10 @@ static void ReExecIfNeeded() {
       CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
       reexec = true;
     } else {
-      VReport(1,
-              "FATAL: ThreadSanitizer: memory layout is incompatible, "
-              "even though ASLR is disabled.\n"
-              "Please file a bug.\n");
+      Printf("FATAL: ThreadSanitizer: memory layout is incompatible, "
+             "even though ASLR is disabled.\n"
+             "Please file a bug.\n");
+      DumpProcessMap();
       Die();
     }
   }
@@ -376,7 +376,8 @@ void InitializePlatformEarly() {
 #  endif
 
 #  if !SANITIZER_GO
-  ReExecIfNeeded();
+  // Heap has not been allocated yet
+  ReExecIfNeeded(false);
 #  endif
 }
 
@@ -394,6 +395,17 @@ void InitializePlatform() {
 #    endif
   }
 
+  // We called ReExecIfNeeded() in InitializePlatformEarly(), but there are
+  // intervening allocations that result in an edge case:
+  // 1) InitializePlatformEarly(): memory layout is compatible
+  // 2) Intervening allocations happen
+  // 3) InitializePlatform(): memory layout is incompatible and fails
+  //    CheckAndProtect()
+#  if !SANITIZER_GO
+  // Heap has already been allocated
+  ReExecIfNeeded(true);
+#  endif
+
   // Earlier initialization steps already re-exec'ed until we got a compatible
   // memory layout, so we don't expect any more issues here.
   if (!CheckAndProtect(true, true, true)) {
@@ -401,6 +413,7 @@ void InitializePlatform() {
         "FATAL: ThreadSanitizer: unexpectedly found incompatible memory "
         "layout.\n");
     Printf("FATAL: Please file a bug.\n");
+    DumpProcessMap();
     Die();
   }
 

>From dee27439eb93d470c85352a811bf13f6ace24b50 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sat, 29 Jun 2024 00:07:47 +0000
Subject: [PATCH 2/2] Formatting

---
 compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
index 6c138ba5ee882..621c679a05db4 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
@@ -290,9 +290,10 @@ static void ReExecIfNeeded(bool ignore_heap) {
       CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
       reexec = true;
     } else {
-      Printf("FATAL: ThreadSanitizer: memory layout is incompatible, "
-             "even though ASLR is disabled.\n"
-             "Please file a bug.\n");
+      Printf(
+          "FATAL: ThreadSanitizer: memory layout is incompatible, "
+          "even though ASLR is disabled.\n"
+          "Please file a bug.\n");
       DumpProcessMap();
       Die();
     }
@@ -401,10 +402,10 @@ void InitializePlatform() {
   // 2) Intervening allocations happen
   // 3) InitializePlatform(): memory layout is incompatible and fails
   //    CheckAndProtect()
-#  if !SANITIZER_GO
+#    if !SANITIZER_GO
   // Heap has already been allocated
   ReExecIfNeeded(true);
-#  endif
+#    endif
 
   // Earlier initialization steps already re-exec'ed until we got a compatible
   // memory layout, so we don't expect any more issues here.



More information about the llvm-commits mailing list