[llvm] [BOLT] Gadget scanner: detect authentication oracles (PR #135663)

Anatoly Trosinenko via llvm-commits llvm-commits at lists.llvm.org
Wed May 28 03:48:57 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]
----------------
atrosinenko wrote:

This test case checks that any unknown usage of a sensitive register is considered unsafe by default, but this is a false positive in this particular case. I should probably add a comment that this false positive is by design. On the other hand, this would probably be a true positive:
```
  autia   x0, x1
  mov     x3, x0
  cbz     x4, 1f
  str     x3, [x4]
  ; some time-consuming computations that never touch x0 or x3
  ; and eventually jump to check_ptr
check_ptr:
  ldr     x2, [x0]
  ret
```
So it is probably better to be suspicious by default.

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


More information about the llvm-commits mailing list