@@ -0,0 +1,228 @@
+// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
+// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
+
+// Test various patterns that should or should not be considered safe
+// materialization of PC-relative addresses.
+//
+// Note that while "instructions that write to the affected registers"
+// section of the report is still technically correct, it does not necessarily
+// mentions the instructions that are used incorrectly.
+//
+// FIXME: Switch to PAC* instructions instead of indirect tail call for testing
+//if a register is considered safe when detection of signing oracles is
+//implemented, as it is more traditional usage of PC-relative
constants.
+//Moreover, using PAC instructions would improve test robustness, as
+//handling of *calls* can be influenced by what BOLT classifies as a
+//tail call, for example.
+
+.text
+
+// Define a function that is reachable by ADR instruction.
+.type sym,@function
+sym:
+ret
+.size sym, .-sym
+
+.globl good_adr
+.type good_adr,@function
+good_adr:
+// CHECK-NOT: good_adr
+adr x0, sym
+br x0
+.size good_adr, .-good_adr
+
+.globl good_adrp
+.type good_adrp,@function
+good_adrp:
+// CHECK-NOT: good_adrp
+adrpx0, sym
+br x0
+.size good_adrp, .-good_adrp
+
+.globl good_adrp_add
+.type good_adrp_add,@function
+good_adrp_add:
+// CHECK-NOT: good_adrp_add
+adrpx0, sym
+add x0, x0, :lo12:sym
+br x0
+.size good_adrp_add, .-good_adrp_add
+
+.globl good_adrp_add_with_const_offset
+.type good_adrp_add_with_const_offset,@function
+good_adrp_add_with_const_offset:
+// CHECK-NOT: good_adrp_add_with_const_offset
+adrpx0, sym
+add x0, x0, :lo12:sym
+add x0, x0, #8
+br x0
+.size good_adrp_add_with_const_offset,
.-good_adrp_add_with_const_offset
+
+.globl bad_adrp_with_nonconst_offset
+.type bad_adrp_with_nonconst_offset,@function
+bad_adrp_with_nonconst_offset:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function
bad_adrp_with_nonconst_offset, 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]+}}: add x0, x0, x1
+// CHECK-NEXT: This happens in the following basic block:
+// CHECK-NEXT: {{[0-9a-f]+}}: adrpx0, #{{.*}}
+// CHECK-NEXT: {{[0-9a-f]+}}: add x0, x0, x1
+// CHECK-NEXT: {{[0-9a-f]+}}: br x0 # TAILCALL
+adrpx0, sym
+add x0, x0, x1
+br x0
+.size bad_adrp_with_nonconst_offset, .-bad_adrp_with_nonconst_offset
+
+.globl bad_split_adrp
+.type bad_split_adrp,@function
+bad_split_adrp:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_split_adrp,
basic block {{[^,]+}}, at address
+// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 #
UNKNOWN CONTROL FLOW
+// CHECK-NEXT: The 1 instructions that write to the affected registers after
any authentication are:
+// CHECK-NEXT: 1. {{[0-9a-f]+}}: add x0, x0, #0x{{[0-9a-f]+}}
+// CHECK-NEXT: This happens in the following basic block:
+// CHECK-NEXT: {{[0-9a-f]+}}: add x0, x0, #0x{{[0-9a-f]+}}
+// CHECK-NEXT: {{[0-9a-f]+}}: br x0 # UNKNOWN CONTROL FLOW
+cbz x2, 1f
+adrpx0, sym
+1:
+add x0, x0, :lo12:sym
+br x0
+.size bad_split_adrp, .-bad_split_adrp
+
+// Materialization of absolute addresses is not expected.
+
+.globl bad_immediate_constant
+.type bad_immediate_constant,@function
+bad_immediate_constant:
+// CHECK-LABEL: GS-PAUTH: non-protected call found in function
bad_immediate_constant, 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]+}}: mov x0, #{{.*}}
+// CHECK-NEXT: This happens in the following basic block:
+// CHECK-NEXT: {{[0-9a-f]+}}: mov x0, #{{.*}}
+// CHECK-NEXT: {{[0-9a-f]+}}: br x0 # TAILCALL
+movzx0, #1234
+br x0
jacobbramley wrote:
I think the classification of good and bad sequences is probably a bit tricky
in general. For example, the `#1234` is not attacker-controlled, and in some
real code we _might_ use `movz` and `movk` to materialise a constant address.
We can surely update these tests as other cases come up, so I don't think this
needs to change, but I wanted to acknowledge i