[compiler-rt] Poison last word of FakeFrame (PR #133689)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 7 23:52:57 PDT 2025


https://github.com/brandb97 updated https://github.com/llvm/llvm-project/pull/133689

>From 03cd392eb1bb027cf70421e4e9f0eb6e5180637b Mon Sep 17 00:00:00 2001
From: lidongyan <502024330056 at smail.nju.edu.cn>
Date: Mon, 31 Mar 2025 15:14:45 +0800
Subject: [PATCH 1/3] Poison last word of FakeFrame

---
 compiler-rt/lib/asan/asan_fake_stack.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index 7443ff166984d..f68dd31ab1610 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -107,7 +107,12 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
     FakeFrame *res = reinterpret_cast<FakeFrame *>(
         GetFrame(stack_size_log, class_id, pos));
     res->real_stack = real_stack;
-    *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
+    u8 **saved_flag_ptr = SavedFlagPtr(reinterpret_cast<uptr>(res), class_id);
+    *saved_flag_ptr = &flags[pos];
+
+    // Poison the last word of FakeFrame
+    u8 *shadow = reinterpret_cast<u8*>(MemToShadow(reinterpret_cast<uptr>(saved_flag_ptr)));
+    *shadow = kMagic1;
     return res;
   }
   return nullptr; // We are out of fake stack.

>From be3221b82d9c12bceaa16236be9df191e1a0f5f3 Mon Sep 17 00:00:00 2001
From: brandb97 <77328395+brandb97 at users.noreply.github.com>
Date: Wed, 2 Apr 2025 20:43:09 +0800
Subject: [PATCH 2/3] replace oxf5 with 0xf3

replace kAsanAfterReturnMagic with kAsanStackRightRedzoneMagic
---
 compiler-rt/lib/asan/asan_fake_stack.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index f68dd31ab1610..590c759d76078 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -112,7 +112,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
 
     // Poison the last word of FakeFrame
     u8 *shadow = reinterpret_cast<u8*>(MemToShadow(reinterpret_cast<uptr>(saved_flag_ptr)));
-    *shadow = kMagic1;
+    *shadow = kAsanStackRightRedzoneMagic;
     return res;
   }
   return nullptr; // We are out of fake stack.

>From 568c2c8a0c5c18441957ee6bc38225cdafaf81cc Mon Sep 17 00:00:00 2001
From: lidongyan <502024330056 at smail.nju.edu.cn>
Date: Tue, 8 Apr 2025 14:52:27 +0800
Subject: [PATCH 3/3] add test & use SetShadow

---
 compiler-rt/lib/asan/asan_fake_stack.cpp      | 22 ++++++++----
 .../asan/TestCases/fakeframe-left-redzone.cpp | 36 +++++++++++++++++++
 2 files changed, 52 insertions(+), 6 deletions(-)
 create mode 100644 compiler-rt/test/asan/TestCases/fakeframe-left-redzone.cpp

diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp
index 590c759d76078..7ce7c527a7167 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cpp
+++ b/compiler-rt/lib/asan/asan_fake_stack.cpp
@@ -27,6 +27,7 @@ static const u64 kAllocaRedzoneMask = 31UL;
 
 // For small size classes inline PoisonShadow for better performance.
 ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
+  CHECK(AddrIsAlignedByGranularity(ptr + size));
   u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
   if (ASAN_SHADOW_SCALE == 3 && class_id <= 6) {
     // This code expects ASAN_SHADOW_SCALE=3.
@@ -107,12 +108,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
     FakeFrame *res = reinterpret_cast<FakeFrame *>(
         GetFrame(stack_size_log, class_id, pos));
     res->real_stack = real_stack;
-    u8 **saved_flag_ptr = SavedFlagPtr(reinterpret_cast<uptr>(res), class_id);
-    *saved_flag_ptr = &flags[pos];
-
-    // Poison the last word of FakeFrame
-    u8 *shadow = reinterpret_cast<u8*>(MemToShadow(reinterpret_cast<uptr>(saved_flag_ptr)));
-    *shadow = kAsanStackRightRedzoneMagic;
+    *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
     return res;
   }
   return nullptr; // We are out of fake stack.
@@ -236,6 +232,13 @@ static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
     return 0;  // Out of fake stack.
   uptr ptr = reinterpret_cast<uptr>(ff);
   SetShadow(ptr, size, class_id, 0);
+
+  // Poison everything beyond user size, use kNumberOfSizeClasses to prevent
+  // SetShadow from inlining PoisonShadow
+  SetShadow(reinterpret_cast<uptr>(ptr + size),
+            FakeStack::BytesInSizeClass(class_id) - size, kNumberOfSizeClasses,
+            kAsanStackRightRedzoneMagic);
+
   return ptr;
 }
 
@@ -249,6 +252,13 @@ static ALWAYS_INLINE uptr OnMallocAlways(uptr class_id, uptr size) {
     return 0;  // Out of fake stack.
   uptr ptr = reinterpret_cast<uptr>(ff);
   SetShadow(ptr, size, class_id, 0);
+
+  // Poison everything beyond user size, use kNumberOfSizeClasses to prevent
+  // SetShadow from inlining PoisonShadow
+  SetShadow(reinterpret_cast<uptr>(ptr + size),
+            FakeStack::BytesInSizeClass(class_id) - size, kNumberOfSizeClasses,
+            kAsanStackRightRedzoneMagic);
+
   return ptr;
 }
 
diff --git a/compiler-rt/test/asan/TestCases/fakeframe-left-redzone.cpp b/compiler-rt/test/asan/TestCases/fakeframe-left-redzone.cpp
new file mode 100644
index 0000000000000..2ce050236e3dc
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/fakeframe-left-redzone.cpp
@@ -0,0 +1,36 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t -fsanitize-address-use-after-return=always && not %run %t 2>&1 | FileCheck %s
+
+#include "defines.h"
+#include <stdint.h>
+#include <string.h>
+
+#define kFrameSize (2048)
+#define KFrameSizeMask (0x07ff)
+
+ATTRIBUTE_NOINLINE
+char *pretend_to_do_something(char *x) {
+  __asm__ __volatile__("" : : "r"(x) : "memory");
+  return x;
+}
+
+ATTRIBUTE_NOINLINE
+char *OverwriteFakeFrameLastWord() {
+  char x[1024];
+  memset(x, 0, sizeof(x));
+  uint64_t ptr_int = (reinterpret_cast<uint64_t>(x) & ~KFrameSizeMask) +
+                     kFrameSize - sizeof(char **);
+  char **ptr = reinterpret_cast<char **>(ptr_int);
+  *ptr = nullptr;
+  return pretend_to_do_something(x);
+}
+
+int main(int argc, char **argv) {
+  char *x = OverwriteFakeFrameLastWord();
+  // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow on address
+  // CHECK: is located in stack of thread T0 at offset {{2040|2044}} in frame
+  // CHECK:  in OverwriteFakeFrameLastWord{{.*}}fakeframe-left-redzone.cpp:
+  // CHECK: [{{16|32}}, {{1040|1056}}) 'x'
+  pretend_to_do_something(x);
+  return 0;
+}
\ No newline at end of file



More information about the llvm-commits mailing list