[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