Skip to content

Commit 0d7952c

Browse files
committed
[HWASAN] Improve tag mismatch diagnostics
Reports correct size and tags when either size is not power of two or offset to bad granule is not zero. Differential revision: https://reviews.llvm.org/D56603 llvm-svn: 351730
1 parent f608dc1 commit 0d7952c

File tree

4 files changed

+43
-13
lines changed

4 files changed

+43
-13
lines changed

compiler-rt/lib/hwasan/hwasan.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -336,14 +336,14 @@ sptr __hwasan_test_shadow(const void *p, uptr sz) {
336336
if (sz == 0)
337337
return -1;
338338
tag_t ptr_tag = GetTagFromPointer((uptr)p);
339-
if (ptr_tag == 0)
340-
return -1;
341339
uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
342340
uptr shadow_first = MemToShadow(ptr_raw);
343341
uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
344342
for (uptr s = shadow_first; s <= shadow_last; ++s)
345-
if (*(tag_t*)s != ptr_tag)
346-
return ShadowToMem(s) - ptr_raw;
343+
if (*(tag_t *)s != ptr_tag) {
344+
sptr offset = ShadowToMem(s) - ptr_raw;
345+
return offset < 0 ? 0 : offset;
346+
}
347347
return -1;
348348
}
349349

compiler-rt/lib/hwasan/hwasan_checks.h

+23-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define HWASAN_CHECKS_H
1515

1616
#include "hwasan_mapping.h"
17+
#include "sanitizer_common/sanitizer_common.h"
1718

1819
namespace __hwasan {
1920
template <unsigned X>
@@ -22,8 +23,8 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
2223
(void)p;
2324
// 0x900 is added to do not interfere with the kernel use of lower values of
2425
// brk immediate.
25-
// FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
26-
asm("brk %0\n\t" ::"n"(0x900 + X));
26+
register uptr x0 asm("x0") = p;
27+
asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X));
2728
#elif defined(__x86_64__)
2829
// INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
2930
// total. The pointer is passed via rdi.
@@ -41,6 +42,25 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
4142
// __builtin_unreachable();
4243
}
4344

45+
// Version with access size which is not power of 2
46+
template <unsigned X>
47+
__attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
48+
#if defined(__aarch64__)
49+
register uptr x0 asm("x0") = p;
50+
register uptr x1 asm("x1") = size;
51+
asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X));
52+
#elif defined(__x86_64__)
53+
// Size is stored in rsi.
54+
asm volatile(
55+
"int3\n"
56+
"nopl %c0(%%rax)\n" ::"n"(0x40 + X),
57+
"D"(p), "S"(size));
58+
#else
59+
__builtin_trap();
60+
#endif
61+
// __builtin_unreachable();
62+
}
63+
4464
enum class ErrorAction { Abort, Recover };
4565
enum class AccessType { Load, Store };
4666

@@ -69,7 +89,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
6989
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
7090
if (UNLIKELY(ptr_tag != *t)) {
7191
SigTrap<0x20 * (EA == ErrorAction::Recover) +
72-
0x10 * (AT == AccessType::Store) + 0xf>(p);
92+
0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
7393
if (EA == ErrorAction::Abort)
7494
__builtin_unreachable();
7595
}

compiler-rt/lib/hwasan/hwasan_report.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -399,13 +399,21 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
399399

400400
Thread *t = GetCurrentThread();
401401

402+
sptr offset =
403+
__hwasan_test_shadow(reinterpret_cast<void *>(tagged_addr), access_size);
404+
CHECK(offset >= 0 && offset < static_cast<sptr>(access_size));
402405
tag_t ptr_tag = GetTagFromPointer(tagged_addr);
403-
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
406+
tag_t *tag_ptr =
407+
reinterpret_cast<tag_t *>(MemToShadow(untagged_addr + offset));
404408
tag_t mem_tag = *tag_ptr;
409+
405410
Printf("%s", d.Access());
406411
Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n",
407412
is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag,
408413
mem_tag, t->unique_id());
414+
if (offset != 0)
415+
Printf("Invalid access starting at offset [%zu, %zu)\n", offset,
416+
Min(access_size, static_cast<uptr>(offset) + (1 << kShadowScale)));
409417
Printf("%s", d.Default());
410418

411419
stack->Print();

compiler-rt/test/hwasan/TestCases/mem-intrinsics.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
#include <unistd.h>
1111

1212
int main() {
13-
char Q[16];
14-
char P[16];
13+
char Q[16] __attribute__((aligned(256)));
14+
char P[16] __attribute__((aligned(256)));
1515
#if TEST_NO == 1
1616
memset(Q, 0, 32);
1717
#elif TEST_NO == 2
@@ -21,15 +21,17 @@ int main() {
2121
#endif
2222
write(STDOUT_FILENO, "recovered\n", 10);
2323
// WRITE: ERROR: HWAddressSanitizer: tag-mismatch on address
24-
// WRITE: WRITE {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
24+
// WRITE: WRITE of size 32 at {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
25+
// WRITE: Invalid access starting at offset [16, 32)
2526
// WRITE: Memory tags around the buggy address (one tag corresponds to 16 bytes):
26-
// WRITE: =>{{.*}}[[MEM_TAG]]
27+
// WRITE: =>{{.*}}[[PTR_TAG]]{{[[:space:]]\[}}[[MEM_TAG]]
2728
// WRITE-NOT: recovered
2829

2930
// READ: ERROR: HWAddressSanitizer: tag-mismatch on address
31+
// READ-NOT: Invalid access starting at offset
3032
// READ: READ {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
3133
// READ: Memory tags around the buggy address (one tag corresponds to 16 bytes):
32-
// READ: =>{{.*}}[[MEM_TAG]]
34+
// READ: =>{{.*}}[[PTR_TAG]]{{[[:space:]]\[}}[[MEM_TAG]]
3335
// READ-NOT: recovered
3436

3537
// RECOVER: recovered

0 commit comments

Comments
 (0)