Skip to content

Commit 4dd8990

Browse files
committed
[BOLT] Gadget scanner: refine class names and debug output (NFC)
Scanning functions without CFG information as well as the detection of authentication oracles requires introducing more classes related to register state analysis. To make the future code easier to understand, rename several classes beforehand. To detect authentication oracles, one has to query the properties of *output* operands of authentication instructions *after* the instruction is executed - this requires adding another analysis that iterates over the instructions in reverse order, and a corresponding state class. As the main difference of the existing `State` class is that it stores the properties of source register operands of the instructions before the instruction's execution, rename it to `SrcState` and `PacRetAnalysis` to `SrcSafetyAnalysis`. Apply minor adjustments to the debug output along the way.
1 parent 2c10723 commit 4dd8990

File tree

3 files changed

+116
-109
lines changed

3 files changed

+116
-109
lines changed

bolt/include/bolt/Passes/PAuthGadgetScanner.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ raw_ostream &operator<<(raw_ostream &OS, const MCInstReference &);
175175

176176
namespace PAuthGadgetScanner {
177177

178-
class PacRetAnalysis;
179-
struct State;
178+
class SrcSafetyAnalysis;
179+
struct SrcState;
180180

181181
/// Description of a gadget kind that can be detected. Intended to be
182182
/// statically allocated to be attached to reports by reference.

bolt/lib/Passes/PAuthGadgetScanner.cpp

+53-50
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class TrackedRegisters {
172172
/// * RET (which is implicitly RET X30) is a protected return if and only if
173173
/// X30 is safe-to-dereference - the state computed for sub- and
174174
/// super-registers is not inspected.
175-
struct State {
175+
struct SrcState {
176176
/// A BitVector containing the registers that are either safe at function
177177
/// entry and were not clobbered yet, or those not clobbered since being
178178
/// authenticated.
@@ -186,12 +186,12 @@ struct State {
186186
std::vector<SmallPtrSet<const MCInst *, 4>> LastInstWritingReg;
187187

188188
/// Construct an empty state.
189-
State() {}
189+
SrcState() {}
190190

191-
State(unsigned NumRegs, unsigned NumRegsToTrack)
191+
SrcState(unsigned NumRegs, unsigned NumRegsToTrack)
192192
: SafeToDerefRegs(NumRegs), LastInstWritingReg(NumRegsToTrack) {}
193193

194-
State &merge(const State &StateIn) {
194+
SrcState &merge(const SrcState &StateIn) {
195195
if (StateIn.empty())
196196
return *this;
197197
if (empty())
@@ -208,11 +208,11 @@ struct State {
208208
/// neither safe, nor unsafe ones.
209209
bool empty() const { return SafeToDerefRegs.empty(); }
210210

211-
bool operator==(const State &RHS) const {
211+
bool operator==(const SrcState &RHS) const {
212212
return SafeToDerefRegs == RHS.SafeToDerefRegs &&
213213
LastInstWritingReg == RHS.LastInstWritingReg;
214214
}
215-
bool operator!=(const State &RHS) const { return !((*this) == RHS); }
215+
bool operator!=(const SrcState &RHS) const { return !((*this) == RHS); }
216216
};
217217

218218
static void printLastInsts(
@@ -228,8 +228,8 @@ static void printLastInsts(
228228
}
229229
}
230230

231-
raw_ostream &operator<<(raw_ostream &OS, const State &S) {
232-
OS << "pacret-state<";
231+
raw_ostream &operator<<(raw_ostream &OS, const SrcState &S) {
232+
OS << "src-state<";
233233
if (S.empty()) {
234234
OS << "empty";
235235
} else {
@@ -240,18 +240,18 @@ raw_ostream &operator<<(raw_ostream &OS, const State &S) {
240240
return OS;
241241
}
242242

243-
class PacStatePrinter {
243+
class SrcStatePrinter {
244244
public:
245-
void print(raw_ostream &OS, const State &State) const;
246-
explicit PacStatePrinter(const BinaryContext &BC) : BC(BC) {}
245+
void print(raw_ostream &OS, const SrcState &State) const;
246+
explicit SrcStatePrinter(const BinaryContext &BC) : BC(BC) {}
247247

248248
private:
249249
const BinaryContext &BC;
250250
};
251251

252-
void PacStatePrinter::print(raw_ostream &OS, const State &S) const {
252+
void SrcStatePrinter::print(raw_ostream &OS, const SrcState &S) const {
253253
RegStatePrinter RegStatePrinter(BC);
254-
OS << "pacret-state<";
254+
OS << "src-state<";
255255
if (S.empty()) {
256256
assert(S.SafeToDerefRegs.empty());
257257
assert(S.LastInstWritingReg.empty());
@@ -265,71 +265,71 @@ void PacStatePrinter::print(raw_ostream &OS, const State &S) const {
265265
OS << ">";
266266
}
267267

268-
class PacRetAnalysis
269-
: public DataflowAnalysis<PacRetAnalysis, State, /*Backward=*/false,
270-
PacStatePrinter> {
268+
class SrcSafetyAnalysis
269+
: public DataflowAnalysis<SrcSafetyAnalysis, SrcState, /*Backward=*/false,
270+
SrcStatePrinter> {
271271
using Parent =
272-
DataflowAnalysis<PacRetAnalysis, State, false, PacStatePrinter>;
272+
DataflowAnalysis<SrcSafetyAnalysis, SrcState, false, SrcStatePrinter>;
273273
friend Parent;
274274

275275
public:
276-
PacRetAnalysis(BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId,
277-
const std::vector<MCPhysReg> &RegsToTrackInstsFor)
276+
SrcSafetyAnalysis(BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId,
277+
const std::vector<MCPhysReg> &RegsToTrackInstsFor)
278278
: Parent(BF, AllocId), NumRegs(BF.getBinaryContext().MRI->getNumRegs()),
279279
RegsToTrackInstsFor(RegsToTrackInstsFor) {}
280-
virtual ~PacRetAnalysis() {}
280+
virtual ~SrcSafetyAnalysis() {}
281281

282282
protected:
283283
const unsigned NumRegs;
284284
/// RegToTrackInstsFor is the set of registers for which the dataflow analysis
285285
/// must compute which the last set of instructions writing to it are.
286286
const TrackedRegisters RegsToTrackInstsFor;
287287

288-
SmallPtrSet<const MCInst *, 4> &lastWritingInsts(State &S,
288+
SmallPtrSet<const MCInst *, 4> &lastWritingInsts(SrcState &S,
289289
MCPhysReg Reg) const {
290290
unsigned Index = RegsToTrackInstsFor.getIndex(Reg);
291291
return S.LastInstWritingReg[Index];
292292
}
293-
const SmallPtrSet<const MCInst *, 4> &lastWritingInsts(const State &S,
293+
const SmallPtrSet<const MCInst *, 4> &lastWritingInsts(const SrcState &S,
294294
MCPhysReg Reg) const {
295295
unsigned Index = RegsToTrackInstsFor.getIndex(Reg);
296296
return S.LastInstWritingReg[Index];
297297
}
298298

299299
void preflight() {}
300300

301-
State createEntryState() {
302-
State S(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
301+
SrcState createEntryState() {
302+
SrcState S(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
303303
for (MCPhysReg Reg : BC.MIB->getTrustedLiveInRegs())
304304
S.SafeToDerefRegs |= BC.MIB->getAliases(Reg, /*OnlySmaller=*/true);
305305
return S;
306306
}
307307

308-
State getStartingStateAtBB(const BinaryBasicBlock &BB) {
308+
SrcState getStartingStateAtBB(const BinaryBasicBlock &BB) {
309309
if (BB.isEntryPoint())
310310
return createEntryState();
311311

312-
return State();
312+
return SrcState();
313313
}
314314

315-
State getStartingStateAtPoint(const MCInst &Point) { return State(); }
315+
SrcState getStartingStateAtPoint(const MCInst &Point) { return SrcState(); }
316316

317-
void doConfluence(State &StateOut, const State &StateIn) {
318-
PacStatePrinter P(BC);
317+
void doConfluence(SrcState &StateOut, const SrcState &StateIn) {
318+
SrcStatePrinter P(BC);
319319
LLVM_DEBUG({
320-
dbgs() << " PacRetAnalysis::Confluence(\n";
321-
dbgs() << " State 1: ";
320+
dbgs() << " SrcSafetyAnalysis::Confluence(\n";
321+
dbgs() << " State 1: ";
322322
P.print(dbgs(), StateOut);
323323
dbgs() << "\n";
324-
dbgs() << " State 2: ";
324+
dbgs() << " State 2: ";
325325
P.print(dbgs(), StateIn);
326326
dbgs() << ")\n";
327327
});
328328

329329
StateOut.merge(StateIn);
330330

331331
LLVM_DEBUG({
332-
dbgs() << " merged state: ";
332+
dbgs() << " merged state: ";
333333
P.print(dbgs(), StateOut);
334334
dbgs() << "\n";
335335
});
@@ -354,7 +354,7 @@ class PacRetAnalysis
354354
// Returns all registers that can be treated as if they are written by an
355355
// authentication instruction.
356356
SmallVector<MCPhysReg> getRegsMadeSafeToDeref(const MCInst &Point,
357-
const State &Cur) const {
357+
const SrcState &Cur) const {
358358
SmallVector<MCPhysReg> Regs;
359359
const MCPhysReg NoReg = BC.MIB->getNoRegister();
360360

@@ -378,10 +378,10 @@ class PacRetAnalysis
378378
return Regs;
379379
}
380380

381-
State computeNext(const MCInst &Point, const State &Cur) {
382-
PacStatePrinter P(BC);
381+
SrcState computeNext(const MCInst &Point, const SrcState &Cur) {
382+
SrcStatePrinter P(BC);
383383
LLVM_DEBUG({
384-
dbgs() << " PacRetAnalysis::ComputeNext(";
384+
dbgs() << " SrcSafetyAnalysis::ComputeNext(";
385385
BC.InstPrinter->printInst(&const_cast<MCInst &>(Point), 0, "", *BC.STI,
386386
dbgs());
387387
dbgs() << ", ";
@@ -395,7 +395,7 @@ class PacRetAnalysis
395395
if (Cur.empty()) {
396396
LLVM_DEBUG(
397397
{ dbgs() << "Skipping computeNext(Point, Cur) as Cur is empty.\n"; });
398-
return State();
398+
return SrcState();
399399
}
400400

401401
// First, compute various properties of the instruction, taking the state
@@ -406,7 +406,7 @@ class PacRetAnalysis
406406
getRegsMadeSafeToDeref(Point, Cur);
407407

408408
// Then, compute the state after this instruction is executed.
409-
State Next = Cur;
409+
SrcState Next = Cur;
410410

411411
Next.SafeToDerefRegs.reset(Clobbered);
412412
// Keep track of this instruction if it writes to any of the registers we
@@ -430,15 +430,15 @@ class PacRetAnalysis
430430
}
431431

432432
LLVM_DEBUG({
433-
dbgs() << " .. result: (";
433+
dbgs() << " .. result: (";
434434
P.print(dbgs(), Next);
435435
dbgs() << ")\n";
436436
});
437437

438438
return Next;
439439
}
440440

441-
StringRef getAnnotationName() const { return StringRef("PacRetAnalysis"); }
441+
StringRef getAnnotationName() const { return StringRef("SrcSafetyAnalysis"); }
442442

443443
public:
444444
std::vector<MCInstReference>
@@ -448,8 +448,8 @@ class PacRetAnalysis
448448
return {};
449449
auto MaybeState = getStateBefore(Inst);
450450
if (!MaybeState)
451-
llvm_unreachable("Expected State to be present");
452-
const State &S = *MaybeState;
451+
llvm_unreachable("Expected state to be present");
452+
const SrcState &S = *MaybeState;
453453
// Due to aliasing registers, multiple registers may have been tracked.
454454
std::set<const MCInst *> LastWritingInsts;
455455
for (MCPhysReg TrackedReg : UsedDirtyRegs) {
@@ -468,7 +468,7 @@ class PacRetAnalysis
468468

469469
static std::shared_ptr<Report>
470470
shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
471-
const State &S) {
471+
const SrcState &S) {
472472
static const GadgetKind RetKind("non-protected ret found");
473473
if (!BC.MIB->isReturn(Inst))
474474
return nullptr;
@@ -496,7 +496,7 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
496496

497497
static std::shared_ptr<Report>
498498
shouldReportCallGadget(const BinaryContext &BC, const MCInstReference &Inst,
499-
const State &S) {
499+
const SrcState &S) {
500500
static const GadgetKind CallKind("non-protected call found");
501501
if (!BC.MIB->isCall(Inst) && !BC.MIB->isBranch(Inst))
502502
return nullptr;
@@ -522,18 +522,19 @@ Analysis::findGadgets(BinaryFunction &BF,
522522
MCPlusBuilder::AllocatorIdTy AllocatorId) {
523523
FunctionAnalysisResult Result;
524524

525-
PacRetAnalysis PRA(BF, AllocatorId, {});
525+
SrcSafetyAnalysis PRA(BF, AllocatorId, {});
526+
LLVM_DEBUG({ dbgs() << "Running src register safety analysis...\n"; });
526527
PRA.run();
527528
LLVM_DEBUG({
528-
dbgs() << " After PacRetAnalysis:\n";
529+
dbgs() << "After src register safety analysis:\n";
529530
BF.dump();
530531
});
531532

532533
BinaryContext &BC = BF.getBinaryContext();
533534
for (BinaryBasicBlock &BB : BF) {
534535
for (int64_t I = 0, E = BB.size(); I < E; ++I) {
535536
MCInstReference Inst(&BB, I);
536-
const State &S = *PRA.getStateBefore(Inst);
537+
const SrcState &S = *PRA.getStateBefore(Inst);
537538

538539
// If non-empty state was never propagated from the entry basic block
539540
// to Inst, assume it to be unreachable and report a warning.
@@ -568,10 +569,12 @@ void Analysis::computeDetailedInfo(BinaryFunction &BF,
568569
std::vector<MCPhysReg> RegsToTrackVec(RegsToTrack.begin(), RegsToTrack.end());
569570

570571
// Re-compute the analysis with register tracking.
571-
PacRetAnalysis PRWIA(BF, AllocatorId, RegsToTrackVec);
572+
SrcSafetyAnalysis PRWIA(BF, AllocatorId, RegsToTrackVec);
573+
LLVM_DEBUG(
574+
{ dbgs() << "\nRunning detailed src register safety analysis...\n"; });
572575
PRWIA.run();
573576
LLVM_DEBUG({
574-
dbgs() << " After detailed PacRetAnalysis:\n";
577+
dbgs() << "After detailed src register safety analysis:\n";
575578
BF.dump();
576579
});
577580

0 commit comments

Comments
 (0)