[compiler-rt] bcc4470 - [compiler-rt][hwasan] Let CheckAddressSized eventually call HandleTagMismatch on Fuchsia

Leonard Chan via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 7 15:10:53 PST 2022


Author: Leonard Chan
Date: 2022-12-07T23:09:53Z
New Revision: bcc4470bade15dbafa879973828a03c7e5194399

URL: https://github.com/llvm/llvm-project/commit/bcc4470bade15dbafa879973828a03c7e5194399
DIFF: https://github.com/llvm/llvm-project/commit/bcc4470bade15dbafa879973828a03c7e5194399.diff

LOG: [compiler-rt][hwasan] Let CheckAddressSized eventually call HandleTagMismatch on Fuchsia

Any hwasan tag checking done through runtime calls like __hwasan_mem* or
__hwasan_load/store* currently raise a sigtrap on a tag mismatch. Hwasan
dumps as much information it knows on the tag mismatch by placing
important values in specific registers before the brk and encoding the
access information in the optional argument supplied to the brk. If the
platform hwasan runs on uses signal handlers, then users can see the
typical pretty hwasan error report, but Fuchsia doesn't use signal
handlers, so it's left up to the platform exception handler to print all
this encoded information.

This patch attempts to enter the regular error reporting path via
HandleTagMismatch if a new macro CAN_GET_REGISTERS is set. For now this
is only defined for Fuchsia + aarch64, but can be expanded for other
platforms.

Differential Revision: https://reviews.llvm.org/D139377

Added: 
    compiler-rt/lib/hwasan/hwasan_registers.h

Modified: 
    compiler-rt/lib/hwasan/hwasan_checks.h

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/hwasan/hwasan_checks.h b/compiler-rt/lib/hwasan/hwasan_checks.h
index b0b37d7a2e2b9..514d351cf7d72 100644
--- a/compiler-rt/lib/hwasan/hwasan_checks.h
+++ b/compiler-rt/lib/hwasan/hwasan_checks.h
@@ -15,17 +15,49 @@
 
 #include "hwasan_allocator.h"
 #include "hwasan_mapping.h"
+#include "hwasan_registers.h"
 #include "sanitizer_common/sanitizer_common.h"
 
 namespace __hwasan {
-template <unsigned X>
+
+enum class ErrorAction { Abort, Recover };
+enum class AccessType { Load, Store };
+
+// Used when the access size is known.
+constexpr unsigned SigTrapEncoding(ErrorAction EA, AccessType AT,
+                                   unsigned LogSize) {
+  return 0x20 * (EA == ErrorAction::Recover) +
+         0x10 * (AT == AccessType::Store) + LogSize;
+}
+
+// Used when the access size varies at runtime.
+constexpr unsigned SigTrapEncoding(ErrorAction EA, AccessType AT) {
+  return SigTrapEncoding(EA, AT, 0xf);
+}
+
+template <ErrorAction EA, AccessType AT, size_t LogSize>
 __attribute__((always_inline)) static void SigTrap(uptr p) {
-#if defined(__aarch64__)
+  // Other platforms like linux can use signals for intercepting an exception
+  // and dispatching to HandleTagMismatch. The fuchsias implementation doesn't
+  // use signals so we can call it here directly instead.
+#if CAN_GET_REGISTERS && SANITIZER_FUCHSIA
+  auto regs = GetRegisters();
+  size_t size = 2 << LogSize;
+  AccessInfo access_info = {
+      .addr = p,
+      .size = size,
+      .is_store = AT == AccessType::Store,
+      .is_load = AT == AccessType::Load,
+      .recover = EA == ErrorAction::Recover,
+  };
+  HandleTagMismatch(access_info, (uptr)__builtin_return_address(0),
+                    (uptr)__builtin_frame_address(0), /*uc=*/nullptr, regs.x);
+#elif defined(__aarch64__)
   (void)p;
   // 0x900 is added to do not interfere with the kernel use of lower values of
   // brk immediate.
   register uptr x0 asm("x0") = p;
-  asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X));
+  asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + SigTrapEncoding(EA, AT, LogSize)));
 #elif defined(__x86_64__)
   // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
   // total. The pointer is passed via rdi.
@@ -34,7 +66,7 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
   // 
diff erent nop command, the three bytes one).
   asm volatile(
       "int3\n"
-      "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+      "nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA, AT, LogSize)),
       "D"(p));
 #elif SANITIZER_RISCV64
   // Put pointer into x10
@@ -44,7 +76,7 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
   asm volatile(
       "ebreak\n"
       "addiw x0, x0, %1\n" ::"r"(x10),
-      "I"(0x40 + X));
+      "I"(0x40 + SigTrapEncoding(EA, AT, LogSize)));
 #else
   // FIXME: not always sigill.
   __builtin_trap();
@@ -53,17 +85,31 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
 }
 
 // Version with access size which is not power of 2
-template <unsigned X>
+template <ErrorAction EA, AccessType AT>
 __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
-#if defined(__aarch64__)
+  // Other platforms like linux can use signals for intercepting an exception
+  // and dispatching to HandleTagMismatch. The fuchsias implementation doesn't
+  // use signals so we can call it here directly instead.
+#if CAN_GET_REGISTERS && SANITIZER_FUCHSIA
+  auto regs = GetRegisters();
+  AccessInfo access_info = {
+      .addr = p,
+      .size = size,
+      .is_store = AT == AccessType::Store,
+      .is_load = AT == AccessType::Load,
+      .recover = EA == ErrorAction::Recover,
+  };
+  HandleTagMismatch(access_info, (uptr)__builtin_return_address(0),
+                    (uptr)__builtin_frame_address(0), /*uc=*/nullptr, regs.x);
+#elif defined(__aarch64__)
   register uptr x0 asm("x0") = p;
   register uptr x1 asm("x1") = size;
-  asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X));
+  asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + SigTrapEncoding(EA, AT)));
 #elif defined(__x86_64__)
   // Size is stored in rsi.
   asm volatile(
       "int3\n"
-      "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+      "nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA, AT)),
       "D"(p), "S"(size));
 #elif SANITIZER_RISCV64
   // Put access size into x11
@@ -72,7 +118,7 @@ __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
   asm volatile(
       "ebreak\n"
       "addiw x0, x0, %2\n" ::"r"(x10),
-      "r"(x11), "I"(0x40 + X));
+      "r"(x11), "I"(0x40 + SigTrapEncoding(EA, AT)));
 #else
   __builtin_trap();
 #endif
@@ -94,9 +140,6 @@ __attribute__((always_inline, nodebug)) static bool PossiblyShortTagMatches(
   return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag;
 }
 
-enum class ErrorAction { Abort, Recover };
-enum class AccessType { Load, Store };
-
 template <ErrorAction EA, AccessType AT, unsigned LogSize>
 __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
   if (!InTaggableRegion(p))
@@ -104,8 +147,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
   uptr ptr_raw = p & ~kAddressTagMask;
   tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
   if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
-    SigTrap<0x20 * (EA == ErrorAction::Recover) +
-            0x10 * (AT == AccessType::Store) + LogSize>(p);
+    SigTrap<EA, AT, LogSize>(p);
     if (EA == ErrorAction::Abort)
       __builtin_unreachable();
   }
@@ -122,8 +164,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
   tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz);
   for (tag_t *t = shadow_first; t < shadow_last; ++t)
     if (UNLIKELY(ptr_tag != *t)) {
-      SigTrap<0x20 * (EA == ErrorAction::Recover) +
-              0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
+      SigTrap<EA, AT>(p, sz);
       if (EA == ErrorAction::Abort)
         __builtin_unreachable();
     }
@@ -132,8 +173,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
   if (UNLIKELY(tail_sz != 0 &&
                !PossiblyShortTagMatches(
                    *shadow_last, end & ~(kShadowAlignment - 1), tail_sz))) {
-    SigTrap<0x20 * (EA == ErrorAction::Recover) +
-            0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
+    SigTrap<EA, AT>(p, sz);
     if (EA == ErrorAction::Abort)
       __builtin_unreachable();
   }

diff  --git a/compiler-rt/lib/hwasan/hwasan_registers.h b/compiler-rt/lib/hwasan/hwasan_registers.h
new file mode 100644
index 0000000000000..f26ce5db0db6b
--- /dev/null
+++ b/compiler-rt/lib/hwasan/hwasan_registers.h
@@ -0,0 +1,56 @@
+//===-- hwasan_registers.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This describes the register state retrieved by hwasan when error reporting.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HWASAN_REGISTERS_H
+#define HWASAN_REGISTERS_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if defined(__aarch64__)
+
+#  define CAN_GET_REGISTERS 1
+
+struct Registers {
+  uptr x[32];
+};
+
+__attribute__((always_inline)) static Registers GetRegisters() {
+  Registers regs;
+  __asm__ volatile(
+      "stp x0, x1, [%1, #(8 * 0)]\n"
+      "stp x2, x3, [%1, #(8 * 2)]\n"
+      "stp x4, x5, [%1, #(8 * 4)]\n"
+      "stp x6, x7, [%1, #(8 * 6)]\n"
+      "stp x8, x9, [%1, #(8 * 8)]\n"
+      "stp x10, x11, [%1, #(8 * 10)]\n"
+      "stp x12, x13, [%1, #(8 * 12)]\n"
+      "stp x14, x15, [%1, #(8 * 14)]\n"
+      "stp x16, x17, [%1, #(8 * 16)]\n"
+      "stp x18, x19, [%1, #(8 * 18)]\n"
+      "stp x20, x21, [%1, #(8 * 20)]\n"
+      "stp x22, x23, [%1, #(8 * 22)]\n"
+      "stp x24, x25, [%1, #(8 * 24)]\n"
+      "stp x26, x27, [%1, #(8 * 26)]\n"
+      "stp x28, x29, [%1, #(8 * 28)]\n"
+      : "=m"(regs)
+      : "r"(regs.x));
+  regs.x[30] = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  regs.x[31] = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
+  return regs;
+}
+
+#else
+#  define CAN_GET_REGISTERS 0
+#endif
+
+#endif  // HWASAN_REGISTERS_H


        


More information about the llvm-commits mailing list