Skip to content

[scudo] Modify header corrupption error message #126812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 12, 2025

Conversation

cferris1000
Copy link
Contributor

Update the error message to be explicit that this is likely due to memory corruption.

In addition, check if the chunk header is all zero, which could mean corruption or an attempt to free a pointer after the memory has been released to the kernel. This case results in a slightly different error message to also indicate this could still be a double free.

Update the error message to be explicit that this is likely due
to memory corruption.

In addition, check if the chunk header is all zero, which could mean
corruption or an attempt to free a pointer after the memory has been
released to the kernel. This case results in a slightly different
error message to also indicate this could still be a double free.
@llvmbot
Copy link
Member

llvmbot commented Feb 11, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Christopher Ferris (cferris1000)

Changes

Update the error message to be explicit that this is likely due to memory corruption.

In addition, check if the chunk header is all zero, which could mean corruption or an attempt to free a pointer after the memory has been released to the kernel. This case results in a slightly different error message to also indicate this could still be a double free.


Full diff: https://github.com/llvm/llvm-project/pull/126812.diff

4 Files Affected:

  • (modified) compiler-rt/lib/scudo/standalone/chunk.h (+1-1)
  • (modified) compiler-rt/lib/scudo/standalone/report.cpp (+13-3)
  • (modified) compiler-rt/lib/scudo/standalone/report.h (+1-2)
  • (modified) compiler-rt/lib/scudo/standalone/tests/report_test.cpp (+17-1)
diff --git a/compiler-rt/lib/scudo/standalone/chunk.h b/compiler-rt/lib/scudo/standalone/chunk.h
index 9228df0471890..a1b8e723d4cb5 100644
--- a/compiler-rt/lib/scudo/standalone/chunk.h
+++ b/compiler-rt/lib/scudo/standalone/chunk.h
@@ -125,7 +125,7 @@ inline void loadHeader(u32 Cookie, const void *Ptr,
   *NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
   if (UNLIKELY(NewUnpackedHeader->Checksum !=
                computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader)))
-    reportHeaderCorruption(const_cast<void *>(Ptr));
+    reportHeaderCorruption(NewUnpackedHeader, const_cast<void *>(Ptr));
 }
 
 inline bool isValid(u32 Cookie, const void *Ptr,
diff --git a/compiler-rt/lib/scudo/standalone/report.cpp b/compiler-rt/lib/scudo/standalone/report.cpp
index 9cef0adc0bb31..14a4066d37200 100644
--- a/compiler-rt/lib/scudo/standalone/report.cpp
+++ b/compiler-rt/lib/scudo/standalone/report.cpp
@@ -9,6 +9,7 @@
 #include "report.h"
 
 #include "atomic_helpers.h"
+#include "chunk.h"
 #include "string_utils.h"
 
 #include <stdarg.h>
@@ -65,9 +66,18 @@ void NORETURN reportInvalidFlag(const char *FlagType, const char *Value) {
 
 // The checksum of a chunk header is invalid. This could be caused by an
 // {over,under}write of the header, a pointer that is not an actual chunk.
-void NORETURN reportHeaderCorruption(void *Ptr) {
-  ScopedErrorReport Report;
-  Report.append("corrupted chunk header at address %p\n", Ptr);
+void NORETURN reportHeaderCorruption(void *Header, void *Ptr) {
+  ScopedErrorReport Report;
+  Report.append("corrupted chunk header at address %p", Ptr);
+  if (*static_cast<Chunk::PackedHeader *>(Header) == 0U) {
+    // Header all zero, which could indicate that this might be a pointer that
+    // has been double freed but the memory has been released to the kernel.
+    Report.append(": chunk header is zero and might indicate memory corruption "
+                  "or a double free\n",
+                  Ptr);
+  } else {
+    Report.append(": most likely due to memory corruption\n", Ptr);
+  }
 }
 
 // The allocator was compiled with parameters that conflict with field size
diff --git a/compiler-rt/lib/scudo/standalone/report.h b/compiler-rt/lib/scudo/standalone/report.h
index a510fdaebb6de..c0214b51560e9 100644
--- a/compiler-rt/lib/scudo/standalone/report.h
+++ b/compiler-rt/lib/scudo/standalone/report.h
@@ -12,7 +12,6 @@
 #include "internal_defs.h"
 
 namespace scudo {
-
 // Reports are *fatal* unless stated otherwise.
 
 // Generic error, adds newline to end of message.
@@ -25,7 +24,7 @@ void NORETURN reportRawError(const char *Message);
 void NORETURN reportInvalidFlag(const char *FlagType, const char *Value);
 
 // Chunk header related errors.
-void NORETURN reportHeaderCorruption(void *Ptr);
+void NORETURN reportHeaderCorruption(void *Header, void *Ptr);
 
 // Sanity checks related error.
 void NORETURN reportSanityCheckError(const char *Field);
diff --git a/compiler-rt/lib/scudo/standalone/tests/report_test.cpp b/compiler-rt/lib/scudo/standalone/tests/report_test.cpp
index 6c46243053d9e..514837df1a43a 100644
--- a/compiler-rt/lib/scudo/standalone/tests/report_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/report_test.cpp
@@ -8,6 +8,7 @@
 
 #include "tests/scudo_unit_test.h"
 
+#include "chunk.h"
 #include "report.h"
 
 TEST(ScudoReportDeathTest, Check) {
@@ -20,9 +21,11 @@ TEST(ScudoReportDeathTest, Check) {
 TEST(ScudoReportDeathTest, Generic) {
   // Potentially unused if EXPECT_DEATH isn't defined.
   UNUSED void *P = reinterpret_cast<void *>(0x42424242U);
+  UNUSED scudo::Chunk::PackedHeader Header = {};
   EXPECT_DEATH(scudo::reportError("TEST123"), "Scudo ERROR.*TEST123");
   EXPECT_DEATH(scudo::reportInvalidFlag("ABC", "DEF"), "Scudo ERROR.*ABC.*DEF");
-  EXPECT_DEATH(scudo::reportHeaderCorruption(P), "Scudo ERROR.*42424242");
+  EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
+               "Scudo ERROR.*42424242");
   EXPECT_DEATH(scudo::reportSanityCheckError("XYZ"), "Scudo ERROR.*XYZ");
   EXPECT_DEATH(scudo::reportAlignmentTooBig(123, 456), "Scudo ERROR.*123.*456");
   EXPECT_DEATH(scudo::reportAllocationSizeTooBig(123, 456, 789),
@@ -54,6 +57,19 @@ TEST(ScudoReportDeathTest, CSpecific) {
                "Scudo ERROR.*123.*456");
 }
 
+TEST(ScudoReportDeathTest, HeaderCorruption) {
+  UNUSED void *P = reinterpret_cast<void *>(0x42424242U);
+  UNUSED scudo::Chunk::PackedHeader Header = {};
+  EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
+               "Scudo ERROR.*corrupted chunk header at address 0x.*42424242: "
+               "chunk header is zero and might indicate memory "
+               "corruption or a double free");
+  Header = 10U;
+  EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
+               "Scudo ERROR.*corrupted chunk header at address 0x.*42424242: "
+               "most likely due to memory corruption");
+}
+
 #if SCUDO_LINUX || SCUDO_TRUSTY || SCUDO_ANDROID
 #include "report_linux.h"
 

@cferris1000 cferris1000 merged commit 9db0f91 into llvm:main Feb 12, 2025
11 checks passed
@cferris1000 cferris1000 deleted the report_header branch February 12, 2025 01:41
flovent pushed a commit to flovent/llvm-project that referenced this pull request Feb 13, 2025
Update the error message to be explicit that this is likely due to
memory corruption.

In addition, check if the chunk header is all zero, which could mean
corruption or an attempt to free a pointer after the memory has been
released to the kernel. This case results in a slightly different error
message to also indicate this could still be a double free.
joaosaffran pushed a commit to joaosaffran/llvm-project that referenced this pull request Feb 14, 2025
Update the error message to be explicit that this is likely due to
memory corruption.

In addition, check if the chunk header is all zero, which could mean
corruption or an attempt to free a pointer after the memory has been
released to the kernel. This case results in a slightly different error
message to also indicate this could still be a double free.
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Feb 24, 2025
Update the error message to be explicit that this is likely due to
memory corruption.

In addition, check if the chunk header is all zero, which could mean
corruption or an attempt to free a pointer after the memory has been
released to the kernel. This case results in a slightly different error
message to also indicate this could still be a double free.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants