[BOLT] Gadget scanner: detect signing oracles (#134146)

Implement the detection of signing oracles. In this patch, a signing
oracle is defined as a sign instruction that accepts a "non-protected"
pointer, but for a slightly different definition of "non-protected"
compared to control flow instructions.

A second BitVector named TrustedRegs is added to the register state
computed by the data-flow analysis. The difference between a
"safe-to-dereference" and a "trusted" register states is that to make
an unsafe register trusted by authentication, one has to make sure
that the authentication succeeded. For example, on AArch64 without
FEAT_PAuth2 and FEAT_EPAC, an authentication instruction produces an
invalid pointer on failure, so that subsequent memory access triggers
an error, but re-signing such pointer would "fix" the signature.

Note that while a separate "trusted" register state may be redundant
depending on the specific semantics of auth and sign operations, it is
still important to check signing operations: while code like this

    resign:
      autda x0, x1
      pacda x0, x2
      ret

is probably safe provided `autda` generates an error on authentication
failure, this function

    sign_anything:
      pacda x0, x1
      ret

is inherently unsafe.
This commit is contained in:
Anatoly Trosinenko
2025-05-20 13:42:53 +03:00
committed by GitHub
parent 67440f0b83
commit 48a2836b4d
8 changed files with 2227 additions and 124 deletions

View File

@@ -0,0 +1,664 @@
// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe -Wl,--emit-relocs
// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
.text
.globl raise_error
.type raise_error,@function
raise_error:
ret
.size raise_error, .-raise_error
.globl resign_no_check
.type resign_no_check,@function
resign_no_check:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_no_check, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
pacia x0, x2
ret
.size resign_no_check, .-resign_no_check
// Test "xpac" check method.
.globl resign_xpaci_good
.type resign_xpaci_good,@function
resign_xpaci_good:
// CHECK-NOT: resign_xpaci_good
autib x0, x1
mov x16, x0
xpaci x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_xpaci_good, .-resign_xpaci_good
.globl resign_xpacd_good
.type resign_xpacd_good,@function
resign_xpacd_good:
// CHECK-NOT: resign_xpacd_good
autdb x0, x1
mov x16, x0
xpacd x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacda x0, x2
ret
.size resign_xpacd_good, .-resign_xpacd_good
.globl resign_xpaci_wrong_error
.type resign_xpaci_wrong_error,@function
resign_xpaci_wrong_error:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_wrong_error, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl raise_error
paciasp
stp x29, x30, [sp, #-16]!
autib x0, x1
mov x16, x0
xpaci x16
cmp x0, x16
b.eq 1f
bl raise_error // should trigger breakpoint instead
1:
pacia x0, x2
ldp x29, x30, [sp], #16
autiasp
ret
.size resign_xpaci_wrong_error, .-resign_xpaci_wrong_error
.globl resign_xpaci_missing_brk
.type resign_xpaci_missing_brk,@function
resign_xpaci_missing_brk:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_missing_brk, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
mov x16, x0
xpaci x16
cmp x0, x16
b.eq 1f
1:
pacia x0, x2
ret
.size resign_xpaci_missing_brk, .-resign_xpaci_missing_brk
.globl resign_xpaci_missing_branch_and_brk
.type resign_xpaci_missing_branch_and_brk,@function
resign_xpaci_missing_branch_and_brk:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_missing_branch_and_brk, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
mov x16, x0
xpaci x16
cmp x0, x16
pacia x0, x2
ret
.size resign_xpaci_missing_branch_and_brk, .-resign_xpaci_missing_branch_and_brk
.globl resign_xpaci_unrelated_auth_and_check
.type resign_xpaci_unrelated_auth_and_check,@function
resign_xpaci_unrelated_auth_and_check:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_unrelated_auth_and_check, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x10, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x10, x1 // made x10 safe-to-dereference
mov x16, x0 // start of checker sequence for x0
xpaci x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacia x10, x2
ret
.size resign_xpaci_unrelated_auth_and_check, .-resign_xpaci_unrelated_auth_and_check
// There are lots of operands to check in the pattern - let's at the very least
// check that each of the three instructions (mov, xpac, cmp) undergoes *some*
// matching. Pay a bit more attention to those instructions and their operands
// that can be obviously replaced without crashing at run-time and making the
// check obviously weaker.
.globl resign_xpaci_wrong_pattern_1
.type resign_xpaci_wrong_pattern_1,@function
resign_xpaci_wrong_pattern_1:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_wrong_pattern_1, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
mov x16, x10 // x10 instead of x0
xpaci x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_xpaci_wrong_pattern_1, .-resign_xpaci_wrong_pattern_1
.globl resign_xpaci_wrong_pattern_2
.type resign_xpaci_wrong_pattern_2,@function
resign_xpaci_wrong_pattern_2:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_wrong_pattern_2, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: xpaci x0
autib x0, x1
mov x16, x0
xpaci x0 // x0 instead of x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_xpaci_wrong_pattern_2, .-resign_xpaci_wrong_pattern_2
.globl resign_xpaci_wrong_pattern_3
.type resign_xpaci_wrong_pattern_3,@function
resign_xpaci_wrong_pattern_3:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_wrong_pattern_3, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
mov x16, x0
xpaci x16
cmp x16, x16 // x16 instead of x0
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_xpaci_wrong_pattern_3, .-resign_xpaci_wrong_pattern_3
.globl resign_xpaci_wrong_pattern_4
.type resign_xpaci_wrong_pattern_4,@function
resign_xpaci_wrong_pattern_4:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_wrong_pattern_4, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
mov x16, x0
xpaci x16
cmp x0, x0 // x0 instead of x16
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_xpaci_wrong_pattern_4, .-resign_xpaci_wrong_pattern_4
.globl resign_xpaci_wrong_pattern_5
.type resign_xpaci_wrong_pattern_5,@function
resign_xpaci_wrong_pattern_5:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaci_wrong_pattern_5, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
mov x16, x0
mov x16, x16 // replace xpaci with a no-op instruction
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_xpaci_wrong_pattern_5, .-resign_xpaci_wrong_pattern_5
// Test "xpac-hint" check method.
.globl resign_xpaclri_good
.type resign_xpaclri_good,@function
resign_xpaclri_good:
// CHECK-NOT: resign_xpaclri_good
paciasp
stp x29, x30, [sp, #-16]!
autib x30, x1
mov x16, x30
xpaclri
cmp x30, x16
b.eq 1f
brk 0x1234
1:
pacia x30, x2
ldp x29, x30, [sp], #16
autiasp
ret
.size resign_xpaclri_good, .-resign_xpaclri_good
.globl xpaclri_check_keeps_lr_safe
.type xpaclri_check_keeps_lr_safe,@function
xpaclri_check_keeps_lr_safe:
// CHECK-NOT: xpaclri_check_keeps_lr_safe
// LR is implicitly safe-to-dereference and trusted here
mov x16, x30
xpaclri // clobbers LR
cmp x30, x16
b.eq 1f
brk 0x1234 // marks LR as trusted and safe-to-dereference
1:
ret // not reporting non-protected return
.size xpaclri_check_keeps_lr_safe, .-xpaclri_check_keeps_lr_safe
.globl xpaclri_check_requires_safe_lr
.type xpaclri_check_requires_safe_lr,@function
xpaclri_check_requires_safe_lr:
// CHECK-LABEL: GS-PAUTH: non-protected ret found in function xpaclri_check_requires_safe_lr, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: xpaclri
mov x30, x0
// LR is not safe-to-dereference here - check that xpac-hint checker
// does not make LR safe-to-dereference, but only *keeps* this state.
mov x16, x30
xpaclri
cmp x30, x16
b.eq 1f
brk 0x1234
1:
ret
.size xpaclri_check_requires_safe_lr, .-xpaclri_check_requires_safe_lr
.globl resign_xpaclri_wrong_reg
.type resign_xpaclri_wrong_reg,@function
resign_xpaclri_wrong_reg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_xpaclri_wrong_reg, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x20, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
autib x20, x1 // consistently using x20 instead of x30
mov x16, x20
xpaclri // ... but xpaclri still operates on x30
cmp x20, x16
b.eq 1f
brk 0x1234
1:
pacia x20, x2
autiasp
ret
.size resign_xpaclri_wrong_reg, .-resign_xpaclri_wrong_reg
// Test that pointer should be authenticated AND checked to be safe-to-sign.
// Checking alone is not enough.
.globl resign_checked_not_authenticated
.type resign_checked_not_authenticated,@function
resign_checked_not_authenticated:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_checked_not_authenticated, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
mov x16, x0
xpaci x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_checked_not_authenticated, .-resign_checked_not_authenticated
// The particular register should be *first* written by an authentication
// instruction and *then* that new value should be checked.
// Such code pattern will probably crash at run-time anyway, but let's check
// "safe-to-dereference" -> "trusted" transition.
.globl resign_checked_before_authenticated
.type resign_checked_before_authenticated,@function
resign_checked_before_authenticated:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_checked_before_authenticated, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
mov x16, x0
xpaci x16
cmp x0, x16
b.eq 1f
brk 0x1234
1:
autib x0, x1
pacia x0, x2
ret
.size resign_checked_before_authenticated, .-resign_checked_before_authenticated
// Test "high-bits-notbi" check method.
.globl resign_high_bits_tbz_good
.type resign_high_bits_tbz_good,@function
resign_high_bits_tbz_good:
// CHECK-NOT: resign_high_bits_tbz_good
autib x0, x1
eor x16, x0, x0, lsl #1
tbz x16, #62, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_good, .-resign_high_bits_tbz_good
// Check BRK matching briefly - this logic is shared with the "xpac" sequence matcher.
.globl resign_high_bits_tbz_wrong_error
.type resign_high_bits_tbz_wrong_error,@function
resign_high_bits_tbz_wrong_error:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_error, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl raise_error
paciasp
stp x29, x30, [sp, #-16]!
autib x0, x1
eor x16, x0, x0, lsl #1
tbz x16, #62, 1f
bl raise_error // should trigger breakpoint instead
1:
pacia x0, x2
ldp x29, x30, [sp], #16
autiasp
ret
.size resign_high_bits_tbz_wrong_error, .-resign_high_bits_tbz_wrong_error
.globl resign_high_bits_tbz_wrong_bit
.type resign_high_bits_tbz_wrong_bit,@function
resign_high_bits_tbz_wrong_bit:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_bit, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
eor x16, x0, x0, lsl #1
tbz x16, #63, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_wrong_bit, .-resign_high_bits_tbz_wrong_bit
.globl resign_high_bits_tbz_wrong_shift_amount
.type resign_high_bits_tbz_wrong_shift_amount,@function
resign_high_bits_tbz_wrong_shift_amount:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_shift_amount, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
eor x16, x0, x0, lsl #2
tbz x16, #62, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_wrong_shift_amount, .-resign_high_bits_tbz_wrong_shift_amount
.globl resign_high_bits_tbz_wrong_shift_type
.type resign_high_bits_tbz_wrong_shift_type,@function
resign_high_bits_tbz_wrong_shift_type:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_shift_type, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
eor x16, x0, x0, lsr #1
tbz x16, #62, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_wrong_shift_type, .-resign_high_bits_tbz_wrong_shift_type
.globl resign_high_bits_tbz_wrong_pattern_1
.type resign_high_bits_tbz_wrong_pattern_1,@function
resign_high_bits_tbz_wrong_pattern_1:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_pattern_1, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
eor x16, x0, x0, lsl #1
tbz x17, #62, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_wrong_pattern_1, .-resign_high_bits_tbz_wrong_pattern_1
.globl resign_high_bits_tbz_wrong_pattern_2
.type resign_high_bits_tbz_wrong_pattern_2,@function
resign_high_bits_tbz_wrong_pattern_2:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_pattern_2, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
eor x16, x10, x0, lsl #1
tbz x16, #62, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_wrong_pattern_2, .-resign_high_bits_tbz_wrong_pattern_2
.globl resign_high_bits_tbz_wrong_pattern_3
.type resign_high_bits_tbz_wrong_pattern_3,@function
resign_high_bits_tbz_wrong_pattern_3:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_high_bits_tbz_wrong_pattern_3, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autib x0, x1
eor x16, x0, x10, lsl #1
tbz x16, #62, 1f
brk 0x1234
1:
pacia x0, x2
ret
.size resign_high_bits_tbz_wrong_pattern_3, .-resign_high_bits_tbz_wrong_pattern_3
// Test checking by loading via the authenticated pointer.
.globl resign_load_good
.type resign_load_good,@function
resign_load_good:
// CHECK-NOT: resign_load_good
autdb x0, x1
ldr x3, [x0]
pacda x0, x2
ret
.size resign_load_good, .-resign_load_good
.globl resign_load_wreg_good
.type resign_load_wreg_good,@function
resign_load_wreg_good:
// CHECK-NOT: resign_load_wreg_good
autdb x0, x1
ldr w3, [x0]
pacda x0, x2
ret
.size resign_load_wreg_good, .-resign_load_wreg_good
.globl resign_load_byte_good
.type resign_load_byte_good,@function
resign_load_byte_good:
// CHECK-NOT: resign_load_byte_good
autdb x0, x1
ldrb w3, [x0]
pacda x0, x2
ret
.size resign_load_byte_good, .-resign_load_byte_good
.globl resign_load_pair_good
.type resign_load_pair_good,@function
resign_load_pair_good:
// CHECK-NOT: resign_load_pair_good
autdb x0, x1
ldp x3, x4, [x0]
pacda x0, x2
ret
.size resign_load_pair_good, .-resign_load_pair_good
.globl resign_load_imm_offset_good
.type resign_load_imm_offset_good,@function
resign_load_imm_offset_good:
// CHECK-NOT: resign_load_imm_offset_good
autdb x0, x1
ldr x3, [x0, #16]
pacda x0, x2
ret
.size resign_load_imm_offset_good, .-resign_load_imm_offset_good
.globl resign_load_preinc_good
.type resign_load_preinc_good,@function
resign_load_preinc_good:
// CHECK-NOT: resign_load_preinc_good
autdb x0, x1
ldr x3, [x0, #16]!
pacda x0, x2
ret
.size resign_load_preinc_good, .-resign_load_preinc_good
.globl resign_load_postinc_good
.type resign_load_postinc_good,@function
resign_load_postinc_good:
// CHECK-NOT: resign_load_postinc_good
autdb x0, x1
ldr x3, [x0], #16
pacda x0, x2
ret
.size resign_load_postinc_good, .-resign_load_postinc_good
.globl resign_load_pair_with_ptr_writeback_good
.type resign_load_pair_with_ptr_writeback_good,@function
resign_load_pair_with_ptr_writeback_good:
// CHECK-NOT: resign_load_pair_with_ptr_writeback_good
autdb x0, x1
ldp x3, x4, [x0, #16]! // three output registers (incl. tied x0 register)
pacda x0, x2
ret
.size resign_load_pair_with_ptr_writeback_good, .-resign_load_pair_with_ptr_writeback_good
.globl resign_load_overwrite
.type resign_load_overwrite,@function
resign_load_overwrite:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_load_overwrite, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x0, [x0]
autdb x0, x1
ldr x0, [x0]
pacda x0, x2
ret
.size resign_load_overwrite, .-resign_load_overwrite
.globl resign_load_overwrite_out2
.type resign_load_overwrite_out2,@function
resign_load_overwrite_out2:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_load_overwrite_out2, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldp x10, x0, [x0]
autdb x0, x1
ldp x10, x0, [x0]
pacda x0, x2
ret
.size resign_load_overwrite_out2, .-resign_load_overwrite_out2
.globl resign_load_partial_overwrite
.type resign_load_partial_overwrite,@function
resign_load_partial_overwrite:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_load_partial_overwrite, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr w0, [x0]
autdb x0, x1
ldr w0, [x0]
pacda x0, x2
ret
.size resign_load_partial_overwrite, .-resign_load_partial_overwrite
.globl resign_load_partial_overwrite_out2
.type resign_load_partial_overwrite_out2,@function
resign_load_partial_overwrite_out2:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_load_partial_overwrite_out2, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x2
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldp w10, w0, [x0]
autdb x0, x1
ldp w10, w0, [x0]
pacda x0, x2
ret
.size resign_load_partial_overwrite_out2, .-resign_load_partial_overwrite_out2
// Test that base register + offset register addressing mode is rejected.
.globl resign_load_reg_plus_reg
.type resign_load_reg_plus_reg,@function
resign_load_reg_plus_reg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_load_reg_plus_reg, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autdb x0, x1
ldr x3, [x0, x4]
pacda x0, x2
ret
.size resign_load_reg_plus_reg, .-resign_load_reg_plus_reg
.globl resign_load_reg_plus_reg_in2
.type resign_load_reg_plus_reg_in2,@function
resign_load_reg_plus_reg_in2:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function resign_load_reg_plus_reg_in2, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x2
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autdb x0, x1
ldr x3, [x4, x0]
pacda x0, x2
ret
.size resign_load_reg_plus_reg_in2, .-resign_load_reg_plus_reg_in2
.globl resign_load_unscaled_good
.type resign_load_unscaled_good,@function
resign_load_unscaled_good:
// CHECK-NOT: resign_load_unscaled_good
autdb x0, x1
ldurb w3, [x0, #-1]
pacda x0, x2
ret
.size resign_load_unscaled_good, .-resign_load_unscaled_good
// Any basic block can check at most one register using a multi-instruction
// pointer-checking sequence, but it can contain an arbitrary number of single-
// instruction pointer checks.
.globl many_checked_regs
.type many_checked_regs,@function
many_checked_regs:
// CHECK-NOT: many_checked_regs
autdzb x0
autdzb x1
autdzb x2
b 1f
1:
ldr w3, [x0] // single-instruction check
ldr w3, [x1] // single-instruction check
mov x16, x2 // start of multi-instruction checker sequence
xpacd x16 // ...
cmp x2, x16 // ...
b.eq 2f // end of basic block
brk 0x1234
2:
pacdza x0
pacdza x1
pacdza x2
ret
.size many_checked_regs, .-many_checked_regs
.globl main
.type main,@function
main:
mov x0, 0
ret
.size main, .-main

View File

@@ -8,13 +8,6 @@
// 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.
//
// 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
@@ -29,7 +22,8 @@ sym:
good_adr:
// CHECK-NOT: good_adr
adr x0, sym
br x0
paciza x0
ret
.size good_adr, .-good_adr
.globl good_adrp
@@ -37,7 +31,8 @@ good_adr:
good_adrp:
// CHECK-NOT: good_adrp
adrp x0, sym
br x0
paciza x0
ret
.size good_adrp, .-good_adrp
.globl good_adrp_add
@@ -46,7 +41,8 @@ good_adrp_add:
// CHECK-NOT: good_adrp_add
adrp x0, sym
add x0, x0, :lo12:sym
br x0
paciza x0
ret
.size good_adrp_add, .-good_adrp_add
.globl good_adrp_add_with_const_offset
@@ -56,40 +52,45 @@ good_adrp_add_with_const_offset:
adrp x0, sym
add x0, x0, :lo12:sym
add x0, x0, #8
br x0
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: 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-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]+}}: br x0 # TAILCALL
// CHECK-NEXT: {{[0-9a-f]+}}: paciza x0
// CHECK-NEXT: {{[0-9a-f]+}}: ret
adrp x0, sym
add x0, x0, x1
br x0
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: 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-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]+}}: br x0 # UNKNOWN CONTROL FLOW
// 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
br x0
paciza x0
ret
.size bad_split_adrp, .-bad_split_adrp
// Materialization of absolute addresses is not handled, as it is not expected
@@ -98,15 +99,17 @@ bad_split_adrp:
.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-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]+}}: br x0 # TAILCALL
// CHECK-NEXT: {{[0-9a-f]+}}: paciza x0
// CHECK-NEXT: {{[0-9a-f]+}}: ret
movz x0, #1234
br x0
paciza x0
ret
.size bad_immediate_constant, .-bad_immediate_constant
// Any ADR or ADRP instruction followed by any number of increments/decrements
@@ -118,7 +121,8 @@ good_adr_with_add:
// CHECK-NOT: good_adr_with_add
adr x0, sym
add x0, x0, :lo12:sym
br x0
paciza x0
ret
.size good_adr_with_add, .-good_adr_with_add
.globl good_adrp_with_add_non_consecutive
@@ -128,7 +132,8 @@ good_adrp_with_add_non_consecutive:
adrp x0, sym
mul x1, x2, x3
add x0, x0, :lo12:sym
br x0
paciza x0
ret
.size good_adrp_with_add_non_consecutive, .-good_adrp_with_add_non_consecutive
.globl good_many_offsets
@@ -138,7 +143,8 @@ good_many_offsets:
adrp x0, sym
add x1, x0, #8
add x2, x1, :lo12:sym
br x2
paciza x2
ret
.size good_many_offsets, .-good_many_offsets
.globl good_negative_offset
@@ -147,7 +153,8 @@ good_negative_offset:
// CHECK-NOT: good_negative_offset
adr x0, sym
sub x1, x0, #8
br x1
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
@@ -161,45 +168,50 @@ good_mov_reg:
adrp x0, sym
mov x1, x0
orr x2, xzr, x1 // the same as "mov x2, x1"
br x2
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: non-protected call found in function bad_orr_not_xzr, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x2 # TAILCALL
// 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]+}}: br x2 # TAILCALL
// 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
br x2
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: non-protected call found in function bad_orr_not_lsl0, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x2 # TAILCALL
// 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]+}}: br x2 # TAILCALL
// 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
br x2
paciza x2
ret
.size bad_orr_not_lsl0, .-bad_orr_not_lsl0
// Check that the input register operands of `add`/`mov` is correct.
@@ -207,33 +219,37 @@ bad_orr_not_lsl0:
.globl bad_add_input_reg
.type bad_add_input_reg,@function
bad_add_input_reg:
// CHECK-LABEL: GS-PAUTH: non-protected call found in function bad_add_input_reg, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # TAILCALL
// 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]+}}: br x0 # TAILCALL
// CHECK-NEXT: {{[0-9a-f]+}}: paciza x0
// CHECK-NEXT: {{[0-9a-f]+}}: ret
adrp x0, sym
add x0, x1, :lo12:sym
br x0
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: non-protected call found in function bad_mov_input_reg, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # TAILCALL
// 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]+}}: br x0 # TAILCALL
// CHECK-NEXT: {{[0-9a-f]+}}: paciza x0
// CHECK-NEXT: {{[0-9a-f]+}}: ret
adrp x0, sym
mov x0, x1
br x0
paciza x0
ret
.size bad_mov_input_reg, .-bad_mov_input_reg
.globl main

View File

@@ -591,7 +591,9 @@ obscure_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:
// CHECK-NOT: 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:

View File

@@ -51,40 +51,40 @@ simple:
// CHECK-NEXT: End of Function "simple"
// CHECK-EMPTY:
// CHECK-NEXT: Running src register safety analysis...
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #25, src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( stp x29, x30, [sp, #-0x10]!, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( b [[BB1]], src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #25, src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( stp x29, x30, [sp, #-0x10]!, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( b [[BB1]], src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: DataflowSrcSafetyAnalysis::Confluence(
// CHECK-NEXT: State 1: src-state<empty>
// CHECK-NEXT: State 2: src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: merged state: src-state<SafeToDerefRegs: , Insts: >
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W0 X0 W0_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state<SafeToDerefRegs: W0 X0 W0_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: State 2: src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: merged state: src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W0 X0 W0_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state<SafeToDerefRegs: W0 X0 W0_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: DataflowSrcSafetyAnalysis::Confluence(
// CHECK-NEXT: State 1: src-state<SafeToDerefRegs: , Insts: >
// CHECK-NEXT: State 2: src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: merged state: src-state<SafeToDerefRegs: , Insts: >
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W0 X0 W0_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state<SafeToDerefRegs: W0 X0 W0_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: State 1: src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >
// CHECK-NEXT: State 2: src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: merged state: src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W0 X0 W0_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state<SafeToDerefRegs: W0 X0 W0_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: , Insts: >)
// CHECK-NEXT: After src register safety analysis:
// CHECK-NEXT: Binary Function "simple" {
// CHECK-NEXT: Number : 1
@@ -94,27 +94,30 @@ simple:
// CHECK-NEXT: }
// CHECK-NEXT: [[BB0]] (3 instructions, align : 1)
// CHECK-NEXT: Entry Point
// CHECK-NEXT: 00000000: paciasp # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000004: stp x29, x30, [sp, #-0x10]! # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000008: b [[BB1]] # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000000: paciasp # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 00000004: stp x29, x30, [sp, #-0x10]! # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 00000008: b [[BB1]] # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: Successors: [[BB1]]
// CHECK-EMPTY:
// CHECK-NEXT: [[BB1]] (5 instructions, align : 1)
// CHECK-NEXT: Predecessors: [[BB0]]
// CHECK-NEXT: 0000000c: autiza x0 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000010: blr x0 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000014: ldp x29, x30, [sp], #0x10 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000018: autiasp # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 0000001c: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 0000000c: autiza x0 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 00000010: blr x0 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 00000014: ldp x29, x30, [sp], #0x10 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 00000018: autiasp # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 0000001c: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-EMPTY:
// CHECK-NEXT: DWARF CFI Instructions:
// CHECK-NEXT: <empty>
// CHECK-NEXT: End of Function "simple"
// CHECK-EMPTY:
// PAUTH-NEXT: Found call inst: 00000000: blr x0 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// PAUTH-NEXT: Found sign inst: 00000000: paciasp # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// PAUTH-NEXT: Signed reg: LR
// PAUTH-NEXT: TrustedRegs: LR W30 W30_HI
// PAUTH-NEXT: Found call inst: 00000000: blr x0 # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// PAUTH-NEXT: Call destination reg: X0
// PAUTH-NEXT: SafeToDerefRegs: W0 X0 W0_HI{{[ \t]*$}}
// CHECK-NEXT: Found RET inst: 00000000: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: Found RET inst: 00000000: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: RetReg: LR
// CHECK-NEXT: Authenticated reg: (none)
// CHECK-NEXT: SafeToDerefRegs: LR W30 W30_HI{{[ \t]*$}}
@@ -129,10 +132,10 @@ clobber:
// CHECK-LABEL:Analyzing in function clobber, AllocatorId 1
// ...
// CHECK: Running src register safety analysis...
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , TrustedRegs: W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: W30_HI , TrustedRegs: W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , TrustedRegs: W30_HI , Insts: >)
// CHECK-NEXT: After src register safety analysis:
// CHECK-NEXT: Binary Function "clobber" {
// ...
@@ -141,16 +144,16 @@ clobber:
// The above output was printed after first run of analysis
// CHECK-EMPTY:
// CHECK-NEXT: Found RET inst: 00000000: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: Found RET inst: 00000000: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: RetReg: LR
// CHECK-NEXT: Authenticated reg: (none)
// CHECK-NEXT: SafeToDerefRegs: W30_HI{{[ \t]*$}}
// CHECK-EMPTY:
// CHECK-NEXT: Running detailed src register safety analysis...
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: LR W30 W30_HI , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , TrustedRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: W30_HI , TrustedRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: W30_HI , TrustedRegs: W30_HI , Insts: [0](0x{{[0-9a-f]+}} )>)
// CHECK-NEXT: After detailed src register safety analysis:
// CHECK-NEXT: Binary Function "clobber" {
// ...
@@ -160,7 +163,7 @@ clobber:
// Iterating over the reports and attaching clobbering info:
// CHECK-EMPTY:
// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: [0](0x{{[0-9a-f]+}} )>
// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # DataflowSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: [0](0x{{[0-9a-f]+}} )>
.globl nocfg
.type nocfg,@function
@@ -193,13 +196,13 @@ nocfg:
// CHECK-NEXT: End of Function "nocfg"
// CHECK-EMPTY:
// CHECK-NEXT: Running src register safety analysis...
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: LR W30 W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , TrustedRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , TrustedRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , TrustedRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: >)
// CHECK-NEXT: Due to label, resetting the state before: 00000000: ret # Offset: 8
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: >)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: >)
// CHECK-NEXT: After src register safety analysis:
// CHECK-NEXT: Binary Function "nocfg" {
// CHECK-NEXT: Number : 3
@@ -208,31 +211,31 @@ nocfg:
// CHECK: Secondary Entry Points : __ENTRY_nocfg@0x[[ENTRY_ADDR]]
// CHECK-NEXT: }
// CHECK-NEXT: .{{[A-Za-z0-9]+}}:
// CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: __ENTRY_nocfg@0x[[ENTRY_ADDR]] (Entry Point):
// CHECK-NEXT: .{{[A-Za-z0-9]+}}:
// CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: DWARF CFI Instructions:
// CHECK-NEXT: <empty>
// CHECK-NEXT: End of Function "nocfg"
// CHECK-EMPTY:
// PAUTH-NEXT: Found call inst: 00000000: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// PAUTH-NEXT: Found call inst: 00000000: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// PAUTH-NEXT: Call destination reg: X0
// PAUTH-NEXT: SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI
// CHECK-NEXT: Found RET inst: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: >
// CHECK-NEXT: Found RET inst: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: >
// CHECK-NEXT: RetReg: LR
// CHECK-NEXT: Authenticated reg: (none)
// CHECK-NEXT: SafeToDerefRegs:
// CHECK-EMPTY:
// CHECK-NEXT: Running detailed src register safety analysis...
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state<SafeToDerefRegs: LR W30 W30_HI , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: [0]()>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: [0]()>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state<SafeToDerefRegs: LR W30 W30_HI , TrustedRegs: LR W30 W30_HI , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , TrustedRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: [0]()>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , TrustedRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI , TrustedRegs: LR W0 W30 X0 W0_HI W30_HI , Insts: [0]()>)
// CHECK-NEXT: Due to label, resetting the state before: 00000000: ret # Offset: 8
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , Insts: [0]()>)
// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state<SafeToDerefRegs: , TrustedRegs: , Insts: [0]()>)
// CHECK-NEXT: .. result: (src-state<SafeToDerefRegs: , TrustedRegs: , Insts: [0]()>)
// CHECK-NEXT: After detailed src register safety analysis:
// CHECK-NEXT: Binary Function "nocfg" {
// CHECK-NEXT: Number : 3
@@ -240,16 +243,16 @@ nocfg:
// CHECK: Secondary Entry Points : __ENTRY_nocfg@0x[[ENTRY_ADDR]]
// CHECK-NEXT: }
// CHECK-NEXT: .{{[A-Za-z0-9]+}}:
// CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: __ENTRY_nocfg@0x[[ENTRY_ADDR]] (Entry Point):
// CHECK-NEXT: .{{[A-Za-z0-9]+}}:
// CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: DWARF CFI Instructions:
// CHECK-NEXT: <empty>
// CHECK-NEXT: End of Function "nocfg"
// CHECK-EMPTY:
// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, Insts: [0]()>
// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state<SafeToDerefRegs: BitVector, TrustedRegs: BitVector, Insts: [0]()>
// CHECK-LABEL:Analyzing in function main, AllocatorId 1
.globl main

View File

@@ -0,0 +1,993 @@
// RUN: %clang %cflags -march=armv8.3-a+pauth-lr -Wl,--no-relax %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
// The detection of compiler-generated explicit pointer checks is tested in
// gs-pauth-address-checks.s, for that reason only test here "dummy-load" and
// "high-bits-notbi" checkers, as the shortest examples of checkers that are
// detected per-instruction and per-BB.
// PACRET-NOT: signing oracle found in function
.text
.type sym,@function
sym:
ret
.size sym, .-sym
.globl callee
.type callee,@function
callee:
ret
.size callee, .-callee
// Test transitions between register states: none, safe-to-dereference (s-t-d), trusted:
// * trusted right away: safe address materialization
// * trusted as checked s-t-d: two variants of checks
// * untrusted: s-t-d, but not checked
// * untrusted: not s-t-d, but checked
// * untrusted: not even s-t-d - from arg and from memory
// * untrusted: {subreg clobbered, function called} X {between address materialization and use, between auth and check, between check and use}
// * untrusted: first checked then auted, auted then auted, checked then checked
.globl good_sign_addr_mat
.type good_sign_addr_mat,@function
good_sign_addr_mat:
// CHECK-NOT: good_sign_addr_mat
adr x0, sym
pacda x0, x1
ret
.size good_sign_addr_mat, .-good_sign_addr_mat
.globl good_sign_auted_checked_ldr
.type good_sign_auted_checked_ldr,@function
good_sign_auted_checked_ldr:
// CHECK-NOT: good_sign_auted_checked_ldr
autda x0, x2
ldr x2, [x0]
pacda x0, x1
ret
.size good_sign_auted_checked_ldr, .-good_sign_auted_checked_ldr
.globl good_sign_auted_checked_brk
.type good_sign_auted_checked_brk,@function
good_sign_auted_checked_brk:
// CHECK-NOT: good_sign_auted_checked_brk
autda x0, x2
eor x16, x0, x0, lsl #1
tbz x16, #62, 1f
brk 0x1234
1:
pacda x0, x1
ret
.size good_sign_auted_checked_brk, .-good_sign_auted_checked_brk
.globl bad_sign_authed_unchecked
.type bad_sign_authed_unchecked,@function
bad_sign_authed_unchecked:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_authed_unchecked, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autda x0, x2
pacda x0, x1
ret
.size bad_sign_authed_unchecked, .-bad_sign_authed_unchecked
.globl bad_sign_checked_not_auted
.type bad_sign_checked_not_auted,@function
bad_sign_checked_not_auted:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_checked_not_auted, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
ldr x2, [x0]
pacda x0, x1
ret
.size bad_sign_checked_not_auted, .-bad_sign_checked_not_auted
.globl bad_sign_plain_arg
.type bad_sign_plain_arg,@function
bad_sign_plain_arg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_plain_arg, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
pacda x0, x1
ret
.size bad_sign_plain_arg, .-bad_sign_plain_arg
.globl bad_sign_plain_mem
.type bad_sign_plain_mem,@function
bad_sign_plain_mem:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_plain_mem, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x0, [x1]
// CHECK-NEXT: This happens in the following basic block:
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x0, [x1]
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ret
ldr x0, [x1]
pacda x0, x1
ret
.size bad_sign_plain_mem, .-bad_sign_plain_mem
.globl bad_clobber_between_addr_mat_and_use
.type bad_clobber_between_addr_mat_and_use,@function
bad_clobber_between_addr_mat_and_use:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_addr_mat_and_use, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w3
// CHECK-NEXT: This happens in the following basic block:
// CHECK-NEXT: {{[0-9a-f]+}}: adr x0, "sym/1"
// CHECK-NEXT: {{[0-9a-f]+}}: mov w0, w3
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ret
adr x0, sym
mov w0, w3
pacda x0, x1
ret
.size bad_clobber_between_addr_mat_and_use, .-bad_clobber_between_addr_mat_and_use
.globl bad_clobber_between_auted_and_checked
.type bad_clobber_between_auted_and_checked,@function
bad_clobber_between_auted_and_checked:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_auted_and_checked, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w3
// CHECK-NEXT: This happens in the following basic block:
// CHECK-NEXT: {{[0-9a-f]+}}: autda x0, x2
// CHECK-NEXT: {{[0-9a-f]+}}: mov w0, w3
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ret
autda x0, x2
mov w0, w3
ldr x2, [x0]
pacda x0, x1
ret
.size bad_clobber_between_auted_and_checked, .-bad_clobber_between_auted_and_checked
.globl bad_clobber_between_checked_and_used
.type bad_clobber_between_checked_and_used,@function
bad_clobber_between_checked_and_used:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_checked_and_used, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w3
// CHECK-NEXT: This happens in the following basic block:
// CHECK-NEXT: {{[0-9a-f]+}}: autda x0, x2
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
// CHECK-NEXT: {{[0-9a-f]+}}: mov w0, w3
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ret
autda x0, x2
ldr x2, [x0]
mov w0, w3
pacda x0, x1
ret
.size bad_clobber_between_checked_and_used, .-bad_clobber_between_checked_and_used
.globl bad_call_between_addr_mat_and_use
.type bad_call_between_addr_mat_and_use,@function
bad_call_between_addr_mat_and_use:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_call_between_addr_mat_and_use, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee
// 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]+}}: adr x0, "sym/1"
// CHECK-NEXT: {{[0-9a-f]+}}: bl callee
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// 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
adr x0, sym
bl callee
pacda x0, x1
ldp x29, x30, [sp], #16
autiasp
ret
.size bad_call_between_addr_mat_and_use, .-bad_call_between_addr_mat_and_use
.globl bad_call_between_auted_and_checked
.type bad_call_between_auted_and_checked,@function
bad_call_between_auted_and_checked:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_call_between_auted_and_checked, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee
// 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]+}}: autda x0, x2
// CHECK-NEXT: {{[0-9a-f]+}}: bl callee
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// 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
autda x0, x2
bl callee
ldr x2, [x0]
pacda x0, x1
ldp x29, x30, [sp], #16
autiasp
ret
.size bad_call_between_auted_and_checked, .-bad_call_between_auted_and_checked
.globl bad_call_between_checked_and_used
.type bad_call_between_checked_and_used,@function
bad_call_between_checked_and_used:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_call_between_checked_and_used, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: bl callee
// 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]+}}: autda x0, x2
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
// CHECK-NEXT: {{[0-9a-f]+}}: bl callee
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// 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
autda x0, x2
ldr x2, [x0]
bl callee
pacda x0, x1
ldp x29, x30, [sp], #16
autiasp
ret
.size bad_call_between_checked_and_used, .-bad_call_between_checked_and_used
.globl bad_transition_check_then_auth
.type bad_transition_check_then_auth,@function
bad_transition_check_then_auth:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_transition_check_then_auth, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
ldr x2, [x0]
autda x0, x2
pacda x0, x1
ret
.size bad_transition_check_then_auth, .-bad_transition_check_then_auth
.globl bad_transition_auth_then_auth
.type bad_transition_auth_then_auth,@function
bad_transition_auth_then_auth:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_transition_auth_then_auth, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autda x0, x2
autda x0, x2
pacda x0, x1
ret
.size bad_transition_auth_then_auth, .-bad_transition_auth_then_auth
.globl bad_transition_check_then_check
.type bad_transition_check_then_check,@function
bad_transition_check_then_check:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_transition_check_then_check, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
ldr x2, [x0]
ldr x2, [x0]
pacda x0, x1
ret
.size bad_transition_check_then_check, .-bad_transition_check_then_check
// Multi-BB test cases.
// Test state propagation across multiple basic blocks.
// Test transitions between register states: none, safe-to-dereference (s-t-d), trusted:
// * trusted right away: safe address materialization
// * trusted as checked s-t-d: two variants of checks
// * untrusted: s-t-d, but not *always* checked
// * untrusted: not *always* s-t-d, but checked
// * untrusted: not even s-t-d - from arg and from memory
// * untrusted: subreg clobbered - between address materialization and use, between auth and check, between check and use
// * trusted in both predecessors but for different reasons
// (the one due to address materialization and the other due to s-t-d then checked)
// * untrusted: auted in one predecessor, checked in the other
.globl good_sign_addr_mat_multi_bb
.type good_sign_addr_mat_multi_bb,@function
good_sign_addr_mat_multi_bb:
// CHECK-NOT: good_sign_addr_mat_multi_bb
adr x0, sym
cbz x3, 1f
nop
1:
pacda x0, x1
ret
.size good_sign_addr_mat_multi_bb, .-good_sign_addr_mat_multi_bb
.globl good_sign_auted_checked_ldr_multi_bb
.type good_sign_auted_checked_ldr_multi_bb,@function
good_sign_auted_checked_ldr_multi_bb:
// CHECK-NOT: good_sign_auted_checked_ldr_multi_bb
autda x0, x2
cbz x3, 1f
nop
1:
ldr x2, [x0]
cbz x4, 2f
nop
2:
pacda x0, x1
ret
.size good_sign_auted_checked_ldr_multi_bb, .-good_sign_auted_checked_ldr_multi_bb
.globl good_sign_auted_checked_brk_multi_bb
.type good_sign_auted_checked_brk_multi_bb,@function
good_sign_auted_checked_brk_multi_bb:
// CHECK-NOT: good_sign_auted_checked_brk_multi_bb
autda x0, x2
cbz x3, 1f
nop
1:
eor x16, x0, x0, lsl #1
tbz x16, #62, 2f
brk 0x1234
2:
cbz x4, 3f
nop
3:
pacda x0, x1
ret
.size good_sign_auted_checked_brk_multi_bb, .-good_sign_auted_checked_brk_multi_bb
.globl bad_sign_authed_unchecked_multi_bb
.type bad_sign_authed_unchecked_multi_bb,@function
bad_sign_authed_unchecked_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_authed_unchecked_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
autda x0, x2
cbz x3, 1f
ldr x2, [x0]
1:
pacda x0, x1
ret
.size bad_sign_authed_unchecked_multi_bb, .-bad_sign_authed_unchecked_multi_bb
.globl bad_sign_checked_not_auted_multi_bb
.type bad_sign_checked_not_auted_multi_bb,@function
bad_sign_checked_not_auted_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_checked_not_auted_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
cbz x3, 1f
autda x0, x2
1:
ldr x2, [x0]
pacda x0, x1
ret
.size bad_sign_checked_not_auted_multi_bb, .-bad_sign_checked_not_auted_multi_bb
.globl bad_sign_plain_arg_multi_bb
.type bad_sign_plain_arg_multi_bb,@function
bad_sign_plain_arg_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_plain_arg_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
cbz x3, 1f
autda x0, x2
ldr x2, [x0]
1:
pacda x0, x1
ret
.size bad_sign_plain_arg_multi_bb, .-bad_sign_plain_arg_multi_bb
.globl bad_sign_plain_mem_multi_bb
.type bad_sign_plain_mem_multi_bb,@function
bad_sign_plain_mem_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_plain_mem_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x0, [x1]
ldr x0, [x1]
cbz x3, 1f
autda x0, x2
ldr x2, [x0]
1:
pacda x0, x1
ret
.size bad_sign_plain_mem_multi_bb, .-bad_sign_plain_mem_multi_bb
.globl bad_clobber_between_addr_mat_and_use_multi_bb
.type bad_clobber_between_addr_mat_and_use_multi_bb,@function
bad_clobber_between_addr_mat_and_use_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_addr_mat_and_use_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w3
adr x0, sym
cbz x4, 1f
mov w0, w3
1:
pacda x0, x1
ret
.size bad_clobber_between_addr_mat_and_use_multi_bb, .-bad_clobber_between_addr_mat_and_use_multi_bb
.globl bad_clobber_between_auted_and_checked_multi_bb
.type bad_clobber_between_auted_and_checked_multi_bb,@function
bad_clobber_between_auted_and_checked_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_auted_and_checked_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w3
autda x0, x2
cbz x4, 1f
mov w0, w3
1:
ldr x2, [x0]
pacda x0, x1
ret
.size bad_clobber_between_auted_and_checked_multi_bb, .-bad_clobber_between_auted_and_checked_multi_bb
.globl bad_clobber_between_checked_and_used_multi_bb
.type bad_clobber_between_checked_and_used_multi_bb,@function
bad_clobber_between_checked_and_used_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_checked_and_used_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w3
autda x0, x2
ldr x2, [x0]
cbz x4, 1f
mov w0, w3
1:
pacda x0, x1
ret
.size bad_clobber_between_checked_and_used_multi_bb, .-bad_clobber_between_checked_and_used_multi_bb
.globl good_both_trusted_multi_bb
.type good_both_trusted_multi_bb,@function
good_both_trusted_multi_bb:
// CHECK-NOT: good_both_trusted_multi_bb
cbz x2, 1f
autdb x0, x1
ldr x2, [x0]
b 2f
1:
adr x0, sym
2:
pacda x0, x1
ret
.size good_both_trusted_multi_bb, .-good_both_trusted_multi_bb
.globl bad_one_auted_one_checked_multi_bb
.type bad_one_auted_one_checked_multi_bb,@function
bad_one_auted_one_checked_multi_bb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_one_auted_one_checked_multi_bb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
cbz x2, 1f
autdb x0, x1
b 2f
1:
ldr x3, [x0]
2:
pacda x0, x1
ret
.size bad_one_auted_one_checked_multi_bb, .-bad_one_auted_one_checked_multi_bb
// Test the detection when no CFG was reconstructed for a function.
// Test transitions between register states: none, safe-to-dereference (s-t-d), trusted:
// * trusted right away: safe address materialization
// * trusted as checked s-t-d: only check by load (FIXME: support BRK-based code sequences)
// * untrusted: s-t-d, but not checked
// * untrusted: not s-t-d, but checked
// * untrusted: not even s-t-d - from arg and from memory
// * untrusted: subreg clobbered - between address materialization and use, between auth and check, between check and use
// * untrusted: first checked then auted, auted then auted, checked then checked
//
// Note that it is important to sign and authenticate LR, as it is not kept
// safe-to-dereference across unconditional branches.
.globl good_sign_addr_mat_nocfg
.type good_sign_addr_mat_nocfg,@function
good_sign_addr_mat_nocfg:
// CHECK-NOT: good_sign_addr_mat_nocfg
paciasp
adr x3, 1f
br x3
1:
adr x0, sym
pacda x0, x1
autiasp
ret
.size good_sign_addr_mat_nocfg, .-good_sign_addr_mat_nocfg
.globl good_sign_auted_checked_ldr_nocfg
.type good_sign_auted_checked_ldr_nocfg,@function
good_sign_auted_checked_ldr_nocfg:
// CHECK-NOT: good_sign_auted_checked_ldr_nocfg
paciasp
adr x3, 1f
br x3
1:
autda x0, x2
ldr x2, [x0]
pacda x0, x1
autiasp
ret
.size good_sign_auted_checked_ldr_nocfg, .-good_sign_auted_checked_ldr_nocfg
.globl bad_sign_authed_unchecked_nocfg
.type bad_sign_authed_unchecked_nocfg,@function
bad_sign_authed_unchecked_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_authed_unchecked_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
adr x3, 1f
br x3
1:
autda x0, x2
pacda x0, x1
autiasp
ret
.size bad_sign_authed_unchecked_nocfg, .-bad_sign_authed_unchecked_nocfg
.globl bad_sign_checked_not_auted_nocfg
.type bad_sign_checked_not_auted_nocfg,@function
bad_sign_checked_not_auted_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_checked_not_auted_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
adr x3, 1f
br x3
1:
ldr x2, [x0]
pacda x0, x1
autiasp
ret
.size bad_sign_checked_not_auted_nocfg, .-bad_sign_checked_not_auted_nocfg
.globl bad_sign_plain_arg_nocfg
.type bad_sign_plain_arg_nocfg,@function
bad_sign_plain_arg_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_plain_arg_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
adr x3, 1f
br x3
1:
pacda x0, x1
autiasp
ret
.size bad_sign_plain_arg_nocfg, .-bad_sign_plain_arg_nocfg
.globl bad_sign_plain_mem_nocfg
.type bad_sign_plain_mem_nocfg,@function
bad_sign_plain_mem_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_sign_plain_mem_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: ldr x0, [x1]
paciasp
adr x3, 1f
br x3
1:
ldr x0, [x1]
pacda x0, x1
autiasp
ret
.size bad_sign_plain_mem_nocfg, .-bad_sign_plain_mem_nocfg
.globl bad_clobber_between_addr_mat_and_use_nocfg
.type bad_clobber_between_addr_mat_and_use_nocfg,@function
bad_clobber_between_addr_mat_and_use_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_addr_mat_and_use_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w4
paciasp
adr x3, 1f
br x3
1:
adr x0, sym
mov w0, w4
pacda x0, x1
autiasp
ret
.size bad_clobber_between_addr_mat_and_use_nocfg, .-bad_clobber_between_addr_mat_and_use_nocfg
.globl bad_clobber_between_auted_and_checked_nocfg
.type bad_clobber_between_auted_and_checked_nocfg,@function
bad_clobber_between_auted_and_checked_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_auted_and_checked_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w4
paciasp
adr x3, 1f
br x3
1:
autda x0, x2
mov w0, w4
ldr x2, [x0]
pacda x0, x1
autiasp
ret
.size bad_clobber_between_auted_and_checked_nocfg, .-bad_clobber_between_auted_and_checked_nocfg
.globl bad_clobber_between_checked_and_used_nocfg
.type bad_clobber_between_checked_and_used_nocfg,@function
bad_clobber_between_checked_and_used_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_clobber_between_checked_and_used_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 1 instructions that write to the affected registers after any authentication are:
// CHECK-NEXT: 1. {{[0-9a-f]+}}: mov w0, w4
paciasp
adr x3, 1f
br x3
1:
autda x0, x2
ldr x2, [x0]
mov w0, w4
pacda x0, x1
autiasp
ret
.size bad_clobber_between_checked_and_used_nocfg, .-bad_clobber_between_checked_and_used_nocfg
.globl bad_transition_check_then_auth_nocfg
.type bad_transition_check_then_auth_nocfg,@function
bad_transition_check_then_auth_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_transition_check_then_auth_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
adr x3, 1f
br x3
1:
ldr x2, [x0]
autda x0, x2
pacda x0, x1
autiasp
ret
.size bad_transition_check_then_auth_nocfg, .-bad_transition_check_then_auth_nocfg
.globl bad_transition_auth_then_auth_nocfg
.type bad_transition_auth_then_auth_nocfg,@function
bad_transition_auth_then_auth_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_transition_auth_then_auth_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
adr x3, 1f
br x3
1:
autda x0, x2
autda x0, x2
pacda x0, x1
autiasp
ret
.size bad_transition_auth_then_auth_nocfg, .-bad_transition_auth_then_auth_nocfg
.globl bad_transition_check_then_check_nocfg
.type bad_transition_check_then_check_nocfg,@function
bad_transition_check_then_check_nocfg:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_transition_check_then_check_nocfg, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
paciasp
adr x3, 1f
br x3
1:
ldr x2, [x0]
ldr x2, [x0]
pacda x0, x1
autiasp
ret
.size bad_transition_check_then_check_nocfg, .-bad_transition_check_then_check_nocfg
// Test resign with offset.
.globl good_resign_with_increment_ldr
.type good_resign_with_increment_ldr,@function
good_resign_with_increment_ldr:
// CHECK-NOT: good_resign_with_increment_ldr
autda x0, x2
add x0, x0, #8
ldr x2, [x0]
sub x1, x0, #16
mov x2, x1
pacda x2, x3
ret
.size good_resign_with_increment_ldr, .-good_resign_with_increment_ldr
.globl good_resign_with_increment_brk
.type good_resign_with_increment_brk,@function
good_resign_with_increment_brk:
// CHECK-NOT: good_resign_with_increment_brk
autda x0, x2
add x0, x0, #8
eor x16, x0, x0, lsl #1
tbz x16, #62, 1f
brk 0x1234
1:
mov x2, x0
pacda x2, x1
ret
.size good_resign_with_increment_brk, .-good_resign_with_increment_brk
.globl bad_nonconstant_auth_increment_check
.type bad_nonconstant_auth_increment_check,@function
bad_nonconstant_auth_increment_check:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_nonconstant_auth_increment_check, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// 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]+}}: autda x0, x2
// CHECK-NEXT: {{[0-9a-f]+}}: add x0, x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ret
autda x0, x2
add x0, x0, x1
ldr x2, [x0]
pacda x0, x1
ret
.size bad_nonconstant_auth_increment_check, .-bad_nonconstant_auth_increment_check
.globl bad_nonconstant_auth_check_increment
.type bad_nonconstant_auth_check_increment,@function
bad_nonconstant_auth_check_increment:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function bad_nonconstant_auth_check_increment, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
// 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]+}}: autda x0, x2
// CHECK-NEXT: {{[0-9a-f]+}}: ldr x2, [x0]
// CHECK-NEXT: {{[0-9a-f]+}}: add x0, x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: pacda x0, x1
// CHECK-NEXT: {{[0-9a-f]+}}: ret
autda x0, x2
ldr x2, [x0]
add x0, x0, x1
pacda x0, x1
ret
.size bad_nonconstant_auth_check_increment, .-bad_nonconstant_auth_check_increment
// Test that all the expected signing instructions are recornized.
.globl inst_pacda
.type inst_pacda,@function
inst_pacda:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacda, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1
pacda x0, x1
ret
.size inst_pacda, .-inst_pacda
.globl inst_pacdza
.type inst_pacdza,@function
inst_pacdza:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacdza, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacdza x0
pacdza x0
ret
.size inst_pacdza, .-inst_pacdza
.globl inst_pacdb
.type inst_pacdb,@function
inst_pacdb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacdb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacdb x0, x1
pacdb x0, x1
ret
.size inst_pacdb, .-inst_pacdb
.globl inst_pacdzb
.type inst_pacdzb,@function
inst_pacdzb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacdzb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacdzb x0
pacdzb x0
ret
.size inst_pacdzb, .-inst_pacdzb
.globl inst_pacia
.type inst_pacia,@function
inst_pacia:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacia, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia x0, x1
pacia x0, x1
ret
.size inst_pacia, .-inst_pacia
.globl inst_pacia1716
.type inst_pacia1716,@function
inst_pacia1716:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacia1716, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia1716
pacia1716
ret
.size inst_pacia1716, .-inst_pacia1716
.globl inst_paciasp
.type inst_paciasp,@function
inst_paciasp:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_paciasp, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciasp
mov x30, x0
paciasp // signs LR
autiasp
ret
.size inst_paciasp, .-inst_paciasp
.globl inst_paciaz
.type inst_paciaz,@function
inst_paciaz:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_paciaz, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciaz
mov x30, x0
paciaz // signs LR
autiaz
ret
.size inst_paciaz, .-inst_paciaz
.globl inst_paciza
.type inst_paciza,@function
inst_paciza:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_paciza, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciza x0
paciza x0
ret
.size inst_paciza, .-inst_paciza
.globl inst_pacia171615
.type inst_pacia171615,@function
inst_pacia171615:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacia171615, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacia171615
mov x30, x0
pacia171615 // signs LR
autia171615
ret
.size inst_pacia171615, .-inst_pacia171615
.globl inst_paciasppc
.type inst_paciasppc,@function
inst_paciasppc:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_paciasppc, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: paciasppc
mov x30, x0
1:
paciasppc // signs LR
autiasppc 1b
ret
.size inst_paciasppc, .-inst_paciasppc
.globl inst_pacib
.type inst_pacib,@function
inst_pacib:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacib, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacib x0, x1
pacib x0, x1
ret
.size inst_pacib, .-inst_pacib
.globl inst_pacib1716
.type inst_pacib1716,@function
inst_pacib1716:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacib1716, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacib1716
pacib1716
ret
.size inst_pacib1716, .-inst_pacib1716
.globl inst_pacibsp
.type inst_pacibsp,@function
inst_pacibsp:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacibsp, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacibsp
mov x30, x0
pacibsp // signs LR
autibsp
ret
.size inst_pacibsp, .-inst_pacibsp
.globl inst_pacibz
.type inst_pacibz,@function
inst_pacibz:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacibz, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacibz
mov x30, x0
pacibz // signs LR
autibz
ret
.size inst_pacibz, .-inst_pacibz
.globl inst_pacizb
.type inst_pacizb,@function
inst_pacizb:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacizb, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacizb x0
pacizb x0
ret
.size inst_pacizb, .-inst_pacizb
.globl inst_pacib171615
.type inst_pacib171615,@function
inst_pacib171615:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacib171615, basic block {{[^,]+}}, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacib171615
mov x30, x0
pacib171615 // signs LR
autib171615
ret
.size inst_pacib171615, .-inst_pacib171615
.globl inst_pacibsppc
.type inst_pacibsppc,@function
inst_pacibsppc:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacibsppc, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacibsppc
mov x30, x0
1:
pacibsppc // signs LR
autibsppc 1b
ret
.size inst_pacibsppc, .-inst_pacibsppc
.globl inst_pacnbiasppc
.type inst_pacnbiasppc,@function
inst_pacnbiasppc:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacnbiasppc, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacnbiasppc
mov x30, x0
1:
pacnbiasppc // signs LR
autiasppc 1b
ret
.size inst_pacnbiasppc, .-inst_pacnbiasppc
.globl inst_pacnbibsppc
.type inst_pacnbibsppc,@function
inst_pacnbibsppc:
// CHECK-LABEL: GS-PAUTH: signing oracle found in function inst_pacnbibsppc, at address
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: pacnbibsppc
mov x30, x0
1:
pacnbibsppc // signs LR
autibsppc 1b
ret
.size inst_pacnbibsppc, .-inst_pacnbibsppc
.globl main
.type main,@function
main:
mov x0, 0
ret
.size main, .-main