diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp index 9cd5032204e78..2eadaf15d3a65 100644 --- a/bolt/lib/Passes/PAuthGadgetScanner.cpp +++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp @@ -737,19 +737,14 @@ template class CFGUnawareAnalysis { // // Then, a function can be split into a number of disjoint contiguous sequences // of instructions without labels in between. These sequences can be processed -// the same way basic blocks are processed by data-flow analysis, assuming -// pessimistically that all registers are unsafe at the start of each sequence. +// the same way basic blocks are processed by data-flow analysis, with the same +// pessimistic estimation of the initial state at the start of each sequence +// (except the first instruction of the function). class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis, public CFGUnawareAnalysis { using SrcSafetyAnalysis::BC; BinaryFunction &BF; - /// Creates a state with all registers marked unsafe (not to be confused - /// with empty state). - SrcState createUnsafeState() const { - return SrcState(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters()); - } - public: CFGUnawareSrcSafetyAnalysis(BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId, @@ -759,6 +754,7 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis, } void run() override { + const SrcState DefaultState = computePessimisticState(BF); SrcState S = createEntryState(); for (auto &I : BF.instrs()) { MCInst &Inst = I.second; @@ -773,7 +769,7 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis, LLVM_DEBUG({ traceInst(BC, "Due to label, resetting the state before", Inst); }); - S = createUnsafeState(); + S = DefaultState; } // Attach the state *before* this instruction executes. diff --git a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s index a32e4324aa923..2dadcef095863 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s +++ b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s @@ -224,20 +224,33 @@ f_unreachable_instruction: ret .size f_unreachable_instruction, .-f_unreachable_instruction -// Expected false positive: without CFG, the state is reset to all-unsafe -// after an unconditional branch. - - .globl state_is_reset_after_indirect_branch_nocfg - .type state_is_reset_after_indirect_branch_nocfg,@function -state_is_reset_after_indirect_branch_nocfg: -// CHECK-LABEL: GS-PAUTH: non-protected ret found in function state_is_reset_after_indirect_branch_nocfg, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret +// Without CFG, the state is reset at labels, assuming every register that can +// be clobbered in the function was actually clobbered. + + .globl lr_untouched_nocfg + .type lr_untouched_nocfg,@function +lr_untouched_nocfg: +// CHECK-NOT: lr_untouched_nocfg + adr x2, 1f + br x2 +1: + ret + .size lr_untouched_nocfg, .-lr_untouched_nocfg + + .globl lr_clobbered_nocfg + .type lr_clobbered_nocfg,@function +lr_clobbered_nocfg: +// CHECK-LABEL: GS-PAUTH: non-protected ret found in function lr_clobbered_nocfg, at address +// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret // CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: adr x2, 1f br x2 1: + b 2f + bl g // never executed, but affects the expected worst-case scenario +2: ret - .size state_is_reset_after_indirect_branch_nocfg, .-state_is_reset_after_indirect_branch_nocfg + .size lr_clobbered_nocfg, .-lr_clobbered_nocfg /// Now do a basic sanity check on every different Authentication instruction: diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s index 717bf40df3d02..c314bc7cfe5a3 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s @@ -491,10 +491,6 @@ good_address_arith_multi_bb: ret .size good_address_arith_multi_bb, .-good_address_arith_multi_bb -// FIXME: Most *_nocfg test cases contain paciasp+autiasp instructions even if -// LR is not spilled - this is a workaround for RET instructions being -// reported as non-protected, because LR state is reset at every label. - .globl good_ret_nocfg .type good_ret_nocfg,@function good_ret_nocfg: @@ -541,14 +537,12 @@ good_branch_nocfg: .type good_load_other_reg_nocfg,@function good_load_other_reg_nocfg: // CHECK-NOT: good_load_other_reg_nocfg - paciasp adr x2, 1f br x2 1: autia x0, x1 ldr x2, [x0] - autiasp ret .size good_load_other_reg_nocfg, .-good_load_other_reg_nocfg @@ -556,14 +550,12 @@ good_load_other_reg_nocfg: .type good_load_same_reg_nocfg,@function good_load_same_reg_nocfg: // CHECK-NOT: good_load_same_reg_nocfg - paciasp adr x2, 1f br x2 1: autia x0, x1 ldr x0, [x0] - autiasp ret .size good_load_same_reg_nocfg, .-good_load_same_reg_nocfg @@ -575,13 +567,11 @@ bad_unchecked_nocfg: // CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_unchecked_nocfg, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 // CHECK-NEXT: The 0 instructions that leak the affected registers are: - paciasp adr x2, 1f br x2 1: autia x0, x1 - autiasp ret .size bad_unchecked_nocfg, .-bad_unchecked_nocfg @@ -615,7 +605,6 @@ bad_unknown_usage_read_nocfg: // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 // CHECK-NEXT: The 1 instructions that leak the affected registers are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: mul x3, x0, x1 - paciasp adr x2, 1f br x2 1: @@ -623,7 +612,6 @@ bad_unknown_usage_read_nocfg: mul x3, x0, x1 ldr x2, [x0] - autiasp ret .size bad_unknown_usage_read_nocfg, .-bad_unknown_usage_read_nocfg @@ -634,7 +622,6 @@ bad_unknown_usage_subreg_read_nocfg: // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 // CHECK-NEXT: The 1 instructions that leak the affected registers are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: mul w3, w0, w1 - paciasp adr x2, 1f br x2 1: @@ -642,7 +629,6 @@ bad_unknown_usage_subreg_read_nocfg: mul w3, w0, w1 ldr x2, [x0] - autiasp ret .size bad_unknown_usage_subreg_read_nocfg, .-bad_unknown_usage_subreg_read_nocfg @@ -653,7 +639,6 @@ bad_unknown_usage_update_nocfg: // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x0, x1 // CHECK-NEXT: The 1 instructions that leak the affected registers are: // CHECK-NEXT: 1. {{[0-9a-f]+}}: movk x0, #0x2a, lsl #16 - paciasp adr x2, 1f br x2 1: @@ -661,7 +646,6 @@ bad_unknown_usage_update_nocfg: movk x0, #42, lsl #16 // does not overwrite x0 completely ldr x2, [x0] - autiasp ret .size bad_unknown_usage_update_nocfg, .-bad_unknown_usage_update_nocfg @@ -669,14 +653,12 @@ bad_unknown_usage_update_nocfg: .type good_overwrite_with_constant_nocfg,@function good_overwrite_with_constant_nocfg: // CHECK-NOT: good_overwrite_with_constant_nocfg - paciasp adr x2, 1f br x2 1: autia x0, x1 mov x0, #42 - autiasp ret .size good_overwrite_with_constant_nocfg, .-good_overwrite_with_constant_nocfg @@ -684,7 +666,6 @@ good_overwrite_with_constant_nocfg: .type good_address_arith_nocfg,@function good_address_arith_nocfg: // CHECK-NOT: good_address_arith_nocfg - paciasp adr x2, 1f br x2 1: @@ -698,7 +679,6 @@ good_address_arith_nocfg: mov x1, #0 mov x2, #0 - autiasp ret .size good_address_arith_nocfg, .-good_address_arith_nocfg diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s index fbb96a63d41ed..b1cec7f92ad05 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s @@ -199,8 +199,8 @@ nocfg: // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: Due to label, resetting the state before: 00000000: ret # Offset: 8 -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) -// CHECK-NEXT: .. result: (src-state) +// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) +// CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: After src register safety analysis: // CHECK-NEXT: Binary Function "nocfg" { // CHECK-NEXT: Number : 3 @@ -223,33 +223,7 @@ nocfg: // PAUTH-NEXT: SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI{{[ \t]*$}} // CHECK-NEXT: Found RET inst: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: RetReg: LR -// CHECK-NEXT: SafeToDerefRegs:{{[ \t]*$}} -// CHECK-EMPTY: -// CHECK-NEXT: Running detailed src register safety analysis... -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: Due to label, resetting the state before: 00000000: ret # Offset: 8 -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: After detailed src register safety analysis: -// CHECK-NEXT: Binary Function "nocfg" { -// CHECK-NEXT: Number : 3 -// ... -// 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 -// CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state -// CHECK-NEXT: __ENTRY_nocfg@0x[[ENTRY_ADDR]] (Entry Point): -// CHECK-NEXT: .{{[A-Za-z0-9]+}}: -// CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state -// CHECK-NEXT: DWARF CFI Instructions: -// CHECK-NEXT: -// CHECK-NEXT: End of Function "nocfg" -// CHECK-EMPTY: -// CHECK-NEXT: Attaching clobbering info to: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state +// CHECK-NEXT: SafeToDerefRegs: LR W30 W30_HI{{[ \t]*$}} .globl auth_oracle .type auth_oracle,@function diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s b/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s index 334a4108d8ab8..3a4d383ec5bc6 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s @@ -505,21 +505,16 @@ bad_one_auted_one_checked_multi_bb: // * 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 @@ -527,14 +522,12 @@ good_sign_addr_mat_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 @@ -544,13 +537,11 @@ 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 @@ -560,13 +551,11 @@ 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 @@ -576,12 +565,10 @@ 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 @@ -592,13 +579,11 @@ bad_sign_plain_mem_nocfg: // 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 @@ -609,14 +594,12 @@ bad_clobber_between_addr_mat_and_use_nocfg: // 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 @@ -627,7 +610,6 @@ bad_clobber_between_auted_and_checked_nocfg: // 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: @@ -635,7 +617,6 @@ bad_clobber_between_auted_and_checked_nocfg: 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 @@ -646,7 +627,6 @@ bad_clobber_between_checked_and_used_nocfg: // 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: @@ -654,7 +634,6 @@ bad_clobber_between_checked_and_used_nocfg: 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 @@ -664,14 +643,12 @@ 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 @@ -681,14 +658,12 @@ 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 @@ -698,14 +673,12 @@ 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