
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.
665 lines
26 KiB
ArmAsm
665 lines
26 KiB
ArmAsm
// 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
|