[llvm] [BOLT] Gadget scanner: detect non-protected indirect calls (PR #131899)
Jacob Bramley via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 27 04:26:43 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:
The short version is that without TBI ("top byte ignore") you get more bits for the PAC, so if you have TBI on for data but off for instruction translations, then `autia` will expect more PAC bits than `autda` (for example).
This test is most interesting as a control case for `bad_indirect_call_mem_chain_of_auts`, I think.
https://github.com/llvm/llvm-project/pull/131899
More information about the llvm-commits
mailing list