Skip to content

[hwasan] Store some report data early #66682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 21, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 40 additions & 25 deletions compiler-rt/lib/hwasan/hwasan_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ class BaseReport {
access_size(access_size),
untagged_addr(UntagAddr(tagged_addr)),
ptr_tag(GetTagFromPointer(tagged_addr)),
mismatch_offset(FindMismatchOffset()),
heap(CopyHeapChunk()),
allocations(CopyAllocations()),
candidate(FindBufferOverflowCandidate()),
Expand Down Expand Up @@ -442,6 +443,7 @@ class BaseReport {
tag_t short_tags[ARRAY_SIZE(tags)] = {};
};

sptr FindMismatchOffset() const;
Shadow CopyShadow() const;
tag_t GetTagCopy(uptr addr) const;
tag_t GetShortTagCopy(uptr addr) const;
Expand All @@ -461,6 +463,7 @@ class BaseReport {
const uptr access_size = 0;
const uptr untagged_addr = 0;
const tag_t ptr_tag = 0;
const sptr mismatch_offset = 0;

const HeapChunk heap;
const Allocations allocations;
Expand All @@ -469,6 +472,37 @@ class BaseReport {
const Shadow shadow;
};

sptr BaseReport::FindMismatchOffset() const {
if (!access_size)
return 0;
sptr offset =
__hwasan_test_shadow(reinterpret_cast<void *>(tagged_addr), access_size);
CHECK_GE(offset, 0);
CHECK_LT(offset, static_cast<sptr>(access_size));
tag_t *tag_ptr =
reinterpret_cast<tag_t *>(MemToShadow(untagged_addr + offset));
tag_t mem_tag = *tag_ptr;

if (mem_tag && mem_tag < kShadowAlignment) {
tag_t *granule_ptr = reinterpret_cast<tag_t *>((untagged_addr + offset) &
~(kShadowAlignment - 1));
// If offset is 0, (untagged_addr + offset) is not aligned to granules.
// This is the offset of the leftmost accessed byte within the bad granule.
u8 in_granule_offset = (untagged_addr + offset) & (kShadowAlignment - 1);
tag_t short_tag = granule_ptr[kShadowAlignment - 1];
// The first mismatch was a short granule that matched the ptr_tag.
if (short_tag == ptr_tag) {
// If the access starts after the end of the short granule, then the first
// bad byte is the first byte of the access; otherwise it is the first
// byte past the end of the short granule
if (mem_tag > in_granule_offset) {
offset += mem_tag - in_granule_offset;
}
}
}
return offset;
}

BaseReport::Shadow BaseReport::CopyShadow() const {
Shadow result;
if (!MemIsApp(untagged_addr))
Expand Down Expand Up @@ -917,31 +951,12 @@ TagMismatchReport::~TagMismatchReport() {

Thread *t = GetCurrentThread();

sptr offset =
__hwasan_test_shadow(reinterpret_cast<void *>(tagged_addr), access_size);
CHECK_GE(offset, 0);
CHECK_LT(offset, static_cast<sptr>(access_size));
tag_t *tag_ptr =
reinterpret_cast<tag_t *>(MemToShadow(untagged_addr + offset));
tag_t mem_tag = *tag_ptr;
tag_t mem_tag = GetTagCopy(MemToShadow(untagged_addr + mismatch_offset));

Printf("%s", d.Access());
if (mem_tag && mem_tag < kShadowAlignment) {
tag_t *granule_ptr = reinterpret_cast<tag_t *>((untagged_addr + offset) &
~(kShadowAlignment - 1));
// If offset is 0, (untagged_addr + offset) is not aligned to granules.
// This is the offset of the leftmost accessed byte within the bad granule.
u8 in_granule_offset = (untagged_addr + offset) & (kShadowAlignment - 1);
tag_t short_tag = granule_ptr[kShadowAlignment - 1];
// The first mismatch was a short granule that matched the ptr_tag.
if (short_tag == ptr_tag) {
// If the access starts after the end of the short granule, then the first
// bad byte is the first byte of the access; otherwise it is the first
// byte past the end of the short granule
if (mem_tag > in_granule_offset) {
offset += mem_tag - in_granule_offset;
}
}
tag_t short_tag =
GetShortTagCopy(MemToShadow(untagged_addr + mismatch_offset));
Printf(
"%s of size %zu at %p tags: %02x/%02x(%02x) (ptr/mem) in thread T%zd\n",
is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag,
Expand All @@ -951,16 +966,16 @@ TagMismatchReport::~TagMismatchReport() {
is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag,
mem_tag, t->unique_id());
}
if (offset != 0)
Printf("Invalid access starting at offset %zu\n", offset);
if (mismatch_offset)
Printf("Invalid access starting at offset %zu\n", mismatch_offset);
Printf("%s", d.Default());

stack->Print();

PrintAddressDescription();
t->Announce();

PrintTags(untagged_addr + offset);
PrintTags(untagged_addr + mismatch_offset);

if (registers_frame)
ReportRegisters(registers_frame, pc);
Expand Down