[llvm] [BOLT] Gadget scanner: detect authentication oracles (PR #135663)
Kristof Beyls via llvm-commits
llvm-commits at lists.llvm.org
Wed May 28 02:22:43 PDT 2025
================
@@ -0,0 +1,739 @@
+// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
+// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s
+// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
+
+// The detection of compiler-generated explicit pointer checks is tested in
+// gs-pauth-address-checks.s, for that reason only test here "dummy-load" and
+// "high-bits-notbi" checkers, as the shortest examples of checkers that are
+// detected per-instruction and per-BB.
+
+// PACRET-NOT: authentication oracle found in function
+
+ .text
+
+ .type sym, at function
+sym:
+ ret
+ .size sym, .-sym
+
+ .globl callee
+ .type callee, at function
+callee:
+ ret
+ .size callee, .-callee
+
+ .globl good_ret
+ .type good_ret, at function
+good_ret:
+// CHECK-NOT: good_ret
+ autia x0, x1
+ ret x0
+ .size good_ret, .-good_ret
+
+ .globl good_call
+ .type good_call, at function
+good_call:
+// CHECK-NOT: good_call
+ paciasp
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ autia x0, x1
+ blr x0
+
+ ldp x29, x30, [sp], #16
+ autiasp
+ ret
+ .size good_call, .-good_call
+
+ .globl good_branch
+ .type good_branch, at function
+good_branch:
+// CHECK-NOT: good_branch
+ autia x0, x1
+ br x0
+ .size good_branch, .-good_branch
+
+ .globl good_load_other_reg
+ .type good_load_other_reg, at function
+good_load_other_reg:
+// CHECK-NOT: good_load_other_reg
+ autia x0, x1
+ ldr x2, [x0]
+ ret
+ .size good_load_other_reg, .-good_load_other_reg
+
+ .globl good_load_same_reg
+ .type good_load_same_reg, at function
+good_load_same_reg:
+// CHECK-NOT: good_load_same_reg
+ autia x0, x1
+ ldr x0, [x0]
+ ret
+ .size good_load_same_reg, .-good_load_same_reg
+
+ .globl good_explicit_check
+ .type good_explicit_check, at function
+good_explicit_check:
+// CHECK-NOT: good_explicit_check
+ autia x0, x1
+ eor x16, x0, x0, lsl #1
+ tbz x16, #62, 1f
+ brk 0x1234
+1:
+ ret
+ .size good_explicit_check, .-good_explicit_check
+
+ .globl bad_unchecked
+ .type bad_unchecked, at function
+bad_unchecked:
+// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unchecked, basic block {{[^,]+}}, at address
+// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1
+// CHECK-NEXT: The 0 instructions that leak the affected registers are:
+ autia x0, x1
+ ret
+ .size bad_unchecked, .-bad_unchecked
+
+ .globl bad_leaked_to_subroutine
+ .type bad_leaked_to_subroutine, at function
+bad_leaked_to_subroutine:
+// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_leaked_to_subroutine, basic block {{[^,]+}}, at address
+// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1
+// CHECK-NEXT: The 1 instructions that leak the affected registers are:
+// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee
+// CHECK-NEXT: This happens in the following basic block:
+// CHECK-NEXT: {{[0-9a-f]+}}: paciasp
+// CHECK-NEXT: {{[0-9a-f]+}}: stp x29, x30, [sp, #-0x10]!
+// CHECK-NEXT: {{[0-9a-f]+}}: mov x29, sp
+// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1
+// CHECK-NEXT: {{[0-9a-f]+}}: bl callee
+// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
+// CHECK-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10
+// CHECK-NEXT: {{[0-9a-f]+}}: autiasp
+// CHECK-NEXT: {{[0-9a-f]+}}: ret
+ paciasp
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ autia x0, x1
+ bl callee
+ ldr x2, [x0]
+
+ ldp x29, x30, [sp], #16
+ autiasp
+ ret
+ .size bad_leaked_to_subroutine, .-bad_leaked_to_subroutine
+
+ .globl bad_unknown_usage_read
+ .type bad_unknown_usage_read, at function
+bad_unknown_usage_read:
+// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unknown_usage_read, basic block {{[^,]+}}, at address
+// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1
+// CHECK-NEXT: The 1 instructions that leak the affected registers are:
+// CHECK-NEXT: 1. {{[0-9a-f]+}}: mul x3, x0, x1
+// CHECK-NEXT: This happens in the following basic block:
+// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1
+// CHECK-NEXT: {{[0-9a-f]+}}: mul x3, x0, x1
+// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
+// CHECK-NEXT: {{[0-9a-f]+}}: ret
+ autia x0, x1
+ mul x3, x0, x1
+ ldr x2, [x0]
----------------
kbeyls wrote:
Do I understand correctly that this could be seen as a false positive?
Register `x3` after the `mul` could contain information about whether the authentication succeeded or not. But there is no way for an attacker to get to `x3` before the `ldr` instruction with abort the program on a failed authentication?
I'm guessing whether this is considered a false positive or not depends on how we assume an attacker could get access to the value in a register?
https://github.com/llvm/llvm-project/pull/135663
More information about the llvm-commits
mailing list