| // 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 --auth-traps-on-failure %t.exe 2>&1 | FileCheck %s |
| // RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s |
| |
| // PACRET-NOT: non-protected call found in function |
| |
| .text |
| |
| .globl callee |
| .type callee,@function |
| callee: |
| ret |
| .size callee, .-callee |
| |
| .globl good_direct_call |
| .type good_direct_call,@function |
| good_direct_call: |
| // CHECK-NOT: good_direct_call |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| bl callee |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_direct_call, .-good_direct_call |
| |
| .globl good_indirect_call_arg |
| .type good_indirect_call_arg,@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,@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,@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,@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,@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,@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,@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,@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,@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] |
| autda x16, x1 |
| ldr x16, [x16] |
| autia x16, x0 |
| blr x16 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_mem_chain_of_auts, .-good_indirect_call_mem_chain_of_auts |
| |
| .globl bad_indirect_call_mem_chain_of_auts |
| .type bad_indirect_call_mem_chain_of_auts,@function |
| bad_indirect_call_mem_chain_of_auts: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_chain_of_auts, 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, [x16] |
| // 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]+}}: autda x16, x1 |
| // CHECK-NEXT: {{[0-9a-f]+}}: ldr x16, [x16] |
| // 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] |
| autda x16, x1 |
| ldr x16, [x16] |
| // Missing AUT of x16. The fact that x16 was authenticated above has nothing to do with it. |
| blr x16 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_chain_of_auts, .-bad_indirect_call_mem_chain_of_auts |
| |
| // Multi-BB test cases. |
| // |
| // Positive ("good") test cases are designed so that the register is made safe |
| // in one BB and used in the other. Negative ("bad") ones are designed so that |
| // there are two predecessors, one of them ends with the register in a safe |
| // state and the other ends with that register being unsafe. |
| |
| .globl good_indirect_call_arg_multi_bb |
| .type good_indirect_call_arg_multi_bb,@function |
| good_indirect_call_arg_multi_bb: |
| // CHECK-NOT: good_indirect_call_arg_multi_bb |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| autia x0, x1 |
| cbz x2, 1f |
| blr x0 |
| 1: |
| ldr x1, [x0] // prevent authentication oracle |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_arg_multi_bb, .-good_indirect_call_arg_multi_bb |
| |
| .globl good_indirect_call_mem_multi_bb |
| .type good_indirect_call_mem_multi_bb,@function |
| good_indirect_call_mem_multi_bb: |
| // CHECK-NOT: good_indirect_call_mem_multi_bb |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autia x16, x0 |
| cbz x2, 1f |
| blr x16 |
| 1: |
| ldr w0, [x16] // prevent authentication oracle |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_mem_multi_bb, .-good_indirect_call_mem_multi_bb |
| |
| .globl bad_indirect_call_arg_multi_bb |
| .type bad_indirect_call_arg_multi_bb,@function |
| bad_indirect_call_arg_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_arg_multi_bb, 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 |
| |
| cbz x2, 1f |
| autia x0, x1 |
| 1: |
| blr x0 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_arg_multi_bb, .-bad_indirect_call_arg_multi_bb |
| |
| .globl bad_indirect_call_mem_multi_bb |
| .type bad_indirect_call_mem_multi_bb,@function |
| bad_indirect_call_mem_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_multi_bb, 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] |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| cbz x2, 1f |
| autia x16, x1 |
| 1: |
| blr x16 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_multi_bb, .-bad_indirect_call_mem_multi_bb |
| |
| .globl bad_indirect_call_arg_clobber_multi_bb |
| .type bad_indirect_call_arg_clobber_multi_bb,@function |
| bad_indirect_call_arg_clobber_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_arg_clobber_multi_bb, 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, w3 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| autia x0, x1 |
| cbz x2, 1f |
| mov w0, w3 |
| 1: |
| blr x0 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_arg_clobber_multi_bb, .-bad_indirect_call_arg_clobber_multi_bb |
| |
| .globl bad_indirect_call_mem_clobber_multi_bb |
| .type bad_indirect_call_mem_clobber_multi_bb,@function |
| bad_indirect_call_mem_clobber_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_clobber_multi_bb, 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 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autia x16, x0 |
| cbz x2, 1f |
| mov w16, w2 |
| 1: |
| blr x16 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_clobber_multi_bb, .-bad_indirect_call_mem_clobber_multi_bb |
| |
| .globl good_indirect_call_mem_chain_of_auts_multi_bb |
| .type good_indirect_call_mem_chain_of_auts_multi_bb,@function |
| good_indirect_call_mem_chain_of_auts_multi_bb: |
| // CHECK-NOT: good_indirect_call_mem_chain_of_auts_multi_bb |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autda x16, x1 |
| ldr x16, [x16] |
| autia x16, x0 |
| cbz x2, 1f |
| blr x16 |
| 1: |
| ldr w0, [x16] // prevent authentication oracle |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_mem_chain_of_auts_multi_bb, .-good_indirect_call_mem_chain_of_auts_multi_bb |
| |
| .globl bad_indirect_call_mem_chain_of_auts_multi_bb |
| .type bad_indirect_call_mem_chain_of_auts_multi_bb,@function |
| bad_indirect_call_mem_chain_of_auts_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_chain_of_auts_multi_bb, 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, [x16] |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autda x16, x1 |
| ldr x16, [x16] |
| cbz x2, 1f |
| autia x16, x0 |
| 1: |
| blr x16 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_chain_of_auts_multi_bb, .-bad_indirect_call_mem_chain_of_auts_multi_bb |
| |
| // Tests for CFG-unaware analysis. |
| // |
| // All these tests use an instruction sequence like this |
| // |
| // adr x2, 1f |
| // br x2 |
| // 1: |
| // ; ... |
| // |
| // to make BOLT unable to reconstruct the control flow. Note that one can easily |
| // tell whether the report corresponds to a function with or without CFG: |
| // normally, the location of the gadget is described like this: |
| // |
| // ... found in function <function_name>, basic block <basic block name>, at address <address> |
| // |
| // When CFG information is not available, this is reduced to |
| // |
| // ... found in function <function_name>, at address <address> |
| |
| .globl good_direct_call_nocfg |
| .type good_direct_call_nocfg,@function |
| good_direct_call_nocfg: |
| // CHECK-NOT: good_direct_call_nocfg |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| bl callee |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_direct_call_nocfg, .-good_direct_call_nocfg |
| |
| .globl good_indirect_call_arg_nocfg |
| .type good_indirect_call_arg_nocfg,@function |
| good_indirect_call_arg_nocfg: |
| // CHECK-NOT: good_indirect_call_arg_nocfg |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| autia x0, x1 |
| blr x0 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_arg_nocfg, .-good_indirect_call_arg_nocfg |
| |
| .globl good_indirect_call_mem_nocfg |
| .type good_indirect_call_mem_nocfg,@function |
| good_indirect_call_mem_nocfg: |
| // CHECK-NOT: good_indirect_call_mem_nocfg |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autia x16, x0 |
| blr x16 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_mem_nocfg, .-good_indirect_call_mem_nocfg |
| |
| .globl good_indirect_call_arg_v83_nocfg |
| .type good_indirect_call_arg_v83_nocfg,@function |
| good_indirect_call_arg_v83_nocfg: |
| // CHECK-NOT: good_indirect_call_arg_v83_nocfg |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| blraa x0, x1 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_arg_v83_nocfg, .-good_indirect_call_arg_v83_nocfg |
| |
| .globl good_indirect_call_mem_v83_nocfg |
| .type good_indirect_call_mem_v83_nocfg,@function |
| good_indirect_call_mem_v83_nocfg: |
| // CHECK-NOT: good_indirect_call_mem_v83_nocfg |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| blraa x16, x0 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_mem_v83_nocfg, .-good_indirect_call_mem_v83_nocfg |
| |
| .globl bad_indirect_call_arg_nocfg |
| .type bad_indirect_call_arg_nocfg,@function |
| bad_indirect_call_arg_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_arg_nocfg, 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 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_arg_nocfg, .-bad_indirect_call_arg_nocfg |
| |
| .globl obscure_indirect_call_arg_nocfg |
| .type obscure_indirect_call_arg_nocfg,@function |
| obscure_indirect_call_arg_nocfg: |
| // CHECK-NOCFG-LABEL: GS-PAUTH: non-protected call found in function obscure_indirect_call_arg_nocfg, at address |
| // CHECK-NOCFG-NEXT: The instruction is {{[0-9a-f]+}}: blr x0 |
| // CHECK-NOCFG-NEXT: The 0 instructions that write to the affected registers after any authentication are: |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| autia x0, x1 // not observed by the checker |
| b 1f |
| 1: |
| // The register state is pessimistically reset after a label, thus |
| // the below branch instruction is reported as non-protected - this is |
| // a known false-positive. |
| blr x0 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size obscure_good_indirect_call_arg_nocfg, .-obscure_good_indirect_call_arg_nocfg |
| |
| .globl safe_lr_at_function_entry_nocfg |
| .type safe_lr_at_function_entry_nocfg,@function |
| safe_lr_at_function_entry_nocfg: |
| // Due to state being reset after a label, paciasp is reported as |
| // a signing oracle - this is a known false positive, ignore it. |
| // CHECK-NOT: non-protected call{{.*}}safe_lr_at_function_entry_nocfg |
| cbz x0, 1f |
| ret // LR is safe at the start of the function |
| 1: |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| adr x2, 2f |
| br x2 |
| 2: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size safe_lr_at_function_entry_nocfg, .-safe_lr_at_function_entry_nocfg |
| |
| .globl lr_is_never_unsafe_before_first_inst_nocfg |
| .type lr_is_never_unsafe_before_first_inst_nocfg,@function |
| // CHECK-NOT: lr_is_never_unsafe_before_first_inst_nocfg |
| lr_is_never_unsafe_before_first_inst_nocfg: |
| 1: |
| // The register state is never reset before the first instruction of |
| // the function. This can lead to a known false-negative if LR is |
| // clobbered and then a jump to the very first instruction of the |
| // function is performed. |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| mov x30, x0 |
| cbz x1, 1b |
| |
| adr x2, 2f |
| br x2 |
| 2: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size lr_is_never_unsafe_before_first_inst_nocfg, .-lr_is_never_unsafe_before_first_inst_nocfg |
| |
| .globl bad_indirect_call_mem_nocfg |
| .type bad_indirect_call_mem_nocfg,@function |
| bad_indirect_call_mem_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_nocfg, 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] |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| blr x16 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_nocfg, .-bad_indirect_call_mem_nocfg |
| |
| .globl bad_indirect_call_arg_clobber_nocfg |
| .type bad_indirect_call_arg_clobber_nocfg,@function |
| bad_indirect_call_arg_clobber_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_arg_clobber_nocfg, 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 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| autia x0, x1 |
| mov w0, w2 |
| blr x0 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_arg_clobber_nocfg, .-bad_indirect_call_arg_clobber_nocfg |
| |
| .globl bad_indirect_call_mem_clobber_nocfg |
| .type bad_indirect_call_mem_clobber_nocfg,@function |
| bad_indirect_call_mem_clobber_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_clobber_nocfg, 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 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autia x16, x0 |
| mov w16, w2 |
| blr x16 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_clobber_nocfg, .-bad_indirect_call_mem_clobber_nocfg |
| |
| .globl good_indirect_call_mem_chain_of_auts_nocfg |
| .type good_indirect_call_mem_chain_of_auts_nocfg,@function |
| good_indirect_call_mem_chain_of_auts_nocfg: |
| // CHECK-NOT: good_indirect_call_mem_chain_of_auts_nocfg |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autda x16, x1 |
| ldr x16, [x16] |
| autia x16, x0 |
| blr x16 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_indirect_call_mem_chain_of_auts_nocfg, .-good_indirect_call_mem_chain_of_auts_nocfg |
| |
| .globl bad_indirect_call_mem_chain_of_auts_nocfg |
| .type bad_indirect_call_mem_chain_of_auts_nocfg,@function |
| bad_indirect_call_mem_chain_of_auts_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_call_mem_chain_of_auts_nocfg, 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, [x16] |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| autda x16, x1 |
| ldr x16, [x16] |
| // Missing AUT of x16. The fact that x16 was authenticated above has nothing to do with it. |
| blr x16 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_indirect_call_mem_chain_of_auts_nocfg, .-bad_indirect_call_mem_chain_of_auts_nocfg |
| |
| // Test tail calls. To somewhat decrease the number of test cases and not |
| // duplicate all of the above, only implement "mem" variant of test cases and |
| // mostly test negative cases. |
| |
| .globl good_direct_tailcall |
| .type good_direct_tailcall,@function |
| good_direct_tailcall: |
| // CHECK-NOT: good_direct_tailcall |
| b callee |
| .size good_direct_tailcall, .-good_direct_tailcall |
| |
| .globl good_indirect_tailcall_mem |
| .type good_indirect_tailcall_mem,@function |
| good_indirect_tailcall_mem: |
| // CHECK-NOT: good_indirect_tailcall_mem |
| ldr x16, [x0] |
| autia x16, x0 |
| br x16 |
| .size good_indirect_tailcall_mem, .-good_indirect_tailcall_mem |
| |
| .globl good_indirect_tailcall_mem_v83 |
| .type good_indirect_tailcall_mem_v83,@function |
| good_indirect_tailcall_mem_v83: |
| // CHECK-NOT: good_indirect_tailcall_mem_v83 |
| ldr x16, [x0] |
| braa x16, x0 |
| .size good_indirect_tailcall_mem_v83, .-good_indirect_tailcall_mem_v83 |
| |
| .globl bad_indirect_tailcall_mem |
| .type bad_indirect_tailcall_mem,@function |
| bad_indirect_tailcall_mem: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br 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]+}}: ldr x16, [x0] |
| // CHECK-NEXT: {{[0-9a-f]+}}: br x16 |
| ldr x16, [x0] |
| br x16 |
| .size bad_indirect_tailcall_mem, .-bad_indirect_tailcall_mem |
| |
| .globl bad_indirect_tailcall_mem_clobber |
| .type bad_indirect_tailcall_mem_clobber,@function |
| bad_indirect_tailcall_mem_clobber: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_clobber, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br 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]+}}: ldr x16, [x0] |
| // CHECK-NEXT: {{[0-9a-f]+}}: autia x16, x0 |
| // CHECK-NEXT: {{[0-9a-f]+}}: mov w16, w2 |
| // CHECK-NEXT: {{[0-9a-f]+}}: br x16 |
| ldr x16, [x0] |
| autia x16, x0 |
| mov w16, w2 |
| br x16 |
| .size bad_indirect_tailcall_mem_clobber, .-bad_indirect_tailcall_mem_clobber |
| |
| .globl bad_indirect_tailcall_mem_chain_of_auts |
| .type bad_indirect_tailcall_mem_chain_of_auts,@function |
| bad_indirect_tailcall_mem_chain_of_auts: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_chain_of_auts, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x16 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x16, [x16] |
| // CHECK-NEXT: This happens in the following basic block: |
| // CHECK-NEXT: {{[0-9a-f]+}}: ldr x16, [x0] |
| // CHECK-NEXT: {{[0-9a-f]+}}: autda x16, x1 |
| // CHECK-NEXT: {{[0-9a-f]+}}: ldr x16, [x16] |
| // CHECK-NEXT: {{[0-9a-f]+}}: br x16 |
| ldr x16, [x0] |
| autda x16, x1 |
| ldr x16, [x16] |
| // Missing AUT of x16. The fact that x16 was authenticated above has nothing to do with it. |
| br x16 |
| .size bad_indirect_tailcall_mem_chain_of_auts, .-bad_indirect_tailcall_mem_chain_of_auts |
| |
| .globl bad_indirect_tailcall_mem_multi_bb |
| .type bad_indirect_tailcall_mem_multi_bb,@function |
| bad_indirect_tailcall_mem_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_multi_bb, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br 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] |
| ldr x16, [x0] |
| cbz x2, 1f |
| autia x16, x1 |
| 1: |
| br x16 |
| .size bad_indirect_tailcall_mem_multi_bb, .-bad_indirect_tailcall_mem_multi_bb |
| |
| .globl bad_indirect_tailcall_mem_clobber_multi_bb |
| .type bad_indirect_tailcall_mem_clobber_multi_bb,@function |
| bad_indirect_tailcall_mem_clobber_multi_bb: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_clobber_multi_bb, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br 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 |
| ldr x16, [x0] |
| autia x16, x0 |
| cbz x2, 1f |
| mov w16, w2 |
| 1: |
| br x16 |
| .size bad_indirect_tailcall_mem_clobber_multi_bb, .-bad_indirect_tailcall_mem_clobber_multi_bb |
| |
| .globl good_direct_tailcall_nocfg |
| .type good_direct_tailcall_nocfg,@function |
| good_direct_tailcall_nocfg: |
| // CHECK-NOT: good_direct_tailcall_nocfg |
| adr x2, 1f |
| br x2 |
| 1: |
| b callee |
| .size good_direct_tailcall_nocfg, .-good_direct_tailcall_nocfg |
| |
| .globl good_indirect_tailcall_mem_nocfg |
| .type good_indirect_tailcall_mem_nocfg,@function |
| good_indirect_tailcall_mem_nocfg: |
| // CHECK-NOT: good_indirect_tailcall_mem_nocfg |
| adr x2, 1f |
| br x2 |
| 1: |
| ldr x16, [x0] |
| autia x16, x0 |
| br x16 |
| .size good_indirect_tailcall_mem_nocfg, .-good_indirect_tailcall_mem_nocfg |
| |
| .globl good_indirect_tailcall_mem_v83_nocfg |
| .type good_indirect_tailcall_mem_v83_nocfg,@function |
| good_indirect_tailcall_mem_v83_nocfg: |
| // CHECK-NOT: good_indirect_tailcall_mem_v83_nocfg |
| adr x2, 1f |
| br x2 |
| 1: |
| ldr x16, [x0] |
| braa x16, x0 |
| .size good_indirect_tailcall_mem_v83_nocfg, .-good_indirect_tailcall_mem_v83_nocfg |
| |
| .globl bad_indirect_tailcall_mem_nocfg |
| .type bad_indirect_tailcall_mem_nocfg,@function |
| bad_indirect_tailcall_mem_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br 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] |
| adr x2, 1f |
| br x2 |
| 1: |
| ldr x16, [x0] |
| br x16 |
| .size bad_indirect_tailcall_mem_nocfg, .-bad_indirect_tailcall_mem_nocfg |
| |
| .globl bad_indirect_tailcall_mem_clobber_nocfg |
| .type bad_indirect_tailcall_mem_clobber_nocfg,@function |
| bad_indirect_tailcall_mem_clobber_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_clobber_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br 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 |
| adr x2, 1f |
| br x2 |
| 1: |
| ldr x16, [x0] |
| autia x16, x0 |
| mov w16, w2 |
| br x16 |
| .size bad_indirect_tailcall_mem_clobber_nocfg, .-bad_indirect_tailcall_mem_clobber_nocfg |
| |
| .globl bad_indirect_tailcall_mem_chain_of_auts_nocfg |
| .type bad_indirect_tailcall_mem_chain_of_auts_nocfg,@function |
| bad_indirect_tailcall_mem_chain_of_auts_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_indirect_tailcall_mem_chain_of_auts_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x16 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x16, [x16] |
| adr x2, 1f |
| br x2 |
| 1: |
| ldr x16, [x0] |
| autda x16, x1 |
| ldr x16, [x16] |
| // Missing AUT of x16. The fact that x16 was authenticated above has nothing to do with it. |
| br x16 |
| .size bad_indirect_tailcall_mem_chain_of_auts_nocfg, .-bad_indirect_tailcall_mem_chain_of_auts_nocfg |
| |
| .globl state_is_reset_at_branch_destination_nocfg |
| .type state_is_reset_at_branch_destination_nocfg,@function |
| state_is_reset_at_branch_destination_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function state_is_reset_at_branch_destination_nocfg, 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 |
| |
| b 1f |
| autia x0, x1 // skipped |
| 1: |
| blr x0 |
| |
| adr x2, 2f |
| br x2 |
| 2: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size state_is_reset_at_branch_destination_nocfg, .-state_is_reset_at_branch_destination_nocfg |
| |
| // Test that calling a function is considered as invalidating safety of every |
| // register. Note that we only have to consider "returning" function calls |
| // (via branch-with-link), but both direct and indirect variants. |
| // Checking different registers: |
| // * x2 - function argument |
| // * x8 - indirect result location |
| // * x10 - temporary |
| // * x16 - intra-procedure-call scratch register |
| // * x18 - platform register |
| // * x20 - callee-saved register |
| |
| .globl direct_call_invalidates_safety |
| .type direct_call_invalidates_safety,@function |
| direct_call_invalidates_safety: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x2 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x8 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x10 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety, 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]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x18 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x20 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| mov x2, x0 |
| autiza x2 |
| bl callee |
| blr x2 |
| |
| mov x8, x0 |
| autiza x8 |
| bl callee |
| blr x8 |
| |
| mov x10, x0 |
| autiza x10 |
| bl callee |
| blr x10 |
| |
| mov x16, x0 |
| autiza x16 |
| bl callee |
| blr x16 |
| |
| mov x18, x0 |
| autiza x18 |
| bl callee |
| blr x18 |
| |
| mov x20, x0 |
| autiza x20 |
| bl callee |
| blr x20 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size direct_call_invalidates_safety, .-direct_call_invalidates_safety |
| |
| .globl indirect_call_invalidates_safety |
| .type indirect_call_invalidates_safety,@function |
| indirect_call_invalidates_safety: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x2 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x2 |
| // Check that only one error is reported per pair of BLRs. |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x2 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x8 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x8 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x8 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x10 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x10 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x10 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety, 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]+}}: blr x16 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x16 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x18 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x18 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x18 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x20 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x20 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x20 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| mov x2, x0 |
| autiza x2 |
| blr x2 // protected call, but makes x2 unsafe |
| blr x2 // unprotected call |
| |
| mov x8, x0 |
| autiza x8 |
| blr x8 // protected call, but makes x8 unsafe |
| blr x8 // unprotected call |
| |
| mov x10, x0 |
| autiza x10 |
| blr x10 // protected call, but makes x10 unsafe |
| blr x10 // unprotected call |
| |
| mov x16, x0 |
| autiza x16 |
| blr x16 // protected call, but makes x16 unsafe |
| blr x16 // unprotected call |
| |
| mov x18, x0 |
| autiza x18 |
| blr x18 // protected call, but makes x18 unsafe |
| blr x18 // unprotected call |
| |
| mov x20, x0 |
| autiza x20 |
| blr x20 // protected call, but makes x20 unsafe |
| blr x20 // unprotected call |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size indirect_call_invalidates_safety, .-indirect_call_invalidates_safety |
| |
| .globl direct_call_invalidates_safety_nocfg |
| .type direct_call_invalidates_safety_nocfg,@function |
| direct_call_invalidates_safety_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x2 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x8 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x10 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety_nocfg, 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]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x18 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function direct_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x20 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| mov x2, x0 |
| autiza x2 |
| bl callee |
| blr x2 |
| |
| mov x8, x0 |
| autiza x8 |
| bl callee |
| blr x8 |
| |
| mov x10, x0 |
| autiza x10 |
| bl callee |
| blr x10 |
| |
| mov x16, x0 |
| autiza x16 |
| bl callee |
| blr x16 |
| |
| mov x18, x0 |
| autiza x18 |
| bl callee |
| blr x18 |
| |
| mov x20, x0 |
| autiza x20 |
| bl callee |
| blr x20 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size direct_call_invalidates_safety_nocfg, .-direct_call_invalidates_safety_nocfg |
| |
| .globl indirect_call_invalidates_safety_nocfg |
| .type indirect_call_invalidates_safety_nocfg,@function |
| indirect_call_invalidates_safety_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x2 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x2 |
| // Check that only one error is reported per pair of BLRs. |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x2 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x8 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x8 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x8 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x10 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x10 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x10 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety_nocfg, 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]+}}: blr x16 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x16 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x18 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x18 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x18 |
| |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function indirect_call_invalidates_safety_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x20 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: blr x20 |
| // CHECK-NOT: The instruction is {{[0-9a-f]+}}: blr x20 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| mov x2, x0 |
| autiza x2 |
| blr x2 // protected call, but makes x2 unsafe |
| blr x2 // unprotected call |
| |
| mov x8, x0 |
| autiza x8 |
| blr x8 // protected call, but makes x8 unsafe |
| blr x8 // unprotected call |
| |
| mov x10, x0 |
| autiza x10 |
| blr x10 // protected call, but makes x10 unsafe |
| blr x10 // unprotected call |
| |
| mov x16, x0 |
| autiza x16 |
| blr x16 // protected call, but makes x16 unsafe |
| blr x16 // unprotected call |
| |
| mov x18, x0 |
| autiza x18 |
| blr x18 // protected call, but makes x18 unsafe |
| blr x18 // unprotected call |
| |
| mov x20, x0 |
| autiza x20 |
| blr x20 // protected call, but makes x20 unsafe |
| blr x20 // unprotected call |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size indirect_call_invalidates_safety_nocfg, .-indirect_call_invalidates_safety_nocfg |
| |
| // Test that fused auth+use Armv8.3 instruction do not mark register as safe. |
| |
| .globl blraa_no_mark_safe |
| .type blraa_no_mark_safe,@function |
| blraa_no_mark_safe: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function blraa_no_mark_safe, 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]+}}: blraa x0, x1 |
| // 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]+}}: blraa x0, x1 |
| // 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 |
| |
| blraa x0, x1 // safe, no write-back, clobbers everything |
| blr x0 // unsafe |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size blraa_no_mark_safe, .-blraa_no_mark_safe |
| |
| .globl blraa_no_mark_safe_nocfg |
| .type blraa_no_mark_safe_nocfg,@function |
| blraa_no_mark_safe_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function blraa_no_mark_safe_nocfg, 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]+}}: blraa x0, x1 |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| blraa x0, x1 // safe, no write-back, clobbers everything |
| blr x0 // detected as unsafe |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size blraa_no_mark_safe_nocfg, .-blraa_no_mark_safe_nocfg |
| |
| // Check that the correct set of registers is used to compute the set of last |
| // writing instructions: both x16 and x17 are tracked in this function, but |
| // only one particular register is used to compute the set of clobbering |
| // instructions in each report. |
| |
| .globl last_insts_writing_to_reg |
| .type last_insts_writing_to_reg,@function |
| last_insts_writing_to_reg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function last_insts_writing_to_reg, 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]+}}: ldr x17, [x1] |
| // CHECK-NEXT: {{[0-9a-f]+}}: blr x17 |
| // CHECK-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10 |
| // CHECK-NEXT: {{[0-9a-f]+}}: autiasp |
| // CHECK-NEXT: {{[0-9a-f]+}}: ret |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function last_insts_writing_to_reg, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x17 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x17, [x1] |
| // 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]+}}: ldr x17, [x1] |
| // CHECK-NEXT: {{[0-9a-f]+}}: blr x17 |
| // 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 |
| ldr x17, [x1] |
| blr x17 |
| |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size last_insts_writing_to_reg, .-last_insts_writing_to_reg |
| |
| .globl last_insts_writing_to_reg_nocfg |
| .type last_insts_writing_to_reg_nocfg,@function |
| last_insts_writing_to_reg_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function last_insts_writing_to_reg_nocfg, 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-LABEL: GS-PAUTH: non-protected call found in function last_insts_writing_to_reg_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x17 |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x17, [x1] |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| ldr x16, [x0] |
| blr x16 |
| ldr x17, [x1] |
| blr x17 |
| |
| adr x2, 1f |
| br x2 |
| 1: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size last_insts_writing_to_reg_nocfg, .-last_insts_writing_to_reg_nocfg |
| |
| // Test that the instructions reported to the user are not cluttered with |
| // annotations attached by data-flow analysis or its CFG-unaware counterpart. |
| |
| .globl printed_instrs_dataflow |
| .type printed_instrs_dataflow,@function |
| printed_instrs_dataflow: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function printed_instrs_dataflow, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # TAILCALL{{ *$}} |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x0, [x0]{{ *$}} |
| // CHECK-NEXT: This happens in the following basic block: |
| // CHECK-NEXT: {{[0-9a-f]+}}: ldr x0, [x0]{{ *$}} |
| // CHECK-NEXT: {{[0-9a-f]+}}: br x0 # TAILCALL{{ *$}} |
| ldr x0, [x0] |
| br x0 |
| .size printed_instrs_dataflow, .-printed_instrs_dataflow |
| |
| .globl printed_instrs_nocfg |
| .type printed_instrs_nocfg,@function |
| printed_instrs_nocfg: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function printed_instrs_nocfg, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # UNKNOWN CONTROL FLOW # Offset: 12{{ *$}} |
| // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: |
| // CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x0, [x0]{{ *$}} |
| adr x2, 1f |
| br x2 |
| 1: |
| ldr x0, [x0] |
| br x0 |
| .size printed_instrs_nocfg, .-printed_instrs_nocfg |
| |
| // Test handling of unreachable basic blocks. |
| // |
| // Basic blocks without any predecessors were observed in real-world optimized |
| // code. At least sometimes they were actually reachable via jump table, which |
| // was not detected, but the function was processed as if its CFG was |
| // reconstructed successfully. |
| // |
| // As a more predictable model example, let's use really unreachable code |
| // for testing. |
| |
| .globl bad_unreachable_call |
| .type bad_unreachable_call,@function |
| bad_unreachable_call: |
| // CHECK-LABEL: GS-PAUTH: Warning: possibly imprecise CFG, the analysis quality may be degraded in this function. According to BOLT, unreachable code is found in function bad_unreachable_call, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x0 |
| // CHECK-NOT: instructions that write to the affected registers after any authentication are: |
| // CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_unreachable_call, 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 |
| |
| b 1f |
| // unreachable basic block: |
| blr x0 |
| |
| 1: // reachable basic block: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size bad_unreachable_call, .-bad_unreachable_call |
| |
| .globl good_unreachable_call |
| .type good_unreachable_call,@function |
| good_unreachable_call: |
| // CHECK-NOT: non-protected call{{.*}}good_unreachable_call |
| // CHECK-LABEL: GS-PAUTH: Warning: possibly imprecise CFG, the analysis quality may be degraded in this function. According to BOLT, unreachable code is found in function good_unreachable_call, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 |
| // CHECK-NOT: instructions that write to the affected registers after any authentication are: |
| // CHECK-NOT: non-protected call{{.*}}good_unreachable_call |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| |
| b 1f |
| // unreachable basic block: |
| autia x0, x1 |
| blr x0 // <-- this call is definitely protected provided at least |
| // basic block boundaries are detected correctly |
| |
| 1: // reachable basic block: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size good_unreachable_call, .-good_unreachable_call |
| |
| .globl unreachable_loop_of_bbs |
| .type unreachable_loop_of_bbs,@function |
| unreachable_loop_of_bbs: |
| // CHECK-NOT: unreachable basic blocks{{.*}}unreachable_loop_of_bbs |
| // CHECK-NOT: non-protected call{{.*}}unreachable_loop_of_bbs |
| // CHECK-LABEL: GS-PAUTH: Warning: possibly imprecise CFG, the analysis quality may be degraded in this function. According to BOLT, unreachable code is found in function unreachable_loop_of_bbs, basic block {{[^,]+}}, at address |
| // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: blr x0 |
| // CHECK-NOT: unreachable basic blocks{{.*}}unreachable_loop_of_bbs |
| // CHECK-NOT: non-protected call{{.*}}unreachable_loop_of_bbs |
| paciasp |
| stp x29, x30, [sp, #-16]! |
| mov x29, sp |
| b .Lreachable_epilogue_bb |
| |
| .Lfirst_unreachable_bb: |
| blr x0 // <-- this call is not analyzed |
| b .Lsecond_unreachable_bb |
| .Lsecond_unreachable_bb: |
| blr x1 // <-- this call is not analyzed |
| b .Lfirst_unreachable_bb |
| |
| .Lreachable_epilogue_bb: |
| ldp x29, x30, [sp], #16 |
| autiasp |
| ret |
| .size unreachable_loop_of_bbs, .-unreachable_loop_of_bbs |
| |
| .globl main |
| .type main,@function |
| main: |
| mov x0, 0 |
| ret |
| .size main, .-main |