From 075ff47469f9a31ba0f4bf9841d412ca7dbde80d Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Thu, 13 Jun 2024 17:32:18 +0000 Subject: [PATCH 1/4] 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 +#include +#include +#include +#include +#include + +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 Date: Thu, 13 Jun 2024 18:20:26 +0000 Subject: [PATCH 2/4] 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 Date: Thu, 13 Jun 2024 17:02:05 -0700 Subject: [PATCH 3/4] 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 = From ed626ed03625c17638af73df73bd010f06751b96 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Thu, 13 Jun 2024 17:25:02 -0700 Subject: [PATCH 4/4] Add FIXME --- compiler-rt/lib/hwasan/hwasan_linux.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp index fe10eb96255b0..ae14906fd3042 100644 --- a/compiler-rt/lib/hwasan/hwasan_linux.cpp +++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp @@ -106,6 +106,7 @@ static uptr GetHighMemEnd() { } static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { + // FIXME: Android should init flags before shadow. if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) { __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base; } else {