[scudo] Detect double free when running with MTE.

Try to trigger an MTE fault on double/invalid free by touching the first
byte of the allocation with the provided pointer.

Differential Revision: https://reviews.llvm.org/D137352
This commit is contained in:
Evgenii Stepanov 2022-11-03 12:42:37 -07:00
parent 87debdadaf
commit 1dd54691b2
2 changed files with 30 additions and 0 deletions

View File

@ -560,7 +560,16 @@ public:
}
}
// Try to detect deallocation with a wrong MTE tag by touching the first
// byte with a correctly tagged pointer. Skip zero-sized allocations that do
// not always store the correct tag value anywhere (for example, a zero
// size, 32 byte aligned allocation in a 32-byte size class will end up with
// header at offset 16 in the block, payload at offset 32, and no space to
// store the tag).
const uptr Size = getSize(Ptr, &Header);
if (useMemoryTagging<Params>(Options) && Size != 0)
*reinterpret_cast<volatile char *>(TaggedPtr);
if (DeleteSize && Options.get(OptionBit::DeleteSizeMismatch)) {
if (UNLIKELY(DeleteSize != Size))
reportDeleteSizeMismatch(Ptr, DeleteSize, Size);

View File

@ -395,6 +395,27 @@ SCUDO_TYPED_TEST(ScudoCombinedDeathTest, UseAfterFree) {
}
}
SCUDO_TYPED_TEST(ScudoCombinedDeathTest, FreeWithTagMismatch) {
auto *Allocator = this->Allocator.get();
if (!Allocator->useMemoryTaggingTestOnly())
return;
// Check that double free is detected.
for (scudo::uptr SizeLog = 0U; SizeLog <= 20U; SizeLog++) {
const scudo::uptr Size = 1U << SizeLog;
EXPECT_DEATH(
{
disableDebuggerdMaybe();
void *P = Allocator->allocate(Size, Origin);
scudo::uptr NewTag = (scudo::extractTag(reinterpret_cast<scudo::uptr>(P)) + 1) % 16;
void *Q = scudo::addFixedTag(scudo::untagPointer(P), NewTag);
Allocator->deallocate(Q, Origin);
},
"");
}
}
SCUDO_TYPED_TEST(ScudoCombinedDeathTest, DisableMemoryTagging) {
auto *Allocator = this->Allocator.get();