[compiler-rt] [HWASan] Prevent same tag for adjacent heap objects (PR #69337)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 17 07:39:08 PDT 2023
https://github.com/KonradHohentanner updated https://github.com/llvm/llvm-project/pull/69337
>From 62120e97084b17ea5d45b2b87b8128855e4bda31 Mon Sep 17 00:00:00 2001
From: Konrad Hohentanner <konrad.hohentanner at aisec.fraunhofer.de>
Date: Tue, 17 Oct 2023 13:09:32 +0000
Subject: [PATCH 1/2] [HWASan] Prevent same tag for adjacent heap objects
---
compiler-rt/lib/hwasan/hwasan_allocator.cpp | 9 +++-
compiler-rt/lib/hwasan/hwasan_thread.cpp | 29 +++++++++++++
compiler-rt/lib/hwasan/hwasan_thread.h | 2 +
.../TestCases/adjacent_tag_collisions_heap.c | 41 +++++++++++++++++++
4 files changed, 79 insertions(+), 2 deletions(-)
create mode 100644 compiler-rt/test/hwasan/TestCases/adjacent_tag_collisions_heap.c
diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
index d21ba024a20e12a..2fc9c6978145999 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
@@ -237,7 +237,10 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
atomic_load_relaxed(&hwasan_allocator_tagging_enabled) &&
flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
- tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
+ tag_t tag = t ? t->GenerateRandomNonCollidingTag((uptr)user_ptr - 1,
+ (uptr)user_ptr + size)
+ : kFallbackAllocTag;
+
uptr tag_size = orig_size ? orig_size : 1;
uptr full_granule_size = RoundDownTo(tag_size, kShadowAlignment);
user_ptr = (void *)TagMemoryAligned((uptr)user_ptr, full_granule_size, tag);
@@ -349,7 +352,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
// would make us attempt to read the memory on a UaF.
// The tag can be zero if tagging is disabled on this thread.
do {
- tag = t->GenerateRandomTag(/*num_bits=*/8);
+ tag = t->GenerateRandomNonCollidingTag((uptr)aligned_ptr - 1,
+ (uptr)aligned_ptr + orig_size,
+ /*num_bits=*/8);
} while (
UNLIKELY((tag < kShadowAlignment || tag == pointer_tag) && tag != 0));
} else {
diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp
index ce36547580e6e60..f9500ef5f99c863 100644
--- a/compiler-rt/lib/hwasan/hwasan_thread.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp
@@ -156,6 +156,35 @@ tag_t Thread::GenerateRandomTag(uptr num_bits) {
return tag;
}
+// Generate a (pseudo-)random non-zero tag and prevent collisions to neighboring
+// objects.
+tag_t Thread::GenerateRandomNonCollidingTag(uptr prev_ptr, uptr foll_ptr,
+ uptr num_bits) {
+ DCHECK_GT(num_bits, 0);
+ if (tagging_disabled_)
+ return 0;
+ tag_t tag;
+ tag_t previous_tag = *(tag_t *)MemToShadow(prev_ptr);
+ tag_t following_tag = *(tag_t *)MemToShadow(foll_ptr);
+ const uptr tag_mask = (1ULL << num_bits) - 1;
+ do {
+ if (flags()->random_tags) {
+ if (!random_buffer_) {
+ EnsureRandomStateInited();
+ random_buffer_ = random_state_ = xorshift(random_state_);
+ }
+ CHECK(random_buffer_);
+ tag = random_buffer_ & tag_mask;
+ random_buffer_ >>= num_bits;
+ } else {
+ EnsureRandomStateInited();
+ random_state_ += 1;
+ tag = random_state_ & tag_mask;
+ }
+ } while (!tag || tag == previous_tag || tag == following_tag);
+ return tag;
+}
+
void EnsureMainThreadIDIsCorrect() {
auto *t = __hwasan::GetCurrentThread();
if (t && (t->IsMainThread()))
diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h
index 9e1b438e48f771b..53fc506b86c981c 100644
--- a/compiler-rt/lib/hwasan/hwasan_thread.h
+++ b/compiler-rt/lib/hwasan/hwasan_thread.h
@@ -58,6 +58,8 @@ class Thread {
StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
tag_t GenerateRandomTag(uptr num_bits = kTagBits);
+ tag_t GenerateRandomNonCollidingTag(uptr prev_ptr, uptr foll_ptr,
+ uptr num_bits = kTagBits);
void DisableTagging() { tagging_disabled_++; }
void EnableTagging() { tagging_disabled_--; }
diff --git a/compiler-rt/test/hwasan/TestCases/adjacent_tag_collisions_heap.c b/compiler-rt/test/hwasan/TestCases/adjacent_tag_collisions_heap.c
new file mode 100644
index 000000000000000..6381c8fd1125f07
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/adjacent_tag_collisions_heap.c
@@ -0,0 +1,41 @@
+// Test that adjacent heap objects are always tagged differently to prevent unexpected under- and overflows.
+// RUN: %clang_hwasan %s -o %t
+// RUN: %env_hwasan_opts=random_tags=1,disable_allocator_tagging=0 %run %t
+
+#include <assert.h>
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/hwasan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const size_t sizes[] = {16, 32, 64, 128, 256, 512, 1024, 2048};
+
+void check_collisions_on_heap(size_t size) {
+ // Allocate 3 heap objects, which should be placed next to each other
+ void *a = malloc(size);
+ void *b = malloc(size);
+ void *c = malloc(size);
+
+ // Confirm that no object can access adjacent objects
+ assert(__hwasan_test_shadow(a, size + 1) != -1);
+ assert(__hwasan_test_shadow(b, size + 1) != -1);
+ assert(__hwasan_test_shadow(c, size + 1) != -1);
+
+ // Confirm that freeing an object does not increase bounds of objects
+ free(b);
+ assert(__hwasan_test_shadow(a, size + 1) != -1);
+ assert(__hwasan_test_shadow(b, size + 1) != -1);
+ assert(__hwasan_test_shadow(c, size + 1) != -1);
+
+ free(a);
+ free(c);
+}
+
+int main() {
+ for (unsigned i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) {
+ for (unsigned j = 0; j < 1000; j++) {
+ check_collisions_on_heap(sizes[i]);
+ }
+ }
+ return 0;
+}
>From 3dd915fb1d6ccf807583e9b67ff29b7247b76ba3 Mon Sep 17 00:00:00 2001
From: Konrad Hohentanner <konrad.hohentanner at aisec.fraunhofer.de>
Date: Tue, 17 Oct 2023 14:38:03 +0000
Subject: [PATCH 2/2] Use TaggedSize to calculate adjacent memory address
---
compiler-rt/lib/hwasan/hwasan_allocator.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
index 2fc9c6978145999..f560bcd09baa3ec 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
@@ -352,9 +352,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
// would make us attempt to read the memory on a UaF.
// The tag can be zero if tagging is disabled on this thread.
do {
- tag = t->GenerateRandomNonCollidingTag((uptr)aligned_ptr - 1,
- (uptr)aligned_ptr + orig_size,
- /*num_bits=*/8);
+ tag = t->GenerateRandomNonCollidingTag(
+ (uptr)aligned_ptr - 1, (uptr)aligned_ptr + TaggedSize(orig_size),
+ /*num_bits=*/8);
} while (
UNLIKELY((tag < kShadowAlignment || tag == pointer_tag) && tag != 0));
} else {
More information about the llvm-commits
mailing list