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 e86dd8f

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 bbec9f8 commit e86dd8f
Copy full SHA for e86dd8f

File tree

5 files changed

+130
-94
lines changed
Filter options

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
@@ -367,17 +367,15 @@ class SrcSafetyAnalysis {
367367
SmallVector<MCPhysReg> getRegsMadeSafeToDeref(const MCInst &Point,
368368
const SrcState &Cur) const {
369369
SmallVector<MCPhysReg> Regs;
370-
const MCPhysReg NoReg = BC.MIB->getNoRegister();
371370

372371
// A signed pointer can be authenticated, or
373-
ErrorOr<MCPhysReg> AutReg = BC.MIB->getAuthenticatedReg(Point);
374-
if (AutReg && *AutReg != NoReg)
372+
bool Dummy = false;
373+
if (auto AutReg = BC.MIB->getWrittenAuthenticatedReg(Point, Dummy))
375374
Regs.push_back(*AutReg);
376375

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

382380
// ... an address can be updated in a safe manner, producing the result
383381
// which is as trusted as the input address.
@@ -393,13 +391,20 @@ class SrcSafetyAnalysis {
393391
SmallVector<MCPhysReg> getRegsMadeTrusted(const MCInst &Point,
394392
const SrcState &Cur) const {
395393
SmallVector<MCPhysReg> Regs;
396-
const MCPhysReg NoReg = BC.MIB->getNoRegister();
397394

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

404409
if (CheckerSequenceInfo.contains(&Point)) {
405410
MCPhysReg CheckedReg;
@@ -414,9 +419,8 @@ class SrcSafetyAnalysis {
414419
}
415420

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

421425
// ... an address can be updated in a safe manner, producing the result
422426
// which is as trusted as the input address.
@@ -731,25 +735,28 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
731735
if (!BC.MIB->isReturn(Inst))
732736
return std::nullopt;
733737

734-
ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB->getRegUsedAsRetDest(Inst);
735-
if (MaybeRetReg.getError()) {
738+
bool IsAuthenticated = false;
739+
std::optional<MCPhysReg> RetReg =
740+
BC.MIB->getRegUsedAsRetDest(Inst, IsAuthenticated);
741+
if (!RetReg) {
736742
return make_generic_report(
737743
Inst, "Warning: pac-ret analysis could not analyze this return "
738744
"instruction");
739745
}
740-
MCPhysReg RetReg = *MaybeRetReg;
746+
if (IsAuthenticated)
747+
return std::nullopt;
748+
749+
assert(*RetReg != BC.MIB->getNoRegister());
741750
LLVM_DEBUG({
742751
traceInst(BC, "Found RET inst", Inst);
743-
traceReg(BC, "RetReg", RetReg);
744-
traceReg(BC, "Authenticated reg", BC.MIB->getAuthenticatedReg(Inst));
752+
traceReg(BC, "RetReg", *RetReg);
753+
traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs);
745754
});
746-
if (BC.MIB->isAuthenticationOfReg(Inst, RetReg))
747-
return std::nullopt;
748-
LLVM_DEBUG({ traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs); });
749-
if (S.SafeToDerefRegs[RetReg])
755+
756+
if (S.SafeToDerefRegs[*RetReg])
750757
return std::nullopt;
751758

752-
return make_report(RetKind, Inst, RetReg);
759+
return make_report(RetKind, Inst, *RetReg);
753760
}
754761

755762
static std::optional<BriefReport<MCPhysReg>>
@@ -782,19 +789,20 @@ shouldReportSigningOracle(const BinaryContext &BC, const MCInstReference &Inst,
782789
const SrcState &S) {
783790
static const GadgetKind SigningOracleKind("signing oracle found");
784791

785-
MCPhysReg SignedReg = BC.MIB->getSignedReg(Inst);
786-
if (SignedReg == BC.MIB->getNoRegister())
792+
std::optional<MCPhysReg> SignedReg = BC.MIB->getSignedReg(Inst);
793+
if (!SignedReg)
787794
return std::nullopt;
788795

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

797-
return make_report(SigningOracleKind, Inst, SignedReg);
805+
return make_report(SigningOracleKind, Inst, *SignedReg);
798806
}
799807

800808
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.