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

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 5 14:26:57 PST 2023


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/73980

>From 294ed9bff3fd0d23d1b97c8a4be07b9168e69f69 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 30 Nov 2023 20:14:00 +0000
Subject: [PATCH 1/4] [hwasan] Add fixed_shadow_base flag

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 | 10 ++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc
index 978fa46b705cb..bb224fbb8eaa8 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, 0,
+    "If non-zero, 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 81226da976d11..e7cf36ef3161c 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -106,8 +106,14 @@ static uptr GetHighMemEnd() {
 }
 
 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
-  __hwasan_shadow_memory_dynamic_address =
-      FindDynamicShadowStart(shadow_size_bytes);
+  // NULL is generally address zero, so it is not a valid location for the
+  // shadow.
+  if (flags()->fixed_shadow_base != 0) {
+    __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) {

>From 48eb300c1a0ee2233f6c2e2e0a3899f591befa94 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 30 Nov 2023 20:56:08 +0000
Subject: [PATCH 2/4] Change "non-fixed shadow" magic value from 0 to -1, per
 offline discussion with Vitaly

---
 compiler-rt/lib/hwasan/hwasan_flags.inc | 4 ++--
 compiler-rt/lib/hwasan/hwasan_linux.cpp | 4 +---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc
index bb224fbb8eaa8..058a0457b9e7f 100644
--- a/compiler-rt/lib/hwasan/hwasan_flags.inc
+++ b/compiler-rt/lib/hwasan/hwasan_flags.inc
@@ -86,8 +86,8 @@ HWASAN_FLAG(bool, fail_without_syscall_abi, true,
             "Exit if fail to request relaxed syscall ABI.")
 
 HWASAN_FLAG(
-    uptr, fixed_shadow_base, 0,
-    "If non-zero, HWASan will attempt to allocate the shadow at this address, "
+    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 e7cf36ef3161c..f01fa42764134 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -106,9 +106,7 @@ static uptr GetHighMemEnd() {
 }
 
 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
-  // NULL is generally address zero, so it is not a valid location for the
-  // shadow.
-  if (flags()->fixed_shadow_base != 0) {
+  if (flags()->fixed_shadow_base != (uptr)-1) {
     __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base;
   } else {
     __hwasan_shadow_memory_dynamic_address =

>From 0896aa86ba9de0f1b681c3e4565cfe597294a0a7 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 5 Dec 2023 22:25:11 +0000
Subject: [PATCH 3/4] Add test

---
 .../hwasan/TestCases/Linux/fixed-shadow.c     | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c

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..9ff57f27de4e1
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c
@@ -0,0 +1,62 @@
+// 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
+//
+// UNSUPPORTED: android
+
+#include <stdio.h> 
+#include <stdlib.h>
+#include <assert.h>  
+#include <sys/mman.h>   
+#include <sanitizer/hwasan_interface.h>   
+#include <sanitizer/allocator_interface.h>
+
+int main() { 
+  __hwasan_enable_allocator_tagging();
+
+  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 | MAP_FIXED, -1, 0);
+      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 < 32);
+  return 0;
+}

>From 2c9a4b43a927b6d20d9eacd3888103d80dfff382 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 5 Dec 2023 22:26:39 +0000
Subject: [PATCH 4/4] clang-format test

---
 .../hwasan/TestCases/Linux/fixed-shadow.c     | 44 +++++++++----------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c b/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c
index 9ff57f27de4e1..154ef5cd44e6c 100644
--- a/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c
+++ b/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c
@@ -13,41 +13,41 @@
 //
 // 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. 
+// compiler instrumentation. To avoid test flake, we do not test this case.
 //
 // Assume 48-bit VMA
 // REQUIRES: aarch64-target-arch
 //
 // UNSUPPORTED: android
 
-#include <stdio.h> 
-#include <stdlib.h>
-#include <assert.h>  
-#include <sys/mman.h>   
-#include <sanitizer/hwasan_interface.h>   
+#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() { 
+int main() {
   __hwasan_enable_allocator_tagging();
 
-  void** mmaps [256];
+  void **mmaps[256];
   // 48-bit VMA
-  for (int i = 0; i < 256; i++) {  
-      unsigned long long addr = (i * (1ULL << 40));
+  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 | MAP_FIXED, -1, 0);
-      mmaps [i] = p;    
+    void *p = mmap((void *)addr, 4096, PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+    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);
-      }
+  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:
@@ -56,7 +56,7 @@ int main() {
   // 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 < 32);
+  printf("Failed: %d\n", failures);
+  assert(failures < 32);
   return 0;
 }



More information about the llvm-commits mailing list