[llvm] [BOLT] Gadget scanner: detect non-protected indirect calls (PR #131899)

Jacob Bramley via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 26 10:29:10 PDT 2025


================
@@ -0,0 +1,777 @@
+// 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
+
+// PACRET-NOT: non-protected call found in function
+
+        .text
+
+        .globl  good_direct_call
+        .type   good_direct_call, at function
+good_direct_call:
+// CHECK-NOT: good_direct_call
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        bl      callee_ext
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size good_direct_call, .-good_direct_call
+
+        .globl  good_indirect_call_arg
+        .type   good_indirect_call_arg, at function
+good_indirect_call_arg:
+// CHECK-NOT: good_indirect_call_arg
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        autia   x0, x1
+        blr     x0
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size good_indirect_call_arg, .-good_indirect_call_arg
+
+        .globl  good_indirect_call_mem
+        .type   good_indirect_call_mem, at function
+good_indirect_call_mem:
+// CHECK-NOT: good_indirect_call_mem
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        ldr     x16, [x0]
+        autia   x16, x0
+        blr     x16
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size good_indirect_call_mem, .-good_indirect_call_mem
+
+        .globl  good_indirect_call_arg_v83
+        .type   good_indirect_call_arg_v83, at function
+good_indirect_call_arg_v83:
+// CHECK-NOT: good_indirect_call_arg_v83
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        blraa   x0, x1
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size good_indirect_call_arg_v83, .-good_indirect_call_arg_v83
+
+        .globl  good_indirect_call_mem_v83
+        .type   good_indirect_call_mem_v83, at function
+good_indirect_call_mem_v83:
+// CHECK-NOT: good_indirect_call_mem_v83
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        ldr     x16, [x0]
+        blraa   x16, x0
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size good_indirect_call_mem_v83, .-good_indirect_call_mem_v83
+
+        .globl  bad_indirect_call_arg
+        .type   bad_indirect_call_arg, at function
+bad_indirect_call_arg:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_arg, basic block {{[^,]+}}, at address
+// CHECK-NEXT:  The instruction is     {{[0-9a-f]+}}:         blr     x0
+// CHECK-NEXT:  The 0 instructions that write to the affected registers after any authentication are:
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        blr     x0
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size bad_indirect_call_arg, .-bad_indirect_call_arg
+
+        .globl  bad_indirect_call_mem
+        .type   bad_indirect_call_mem, at function
+bad_indirect_call_mem:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem, basic block {{[^,]+}}, at address
+// CHECK-NEXT:  The instruction is     {{[0-9a-f]+}}:         blr     x16
+// CHECK-NEXT:  The 1 instructions that write to the affected registers after any authentication are:
+// CHECK-NEXT:  1.     {{[0-9a-f]+}}:      ldr     x16, [x0]
+// 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]+}}:   ldr     x16, [x0]
+// CHECK-NEXT:  {{[0-9a-f]+}}:   blr     x16
+// 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
+
+        ldr     x16, [x0]
+        blr     x16
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size bad_indirect_call_mem, .-bad_indirect_call_mem
+
+        .globl  bad_indirect_call_arg_clobber
+        .type   bad_indirect_call_arg_clobber, at function
+bad_indirect_call_arg_clobber:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_arg_clobber, basic block {{[^,]+}}, at address
+// CHECK-NEXT:  The instruction is     {{[0-9a-f]+}}:         blr     x0
+// CHECK-NEXT:  The 1 instructions that write to the affected registers after any authentication are:
+// CHECK-NEXT:  1.     {{[0-9a-f]+}}:      mov     w0, w2
+// 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]+}}:   mov     w0, w2
+// CHECK-NEXT:  {{[0-9a-f]+}}:   blr     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
+        mov     w0, w2
+        blr     x0
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size bad_indirect_call_arg_clobber, .-bad_indirect_call_arg_clobber
+
+        .globl  bad_indirect_call_mem_clobber
+        .type   bad_indirect_call_mem_clobber, at function
+bad_indirect_call_mem_clobber:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_clobber, basic block {{[^,]+}}, at address
+// CHECK-NEXT:  The instruction is     {{[0-9a-f]+}}:         blr     x16
+// CHECK-NEXT:  The 1 instructions that write to the affected registers after any authentication are:
+// CHECK-NEXT:  1.     {{[0-9a-f]+}}:      mov     w16, w2
+// 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]+}}:   ldr     x16, [x0]
+// CHECK-NEXT:  {{[0-9a-f]+}}:   autia   x16, x0
+// CHECK-NEXT:  {{[0-9a-f]+}}:   mov     w16, w2
+// CHECK-NEXT:  {{[0-9a-f]+}}:   blr     x16
+// 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
+
+        ldr     x16, [x0]
+        autia   x16, x0
+        mov     w16, w2
+        blr     x16
+
+        ldp     x29, x30, [sp], #16
+        autiasp
+        ret
+        .size bad_indirect_call_mem_clobber, .-bad_indirect_call_mem_clobber
+
+        .globl  good_indirect_call_mem_chain_of_auts
+        .type   good_indirect_call_mem_chain_of_auts, at function
+good_indirect_call_mem_chain_of_auts:
+// CHECK-NOT: good_indirect_call_mem_chain_of_auts
+        paciasp
+        stp     x29, x30, [sp, #-16]!
+        mov     x29, sp
+
+        ldr     x16, [x0]
+        autia   x16, x1
+        ldr     x16, [x16]
----------------
jacobbramley wrote:

My thinking was that TBI can be configured differently for data and instruction pointers, so it's likely a programming error to mix them up.

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


More information about the llvm-commits mailing list