From 1dd54691b20d8bf65156cdf35d241cfcd684cb54 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Thu, 3 Nov 2022 12:42:37 -0700 Subject: [PATCH] [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 --- compiler-rt/lib/scudo/standalone/combined.h | 9 ++++++++ .../scudo/standalone/tests/combined_test.cpp | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h index 365720d4a5f4..6b0cf879ccf0 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -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(Options) && Size != 0) + *reinterpret_cast(TaggedPtr); + if (DeleteSize && Options.get(OptionBit::DeleteSizeMismatch)) { if (UNLIKELY(DeleteSize != Size)) reportDeleteSizeMismatch(Ptr, DeleteSize, Size); diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp index 7d5cacd4c976..58d444d63793 100644 --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -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(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();