Skip to content

Commit 2ec11ea

Browse files
committed
Merge remote-tracking branch 'origin/main' into pr/riscv-xqciint-push-pop
2 parents bdf6ddc + 92c93f5 commit 2ec11ea

File tree

840 files changed

+23734
-7039
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

840 files changed

+23734
-7039
lines changed

bolt/include/bolt/Core/MCPlusBuilder.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,16 @@ class MCPlusBuilder {
577577
return getNoRegister();
578578
}
579579

580+
/// Returns the register used as call destination, or no-register, if not
581+
/// an indirect call. Sets IsAuthenticatedInternally if the instruction
582+
/// accepts a signed pointer as its operand and authenticates it internally.
583+
virtual MCPhysReg
584+
getRegUsedAsCallDest(const MCInst &Inst,
585+
bool &IsAuthenticatedInternally) const {
586+
llvm_unreachable("not implemented");
587+
return getNoRegister();
588+
}
589+
580590
virtual bool isTerminator(const MCInst &Inst) const;
581591

582592
virtual bool isNoop(const MCInst &Inst) const {
@@ -1741,6 +1751,15 @@ class MCPlusBuilder {
17411751
return {};
17421752
}
17431753

1754+
/// Create a sequence of instructions to compare contents of a register
1755+
/// \p RegNo to immediate \Imm and jump to \p Target if they are different.
1756+
virtual InstructionListType createCmpJNE(MCPhysReg RegNo, int64_t Imm,
1757+
const MCSymbol *Target,
1758+
MCContext *Ctx) const {
1759+
llvm_unreachable("not implemented");
1760+
return {};
1761+
}
1762+
17441763
/// Creates inline memcpy instruction. If \p ReturnEnd is true, then return
17451764
/// (dest + n) instead of dest.
17461765
virtual InstructionListType createInlineMemcpy(bool ReturnEnd) const {

bolt/include/bolt/Passes/PAuthGadgetScanner.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ struct FunctionAnalysisResult {
248248
};
249249

250250
class Analysis : public BinaryFunctionPass {
251+
/// Only search for pac-ret violations.
252+
bool PacRetGadgetsOnly;
253+
251254
void runOnFunction(BinaryFunction &Function,
252255
MCPlusBuilder::AllocatorIdTy AllocatorId);
253256
FunctionAnalysisResult findGadgets(BinaryFunction &BF,
@@ -261,7 +264,8 @@ class Analysis : public BinaryFunctionPass {
261264
std::mutex AnalysisResultsMutex;
262265

263266
public:
264-
explicit Analysis() : BinaryFunctionPass(false) {}
267+
explicit Analysis(bool PacRetGadgetsOnly)
268+
: BinaryFunctionPass(false), PacRetGadgetsOnly(PacRetGadgetsOnly) {}
265269

266270
const char *getName() const override { return "pauth-gadget-scanner"; }
267271

bolt/include/bolt/Utils/CommandLineOpts.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ extern llvm::cl::opt<unsigned> Verbosity;
8181
/// Return true if we should process all functions in the binary.
8282
bool processAllFunctions();
8383

84-
enum GadgetScannerKind { GS_PACRET, GS_ALL };
84+
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
8585

86-
extern llvm::cl::list<GadgetScannerKind> GadgetScannersToRun;
86+
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
8787

8888
} // namespace opts
8989

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,11 @@ class PacRetAnalysis
401401

402402
public:
403403
std::vector<MCInstReference>
404-
getLastClobberingInsts(const MCInst Ret, BinaryFunction &BF,
405-
const ArrayRef<MCPhysReg> UsedDirtyRegs) const {
404+
getLastClobberingInsts(const MCInst &Inst, BinaryFunction &BF,
405+
const ArrayRef<MCPhysReg> UsedDirtyRegs) {
406406
if (RegsToTrackInstsFor.empty())
407407
return {};
408-
auto MaybeState = getStateAt(Ret);
408+
auto MaybeState = getStateBefore(Inst);
409409
if (!MaybeState)
410410
llvm_unreachable("Expected State to be present");
411411
const State &S = *MaybeState;
@@ -453,6 +453,29 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
453453
return std::make_shared<GadgetReport>(RetKind, Inst, RetReg);
454454
}
455455

456+
static std::shared_ptr<Report>
457+
shouldReportCallGadget(const BinaryContext &BC, const MCInstReference &Inst,
458+
const State &S) {
459+
static const GadgetKind CallKind("non-protected call found");
460+
if (!BC.MIB->isCall(Inst) && !BC.MIB->isBranch(Inst))
461+
return nullptr;
462+
463+
bool IsAuthenticated = false;
464+
MCPhysReg DestReg = BC.MIB->getRegUsedAsCallDest(Inst, IsAuthenticated);
465+
if (IsAuthenticated || DestReg == BC.MIB->getNoRegister())
466+
return nullptr;
467+
468+
LLVM_DEBUG({
469+
traceInst(BC, "Found call inst", Inst);
470+
traceReg(BC, "Call destination reg", DestReg);
471+
traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs);
472+
});
473+
if (S.SafeToDerefRegs[DestReg])
474+
return nullptr;
475+
476+
return std::make_shared<GadgetReport>(CallKind, Inst, DestReg);
477+
}
478+
456479
FunctionAnalysisResult
457480
Analysis::findGadgets(BinaryFunction &BF,
458481
MCPlusBuilder::AllocatorIdTy AllocatorId) {
@@ -469,7 +492,7 @@ Analysis::findGadgets(BinaryFunction &BF,
469492
for (BinaryBasicBlock &BB : BF) {
470493
for (int64_t I = 0, E = BB.size(); I < E; ++I) {
471494
MCInstReference Inst(&BB, I);
472-
const State &S = *PRA.getStateAt(Inst);
495+
const State &S = *PRA.getStateBefore(Inst);
473496

474497
// If non-empty state was never propagated from the entry basic block
475498
// to Inst, assume it to be unreachable and report a warning.
@@ -481,6 +504,12 @@ Analysis::findGadgets(BinaryFunction &BF,
481504

482505
if (auto Report = shouldReportReturnGadget(BC, Inst, S))
483506
Result.Diagnostics.push_back(Report);
507+
508+
if (PacRetGadgetsOnly)
509+
continue;
510+
511+
if (auto Report = shouldReportCallGadget(BC, Inst, S))
512+
Result.Diagnostics.push_back(Report);
484513
}
485514
}
486515
return Result;

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,14 @@ static cl::opt<bool> WriteBoltInfoSection(
247247
"bolt-info", cl::desc("write bolt info section in the output binary"),
248248
cl::init(true), cl::Hidden, cl::cat(BoltOutputCategory));
249249

250-
cl::list<GadgetScannerKind>
251-
GadgetScannersToRun("scanners", cl::desc("which gadget scanners to run"),
252-
cl::values(clEnumValN(GS_PACRET, "pacret", "pac-ret"),
253-
clEnumValN(GS_ALL, "all", "all")),
254-
cl::ZeroOrMore, cl::CommaSeparated,
255-
cl::cat(BinaryAnalysisCategory));
250+
cl::bits<GadgetScannerKind> GadgetScannersToRun(
251+
"scanners", cl::desc("which gadget scanners to run"),
252+
cl::values(
253+
clEnumValN(GS_PACRET, "pacret",
254+
"pac-ret: return address protection (subset of \"pauth\")"),
255+
clEnumValN(GS_PAUTH, "pauth", "All Pointer Authentication scanners"),
256+
clEnumValN(GS_ALL, "all", "All implemented scanners")),
257+
cl::ZeroOrMore, cl::CommaSeparated, cl::cat(BinaryAnalysisCategory));
256258

257259
} // namespace opts
258260

@@ -3539,12 +3541,18 @@ void RewriteInstance::runBinaryAnalyses() {
35393541
// FIXME: add a pass that warns about which functions do not have CFG,
35403542
// and therefore, analysis is most likely to be less accurate.
35413543
using GSK = opts::GadgetScannerKind;
3542-
// if no command line option was given, act as if "all" was specified.
3543-
if (opts::GadgetScannersToRun.empty())
3544-
opts::GadgetScannersToRun.addValue(GSK::GS_ALL);
3545-
for (GSK ScannerToRun : opts::GadgetScannersToRun) {
3546-
if (ScannerToRun == GSK::GS_PACRET || ScannerToRun == GSK::GS_ALL)
3547-
Manager.registerPass(std::make_unique<PAuthGadgetScanner::Analysis>());
3544+
using PAuthScanner = PAuthGadgetScanner::Analysis;
3545+
3546+
// If no command line option was given, act as if "all" was specified.
3547+
bool RunAll = !opts::GadgetScannersToRun.getBits() ||
3548+
opts::GadgetScannersToRun.isSet(GSK::GS_ALL);
3549+
3550+
if (RunAll || opts::GadgetScannersToRun.isSet(GSK::GS_PAUTH)) {
3551+
Manager.registerPass(
3552+
std::make_unique<PAuthScanner>(/*OnlyPacRetChecks=*/false));
3553+
} else if (RunAll || opts::GadgetScannersToRun.isSet(GSK::GS_PACRET)) {
3554+
Manager.registerPass(
3555+
std::make_unique<PAuthScanner>(/*OnlyPacRetChecks=*/true));
35483556
}
35493557

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

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,33 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
277277
}
278278
}
279279

280+
MCPhysReg
281+
getRegUsedAsCallDest(const MCInst &Inst,
282+
bool &IsAuthenticatedInternally) const override {
283+
assert(isCall(Inst) || isBranch(Inst));
284+
IsAuthenticatedInternally = false;
285+
286+
switch (Inst.getOpcode()) {
287+
case AArch64::BR:
288+
case AArch64::BLR:
289+
return Inst.getOperand(0).getReg();
290+
case AArch64::BRAA:
291+
case AArch64::BRAB:
292+
case AArch64::BRAAZ:
293+
case AArch64::BRABZ:
294+
case AArch64::BLRAA:
295+
case AArch64::BLRAB:
296+
case AArch64::BLRAAZ:
297+
case AArch64::BLRABZ:
298+
IsAuthenticatedInternally = true;
299+
return Inst.getOperand(0).getReg();
300+
default:
301+
if (isIndirectCall(Inst) || isIndirectBranch(Inst))
302+
llvm_unreachable("Unhandled indirect branch");
303+
return getNoRegister();
304+
}
305+
}
306+
280307
bool isADRP(const MCInst &Inst) const override {
281308
return Inst.getOpcode() == AArch64::ADRP;
282309
}
@@ -1334,17 +1361,47 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
13341361

13351362
int getUncondBranchEncodingSize() const override { return 28; }
13361363

1364+
// This helper function creates the snippet of code that compares a register
1365+
// RegNo with an immedaite Imm, and jumps to Target if they are equal.
1366+
// cmp RegNo, #Imm
1367+
// b.eq Target
1368+
// where cmp is an alias for subs, which results in the code below:
1369+
// subs xzr, RegNo, #Imm
1370+
// b.eq Target.
13371371
InstructionListType createCmpJE(MCPhysReg RegNo, int64_t Imm,
13381372
const MCSymbol *Target,
13391373
MCContext *Ctx) const override {
13401374
InstructionListType Code;
13411375
Code.emplace_back(MCInstBuilder(AArch64::SUBSXri)
1342-
.addReg(RegNo)
1376+
.addReg(AArch64::XZR)
13431377
.addReg(RegNo)
13441378
.addImm(Imm)
13451379
.addImm(0));
13461380
Code.emplace_back(MCInstBuilder(AArch64::Bcc)
1381+
.addImm(AArch64CC::EQ)
1382+
.addExpr(MCSymbolRefExpr::create(
1383+
Target, MCSymbolRefExpr::VK_None, *Ctx)));
1384+
return Code;
1385+
}
1386+
1387+
// This helper function creates the snippet of code that compares a register
1388+
// RegNo with an immedaite Imm, and jumps to Target if they are not equal.
1389+
// cmp RegNo, #Imm
1390+
// b.ne Target
1391+
// where cmp is an alias for subs, which results in the code below:
1392+
// subs xzr, RegNo, #Imm
1393+
// b.ne Target.
1394+
InstructionListType createCmpJNE(MCPhysReg RegNo, int64_t Imm,
1395+
const MCSymbol *Target,
1396+
MCContext *Ctx) const override {
1397+
InstructionListType Code;
1398+
Code.emplace_back(MCInstBuilder(AArch64::SUBSXri)
1399+
.addReg(AArch64::XZR)
1400+
.addReg(RegNo)
13471401
.addImm(Imm)
1402+
.addImm(0));
1403+
Code.emplace_back(MCInstBuilder(AArch64::Bcc)
1404+
.addImm(AArch64CC::NE)
13481405
.addExpr(MCSymbolRefExpr::create(
13491406
Target, MCSymbolRefExpr::VK_None, *Ctx)));
13501407
return Code;

bolt/lib/Target/X86/X86MCPlusBuilder.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,18 @@ class X86MCPlusBuilder : public MCPlusBuilder {
24262426
return Code;
24272427
}
24282428

2429+
InstructionListType createCmpJNE(MCPhysReg RegNo, int64_t Imm,
2430+
const MCSymbol *Target,
2431+
MCContext *Ctx) const override {
2432+
InstructionListType Code;
2433+
Code.emplace_back(MCInstBuilder(X86::CMP64ri8).addReg(RegNo).addImm(Imm));
2434+
Code.emplace_back(MCInstBuilder(X86::JCC_1)
2435+
.addExpr(MCSymbolRefExpr::create(
2436+
Target, MCSymbolRefExpr::VK_None, *Ctx))
2437+
.addImm(X86::COND_NE));
2438+
return Code;
2439+
}
2440+
24292441
std::optional<Relocation>
24302442
createRelocation(const MCFixup &Fixup,
24312443
const MCAsmBackend &MAB) const override {

bolt/test/binary-analysis/AArch64/cmdline-args.test

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ HELP-EMPTY:
3333
HELP-NEXT: BinaryAnalysis options:
3434
HELP-EMPTY:
3535
HELP-NEXT: --scanners=<value> - which gadget scanners to run
36-
HELP-NEXT: =pacret - pac-ret
37-
HELP-NEXT: =all - all
36+
HELP-NEXT: =pacret - pac-ret: return address protection (subset of "pauth")
37+
HELP-NEXT: =pauth - All Pointer Authentication scanners
38+
HELP-NEXT: =all - All implemented scanners
3839
HELP-EMPTY:
3940
HELP-NEXT: Generic Options:

0 commit comments

Comments
 (0)