Skip to content

Commit cf9baa5

Browse files
committed
[BOLT] Gadget scanner: streamline issue reporting
In preparation for adding more gadget kinds to detect, streamline issue reporting. Rename classes representing issue reports. In particular, rename `Annotation` base class to `Report`, as it has nothing to do with "annotations" in `MCPlus` terms anymore. Remove references to "return instructions" from variable names and report messages, use generic terms instead. Rename NonPacProtectedRetAnalysis to PAuthGadgetScanner. Remove `GeneralDiagnostic` as a separate class, make `GenericReport` (former `GenDiag`) store `std::string Text` directly. Remove unused `operator=` and `operator==` methods, as `Report`s are created on the heap and referenced via `shared_ptr`s. Introduce `GadgetKind` class - currently, it only wraps a `const char *` description to display to the user. This description is intended to be a per-gadget-kind constant (or a few hard-coded constants), so no need to store it to `std::string` field in each report instance. To handle both free-form `GenericReport`s and statically-allocated messages without unnecessary overhead, move printing of the report header to the base class (and take the message argument as a `StringRef`).
1 parent 9761e5d commit cf9baa5

File tree

6 files changed

+161
-159
lines changed

6 files changed

+161
-159
lines changed

bolt/include/bolt/Passes/NonPacProtectedRetAnalysis.h renamed to bolt/include/bolt/Passes/PAuthGadgetScanner.h

+43-47
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
//===- bolt/Passes/NonPacProtectedRetAnalysis.h -----------------*- C++ -*-===//
1+
//===- bolt/Passes/PAuthGadgetScanner.h -------------------------*- C++ -*-===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#ifndef BOLT_PASSES_NONPACPROTECTEDRETANALYSIS_H
10-
#define BOLT_PASSES_NONPACPROTECTEDRETANALYSIS_H
9+
#ifndef BOLT_PASSES_PAUTHGADGETSCANNER_H
10+
#define BOLT_PASSES_PAUTHGADGETSCANNER_H
1111

1212
#include "bolt/Core/BinaryContext.h"
1313
#include "bolt/Core/BinaryFunction.h"
@@ -173,63 +173,59 @@ struct MCInstReference {
173173

174174
raw_ostream &operator<<(raw_ostream &OS, const MCInstReference &);
175175

176-
struct GeneralDiagnostic {
177-
std::string Text;
178-
GeneralDiagnostic(const std::string &Text) : Text(Text) {}
179-
bool operator==(const GeneralDiagnostic &RHS) const {
180-
return Text == RHS.Text;
181-
}
176+
namespace PAuthGadgetScanner {
177+
178+
class PacRetAnalysis;
179+
struct State;
180+
181+
/// Description of a gadget kind that can be detected. Intended to be
182+
/// statically allocated to be attached to reports by reference.
183+
class GadgetKind {
184+
const char *Description;
185+
186+
public:
187+
GadgetKind(const char *Description) : Description(Description) {}
188+
189+
const StringRef getDescription() const { return Description; }
182190
};
183191

184-
raw_ostream &operator<<(raw_ostream &OS, const GeneralDiagnostic &Diag);
192+
/// Base report located at some instruction, without any additional information.
193+
struct Report {
194+
MCInstReference Location;
195+
196+
Report(MCInstReference Location) : Location(Location) {}
197+
virtual ~Report() {}
185198

186-
namespace NonPacProtectedRetAnalysis {
187-
struct Annotation {
188-
MCInstReference RetInst;
189-
Annotation(MCInstReference RetInst) : RetInst(RetInst) {}
190-
virtual bool operator==(const Annotation &RHS) const {
191-
return RetInst == RHS.RetInst;
192-
}
193-
Annotation &operator=(const Annotation &Other) {
194-
if (this == &Other)
195-
return *this;
196-
RetInst = Other.RetInst;
197-
return *this;
198-
}
199-
virtual ~Annotation() {}
200199
virtual void generateReport(raw_ostream &OS,
201200
const BinaryContext &BC) const = 0;
201+
202+
void printBasicInfo(raw_ostream &OS, const BinaryContext &BC,
203+
StringRef IssueKind) const;
202204
};
203205

204-
struct Gadget : public Annotation {
205-
std::vector<MCInstReference> OverwritingRetRegInst;
206-
virtual bool operator==(const Gadget &RHS) const {
207-
return Annotation::operator==(RHS) &&
208-
OverwritingRetRegInst == RHS.OverwritingRetRegInst;
209-
}
210-
Gadget(MCInstReference RetInst,
211-
const std::vector<MCInstReference> &OverwritingRetRegInst)
212-
: Annotation(RetInst), OverwritingRetRegInst(OverwritingRetRegInst) {}
213-
virtual void generateReport(raw_ostream &OS,
214-
const BinaryContext &BC) const override;
206+
struct GadgetReport : public Report {
207+
const GadgetKind &Kind;
208+
std::vector<MCInstReference> OverwritingInstrs;
209+
210+
GadgetReport(const GadgetKind &Kind, MCInstReference Location,
211+
std::vector<MCInstReference> OverwritingInstrs)
212+
: Report(Location), Kind(Kind), OverwritingInstrs(OverwritingInstrs) {}
213+
214+
void generateReport(raw_ostream &OS, const BinaryContext &BC) const override;
215215
};
216216

217-
struct GenDiag : public Annotation {
218-
GeneralDiagnostic Diag;
219-
virtual bool operator==(const GenDiag &RHS) const {
220-
return Annotation::operator==(RHS) && Diag == RHS.Diag;
221-
}
222-
GenDiag(MCInstReference RetInst, const std::string &Text)
223-
: Annotation(RetInst), Diag(Text) {}
217+
/// Report with a free-form message attached.
218+
struct GenericReport : public Report {
219+
std::string Text;
220+
GenericReport(MCInstReference Location, const std::string &Text)
221+
: Report(Location), Text(Text) {}
224222
virtual void generateReport(raw_ostream &OS,
225223
const BinaryContext &BC) const override;
226224
};
227225

228-
class PacRetAnalysis;
229-
230226
struct FunctionAnalysisResult {
231227
SmallSet<MCPhysReg, 1> RegistersAffected;
232-
std::vector<std::shared_ptr<Annotation>> Diagnostics;
228+
std::vector<std::shared_ptr<Report>> Diagnostics;
233229
};
234230

235231
class Analysis : public BinaryFunctionPass {
@@ -245,13 +241,13 @@ class Analysis : public BinaryFunctionPass {
245241
public:
246242
explicit Analysis() : BinaryFunctionPass(false) {}
247243

248-
const char *getName() const override { return "non-pac-protected-rets"; }
244+
const char *getName() const override { return "pauth-gadget-scanner"; }
249245

250246
/// Pass entry point
251247
Error runOnFunctions(BinaryContext &BC) override;
252248
};
253249

254-
} // namespace NonPacProtectedRetAnalysis
250+
} // namespace PAuthGadgetScanner
255251
} // namespace bolt
256252
} // namespace llvm
257253

bolt/lib/Passes/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ add_llvm_library(LLVMBOLTPasses
2323
LoopInversionPass.cpp
2424
LivenessAnalysis.cpp
2525
MCF.cpp
26-
NonPacProtectedRetAnalysis.cpp
2726
PatchEntries.cpp
27+
PAuthGadgetScanner.cpp
2828
PettisAndHansen.cpp
2929
PLTCall.cpp
3030
ProfileQualityStats.cpp

bolt/lib/Passes/NonPacProtectedRetAnalysis.cpp renamed to bolt/lib/Passes/PAuthGadgetScanner.cpp

+43-36
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===- bolt/Passes/NonPacProtectedRetAnalysis.cpp -------------------------===//
1+
//===- bolt/Passes/PAuthGadgetScanner.cpp ---------------------------------===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,7 +11,7 @@
1111
//
1212
//===----------------------------------------------------------------------===//
1313

14-
#include "bolt/Passes/NonPacProtectedRetAnalysis.h"
14+
#include "bolt/Passes/PAuthGadgetScanner.h"
1515
#include "bolt/Core/ParallelUtilities.h"
1616
#include "bolt/Passes/DataflowAnalysis.h"
1717
#include "llvm/ADT/STLExtras.h"
@@ -20,7 +20,7 @@
2020
#include "llvm/Support/Format.h"
2121
#include <memory>
2222

23-
#define DEBUG_TYPE "bolt-nonpacprotectedret"
23+
#define DEBUG_TYPE "bolt-pauth-scanner"
2424

2525
namespace llvm {
2626
namespace bolt {
@@ -57,7 +57,7 @@ raw_ostream &operator<<(raw_ostream &OS, const MCInstReference &Ref) {
5757
llvm_unreachable("");
5858
}
5959

60-
namespace NonPacProtectedRetAnalysis {
60+
namespace PAuthGadgetScanner {
6161

6262
static void traceInst(const BinaryContext &BC, StringRef Label,
6363
const MCInst &MI) {
@@ -395,7 +395,7 @@ Analysis::computeDfState(PacRetAnalysis &PRA, BinaryFunction &BF,
395395
if (BC.MIB->isReturn(Inst)) {
396396
ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB->getRegUsedAsRetDest(Inst);
397397
if (MaybeRetReg.getError()) {
398-
Result.Diagnostics.push_back(std::make_shared<GenDiag>(
398+
Result.Diagnostics.push_back(std::make_shared<GenericReport>(
399399
MCInstInBBReference(&BB, I),
400400
"Warning: pac-ret analysis could not analyze this return "
401401
"instruction"));
@@ -416,9 +416,10 @@ Analysis::computeDfState(PacRetAnalysis &PRA, BinaryFunction &BF,
416416
LLVM_DEBUG(
417417
{ traceRegMask(BC, "Intersection with RetReg", UsedDirtyRegs); });
418418
if (UsedDirtyRegs.any()) {
419+
static const GadgetKind RetKind("non-protected ret found");
419420
// This return instruction needs to be reported
420-
Result.Diagnostics.push_back(std::make_shared<Gadget>(
421-
MCInstInBBReference(&BB, I),
421+
Result.Diagnostics.push_back(std::make_shared<GadgetReport>(
422+
RetKind, MCInstInBBReference(&BB, I),
422423
PRA.getLastClobberingInsts(Inst, BF, UsedDirtyRegs)));
423424
for (MCPhysReg RetRegWithGadget : UsedDirtyRegs.set_bits())
424425
Result.RegistersAffected.insert(RetRegWithGadget);
@@ -480,28 +481,43 @@ static void printBB(const BinaryContext &BC, const BinaryBasicBlock *BB,
480481

481482
static void reportFoundGadgetInSingleBBSingleOverwInst(
482483
raw_ostream &OS, const BinaryContext &BC, const MCInstReference OverwInst,
483-
const MCInstReference RetInst) {
484-
BinaryBasicBlock *BB = RetInst.getBasicBlock();
484+
const MCInstReference Location) {
485+
BinaryBasicBlock *BB = Location.getBasicBlock();
485486
assert(OverwInst.ParentKind == MCInstReference::BasicBlockParent);
486-
assert(RetInst.ParentKind == MCInstReference::BasicBlockParent);
487+
assert(Location.ParentKind == MCInstReference::BasicBlockParent);
487488
MCInstInBBReference OverwInstBB = OverwInst.U.BBRef;
488489
if (BB == OverwInstBB.BB) {
489490
// overwriting inst and ret instruction are in the same basic block.
490-
assert(OverwInstBB.BBIndex < RetInst.U.BBRef.BBIndex);
491+
assert(OverwInstBB.BBIndex < Location.U.BBRef.BBIndex);
491492
OS << " This happens in the following basic block:\n";
492493
printBB(BC, BB);
493494
}
494495
}
495496

496-
void Gadget::generateReport(raw_ostream &OS, const BinaryContext &BC) const {
497-
GenDiag(RetInst, "non-protected ret found").generateReport(OS, BC);
497+
void Report::printBasicInfo(raw_ostream &OS, const BinaryContext &BC,
498+
StringRef IssueKind) const {
499+
BinaryFunction *BF = Location.getFunction();
500+
BinaryBasicBlock *BB = Location.getBasicBlock();
501+
502+
OS << "\nGS-PAUTH: " << IssueKind;
503+
OS << " in function " << BF->getPrintName();
504+
if (BB)
505+
OS << ", basic block " << BB->getName();
506+
OS << ", at address " << llvm::format("%x", Location.getAddress()) << "\n";
507+
OS << " The instruction is ";
508+
BC.printInstruction(OS, Location, Location.getAddress(), BF);
509+
}
498510

499-
BinaryFunction *BF = RetInst.getFunction();
500-
OS << " The " << OverwritingRetRegInst.size()
501-
<< " instructions that write to the return register after any "
511+
void GadgetReport::generateReport(raw_ostream &OS,
512+
const BinaryContext &BC) const {
513+
printBasicInfo(OS, BC, Kind.getDescription());
514+
515+
BinaryFunction *BF = Location.getFunction();
516+
OS << " The " << OverwritingInstrs.size()
517+
<< " instructions that write to the affected registers after any "
502518
"authentication are:\n";
503519
// Sort by address to ensure output is deterministic.
504-
std::vector<MCInstReference> ORRI = OverwritingRetRegInst;
520+
std::vector<MCInstReference> ORRI = OverwritingInstrs;
505521
llvm::sort(ORRI, [](const MCInstReference &A, const MCInstReference &B) {
506522
return A.getAddress() < B.getAddress();
507523
});
@@ -510,24 +526,16 @@ void Gadget::generateReport(raw_ostream &OS, const BinaryContext &BC) const {
510526
OS << " " << (I + 1) << ". ";
511527
BC.printInstruction(OS, InstRef, InstRef.getAddress(), BF);
512528
};
513-
if (OverwritingRetRegInst.size() == 1) {
514-
const MCInstReference OverwInst = OverwritingRetRegInst[0];
529+
if (OverwritingInstrs.size() == 1) {
530+
const MCInstReference OverwInst = OverwritingInstrs[0];
515531
assert(OverwInst.ParentKind == MCInstReference::BasicBlockParent);
516-
reportFoundGadgetInSingleBBSingleOverwInst(OS, BC, OverwInst, RetInst);
532+
reportFoundGadgetInSingleBBSingleOverwInst(OS, BC, OverwInst, Location);
517533
}
518534
}
519535

520-
void GenDiag::generateReport(raw_ostream &OS, const BinaryContext &BC) const {
521-
BinaryFunction *BF = RetInst.getFunction();
522-
BinaryBasicBlock *BB = RetInst.getBasicBlock();
523-
524-
OS << "\nGS-PACRET: " << Diag.Text;
525-
OS << " in function " << BF->getPrintName();
526-
if (BB)
527-
OS << ", basic block " << BB->getName();
528-
OS << ", at address " << llvm::format("%x", RetInst.getAddress()) << "\n";
529-
OS << " The return instruction is ";
530-
BC.printInstruction(OS, RetInst, RetInst.getAddress(), BF);
536+
void GenericReport::generateReport(raw_ostream &OS,
537+
const BinaryContext &BC) const {
538+
printBasicInfo(OS, BC, Text);
531539
}
532540

533541
Error Analysis::runOnFunctions(BinaryContext &BC) {
@@ -542,17 +550,16 @@ Error Analysis::runOnFunctions(BinaryContext &BC) {
542550

543551
ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
544552
BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun,
545-
SkipFunc, "NonPacProtectedRetAnalysis");
553+
SkipFunc, "PAuthGadgetScanner");
546554

547555
for (BinaryFunction *BF : BC.getAllBinaryFunctions())
548556
if (AnalysisResults.count(BF) > 0) {
549-
for (const std::shared_ptr<Annotation> &A :
550-
AnalysisResults[BF].Diagnostics)
551-
A->generateReport(outs(), BC);
557+
for (const std::shared_ptr<Report> &R : AnalysisResults[BF].Diagnostics)
558+
R->generateReport(outs(), BC);
552559
}
553560
return Error::success();
554561
}
555562

556-
} // namespace NonPacProtectedRetAnalysis
563+
} // namespace PAuthGadgetScanner
557564
} // namespace bolt
558565
} // namespace llvm

bolt/lib/Rewrite/RewriteInstance.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "bolt/Passes/BinaryPasses.h"
2121
#include "bolt/Passes/CacheMetrics.h"
2222
#include "bolt/Passes/IdenticalCodeFolding.h"
23-
#include "bolt/Passes/NonPacProtectedRetAnalysis.h"
23+
#include "bolt/Passes/PAuthGadgetScanner.h"
2424
#include "bolt/Passes/ReorderFunctions.h"
2525
#include "bolt/Profile/BoltAddressTranslation.h"
2626
#include "bolt/Profile/DataAggregator.h"
@@ -3520,8 +3520,7 @@ void RewriteInstance::runBinaryAnalyses() {
35203520
opts::GadgetScannersToRun.addValue(GSK::GS_ALL);
35213521
for (GSK ScannerToRun : opts::GadgetScannersToRun) {
35223522
if (ScannerToRun == GSK::GS_PACRET || ScannerToRun == GSK::GS_ALL)
3523-
Manager.registerPass(
3524-
std::make_unique<NonPacProtectedRetAnalysis::Analysis>());
3523+
Manager.registerPass(std::make_unique<PAuthGadgetScanner::Analysis>());
35253524
}
35263525

35273526
BC->logBOLTErrorsAndQuitOnFatal(Manager.runPasses());

0 commit comments

Comments
 (0)