Skip to content

Commit 9db0f91

Browse files
authored
[scudo] Modify header corrupption error message (#126812)
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.
1 parent 934c97d commit 9db0f91

File tree

4 files changed

+32
-7
lines changed

4 files changed

+32
-7
lines changed

compiler-rt/lib/scudo/standalone/chunk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ inline void loadHeader(u32 Cookie, const void *Ptr,
125125
*NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
126126
if (UNLIKELY(NewUnpackedHeader->Checksum !=
127127
computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader)))
128-
reportHeaderCorruption(const_cast<void *>(Ptr));
128+
reportHeaderCorruption(NewUnpackedHeader, const_cast<void *>(Ptr));
129129
}
130130

131131
inline bool isValid(u32 Cookie, const void *Ptr,

compiler-rt/lib/scudo/standalone/report.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "report.h"
1010

1111
#include "atomic_helpers.h"
12+
#include "chunk.h"
1213
#include "string_utils.h"
1314

1415
#include <stdarg.h>
@@ -65,9 +66,18 @@ void NORETURN reportInvalidFlag(const char *FlagType, const char *Value) {
6566

6667
// The checksum of a chunk header is invalid. This could be caused by an
6768
// {over,under}write of the header, a pointer that is not an actual chunk.
68-
void NORETURN reportHeaderCorruption(void *Ptr) {
69-
ScopedErrorReport Report;
70-
Report.append("corrupted chunk header at address %p\n", Ptr);
69+
void NORETURN reportHeaderCorruption(void *Header, void *Ptr) {
70+
ScopedErrorReport Report;
71+
Report.append("corrupted chunk header at address %p", Ptr);
72+
if (*static_cast<Chunk::PackedHeader *>(Header) == 0U) {
73+
// Header all zero, which could indicate that this might be a pointer that
74+
// has been double freed but the memory has been released to the kernel.
75+
Report.append(": chunk header is zero and might indicate memory corruption "
76+
"or a double free\n",
77+
Ptr);
78+
} else {
79+
Report.append(": most likely due to memory corruption\n", Ptr);
80+
}
7181
}
7282

7383
// The allocator was compiled with parameters that conflict with field size

compiler-rt/lib/scudo/standalone/report.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "internal_defs.h"
1313

1414
namespace scudo {
15-
1615
// Reports are *fatal* unless stated otherwise.
1716

1817
// Generic error, adds newline to end of message.
@@ -25,7 +24,7 @@ void NORETURN reportRawError(const char *Message);
2524
void NORETURN reportInvalidFlag(const char *FlagType, const char *Value);
2625

2726
// Chunk header related errors.
28-
void NORETURN reportHeaderCorruption(void *Ptr);
27+
void NORETURN reportHeaderCorruption(void *Header, void *Ptr);
2928

3029
// Sanity checks related error.
3130
void NORETURN reportSanityCheckError(const char *Field);

compiler-rt/lib/scudo/standalone/tests/report_test.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "tests/scudo_unit_test.h"
1010

11+
#include "chunk.h"
1112
#include "report.h"
1213

1314
TEST(ScudoReportDeathTest, Check) {
@@ -20,9 +21,11 @@ TEST(ScudoReportDeathTest, Check) {
2021
TEST(ScudoReportDeathTest, Generic) {
2122
// Potentially unused if EXPECT_DEATH isn't defined.
2223
UNUSED void *P = reinterpret_cast<void *>(0x42424242U);
24+
UNUSED scudo::Chunk::PackedHeader Header = {};
2325
EXPECT_DEATH(scudo::reportError("TEST123"), "Scudo ERROR.*TEST123");
2426
EXPECT_DEATH(scudo::reportInvalidFlag("ABC", "DEF"), "Scudo ERROR.*ABC.*DEF");
25-
EXPECT_DEATH(scudo::reportHeaderCorruption(P), "Scudo ERROR.*42424242");
27+
EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
28+
"Scudo ERROR.*42424242");
2629
EXPECT_DEATH(scudo::reportSanityCheckError("XYZ"), "Scudo ERROR.*XYZ");
2730
EXPECT_DEATH(scudo::reportAlignmentTooBig(123, 456), "Scudo ERROR.*123.*456");
2831
EXPECT_DEATH(scudo::reportAllocationSizeTooBig(123, 456, 789),
@@ -54,6 +57,19 @@ TEST(ScudoReportDeathTest, CSpecific) {
5457
"Scudo ERROR.*123.*456");
5558
}
5659

60+
TEST(ScudoReportDeathTest, HeaderCorruption) {
61+
UNUSED void *P = reinterpret_cast<void *>(0x42424242U);
62+
UNUSED scudo::Chunk::PackedHeader Header = {};
63+
EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
64+
"Scudo ERROR.*corrupted chunk header at address 0x.*42424242: "
65+
"chunk header is zero and might indicate memory "
66+
"corruption or a double free");
67+
Header = 10U;
68+
EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
69+
"Scudo ERROR.*corrupted chunk header at address 0x.*42424242: "
70+
"most likely due to memory corruption");
71+
}
72+
5773
#if SCUDO_LINUX || SCUDO_TRUSTY || SCUDO_ANDROID
5874
#include "report_linux.h"
5975

0 commit comments

Comments
 (0)