Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 099c22b

Browse filesBrowse files
committed
[BOLT] Gadget scanner: clarify MCPlusBuilder callbacks interface
Clarify the semantics of `getAuthenticatedReg` and remove a redundant `isAuthenticationOfReg` method, as combined auth+something instructions (such as `retaa` on AArch64) should be handled carefully, especially when searching for authentication oracles: usually, such instructions cannot be authentication oracles and only some of them actually write an authenticated pointer to a register (such as "ldra x0, [x1]!"). Use `std::optional<MCPhysReg>` returned type instead of plain MCPhysReg and returning `getNoRegister()` as a "not applicable" indication. Document a few existing methods, add information about preconditions.
1 parent 21f15ce commit 099c22b
Copy full SHA for 099c22b

File tree

Expand file treeCollapse file tree

5 files changed

+130
-94
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+130
-94
lines changed

‎bolt/include/bolt/Core/MCPlusBuilder.h

Copy file name to clipboardExpand all lines: bolt/include/bolt/Core/MCPlusBuilder.h
+42-19Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -562,30 +562,50 @@ class MCPlusBuilder {
562562
return {};
563563
}
564564

565-
virtual ErrorOr<MCPhysReg> getAuthenticatedReg(const MCInst &Inst) const {
566-
llvm_unreachable("not implemented");
567-
return getNoRegister();
568-
}
569-
570-
virtual bool isAuthenticationOfReg(const MCInst &Inst,
571-
MCPhysReg AuthenticatedReg) const {
565+
/// Returns the register where an authenticated pointer is written to by Inst,
566+
/// or std::nullopt if not authenticating any register.
567+
///
568+
/// Sets IsChecked if the instruction always checks authenticated pointer,
569+
/// i.e. it either returns a successfully authenticated pointer or terminates
570+
/// the program abnormally (such as "ldra x0, [x1]!" on AArch64, which crashes
571+
/// on authentication failure even if FEAT_FPAC is not implemented).
572+
virtual std::optional<MCPhysReg>
573+
getWrittenAuthenticatedReg(const MCInst &Inst, bool &IsChecked) const {
572574
llvm_unreachable("not implemented");
573-
return false;
575+
return std::nullopt;
574576
}
575577

576-
virtual MCPhysReg getSignedReg(const MCInst &Inst) const {
578+
/// Returns the register signed by Inst, or std::nullopt if not signing any
579+
/// register.
580+
///
581+
/// The returned register is assumed to be both input and output operand,
582+
/// as it is done on AArch64.
583+
virtual std::optional<MCPhysReg> getSignedReg(const MCInst &Inst) const {
577584
llvm_unreachable("not implemented");
578-
return getNoRegister();
585+
return std::nullopt;
579586
}
580587

581-
virtual ErrorOr<MCPhysReg> getRegUsedAsRetDest(const MCInst &Inst) const {
588+
/// Returns the register used as a return address. Returns std::nullopt if
589+
/// not applicable, such as reading the return address from a system register
590+
/// or from the stack.
591+
///
592+
/// Sets IsAuthenticatedInternally if the instruction accepts a signed
593+
/// pointer as its operand and authenticates it internally.
594+
///
595+
/// Should only be called when isReturn(Inst) is true.
596+
virtual std::optional<MCPhysReg>
597+
getRegUsedAsRetDest(const MCInst &Inst,
598+
bool &IsAuthenticatedInternally) const {
582599
llvm_unreachable("not implemented");
583-
return getNoRegister();
600+
return std::nullopt;
584601
}
585602

586603
/// Returns the register used as the destination of an indirect branch or call
587604
/// instruction. Sets IsAuthenticatedInternally if the instruction accepts
588605
/// a signed pointer as its operand and authenticates it internally.
606+
///
607+
/// Should only be called if isIndirectCall(Inst) or isIndirectBranch(Inst)
608+
/// returns true.
589609
virtual MCPhysReg
590610
getRegUsedAsIndirectBranchDest(const MCInst &Inst,
591611
bool &IsAuthenticatedInternally) const {
@@ -602,14 +622,14 @@ class MCPlusBuilder {
602622
/// controlled, under the Pointer Authentication threat model.
603623
///
604624
/// If the instruction does not write to any register satisfying the above
605-
/// two conditions, NoRegister is returned.
625+
/// two conditions, std::nullopt is returned.
606626
///
607627
/// The Pointer Authentication threat model assumes an attacker is able to
608628
/// modify any writable memory, but not executable code (due to W^X).
609-
virtual MCPhysReg
629+
virtual std::optional<MCPhysReg>
610630
getMaterializedAddressRegForPtrAuth(const MCInst &Inst) const {
611631
llvm_unreachable("not implemented");
612-
return getNoRegister();
632+
return std::nullopt;
613633
}
614634

615635
/// Analyzes if this instruction can safely perform address arithmetics
@@ -622,10 +642,13 @@ class MCPlusBuilder {
622642
/// controlled, provided InReg and executable code are not. Please note that
623643
/// registers other than InReg as well as the contents of memory which is
624644
/// writable by the process should be considered attacker-controlled.
645+
///
646+
/// The instruction should not write any values derived from InReg anywhere,
647+
/// except for OutReg.
625648
virtual std::optional<std::pair<MCPhysReg, MCPhysReg>>
626649
analyzeAddressArithmeticsForPtrAuth(const MCInst &Inst) const {
627650
llvm_unreachable("not implemented");
628-
return std::make_pair(getNoRegister(), getNoRegister());
651+
return std::nullopt;
629652
}
630653

631654
/// Analyzes if a pointer is checked to be authenticated successfully
@@ -670,10 +693,10 @@ class MCPlusBuilder {
670693
///
671694
/// Use this function for simple, single-instruction patterns instead of
672695
/// its getAuthCheckedReg(BB) counterpart.
673-
virtual MCPhysReg getAuthCheckedReg(const MCInst &Inst,
674-
bool MayOverwrite) const {
696+
virtual std::optional<MCPhysReg> getAuthCheckedReg(const MCInst &Inst,
697+
bool MayOverwrite) const {
675698
llvm_unreachable("not implemented");
676-
return getNoRegister();
699+
return std::nullopt;
677700
}
678701

679702
virtual bool isTerminator(const MCInst &Inst) const;

‎bolt/lib/Passes/PAuthGadgetScanner.cpp

Copy file name to clipboardExpand all lines: bolt/lib/Passes/PAuthGadgetScanner.cpp
+36-28Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -365,17 +365,15 @@ class SrcSafetyAnalysis {
365365
SmallVector<MCPhysReg> getRegsMadeSafeToDeref(const MCInst &Point,
366366
const SrcState &Cur) const {
367367
SmallVector<MCPhysReg> Regs;
368-
const MCPhysReg NoReg = BC.MIB->getNoRegister();
369368

370369
// A signed pointer can be authenticated, or
371-
ErrorOr<MCPhysReg> AutReg = BC.MIB->getAuthenticatedReg(Point);
372-
if (AutReg && *AutReg != NoReg)
370+
bool Dummy = false;
371+
if (auto AutReg = BC.MIB->getWrittenAuthenticatedReg(Point, Dummy))
373372
Regs.push_back(*AutReg);
374373

375374
// ... a safe address can be materialized, or
376-
MCPhysReg NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point);
377-
if (NewAddrReg != NoReg)
378-
Regs.push_back(NewAddrReg);
375+
if (auto NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point))
376+
Regs.push_back(*NewAddrReg);
379377

380378
// ... an address can be updated in a safe manner, producing the result
381379
// which is as trusted as the input address.
@@ -391,13 +389,20 @@ class SrcSafetyAnalysis {
391389
SmallVector<MCPhysReg> getRegsMadeTrusted(const MCInst &Point,
392390
const SrcState &Cur) const {
393391
SmallVector<MCPhysReg> Regs;
394-
const MCPhysReg NoReg = BC.MIB->getNoRegister();
395392

396393
// An authenticated pointer can be checked, or
397-
MCPhysReg CheckedReg =
394+
std::optional<MCPhysReg> CheckedReg =
398395
BC.MIB->getAuthCheckedReg(Point, /*MayOverwrite=*/false);
399-
if (CheckedReg != NoReg && Cur.SafeToDerefRegs[CheckedReg])
400-
Regs.push_back(CheckedReg);
396+
if (CheckedReg && Cur.SafeToDerefRegs[*CheckedReg])
397+
Regs.push_back(*CheckedReg);
398+
399+
// ... a pointer can be authenticated by an instruction that always checks
400+
// the pointer, or
401+
bool IsChecked = false;
402+
std::optional<MCPhysReg> AutReg =
403+
BC.MIB->getWrittenAuthenticatedReg(Point, IsChecked);
404+
if (AutReg && IsChecked)
405+
Regs.push_back(*AutReg);
401406

402407
if (CheckerSequenceInfo.contains(&Point)) {
403408
MCPhysReg CheckedReg;
@@ -413,9 +418,8 @@ class SrcSafetyAnalysis {
413418
}
414419

415420
// ... a safe address can be materialized, or
416-
MCPhysReg NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point);
417-
if (NewAddrReg != NoReg)
418-
Regs.push_back(NewAddrReg);
421+
if (auto NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point))
422+
Regs.push_back(*NewAddrReg);
419423

420424
// ... an address can be updated in a safe manner, producing the result
421425
// which is as trusted as the input address.
@@ -734,25 +738,28 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
734738
if (!BC.MIB->isReturn(Inst))
735739
return std::nullopt;
736740

737-
ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB->getRegUsedAsRetDest(Inst);
738-
if (MaybeRetReg.getError()) {
741+
bool IsAuthenticated = false;
742+
std::optional<MCPhysReg> RetReg =
743+
BC.MIB->getRegUsedAsRetDest(Inst, IsAuthenticated);
744+
if (!RetReg) {
739745
return make_generic_report(
740746
Inst, "Warning: pac-ret analysis could not analyze this return "
741747
"instruction");
742748
}
743-
MCPhysReg RetReg = *MaybeRetReg;
749+
if (IsAuthenticated)
750+
return std::nullopt;
751+
752+
assert(*RetReg != BC.MIB->getNoRegister());
744753
LLVM_DEBUG({
745754
traceInst(BC, "Found RET inst", Inst);
746-
traceReg(BC, "RetReg", RetReg);
747-
traceReg(BC, "Authenticated reg", BC.MIB->getAuthenticatedReg(Inst));
755+
traceReg(BC, "RetReg", *RetReg);
756+
traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs);
748757
});
749-
if (BC.MIB->isAuthenticationOfReg(Inst, RetReg))
750-
return std::nullopt;
751-
LLVM_DEBUG({ traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs); });
752-
if (S.SafeToDerefRegs[RetReg])
758+
759+
if (S.SafeToDerefRegs[*RetReg])
753760
return std::nullopt;
754761

755-
return make_report(RetKind, Inst, RetReg);
762+
return make_report(RetKind, Inst, *RetReg);
756763
}
757764

758765
static std::optional<BriefReport<MCPhysReg>>
@@ -785,19 +792,20 @@ shouldReportSigningOracle(const BinaryContext &BC, const MCInstReference &Inst,
785792
const SrcState &S) {
786793
static const GadgetKind SigningOracleKind("signing oracle found");
787794

788-
MCPhysReg SignedReg = BC.MIB->getSignedReg(Inst);
789-
if (SignedReg == BC.MIB->getNoRegister())
795+
std::optional<MCPhysReg> SignedReg = BC.MIB->getSignedReg(Inst);
796+
if (!SignedReg)
790797
return std::nullopt;
791798

799+
assert(*SignedReg != BC.MIB->getNoRegister());
792800
LLVM_DEBUG({
793801
traceInst(BC, "Found sign inst", Inst);
794-
traceReg(BC, "Signed reg", SignedReg);
802+
traceReg(BC, "Signed reg", *SignedReg);
795803
traceRegMask(BC, "TrustedRegs", S.TrustedRegs);
796804
});
797-
if (S.TrustedRegs[SignedReg])
805+
if (S.TrustedRegs[*SignedReg])
798806
return std::nullopt;
799807

800-
return make_report(SigningOracleKind, Inst, SignedReg);
808+
return make_report(SigningOracleKind, Inst, *SignedReg);
801809
}
802810

803811
template <typename T> static void iterateOverInstrs(BinaryFunction &BF, T Fn) {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.