Skip to content

Commit bae9527

Browse files
committed
[hwasan] Add report for wild frees.
Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D107577
1 parent 970129a commit bae9527

File tree

7 files changed

+113
-12
lines changed

7 files changed

+113
-12
lines changed

compiler-rt/lib/hwasan/hwasan_allocator.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,21 +201,35 @@ static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
201201
return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
202202
}
203203

204+
static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr,
205+
void *tagged_ptr) {
206+
// This function can return true if halt_on_error is false.
207+
if (!allocator.PointerIsMine(untagged_ptr) ||
208+
!PointerAndMemoryTagsMatch(tagged_ptr)) {
209+
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
210+
return true;
211+
}
212+
return false;
213+
}
214+
204215
static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
205216
CHECK(tagged_ptr);
206217
HWASAN_FREE_HOOK(tagged_ptr);
207-
208-
if (!PointerAndMemoryTagsMatch(tagged_ptr))
209-
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
210-
211218
void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
212219
? UntagPtr(tagged_ptr)
213220
: tagged_ptr;
221+
if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr))
222+
return;
223+
214224
void *aligned_ptr = reinterpret_cast<void *>(
215225
RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
216226
tag_t pointer_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr));
217227
Metadata *meta =
218228
reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
229+
if (!meta) {
230+
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
231+
return;
232+
}
219233
uptr orig_size = meta->get_requested_size();
220234
u32 free_context_id = StackDepotPut(*stack);
221235
u32 alloc_context_id = meta->alloc_context_id;
@@ -278,13 +292,15 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
278292

279293
static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
280294
uptr new_size, uptr alignment) {
281-
if (!PointerAndMemoryTagsMatch(tagged_ptr_old))
282-
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr_old));
283-
295+
void *untagged_ptr_old =
296+
InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr_old))
297+
? UntagPtr(tagged_ptr_old)
298+
: tagged_ptr_old;
299+
if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old))
300+
return nullptr;
284301
void *tagged_ptr_new =
285302
HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
286303
if (tagged_ptr_old && tagged_ptr_new) {
287-
void *untagged_ptr_old = UntagPtr(tagged_ptr_old);
288304
Metadata *meta =
289305
reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
290306
internal_memcpy(
@@ -305,6 +321,8 @@ static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
305321
}
306322

307323
HwasanChunkView FindHeapChunkByAddress(uptr address) {
324+
if (!allocator.PointerIsMine(reinterpret_cast<void *>(address)))
325+
return HwasanChunkView();
308326
void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address));
309327
if (!block)
310328
return HwasanChunkView();

compiler-rt/lib/hwasan/hwasan_report.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,12 @@ void PrintAddressDescription(
372372
int num_descriptions_printed = 0;
373373
uptr untagged_addr = UntagAddr(tagged_addr);
374374

375+
if (MemIsShadow(untagged_addr)) {
376+
Printf("%s%p is HWAsan shadow memory.\n%s", d.Location(), untagged_addr,
377+
d.Default());
378+
return;
379+
}
380+
375381
// Print some very basic information about the address, if it's a heap.
376382
HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
377383
if (uptr beg = chunk.Beg()) {
@@ -559,8 +565,15 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
559565

560566
uptr untagged_addr = UntagAddr(tagged_addr);
561567
tag_t ptr_tag = GetTagFromPointer(tagged_addr);
562-
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
563-
tag_t mem_tag = *tag_ptr;
568+
tag_t *tag_ptr = nullptr;
569+
tag_t mem_tag = 0;
570+
if (MemIsApp(untagged_addr)) {
571+
tag_ptr = reinterpret_cast<tag_t *>(MemToShadow(untagged_addr));
572+
if (MemIsShadow(reinterpret_cast<uptr>(tag_ptr)))
573+
mem_tag = *tag_ptr;
574+
else
575+
tag_ptr = nullptr;
576+
}
564577
Decorator d;
565578
Printf("%s", d.Error());
566579
uptr pc = GetTopPc(stack);
@@ -574,14 +587,16 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
574587
SanitizerToolName, bug_type, untagged_addr, pc);
575588
}
576589
Printf("%s", d.Access());
577-
Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag);
590+
if (tag_ptr)
591+
Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag);
578592
Printf("%s", d.Default());
579593

580594
stack->Print();
581595

582596
PrintAddressDescription(tagged_addr, 0, nullptr);
583597

584-
PrintTagsAroundAddr(tag_ptr);
598+
if (tag_ptr)
599+
PrintTagsAroundAddr(tag_ptr);
585600

586601
ReportErrorSummary(bug_type, stack);
587602
}

compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ class SizeClassAllocator64 {
282282
CHECK(kMetadataSize);
283283
uptr class_id = GetSizeClass(p);
284284
uptr size = ClassIdToSize(class_id);
285+
if (!size)
286+
return nullptr;
285287
uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
286288
uptr region_beg = GetRegionBeginBySizeClass(class_id);
287289
return reinterpret_cast<void *>(GetMetadataEnd(region_beg) -
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
2+
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
6+
#include <sanitizer/hwasan_interface.h>
7+
8+
int main() {
9+
__hwasan_enable_allocator_tagging();
10+
char *p = (char *)malloc(1);
11+
fprintf(stderr, "ALLOC %p\n", __hwasan_tag_pointer(p, 0));
12+
// CHECK: ALLOC {{[0x]+}}[[ADDR:.*]]
13+
free(p - 8);
14+
// CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}}
15+
// CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in free
16+
// CHECK: #1 {{.*}} in main {{.*}}wild-free-close.c:[[@LINE-3]]
17+
// CHECK: is located 8 bytes to the left of 1-byte region [{{[0x]+}}{{.*}}[[ADDR]]
18+
// CHECK-NOT: Segmentation fault
19+
// CHECK-NOT: SIGSEGV
20+
return 0;
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
2+
3+
#include <stdlib.h>
4+
5+
int main() {
6+
char *p = (char *)malloc(1);
7+
realloc(p + 0x10000000000, 2);
8+
// CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}}
9+
// CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in realloc
10+
// CHECK: #1 {{.*}} in main {{.*}}wild-free-realloc.c:[[@LINE-3]]
11+
// CHECK-NOT: Segmentation fault
12+
// CHECK-NOT: SIGSEGV
13+
return 0;
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
2+
3+
#include <stdlib.h>
4+
5+
extern void *__hwasan_shadow_memory_dynamic_address;
6+
7+
int main() {
8+
char *p = (char *)malloc(1);
9+
free(__hwasan_shadow_memory_dynamic_address);
10+
// CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{[0x]+}}[[PTR:.*]] at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}}
11+
// CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in free
12+
// CHECK: #1 {{.*}} in main {{.*}}wild-free-shadow.c:[[@LINE-3]]
13+
// CHECK: {{[0x]+}}{{.*}}[[PTR]] is HWAsan shadow memory.
14+
// CHECK-NOT: Segmentation fault
15+
// CHECK-NOT: SIGSEGV
16+
return 0;
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
2+
3+
#include <stdlib.h>
4+
5+
int main() {
6+
char *p = (char *)malloc(1);
7+
free(p + 0x10000000000);
8+
// CHECK: ERROR: HWAddressSanitizer: invalid-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}}
9+
// CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in free
10+
// CHECK: #1 {{.*}} in main {{.*}}wild-free.c:[[@LINE-3]]
11+
// CHECK-NOT: Segmentation fault
12+
// CHECK-NOT: SIGSEGV
13+
return 0;
14+
}

0 commit comments

Comments
 (0)