Skip to content

Commit 6ca76c6

Browse files
committed
Improve estimation of the initial state of unreachable BBs
1 parent a5ac9f3 commit 6ca76c6

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 {
@@ -342,10 +358,27 @@ class SrcSafetyAnalysis {
342358
return S;
343359
}
344360

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

351384
BitVector getClobberedRegs(const MCInst &Point) const {
@@ -551,6 +584,10 @@ class DataflowSrcSafetyAnalysis
551584
using SrcSafetyAnalysis::BC;
552585
using SrcSafetyAnalysis::computeNext;
553586

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

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

601643
return SrcState();
602644
}
@@ -702,6 +744,12 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis,
702744
using SrcSafetyAnalysis::BC;
703745
BinaryFunction &BF;
704746

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

1343-
template <typename T> static void iterateOverInstrs(BinaryFunction &BF, T Fn) {
1344-
if (BF.hasCFG()) {
1345-
for (BinaryBasicBlock &BB : BF)
1346-
for (int64_t I = 0, E = BB.size(); I < E; ++I)
1347-
Fn(MCInstInBBReference(&BB, I));
1348-
} else {
1349-
for (auto I : BF.instrs())
1350-
Fn(MCInstInBFReference(&BF, I.first));
1351-
}
1352-
}
1353-
13541391
static SmallVector<MCPhysReg>
13551392
collectRegsToTrack(ArrayRef<PartialReport<MCPhysReg>> Reports) {
13561393
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)