Skip to content

Commit 81bb101

Browse files
committed
Improve estimation of the initial state of unreachable BBs
1 parent 175d6cd commit 81bb101

File tree

2 files changed

+56
-24
lines changed

2 files changed

+56
-24
lines changed

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ namespace PAuthGadgetScanner {
8282
dbgs() << "\n";
8383
}
8484

85+
// Iterates over BinaryFunction's instructions like a range-based for loop:
86+
//
87+
// iterateOverInstrs(BF, [&](MCInstReference Inst) {
88+
// // loop body
89+
// });
90+
template <typename T> static void iterateOverInstrs(BinaryFunction &BF, T Fn) {
91+
if (BF.hasCFG()) {
92+
for (BinaryBasicBlock &BB : BF)
93+
for (int64_t I = 0, E = BB.size(); I < E; ++I)
94+
Fn(MCInstInBBReference(&BB, I));
95+
} else {
96+
for (auto I : BF.instrs())
97+
Fn(MCInstInBFReference(&BF, I.first));
98+
}
99+
}
100+
85101
// This class represents mapping from a set of arbitrary physical registers to
86102
// consecutive array indexes.
87103
class TrackedRegisters {
@@ -341,10 +357,27 @@ class SrcSafetyAnalysis {
341357
return S;
342358
}
343359

344-
/// Creates a state with all registers marked unsafe (not to be confused
345-
/// with empty state).
346-
SrcState createUnsafeState() const {
347-
return SrcState(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
360+
/// Computes a reasonably pessimistic estimation of the register state when
361+
/// the previous instruction is not known for sure. Takes the set of registers
362+
/// which are trusted at function entry and removes all registers that can be
363+
/// clobbered inside this function.
364+
SrcState computePessimisticState(BinaryFunction &BF) {
365+
BitVector ClobberedRegs(NumRegs);
366+
iterateOverInstrs(BF, [&](MCInstReference Inst) {
367+
BC.MIB->getClobberedRegs(Inst, ClobberedRegs);
368+
369+
// If this is a call instruction, no register is safe anymore, unless
370+
// it is a tail call. Ignore tail calls for the purpose of estimating the
371+
// worst-case scenario, assuming no instructions are executed in the
372+
// caller after this point anyway.
373+
if (BC.MIB->isCall(Inst) && !BC.MIB->isTailCall(Inst))
374+
ClobberedRegs.set();
375+
});
376+
377+
SrcState S = createEntryState();
378+
S.SafeToDerefRegs.reset(ClobberedRegs);
379+
S.TrustedRegs.reset(ClobberedRegs);
380+
return S;
348381
}
349382

350383
BitVector getClobberedRegs(const MCInst &Point) const {
@@ -550,6 +583,10 @@ class DataflowSrcSafetyAnalysis
550583
using SrcSafetyAnalysis::BC;
551584
using SrcSafetyAnalysis::computeNext;
552585

586+
// Pessimistic initial state for basic blocks without any predecessors
587+
// (not needed for most functions, thus initialized lazily).
588+
SrcState PessimisticState;
589+
553590
public:
554591
DataflowSrcSafetyAnalysis(BinaryFunction &BF,
555592
MCPlusBuilder::AllocatorIdTy AllocId,
@@ -592,10 +629,15 @@ class DataflowSrcSafetyAnalysis
592629

593630
// If a basic block without any predecessors is found in an optimized code,
594631
// this likely means that some CFG edges were not detected. Pessimistically
595-
// assume all registers to be unsafe before this basic block and warn about
596-
// this fact in FunctionAnalysis::findUnsafeUses().
597-
if (BB.pred_empty())
598-
return createUnsafeState();
632+
// assume any register that can ever be clobbered in this function to be
633+
// unsafe before this basic block.
634+
// Warn about this fact in FunctionAnalysis::findUnsafeUses(), as it likely
635+
// means imprecise CFG information.
636+
if (BB.pred_empty()) {
637+
if (PessimisticState.empty())
638+
PessimisticState = computePessimisticState(*BB.getParent());
639+
return PessimisticState;
640+
}
599641

600642
return SrcState();
601643
}
@@ -701,6 +743,12 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis,
701743
using SrcSafetyAnalysis::BC;
702744
BinaryFunction &BF;
703745

746+
/// Creates a state with all registers marked unsafe (not to be confused
747+
/// with empty state).
748+
SrcState createUnsafeState() const {
749+
return SrcState(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
750+
}
751+
704752
public:
705753
CFGUnawareSrcSafetyAnalysis(BinaryFunction &BF,
706754
MCPlusBuilder::AllocatorIdTy AllocId,
@@ -1326,17 +1374,6 @@ shouldReportAuthOracle(const BinaryContext &BC, const MCInstReference &Inst,
13261374
return make_gadget_report(AuthOracleKind, Inst, *AuthReg);
13271375
}
13281376

1329-
template <typename T> static void iterateOverInstrs(BinaryFunction &BF, T Fn) {
1330-
if (BF.hasCFG()) {
1331-
for (BinaryBasicBlock &BB : BF)
1332-
for (int64_t I = 0, E = BB.size(); I < E; ++I)
1333-
Fn(MCInstInBBReference(&BB, I));
1334-
} else {
1335-
for (auto I : BF.instrs())
1336-
Fn(MCInstInBFReference(&BF, I.first));
1337-
}
1338-
}
1339-
13401377
static SmallVector<MCPhysReg>
13411378
collectRegsToTrack(ArrayRef<PartialReport<MCPhysReg>> Reports) {
13421379
SmallSet<MCPhysReg, 4> RegsToTrack;

bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,9 @@ f_unreachable_instruction:
218218
// CHECK-LABEL: GS-PAUTH: Warning: the function has unreachable basic blocks (possibly incomplete CFG) in function f_unreachable_instruction, basic block {{[0-9a-zA-Z.]+}}, at address
219219
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: add x0, x1, x2
220220
// CHECK-NOT: instructions that write to the affected registers after any authentication are:
221-
// CHECK-LABEL: GS-PAUTH: non-protected ret found in function f_unreachable_instruction, basic block {{[0-9a-zA-Z.]+}}, at address
222-
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret
223-
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
224221
b 1f
225222
add x0, x1, x2
226223
1:
227-
// "ret" is reported as unprotected, as LR is pessimistically assumed
228-
// unsafe at "add x0, x1, x2", thus it is unsafe at "ret" as well.
229224
ret
230225
.size f_unreachable_instruction, .-f_unreachable_instruction
231226

0 commit comments

Comments
 (0)