[compiler-rt] Reland '[hwasan] Add fixed_shadow_base flag (#73980)' (PR #95445)

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 13 17:02:14 PDT 2024


https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/95445

>From 075ff47469f9a31ba0f4bf9841d412ca7dbde80d Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 13 Jun 2024 17:32:18 +0000
Subject: [PATCH 1/3] Reland '[hwasan] Add fixed_shadow_base flag (#73980)'

This was reverted in https://github.com/llvm/llvm-project/pull/95435 because it broke Android static hwasan binaries. This reland excludes Android from the logic, as suggested by Vitaly.

Original commit message:
When set to non-zero, the HWASan runtime will map the shadow base at the
specified constant address.

This is particularly useful in conjunction with the existing compiler option
'hwasan-mapping-offset', which bakes a hardcoded constant address into
the instrumentation.
---
 compiler-rt/lib/hwasan/hwasan_flags.inc       |  7 ++
 compiler-rt/lib/hwasan/hwasan_linux.cpp       |  9 ++-
 .../hwasan/TestCases/Linux/fixed-shadow.c     | 76 +++++++++++++++++++
 3 files changed, 90 insertions(+), 2 deletions(-)
 create mode 100644 compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c

diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc
index 978fa46b705cb..058a0457b9e7f 100644
--- a/compiler-rt/lib/hwasan/hwasan_flags.inc
+++ b/compiler-rt/lib/hwasan/hwasan_flags.inc
@@ -84,3 +84,10 @@ HWASAN_FLAG(bool, malloc_bisect_dump, false,
 // are untagged before the call.
 HWASAN_FLAG(bool, fail_without_syscall_abi, true,
             "Exit if fail to request relaxed syscall ABI.")
+
+HWASAN_FLAG(
+    uptr, fixed_shadow_base, -1,
+    "If not -1, HWASan will attempt to allocate the shadow at this address, "
+    "instead of choosing one dynamically."
+    "Tip: this can be combined with the compiler option, "
+    "-hwasan-mapping-offset, to optimize the instrumentation.")
diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp
index c254670ee2d48..ce15b80c1e6cc 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -106,8 +106,13 @@ static uptr GetHighMemEnd() {
 }
 
 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
-  __hwasan_shadow_memory_dynamic_address =
-      FindDynamicShadowStart(shadow_size_bytes);
+  // Android static HWASan doesn't initialize flags correctly
+  if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) {
+    __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base;
+  } else {
+    __hwasan_shadow_memory_dynamic_address =
+        FindDynamicShadowStart(shadow_size_bytes);
+  }
 }
 
 static void MaybeDieIfNoTaggingAbi(const char *message) {
diff --git a/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c b/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c
new file mode 100644
index 0000000000000..4ff1d3e64c1d0
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c
@@ -0,0 +1,76 @@
+// Test fixed shadow base functionality.
+//
+// Default compiler instrumentation works with any shadow base (dynamic or fixed).
+// RUN: %clang_hwasan %s -o %t && %run %t
+// RUN: %clang_hwasan %s -o %t && HWASAN_OPTIONS=fixed_shadow_base=263878495698944 %run %t
+// RUN: %clang_hwasan %s -o %t && HWASAN_OPTIONS=fixed_shadow_base=4398046511104 %run %t
+//
+// If -hwasan-mapping-offset is set, then the fixed_shadow_base needs to match.
+// RUN: %clang_hwasan %s -mllvm -hwasan-mapping-offset=263878495698944 -o %t && HWASAN_OPTIONS=fixed_shadow_base=263878495698944 %run %t
+// RUN: %clang_hwasan %s -mllvm -hwasan-mapping-offset=4398046511104 -o %t && HWASAN_OPTIONS=fixed_shadow_base=4398046511104 %run %t
+// RUN: %clang_hwasan %s -mllvm -hwasan-mapping-offset=263878495698944 -o %t && HWASAN_OPTIONS=fixed_shadow_base=4398046511104 not %run %t
+// RUN: %clang_hwasan %s -mllvm -hwasan-mapping-offset=4398046511104 -o %t && HWASAN_OPTIONS=fixed_shadow_base=263878495698944 not %run %t
+//
+// Note: if fixed_shadow_base is not set, compiler-rt will dynamically choose a
+// shadow base, which has a tiny but non-zero probability of matching the
+// compiler instrumentation. To avoid test flake, we do not test this case.
+//
+// Assume 48-bit VMA
+// REQUIRES: aarch64-target-arch
+//
+// REQUIRES: Clang
+//
+// UNSUPPORTED: android
+
+#include <assert.h>
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/hwasan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+int main() {
+  __hwasan_enable_allocator_tagging();
+
+  // We test that the compiler instrumentation is able to access shadow memory
+  // for many different addresses. If we only test a small number of addresses,
+  // it might work by chance even if the shadow base does not match between the
+  // compiler instrumentation and compiler-rt.
+  void **mmaps[256];
+  // 48-bit VMA
+  for (int i = 0; i < 256; i++) {
+    unsigned long long addr = (i * (1ULL << 40));
+
+    void *p = mmap((void *)addr, 4096, PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    // We don't use MAP_FIXED, to avoid overwriting critical memory.
+    // However, if we don't get allocated the requested address, it
+    // isn't a useful test.
+    if ((unsigned long long)p != addr) {
+      munmap(p, 4096);
+      mmaps[i] = MAP_FAILED;
+    } else {
+      mmaps[i] = p;
+    }
+  }
+
+  int failures = 0;
+  for (int i = 0; i < 256; i++) {
+    if (mmaps[i] == MAP_FAILED) {
+      failures++;
+    } else {
+      printf("%d %p\n", i, mmaps[i]);
+      munmap(mmaps[i], 4096);
+    }
+  }
+
+  // We expect roughly 17 failures:
+  // - the page at address zero
+  // - 16 failures because the shadow memory takes up 1/16th of the address space
+  // We could also get unlucky e.g., if libraries or binaries are loaded into the
+  // exact addresses where we tried to map.
+  // To avoid test flake, we allow some margin of error.
+  printf("Failed: %d\n", failures);
+  assert(failures < 48);
+  return 0;
+}

>From ac873a7ab55a2ffd54ce889f7180d769c216d9f7 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 13 Jun 2024 18:20:26 +0000
Subject: [PATCH 2/3] Updated to use SANITIZER_CAN_USE_PREINIT_ARRAY per
 Vitaly's feedback

---
 compiler-rt/lib/hwasan/hwasan_linux.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp
index ce15b80c1e6cc..aedd570d2e658 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -106,8 +106,8 @@ static uptr GetHighMemEnd() {
 }
 
 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
-  // Android static HWASan doesn't initialize flags correctly
-  if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) {
+  if (SANITIZER_CAN_USE_PREINIT_ARRAY &&
+      flags()->fixed_shadow_base != (uptr)-1) {
     __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base;
   } else {
     __hwasan_shadow_memory_dynamic_address =

>From 8b6c0349b8885e5183d51d98c6d30927b978e842 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at gmail.com>
Date: Thu, 13 Jun 2024 17:02:05 -0700
Subject: [PATCH 3/3] Switch back to SANITIZER_ANDROID

---
 compiler-rt/lib/hwasan/hwasan_linux.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp
index aedd570d2e658..fe10eb96255b0 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -106,8 +106,7 @@ static uptr GetHighMemEnd() {
 }
 
 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
-  if (SANITIZER_CAN_USE_PREINIT_ARRAY &&
-      flags()->fixed_shadow_base != (uptr)-1) {
+  if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) {
     __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base;
   } else {
     __hwasan_shadow_memory_dynamic_address =



More information about the llvm-commits mailing list