// -Wl,--no-relax prevents converting ADRP+ADD pairs into NOP+ADR. // RUN: %clang %cflags -march=armv8.3-a -Wl,--no-relax %s -o %t.exe // RUN: llvm-bolt-binary-analysis --scanners=ptrauth-all %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 // mention the instructions that are used incorrectly. .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 paciza x0 ret .size good_adr, .-good_adr .globl good_adrp .type good_adrp,@function good_adrp: // CHECK-NOT: good_adrp adrp x0, sym paciza x0 ret .size good_adrp, .-good_adrp .globl good_adrp_add .type good_adrp_add,@function good_adrp_add: // CHECK-NOT: good_adrp_add adrp x0, sym add x0, x0, :lo12:sym paciza x0 ret .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 adrp x0, sym add x0, x0, :lo12:sym add x0, x0, #8 paciza x0 ret .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: signing oracle found in function bad_adrp_with_nonconst_offset, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x0 // 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]+}}: adrp x0, #{{.*}} // CHECK-NEXT: {{[0-9a-f]+}}: add x0, x0, x1 // CHECK-NEXT: {{[0-9a-f]+}}: paciza x0 // CHECK-NEXT: {{[0-9a-f]+}}: ret adrp x0, sym add x0, x0, x1 paciza x0 ret .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: signing oracle found in function bad_split_adrp, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x0 // 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]+}}: paciza x0 // CHECK-NEXT: {{[0-9a-f]+}}: ret cbz x2, 1f adrp x0, sym 1: add x0, x0, :lo12:sym paciza x0 ret .size bad_split_adrp, .-bad_split_adrp // Materialization of absolute addresses is not handled, as it is not expected // to be used by real-world code, but can be supported if needed. .globl bad_immediate_constant .type bad_immediate_constant,@function bad_immediate_constant: // CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_immediate_constant, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x0 // 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]+}}: paciza x0 // CHECK-NEXT: {{[0-9a-f]+}}: ret movz x0, #1234 paciza x0 ret .size bad_immediate_constant, .-bad_immediate_constant // Any ADR or ADRP instruction followed by any number of increments/decrements // by constant is considered safe. .globl good_adr_with_add .type good_adr_with_add,@function good_adr_with_add: // CHECK-NOT: good_adr_with_add adr x0, sym add x0, x0, :lo12:sym paciza x0 ret .size good_adr_with_add, .-good_adr_with_add .globl good_adrp_with_add_non_consecutive .type good_adrp_with_add_non_consecutive,@function good_adrp_with_add_non_consecutive: // CHECK-NOT: good_adrp_with_add_non_consecutive adrp x0, sym mul x1, x2, x3 add x0, x0, :lo12:sym paciza x0 ret .size good_adrp_with_add_non_consecutive, .-good_adrp_with_add_non_consecutive .globl good_many_offsets .type good_many_offsets,@function good_many_offsets: // CHECK-NOT: good_many_offsets adrp x0, sym add x1, x0, #8 add x2, x1, :lo12:sym paciza x2 ret .size good_many_offsets, .-good_many_offsets .globl good_negative_offset .type good_negative_offset,@function good_negative_offset: // CHECK-NOT: good_negative_offset adr x0, sym sub x1, x0, #8 paciza x1 ret .size good_negative_offset, .-good_negative_offset // MOV Xd, Xm (which is an alias of ORR Xd, XZR, Xm) is handled as part of // support for address arithmetics, but ORR in general is not. // This restriction may be relaxed in the future. .globl good_mov_reg .type good_mov_reg,@function good_mov_reg: // CHECK-NOT: good_mov_reg adrp x0, sym mov x1, x0 orr x2, xzr, x1 // the same as "mov x2, x1" paciza x2 ret .size good_mov_reg, .-good_mov_reg .globl bad_orr_not_xzr .type bad_orr_not_xzr,@function bad_orr_not_xzr: // CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_orr_not_xzr, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x2 // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: orr x2, x1, x0 // CHECK-NEXT: This happens in the following basic block: // CHECK-NEXT: {{[0-9a-f]+}}: adrp x0, #{{(0x)?[0-9a-f]+}} // CHECK-NEXT: {{[0-9a-f]+}}: mov x1, #0 // CHECK-NEXT: {{[0-9a-f]+}}: orr x2, x1, x0 // CHECK-NEXT: {{[0-9a-f]+}}: paciza x2 // CHECK-NEXT: {{[0-9a-f]+}}: ret adrp x0, sym // The generic case of "orr Xd, Xn, Xm" is not allowed so far, // even if Xn is known to be safe movz x1, #0 orr x2, x1, x0 paciza x2 ret .size bad_orr_not_xzr, .-bad_orr_not_xzr .globl bad_orr_not_lsl0 .type bad_orr_not_lsl0,@function bad_orr_not_lsl0: // CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_orr_not_lsl0, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x2 // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: orr x2, xzr, x0, lsl #1 // CHECK-NEXT: This happens in the following basic block: // CHECK-NEXT: {{[0-9a-f]+}}: adrp x0, #{{(0x)?[0-9a-f]+}} // CHECK-NEXT: {{[0-9a-f]+}}: orr x2, xzr, x0, lsl #1 // CHECK-NEXT: {{[0-9a-f]+}}: paciza x2 // CHECK-NEXT: {{[0-9a-f]+}}: ret adrp x0, sym // Currently, the only allowed form of "orr" is that used by "mov Xd, Xn" alias. // This can be relaxed in the future. orr x2, xzr, x0, lsl #1 paciza x2 ret .size bad_orr_not_lsl0, .-bad_orr_not_lsl0 // Check that the input register operands of `add`/`mov` is correct. .globl bad_add_input_reg .type bad_add_input_reg,@function bad_add_input_reg: // CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_add_input_reg, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x0 // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: add x0, x1, #0x{{[0-9a-f]+}} // CHECK-NEXT: This happens in the following basic block: // CHECK-NEXT: {{[0-9a-f]+}}: adrp x0, #{{(0x)?[0-9a-f]+}} // CHECK-NEXT: {{[0-9a-f]+}}: add x0, x1, #0x{{[0-9a-f]+}} // CHECK-NEXT: {{[0-9a-f]+}}: paciza x0 // CHECK-NEXT: {{[0-9a-f]+}}: ret adrp x0, sym add x0, x1, :lo12:sym paciza x0 ret .size bad_add_input_reg, .-bad_add_input_reg .globl bad_mov_input_reg .type bad_mov_input_reg,@function bad_mov_input_reg: // CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_mov_input_reg, basic block {{[^,]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x0 // CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: mov x0, x1 // CHECK-NEXT: This happens in the following basic block: // CHECK-NEXT: {{[0-9a-f]+}}: adrp x0, #{{(0x)?[0-9a-f]+}} // CHECK-NEXT: {{[0-9a-f]+}}: mov x0, x1 // CHECK-NEXT: {{[0-9a-f]+}}: paciza x0 // CHECK-NEXT: {{[0-9a-f]+}}: ret adrp x0, sym mov x0, x1 paciza x0 ret .size bad_mov_input_reg, .-bad_mov_input_reg .globl main .type main,@function main: mov x0, 0 ret .size main, .-main