diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp index bda971bcd9343..cfe86d32df798 100644 --- a/bolt/lib/Passes/PAuthGadgetScanner.cpp +++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp @@ -14,6 +14,7 @@ #include "bolt/Passes/PAuthGadgetScanner.h" #include "bolt/Core/ParallelUtilities.h" #include "bolt/Passes/DataflowAnalysis.h" +#include "bolt/Utils/CommandLineOpts.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/MC/MCInst.h" @@ -26,6 +27,11 @@ namespace llvm { namespace bolt { namespace PAuthGadgetScanner { +static cl::opt AuthTrapsOnFailure( + "auth-traps-on-failure", + cl::desc("Assume authentication instructions always trap on failure"), + cl::cat(opts::BinaryAnalysisCategory)); + [[maybe_unused]] static void traceInst(const BinaryContext &BC, StringRef Label, const MCInst &MI) { dbgs() << " " << Label << ": "; @@ -365,6 +371,34 @@ class SrcSafetyAnalysis { return Clobbered; } + std::optional getRegMadeTrustedByChecking(const MCInst &Inst, + SrcState Cur) const { + // This functions cannot return multiple registers. This is never the case + // on AArch64. + std::optional RegCheckedByInst = + BC.MIB->getAuthCheckedReg(Inst, /*MayOverwrite=*/false); + if (RegCheckedByInst && Cur.SafeToDerefRegs[*RegCheckedByInst]) + return *RegCheckedByInst; + + auto It = CheckerSequenceInfo.find(&Inst); + if (It == CheckerSequenceInfo.end()) + return std::nullopt; + + MCPhysReg RegCheckedBySequence = It->second.first; + const MCInst *FirstCheckerInst = It->second.second; + + // FirstCheckerInst should belong to the same basic block (see the + // assertion in DataflowSrcSafetyAnalysis::run()), meaning it was + // deterministically processed a few steps before this instruction. + const SrcState &StateBeforeChecker = getStateBefore(*FirstCheckerInst); + + // The sequence checks the register, but it should be authenticated before. + if (!StateBeforeChecker.SafeToDerefRegs[RegCheckedBySequence]) + return std::nullopt; + + return RegCheckedBySequence; + } + // Returns all registers that can be treated as if they are written by an // authentication instruction. SmallVector getRegsMadeSafeToDeref(const MCInst &Point, @@ -387,18 +421,38 @@ class SrcSafetyAnalysis { Regs.push_back(DstAndSrc->first); } + // Make sure explicit checker sequence keeps register safe-to-dereference + // when the register would be clobbered according to the regular rules: + // + // ; LR is safe to dereference here + // mov x16, x30 ; start of the sequence, LR is s-t-d right before + // xpaclri ; clobbers LR, LR is not safe anymore + // cmp x30, x16 + // b.eq 1f ; end of the sequence: LR is marked as trusted + // brk 0x1234 + // 1: + // ; at this point LR would be marked as trusted, + // ; but not safe-to-dereference + // + // or even just + // + // ; X1 is safe to dereference here + // ldr x0, [x1, #8]! + // ; X1 is trusted here, but it was clobbered due to address write-back + if (auto CheckedReg = getRegMadeTrustedByChecking(Point, Cur)) + Regs.push_back(*CheckedReg); + return Regs; } // Returns all registers made trusted by this instruction. SmallVector getRegsMadeTrusted(const MCInst &Point, const SrcState &Cur) const { + assert(!AuthTrapsOnFailure && "Use getRegsMadeSafeToDeref instead"); SmallVector Regs; // An authenticated pointer can be checked, or - std::optional CheckedReg = - BC.MIB->getAuthCheckedReg(Point, /*MayOverwrite=*/false); - if (CheckedReg && Cur.SafeToDerefRegs[*CheckedReg]) + if (auto CheckedReg = getRegMadeTrustedByChecking(Point, Cur)) Regs.push_back(*CheckedReg); // ... a pointer can be authenticated by an instruction that always checks @@ -409,19 +463,6 @@ class SrcSafetyAnalysis { if (AutReg && IsChecked) Regs.push_back(*AutReg); - if (CheckerSequenceInfo.contains(&Point)) { - MCPhysReg CheckedReg; - const MCInst *FirstCheckerInst; - std::tie(CheckedReg, FirstCheckerInst) = CheckerSequenceInfo.at(&Point); - - // FirstCheckerInst should belong to the same basic block (see the - // assertion in DataflowSrcSafetyAnalysis::run()), meaning it was - // deterministically processed a few steps before this instruction. - const SrcState &StateBeforeChecker = getStateBefore(*FirstCheckerInst); - if (StateBeforeChecker.SafeToDerefRegs[CheckedReg]) - Regs.push_back(CheckedReg); - } - // ... a safe address can be materialized, or if (auto NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point)) Regs.push_back(*NewAddrReg); @@ -465,28 +506,11 @@ class SrcSafetyAnalysis { BitVector Clobbered = getClobberedRegs(Point); SmallVector NewSafeToDerefRegs = getRegsMadeSafeToDeref(Point, Cur); - SmallVector NewTrustedRegs = getRegsMadeTrusted(Point, Cur); - - // Ideally, being trusted is a strictly stronger property than being - // safe-to-dereference. To simplify the computation of Next state, enforce - // this for NewSafeToDerefRegs and NewTrustedRegs. Additionally, this - // fixes the properly for "cumulative" register states in tricky cases - // like the following: - // - // ; LR is safe to dereference here - // mov x16, x30 ; start of the sequence, LR is s-t-d right before - // xpaclri ; clobbers LR, LR is not safe anymore - // cmp x30, x16 - // b.eq 1f ; end of the sequence: LR is marked as trusted - // brk 0x1234 - // 1: - // ; at this point LR would be marked as trusted, - // ; but not safe-to-dereference - // - for (auto TrustedReg : NewTrustedRegs) { - if (!is_contained(NewSafeToDerefRegs, TrustedReg)) - NewSafeToDerefRegs.push_back(TrustedReg); - } + // If authentication instructions trap on failure, safe-to-dereference + // registers are always trusted. + SmallVector NewTrustedRegs = + AuthTrapsOnFailure ? NewSafeToDerefRegs + : getRegsMadeTrusted(Point, Cur); // Then, compute the state after this instruction is executed. SrcState Next = Cur; @@ -523,6 +547,11 @@ class SrcSafetyAnalysis { dbgs() << ")\n"; }); + // Being trusted is a strictly stronger property than being + // safe-to-dereference. + assert(!Next.TrustedRegs.test(Next.SafeToDerefRegs) && + "SafeToDerefRegs should contain all TrustedRegs"); + return Next; } @@ -1084,6 +1113,11 @@ class DataflowDstSafetyAnalysis } void run() override { + // As long as DstSafetyAnalysis is only computed to detect authentication + // oracles, it is a waste of time to compute it when authentication + // instructions are known to always trap on failure. + assert(!AuthTrapsOnFailure && + "DstSafetyAnalysis is useless with faulting auth"); for (BinaryBasicBlock &BB : Func) { if (auto CheckerInfo = BC.MIB->getAuthCheckedReg(BB)) { LLVM_DEBUG({ @@ -1542,6 +1576,8 @@ void FunctionAnalysisContext::findUnsafeDefs( SmallVector> &Reports) { if (PacRetGadgetsOnly) return; + if (AuthTrapsOnFailure) + return; auto Analysis = DstSafetyAnalysis::create(BF, AllocatorId, {}); LLVM_DEBUG({ dbgs() << "Running dst register safety analysis...\n"; }); diff --git a/bolt/test/binary-analysis/AArch64/cmdline-args.test b/bolt/test/binary-analysis/AArch64/cmdline-args.test index 76f7c3ba0a1c7..27069436092b3 100644 --- a/bolt/test/binary-analysis/AArch64/cmdline-args.test +++ b/bolt/test/binary-analysis/AArch64/cmdline-args.test @@ -32,6 +32,7 @@ HELP-NEXT: OPTIONS: HELP-EMPTY: HELP-NEXT: BinaryAnalysis options: HELP-EMPTY: +HELP-NEXT: --auth-traps-on-failure - Assume authentication instructions always trap on failure HELP-NEXT: --scanners= - which gadget scanners to run HELP-NEXT: =pacret - pac-ret: return address protection (subset of "pauth") HELP-NEXT: =pauth - All Pointer Authentication scanners 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 b199c3056ba5b..f5d3b870244f4 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-authentication-oracles.s @@ -1,6 +1,7 @@ // RUN: %clang %cflags -march=armv8.3-a %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 +// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefix=FPAC %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 @@ -8,6 +9,7 @@ // detected per-instruction and per-BB. // PACRET-NOT: authentication oracle found in function +// FPAC-NOT: authentication oracle found in function .text diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s b/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s index 5f49918c39c94..26ebe2d2436a1 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-calls.s @@ -1,6 +1,7 @@ // RUN: %clang %cflags -march=armv8.3-a %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 +// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s // PACRET-NOT: non-protected call found in function 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 75341063ab816..e99599c7463c6 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s @@ -1,10 +1,14 @@ // REQUIRES: asserts // // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe -// RUN: llvm-bolt-binary-analysis --scanners=pacret -no-threads \ -// RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck %s -// RUN: llvm-bolt-binary-analysis --scanners=pauth -no-threads \ -// RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,PAUTH %s +// RUN: llvm-bolt-binary-analysis --scanners=pacret --no-threads \ +// RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s +// RUN: llvm-bolt-binary-analysis --scanners=pacret --no-threads --auth-traps-on-failure \ +// RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --no-threads \ +// RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC,AUTH-ORACLES,PAUTH %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --no-threads --auth-traps-on-failure \ +// RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC,PAUTH %s // Check the debug output generated by PAuth gadget scanner to make sure the // that output is kept meaningful and to provide an overview of what happens @@ -61,30 +65,54 @@ simple: // CHECK-NEXT: State 1: src-state // CHECK-NEXT: State 2: src-state) // CHECK-NEXT: merged state: src-state -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: DataflowSrcSafetyAnalysis::Confluence( -// CHECK-NEXT: State 1: src-state -// CHECK-NEXT: State 2: src-state) -// CHECK-NEXT: merged state: src-state -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) -// CHECK-NEXT: .. result: (src-state) -// CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) -// CHECK-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: DataflowSrcSafetyAnalysis::Confluence( +// NOFPAC-NEXT: State 1: src-state +// NOFPAC-NEXT: State 2: src-state) +// NOFPAC-NEXT: merged state: src-state +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// NOFPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) +// NOFPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: DataflowSrcSafetyAnalysis::Confluence( +// FPAC-NEXT: State 1: src-state +// FPAC-NEXT: State 2: src-state) +// FPAC-NEXT: merged state: src-state +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) +// FPAC-NEXT: .. result: (src-state) +// FPAC-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) +// FPAC-NEXT: .. result: (src-state) // CHECK-NEXT: After src register safety analysis: // CHECK-NEXT: Binary Function "simple" { // CHECK-NEXT: Number : 1 @@ -255,53 +283,56 @@ auth_oracle: // ... // CHECK: End of Function "auth_oracle" // ... -// PAUTH: Running dst register safety analysis... -// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) -// PAUTH-NEXT: .. result: (dst-state) -// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) -// PAUTH-NEXT: .. result: (dst-state) -// PAUTH-NEXT: After dst register safety analysis: -// PAUTH-NEXT: Binary Function "auth_oracle" { -// PAUTH-NEXT: Number : 4 -// PAUTH-NEXT: State : CFG constructed +// FPAC-NOT: Running dst register safety analysis +// FPAC-NOT: DstSafetyAnalysis::ComputeNext +// FPAC-NOT: {{.*dst-state.*}} +// AUTH-ORACLES: Running dst register safety analysis... +// AUTH-ORACLES-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) +// AUTH-ORACLES-NEXT: .. result: (dst-state) +// AUTH-ORACLES-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) +// AUTH-ORACLES-NEXT: .. result: (dst-state) +// AUTH-ORACLES-NEXT: After dst register safety analysis: +// AUTH-ORACLES-NEXT: Binary Function "auth_oracle" { +// AUTH-ORACLES-NEXT: Number : 4 +// AUTH-ORACLES-NEXT: State : CFG constructed // ... -// PAUTH: BB Layout : [[BB0]] -// PAUTH-NEXT: } -// PAUTH-NEXT: [[BB0]] (2 instructions, align : 1) -// PAUTH-NEXT: Entry Point -// PAUTH-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state -// PAUTH-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state -// PAUTH-EMPTY: -// PAUTH-NEXT: DWARF CFI Instructions: -// PAUTH-NEXT: -// PAUTH-NEXT: End of Function "auth_oracle" -// PAUTH-EMPTY: -// PAUTH-NEXT: Found auth inst: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state -// PAUTH-NEXT: Authenticated reg: X0 -// PAUTH-NEXT: safe output registers: LR W30 W30_HI -// PAUTH-EMPTY: -// PAUTH-NEXT: Running detailed dst register safety analysis... -// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) -// PAUTH-NEXT: .. result: (dst-state) -// PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) -// PAUTH-NEXT: .. result: (dst-state) -// PAUTH-NEXT: After detailed dst register safety analysis: -// PAUTH-NEXT: Binary Function "auth_oracle" { -// PAUTH-NEXT: Number : 4 -// PAUTH-NEXT: State : CFG constructed +// AUTH-ORACLES: BB Layout : [[BB0]] +// AUTH-ORACLES-NEXT: } +// AUTH-ORACLES-NEXT: [[BB0]] (2 instructions, align : 1) +// AUTH-ORACLES-NEXT: Entry Point +// AUTH-ORACLES-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// AUTH-ORACLES-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state +// AUTH-ORACLES-EMPTY: +// AUTH-ORACLES-NEXT: DWARF CFI Instructions: +// AUTH-ORACLES-NEXT: +// AUTH-ORACLES-NEXT: End of Function "auth_oracle" +// AUTH-ORACLES-EMPTY: +// AUTH-ORACLES-NEXT: Found auth inst: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// AUTH-ORACLES-NEXT: Authenticated reg: X0 +// AUTH-ORACLES-NEXT: safe output registers: LR W30 W30_HI +// AUTH-ORACLES-EMPTY: +// AUTH-ORACLES-NEXT: Running detailed dst register safety analysis... +// AUTH-ORACLES-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) +// AUTH-ORACLES-NEXT: .. result: (dst-state) +// AUTH-ORACLES-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) +// AUTH-ORACLES-NEXT: .. result: (dst-state) +// AUTH-ORACLES-NEXT: After detailed dst register safety analysis: +// AUTH-ORACLES-NEXT: Binary Function "auth_oracle" { +// AUTH-ORACLES-NEXT: Number : 4 +// AUTH-ORACLES-NEXT: State : CFG constructed // ... -// PAUTH: BB Layout : [[BB0]] -// PAUTH-NEXT: } -// PAUTH-NEXT: [[BB0]] (2 instructions, align : 1) -// PAUTH-NEXT: Entry Point -// PAUTH-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state -// PAUTH-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state -// PAUTH-EMPTY: -// PAUTH-NEXT: DWARF CFI Instructions: -// PAUTH-NEXT: -// PAUTH-NEXT: End of Function "auth_oracle" -// PAUTH-EMPTY: -// PAUTH-NEXT: Attaching leakage info to: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// AUTH-ORACLES: BB Layout : [[BB0]] +// AUTH-ORACLES-NEXT: } +// AUTH-ORACLES-NEXT: [[BB0]] (2 instructions, align : 1) +// AUTH-ORACLES-NEXT: Entry Point +// AUTH-ORACLES-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state +// AUTH-ORACLES-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state +// AUTH-ORACLES-EMPTY: +// AUTH-ORACLES-NEXT: DWARF CFI Instructions: +// AUTH-ORACLES-NEXT: +// AUTH-ORACLES-NEXT: End of Function "auth_oracle" +// AUTH-ORACLES-EMPTY: +// AUTH-ORACLES-NEXT: Attaching leakage info to: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state // Gadget scanner should not crash on CFI instructions, including when debug-printing them. // Note that the particular debug output is not checked, but BOLT should be diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-jump-table.s b/bolt/test/binary-analysis/AArch64/gs-pauth-jump-table.s index 5a42ed078e9c2..e1f4fd58bd7b9 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-jump-table.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-jump-table.s @@ -2,9 +2,11 @@ // Without -Wl,--emit-relocs BOLT refuses to create CFG information for the below functions. // RUN: %clang %cflags -march=armv8.3-a -Wl,--no-relax -Wl,--emit-relocs %s -o %t.exe -// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck --check-prefixes=CHECK,CFG %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck --check-prefixes=CHECK,CFG %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck --check-prefixes=CHECK,CFG %s // RUN: %clang %cflags -march=armv8.3-a -Wl,--no-relax %s -o %t.exe -// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck --check-prefixes=CHECK,NOCFG %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck --check-prefixes=CHECK,NOCFG %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck --check-prefixes=CHECK,NOCFG %s // FIXME: Labels could be further validated. Specifically, it could be checked // that the jump table itself is located in a read-only data section. 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 94b2c55f3bfa6..0393ac96249e6 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-signing-oracles.s @@ -1,6 +1,7 @@ // 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 +// 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 -check-prefixes=CHECK,NOFPAC %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %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 @@ -66,9 +67,10 @@ 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: +// FPAC-NOT: bad_sign_authed_unchecked +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_sign_authed_unchecked, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: autda x0, x2 pacda x0, x1 ret @@ -266,9 +268,10 @@ 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: +// FPAC-NOT: bad_transition_check_then_auth +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_transition_check_then_auth, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: ldr x2, [x0] autda x0, x2 pacda x0, x1 @@ -278,9 +281,10 @@ 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: +// FPAC-NOT: bad_transition_auth_then_auth +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_transition_auth_then_auth, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: autda x0, x2 autda x0, x2 pacda x0, x1 @@ -363,9 +367,10 @@ 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: +// FPAC-NOT: bad_sign_authed_unchecked_multi_bb +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_sign_authed_unchecked_multi_bb, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: autda x0, x2 cbz x3, 1f ldr x2, [x0] @@ -534,9 +539,10 @@ 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: +// FPAC-NOT: bad_sign_authed_unchecked_nocfg +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_sign_authed_unchecked_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: adr x3, 1f br x3 1: @@ -640,9 +646,10 @@ 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: +// FPAC-NOT: bad_transition_check_then_auth_nocfg +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_transition_check_then_auth_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: adr x3, 1f br x3 1: @@ -655,9 +662,10 @@ 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: +// FPAC-NOT: bad_transition_auth_then_auth_nocfg +// NOFPAC-LABEL: GS-PAUTH: signing oracle found in function bad_transition_auth_then_auth_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: pacda x0, x1 +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: adr x3, 1f br x3 1: diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s b/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s index 2d3c2f1a632ca..59b7d929275a9 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-tail-calls.s @@ -1,6 +1,7 @@ // RUN: %clang %cflags -Wl,--entry=_custom_start -march=armv8.3-a %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 +// RUN: llvm-bolt-binary-analysis --scanners=pacret %t.exe 2>&1 | FileCheck -check-prefix=PACRET %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth --auth-traps-on-failure %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,FPAC %s +// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,NOFPAC %s // PACRET-NOT: untrusted link register found before tail call @@ -89,19 +90,20 @@ bad_indirect_tailcall_not_auted: .globl bad_direct_tailcall_untrusted .type bad_direct_tailcall_untrusted,@function bad_direct_tailcall_untrusted: -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_direct_tailcall_untrusted, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: b callee # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_direct_tailcall_untrusted, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: b callee # TAILCALL -// 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]+}}: ldp x29, x30, [sp], #0x10 -// CHECK-NEXT: {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: {{[0-9a-f]+}}: b callee # TAILCALL +// FPAC-NOT: bad_direct_tailcall_untrusted +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_direct_tailcall_untrusted, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: b callee # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_direct_tailcall_untrusted, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: b callee # TAILCALL +// NOFPAC-NEXT: This happens in the following basic block: +// NOFPAC-NEXT: {{[0-9a-f]+}}: paciasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: stp x29, x30, [sp, #-0x10]! +// NOFPAC-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10 +// NOFPAC-NEXT: {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: b callee # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! ldp x29, x30, [sp], #0x10 @@ -114,19 +116,20 @@ bad_direct_tailcall_untrusted: bad_plt_tailcall_untrusted: // FIXME: Calls via PLT are disassembled incorrectly. Nevertheless, they are // still detected as tail calls. -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_plt_tailcall_untrusted, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_plt_tailcall_untrusted, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted # TAILCALL -// 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]+}}: ldp x29, x30, [sp], #0x10 -// CHECK-NEXT: {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted # TAILCALL +// FPAC-NOT: bad_plt_tailcall_untrusted +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_plt_tailcall_untrusted, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_plt_tailcall_untrusted, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted # TAILCALL +// NOFPAC-NEXT: This happens in the following basic block: +// NOFPAC-NEXT: {{[0-9a-f]+}}: paciasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: stp x29, x30, [sp, #-0x10]! +// NOFPAC-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10 +// NOFPAC-NEXT: {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! ldp x29, x30, [sp], #0x10 @@ -137,20 +140,21 @@ bad_plt_tailcall_untrusted: .globl bad_indirect_tailcall_untrusted .type bad_indirect_tailcall_untrusted,@function bad_indirect_tailcall_untrusted: -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_indirect_tailcall_untrusted, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: br x0 # TAILCALL -// 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]+}}: ldp x29, x30, [sp], #0x10 -// CHECK-NEXT: {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: {{[0-9a-f]+}}: autia x0, x1 -// CHECK-NEXT: {{[0-9a-f]+}}: br x0 # TAILCALL +// FPAC-NOT: bad_indirect_tailcall_untrusted +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_indirect_tailcall_untrusted, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: br x0 # TAILCALL +// NOFPAC-NEXT: This happens in the following basic block: +// NOFPAC-NEXT: {{[0-9a-f]+}}: paciasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: stp x29, x30, [sp, #-0x10]! +// NOFPAC-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10 +// NOFPAC-NEXT: {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: autia x0, x1 +// NOFPAC-NEXT: {{[0-9a-f]+}}: br x0 # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! ldp x29, x30, [sp], #0x10 @@ -251,13 +255,14 @@ bad_indirect_tailcall_not_auted_multi_bb: .globl bad_direct_tailcall_untrusted_multi_bb .type bad_direct_tailcall_untrusted_multi_bb,@function bad_direct_tailcall_untrusted_multi_bb: -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_direct_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: b callee # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_direct_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: b callee # TAILCALL +// FPAC-NOT: bad_direct_tailcall_untrusted_multi_bb +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_direct_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: b callee # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_direct_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: b callee # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! ldp x29, x30, [sp], #0x10 @@ -271,12 +276,13 @@ bad_direct_tailcall_untrusted_multi_bb: .globl bad_indirect_tailcall_untrusted_multi_bb .type bad_indirect_tailcall_untrusted_multi_bb,@function bad_indirect_tailcall_untrusted_multi_bb: -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_indirect_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # UNKNOWN CONTROL FLOW -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 0 instructions that leak the affected registers are: +// FPAC-NOT: bad_indirect_tailcall_untrusted_multi_bb +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_indirect_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: br x0 # UNKNOWN CONTROL FLOW +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted_multi_bb, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 0 instructions that leak the affected registers are: paciasp stp x29, x30, [sp, #-0x10]! ldp x29, x30, [sp], #0x10 @@ -397,13 +403,14 @@ bad_indirect_tailcall_not_auted_nocfg: .globl bad_direct_tailcall_untrusted_nocfg .type bad_direct_tailcall_untrusted_nocfg,@function bad_direct_tailcall_untrusted_nocfg: -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_direct_tailcall_untrusted_nocfg, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: b callee # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_direct_tailcall_untrusted_nocfg, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: b callee # TAILCALL +// FPAC-NOT: bad_direct_tailcall_untrusted_nocfg +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_direct_tailcall_untrusted_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: b callee # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_direct_tailcall_untrusted_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: b callee # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! adr x3, 1f @@ -419,13 +426,14 @@ bad_direct_tailcall_untrusted_nocfg: bad_plt_tailcall_untrusted_nocfg: // FIXME: Calls via PLT are disassembled incorrectly. Nevertheless, they are // still detected as tail calls. -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_plt_tailcall_untrusted_nocfg, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted_nocfg # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_plt_tailcall_untrusted_nocfg, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted_nocfg # TAILCALL +// FPAC-NOT: bad_plt_tailcall_untrusted_nocfg +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_plt_tailcall_untrusted_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted_nocfg # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_plt_tailcall_untrusted_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: b bad_indirect_tailcall_untrusted_nocfg # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! adr x3, 1f @@ -441,11 +449,12 @@ bad_plt_tailcall_untrusted_nocfg: bad_indirect_tailcall_untrusted_nocfg: // Known false negative: ignoring UNKNOWN CONTROL FLOW without CFG. // Authentication oracle is found by a generic checker, though. -// CHECK-NOT: untrusted link register{{.*}}bad_indirect_tailcall_untrusted_nocfg -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted_nocfg, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 0 instructions that leak the affected registers are: -// CHECK-NOT: untrusted link register{{.*}}bad_indirect_tailcall_untrusted_nocfg +// FPAC-NOT: bad_indirect_tailcall_untrusted_nocfg +// NOFPAC-NOT: untrusted link register{{.*}}bad_indirect_tailcall_untrusted_nocfg +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted_nocfg, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 0 instructions that leak the affected registers are: +// NOFPAC-NOT: untrusted link register{{.*}}bad_indirect_tailcall_untrusted_nocfg paciasp stp x29, x30, [sp, #-0x10]! adr x3, 1f @@ -515,19 +524,20 @@ good_indirect_tailcall_no_clobber_v83: .globl bad_indirect_tailcall_untrusted_v83 .type bad_indirect_tailcall_untrusted_v83,@function bad_indirect_tailcall_untrusted_v83: -// CHECK-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_indirect_tailcall_untrusted_v83, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: braa x0, x1 # TAILCALL -// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are: -// CHECK-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted_v83, basic block {{[^,]+}}, at address -// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: The 1 instructions that leak the affected registers are: -// CHECK-NEXT: 1. {{[0-9a-f]+}}: braa x0, x1 # TAILCALL -// 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]+}}: ldp x29, x30, [sp], #0x10 -// CHECK-NEXT: {{[0-9a-f]+}}: autiasp -// CHECK-NEXT: {{[0-9a-f]+}}: braa x0, x1 # TAILCALL +// FPAC-NOT: bad_indirect_tailcall_untrusted_v83 +// NOFPAC-LABEL: GS-PAUTH: untrusted link register found before tail call in function bad_indirect_tailcall_untrusted_v83, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: braa x0, x1 # TAILCALL +// NOFPAC-NEXT: The 0 instructions that write to the affected registers after any authentication are: +// NOFPAC-LABEL: GS-PAUTH: authentication oracle found in function bad_indirect_tailcall_untrusted_v83, basic block {{[^,]+}}, at address +// NOFPAC-NEXT: The instruction is {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: The 1 instructions that leak the affected registers are: +// NOFPAC-NEXT: 1. {{[0-9a-f]+}}: braa x0, x1 # TAILCALL +// NOFPAC-NEXT: This happens in the following basic block: +// NOFPAC-NEXT: {{[0-9a-f]+}}: paciasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: stp x29, x30, [sp, #-0x10]! +// NOFPAC-NEXT: {{[0-9a-f]+}}: ldp x29, x30, [sp], #0x10 +// NOFPAC-NEXT: {{[0-9a-f]+}}: autiasp +// NOFPAC-NEXT: {{[0-9a-f]+}}: braa x0, x1 # TAILCALL paciasp stp x29, x30, [sp, #-0x10]! ldp x29, x30, [sp], #0x10