[compiler-rt] 7db28dd - [hwasan] Classify stack overflow, and use after scope (#76133)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 21 17:51:18 PST 2023
Author: Vitaly Buka
Date: 2023-12-21T17:51:14-08:00
New Revision: 7db28dd3f897a8a851bb52741e2de6959a46ddf0
URL: https://github.com/llvm/llvm-project/commit/7db28dd3f897a8a851bb52741e2de6959a46ddf0
DIFF: https://github.com/llvm/llvm-project/commit/7db28dd3f897a8a851bb52741e2de6959a46ddf0.diff
LOG: [hwasan] Classify stack overflow, and use after scope (#76133)
We can't distinguish UAR and UAS, but by definition
UAR is already UAS.
Added:
compiler-rt/test/hwasan/TestCases/stack-overflow.c
compiler-rt/test/hwasan/TestCases/stack-underflow.c
Modified:
compiler-rt/lib/hwasan/hwasan_report.cpp
compiler-rt/test/hwasan/TestCases/stack-uar-dynamic.c
compiler-rt/test/hwasan/TestCases/stack-uar.c
Removed:
################################################################################
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index e9dd919d414972..5b3a99adfea7c5 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -221,22 +221,49 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
for (LocalInfo &local : frame.locals) {
if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset)
continue;
+ if (!(local.name && internal_strlen(local.name)) &&
+ !(local.function_name && internal_strlen(local.name)) &&
+ !(local.decl_file && internal_strlen(local.decl_file)))
+ continue;
tag_t obj_tag = base_tag ^ local.tag_offset;
if (obj_tag != addr_tag)
continue;
- // Calculate the offset from the object address to the faulting
- // address. Because we only store bits 4-19 of FP (bits 0-3 are
- // guaranteed to be zero), the calculation is performed mod 2^20 and may
- // harmlessly underflow if the address mod 2^20 is below the object
- // address.
- uptr obj_offset =
- (untagged_addr - fp - local.frame_offset) & (kRecordFPModulus - 1);
- if (obj_offset >= local.size)
- continue;
+ // Guess top bits of local variable from the faulting address, because
+ // we only store bits 4-19 of FP (bits 0-3 are guaranteed to be zero).
+ uptr local_beg = (fp + local.frame_offset) |
+ (untagged_addr & ~(uptr(kRecordFPModulus) - 1));
+ uptr local_end = local_beg + local.size;
+
if (!found_local) {
Printf("\nPotentially referenced stack objects:\n");
found_local = true;
}
+
+ uptr offset;
+ const char *whence;
+ const char *cause;
+ if (local_beg <= untagged_addr && untagged_addr < local_end) {
+ offset = untagged_addr - local_beg;
+ whence = "inside";
+ cause = "use-after-scope";
+ } else if (untagged_addr >= local_end) {
+ offset = untagged_addr - local_end;
+ whence = "after";
+ cause = "stack-buffer-overflow";
+ } else {
+ offset = local_beg - untagged_addr;
+ whence = "before";
+ cause = "stack-buffer-overflow";
+ }
+ Decorator d;
+ Printf("%s", d.Error());
+ Printf("Cause: %s\n", cause);
+ Printf("%s", d.Default());
+ Printf("%s", d.Location());
+ Printf("%p is located %zd bytes %s a %zd-byte region [%p,%p)\n",
+ untagged_addr, offset, whence, local_end - local_beg, local_beg,
+ local_end);
+ Printf("%s", d.Allocation());
StackTracePrinter::GetOrInit()->RenderSourceLocation(
&location, local.decl_file, local.decl_line, /* column= */ 0,
common_flags()->symbolize_vs_style,
@@ -244,6 +271,7 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
Printf(" %s in %s %s\n", local.name, local.function_name,
location.data());
location.clear();
+ Printf("%s\n", d.Default());
}
frame.Clear();
}
@@ -751,8 +779,6 @@ void BaseReport::PrintAddressDescription() const {
// Check stack first. If the address is on the stack of a live thread, we
// know it cannot be a heap / global overflow.
for (const auto &sa : allocations.stack) {
- // TODO(fmayer): figure out how to distinguish use-after-return and
- // stack-buffer-overflow.
Printf("%s", d.Error());
Printf("\nCause: stack tag-mismatch\n");
Printf("%s", d.Location());
diff --git a/compiler-rt/test/hwasan/TestCases/stack-overflow.c b/compiler-rt/test/hwasan/TestCases/stack-overflow.c
new file mode 100644
index 00000000000000..10e8d9c59e4bb6
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/stack-overflow.c
@@ -0,0 +1,25 @@
+// RUN: %clang_hwasan -g %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Stack histories currently are not recorded on x86.
+// XFAIL: target=x86_64{{.*}}
+
+__attribute((noinline)) void buggy() {
+ char c[64];
+ char *volatile p = c;
+ p[65] = 0;
+}
+
+int main() {
+ buggy();
+ // CHECK: WRITE of size 1 at
+ // CHECK: #0 {{.*}} in buggy{{.*}}stack-overflow.c:[[@LINE-6]]
+ // CHECK: Cause: stack tag-mismatch
+ // CHECK: is located in stack of thread
+ // CHECK: Potentially referenced stack objects:
+ // CHECK: Cause: stack-buffer-overflow
+ // CHECK-NEXT: 0x{{.*}} is located 1 bytes after a 64-byte region
+ // CHECK-NEXT: c in buggy {{.*}}stack-overflow.c:
+ // CHECK: Memory tags around the buggy address
+
+ // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in buggy
+}
diff --git a/compiler-rt/test/hwasan/TestCases/stack-uar-dynamic.c b/compiler-rt/test/hwasan/TestCases/stack-uar-dynamic.c
index b06568e12eba7c..7a2a11593e7afe 100644
--- a/compiler-rt/test/hwasan/TestCases/stack-uar-dynamic.c
+++ b/compiler-rt/test/hwasan/TestCases/stack-uar-dynamic.c
@@ -21,6 +21,8 @@ char *buggy(int b) {
int main() {
char *p = buggy(1);
// CHECK: Potentially referenced stack objects:
+ // CHECK-NEXT: use-after-scope
+ // CHECK-NEXT: 0x{{.*}} is located 0 bytes inside a 64-byte region
// CHECK-NEXT: c in buggy
p[0] = 0;
}
diff --git a/compiler-rt/test/hwasan/TestCases/stack-uar.c b/compiler-rt/test/hwasan/TestCases/stack-uar.c
index 29941e617ad675..8810701f0c9cac 100644
--- a/compiler-rt/test/hwasan/TestCases/stack-uar.c
+++ b/compiler-rt/test/hwasan/TestCases/stack-uar.c
@@ -50,6 +50,8 @@ int main() {
// CHECK: Cause: stack tag-mismatch
// CHECK: is located in stack of thread
// CHECK: Potentially referenced stack objects:
+ // CHECK: Cause: use-after-scope
+ // CHECK-NEXT: 0x{{.*}} is located 0 bytes inside a 2048-byte region
// CHECK-NEXT: {{zzz|yyy}} in buggy {{.*}}stack-uar.c:
// CHECK: Memory tags around the buggy address
diff --git a/compiler-rt/test/hwasan/TestCases/stack-underflow.c b/compiler-rt/test/hwasan/TestCases/stack-underflow.c
new file mode 100644
index 00000000000000..8e5174519272f4
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/stack-underflow.c
@@ -0,0 +1,25 @@
+// RUN: %clang_hwasan -g %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Stack histories currently are not recorded on x86.
+// XFAIL: target=x86_64{{.*}}
+
+__attribute((noinline)) void buggy() {
+ char c[64];
+ char *volatile p = c;
+ p[-2] = 0;
+}
+
+int main() {
+ buggy();
+ // CHECK: WRITE of size 1 at
+ // CHECK: #0 {{.*}} in buggy{{.*}}stack-underflow.c:[[@LINE-6]]
+ // CHECK: Cause: stack tag-mismatch
+ // CHECK: is located in stack of thread
+ // CHECK: Potentially referenced stack objects:
+ // CHECK: Cause: stack-buffer-overflow
+ // CHECK-NEXT: 0x{{.*}} is located 2 bytes before a 64-byte region
+ // CHECK-NEXT: c in buggy {{.*}}stack-underflow.c:
+ // CHECK: Memory tags around the buggy address
+
+ // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in buggy
+}
More information about the llvm-commits
mailing list