[llvm] [BOLT] Gadget scanner: account for BRK when searching for auth oracles (PR #137975)

Anatoly Trosinenko via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 25 04:05:11 PDT 2025


================
@@ -0,0 +1,213 @@
+// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe -Wl,--emit-relocs
+// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
+
+// Test what instructions can be used to terminate the program abnormally
+// on security violation.
+//
+// All test cases have the same structure:
+//
+//      cbz     x0, 1f    // [a], ensures [c] is never reported as unreachable
+//      autia   x2, x3
+//      cbz     x1, 2f    // [b]
+//      [instruction under test]
+// 1:
+//      ret               // [c]
+// 2:
+//      ldr     x0, [x2]
+//      ret
+//
+// This is to handle three possible cases: the instruction under test may be
+// considered by BOLT as
+// * trapping (and thus no-return): after being authenticated, x2 is ether
+//   checked by LDR (if [b] is taken) or the program is terminated
+//   immediately without leaking x2 (if [b] falls through to the trapping
+//   instruction under test). Nothing is reported.
+// * non-trapping, but no-return (such as calling abort()): x2 is leaked if [b]
+//   falls through. Authentication oracle is reported.
+// * non-trapping and falling-through (i.e. a regular instruction):
+//   x2 is leaked by [c]. Authentication oracle is reported.
+
+        .text
+
+        .globl  brk_key_ia
+        .type   brk_key_ia, at function
+brk_key_ia:
+// CHECK-NOT: brk_key_ia
+        cbz     x0, 1f
+        autia   x2, x3
+        cbz     x1, 2f
+        brk     0xc470
+1:
+        ret
+2:
+        ldr     x0, [x2]
+        ret
+        .size   brk_key_ia, .-brk_key_ia
+
+        .globl  brk_key_ib
+        .type   brk_key_ib, at function
+brk_key_ib:
+// CHECK-NOT: brk_key_ib
+        cbz     x0, 1f
+        autia   x2, x3
+        cbz     x1, 2f
+        brk     0xc471
+1:
+        ret
+2:
+        ldr     x0, [x2]
+        ret
+        .size   brk_key_ib, .-brk_key_ib
+
+        .globl  brk_key_da
+        .type   brk_key_da, at function
+brk_key_da:
+// CHECK-NOT: brk_key_da
+        cbz     x0, 1f
+        autia   x2, x3
+        cbz     x1, 2f
+        brk     0xc472
+1:
+        ret
+2:
+        ldr     x0, [x2]
+        ret
+        .size   brk_key_da, .-brk_key_da
+
+        .globl  brk_key_db
+        .type   brk_key_db, at function
+brk_key_db:
+// CHECK-NOT: brk_key_db
+        cbz     x0, 1f
+        autia   x2, x3
+        cbz     x1, 2f
+        brk     0xc473
+1:
+        ret
+2:
+        ldr     x0, [x2]
+        ret
+        .size   brk_key_db, .-brk_key_db
+
+// The immediate operand of BRK instruction may indicate whether the instruction
+// is intended to be a non-recoverable trap: for example, for this code
+//
+//     int test_trap(void) {
+//       __builtin_trap();
+//       return 42;
+//     }
+//     int test_debugtrap(void) {
+//       __builtin_debugtrap();
+//       return 42;
+//     }
+//
+// Clang produces the following assembly:
+//
+//     test_trap:
+//             brk     #0x1
+//     test_debugtrap:
+//             brk     #0xf000
+//             mov     w0, #42
+//             ret
+//
+// In GCC, __builtin_trap() uses "brk 0x3e8" (i.e. decimal 1000) and
+// __builtin_debugtrap() is not supported.
+//
+// At the time of writing these test cases, any BRK instruction is considered
+// no-return by BOLT, thus it ends its basic block and prevents falling through
+// to the next BB.
+// FIXME: Make BOLT handle __builtin_debugtrap() properly from the CFG point
----------------
atrosinenko wrote:

Documented this in #155232, thanks.

https://github.com/llvm/llvm-project/pull/137975


More information about the llvm-commits mailing list