Skip to content

Commit a5d8504

Browse files
committed
Address more review comments
1 parent de12f94 commit a5d8504

File tree

5 files changed

+47
-35
lines changed

5 files changed

+47
-35
lines changed

bolt/include/bolt/Core/MCPlusBuilder.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -587,18 +587,29 @@ class MCPlusBuilder {
587587
return getNoRegister();
588588
}
589589

590-
virtual MCPhysReg getSafelyMaterializedAddressReg(const MCInst &Inst) const {
590+
/// Returns the register containing an address which is safely materialized
591+
/// under Pointer Authentication threat model, or NoRegister otherwise.
592+
///
593+
/// The produced address should not be attacker-controlled, assuming an
594+
/// attacker is able to modify any writable memory, but not executable code
595+
/// (as it should be W^X).
596+
virtual MCPhysReg getMaterializedAddressRegForPtrAuth(const MCInst &Inst) const {
591597
llvm_unreachable("not implemented");
592598
return getNoRegister();
593599
}
594600

595-
/// Analyzes if this instruction can safely perform address arithmetics.
601+
/// Analyzes if this instruction can safely perform address arithmetics
602+
/// under Pointer Authentication threat model.
603+
///
604+
/// If an (OutReg, InReg) pair is returned, then after Inst is executed,
605+
/// OutReg is as trusted as InReg is.
596606
///
597-
/// If the first element of the returned pair is no-register, this instruction
598-
/// is considered unknown. Otherwise, (output, input) pair is returned,
599-
/// so that output is as trusted as input is.
600-
virtual std::pair<MCPhysReg, MCPhysReg>
601-
analyzeSafeAddressArithmetics(const MCInst &Inst) const {
607+
/// The arithmetic instruction is considered safe if OutReg is not attacker-
608+
/// controlled, provided InReg and executable code are not. Please note that
609+
/// registers other than InReg as well as the contents of memory which is
610+
/// writable by the process should be considered attacker-controlled.
611+
virtual std::optional<std::pair<MCPhysReg, MCPhysReg>>
612+
analyzeAddressArithmeticsForPtrAuth(const MCInst &Inst) const {
602613
llvm_unreachable("not implemented");
603614
return std::make_pair(getNoRegister(), getNoRegister());
604615
}

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,8 @@ class PacRetAnalysis
353353

354354
// Returns all registers that can be treated as if they are written by an
355355
// authentication instruction.
356-
SmallVector<MCPhysReg> getAuthenticatedRegs(const MCInst &Point,
357-
const State &Cur) const {
356+
SmallVector<MCPhysReg> getRegsMadeSafeToDeref(const MCInst &Point,
357+
const State &Cur) const {
358358
SmallVector<MCPhysReg> Regs;
359359
const MCPhysReg NoReg = BC.MIB->getNoRegister();
360360

@@ -364,17 +364,16 @@ class PacRetAnalysis
364364
Regs.push_back(*AutReg);
365365

366366
// ... a safe address can be materialized, or
367-
MCPhysReg NewAddrReg = BC.MIB->getSafelyMaterializedAddressReg(Point);
367+
MCPhysReg NewAddrReg = BC.MIB->getMaterializedAddressRegForPtrAuth(Point);
368368
if (NewAddrReg != NoReg)
369369
Regs.push_back(NewAddrReg);
370370

371371
// ... an address can be updated in a safe manner, producing the result
372372
// which is as trusted as the input address.
373-
MCPhysReg ArithResult, ArithSrc;
374-
std::tie(ArithResult, ArithSrc) =
375-
BC.MIB->analyzeSafeAddressArithmetics(Point);
376-
if (ArithResult != NoReg && Cur.SafeToDerefRegs[ArithSrc])
377-
Regs.push_back(ArithResult);
373+
if (auto DstAndSrc = BC.MIB->analyzeAddressArithmeticsForPtrAuth(Point)) {
374+
if (Cur.SafeToDerefRegs[DstAndSrc->second])
375+
Regs.push_back(DstAndSrc->first);
376+
}
378377

379378
return Regs;
380379
}
@@ -403,12 +402,8 @@ class PacRetAnalysis
403402
// before its execution into account, if necessary.
404403

405404
BitVector Clobbered = getClobberedRegs(Point);
406-
// Compute the set of registers that can be considered as written by
407-
// an authentication instruction. This includes operations that are
408-
// *strictly better* than authentication, such as materializing a
409-
// PC-relative constant.
410-
SmallVector<MCPhysReg> AuthenticatedOrBetter =
411-
getAuthenticatedRegs(Point, Cur);
405+
SmallVector<MCPhysReg> NewSafeToDerefRegs =
406+
getRegsMadeSafeToDeref(Point, Cur);
412407

413408
// Then, compute the state after this instruction is executed.
414409
State Next = Cur;
@@ -423,12 +418,12 @@ class PacRetAnalysis
423418
// After accounting for clobbered registers in general, override the state
424419
// according to authentication and other *special cases* of clobbering.
425420

426-
// The sub-registers of each authenticated register are also trusted now,
427-
// but not their super-registers (as they retain untrusted register units).
428-
BitVector AuthenticatedSubregs(NumRegs);
429-
for (MCPhysReg AutReg : AuthenticatedOrBetter)
430-
AuthenticatedSubregs |= BC.MIB->getAliases(AutReg, /*OnlySmaller=*/true);
431-
for (MCPhysReg Reg : AuthenticatedSubregs.set_bits()) {
421+
// The sub-registers are also safe-to-dereference now, but not their
422+
// super-registers (as they retain untrusted register units).
423+
BitVector NewSafeSubregs(NumRegs);
424+
for (MCPhysReg AutReg : NewSafeToDerefRegs)
425+
NewSafeSubregs |= BC.MIB->getAliases(AutReg, /*OnlySmaller=*/true);
426+
for (MCPhysReg Reg : NewSafeSubregs.set_bits()) {
432427
Next.SafeToDerefRegs.set(Reg);
433428
if (RegsToTrackInstsFor.isTracked(Reg))
434429
lastWritingInsts(Next, Reg).clear();

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,30 +304,36 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
304304
}
305305
}
306306

307-
MCPhysReg getSafelyMaterializedAddressReg(const MCInst &Inst) const override {
307+
MCPhysReg getMaterializedAddressRegForPtrAuth(const MCInst &Inst) const override {
308308
switch (Inst.getOpcode()) {
309309
case AArch64::ADR:
310310
case AArch64::ADRP:
311+
// These instructions produce an address value based on the information
312+
// encoded into the instruction itself (which should reside in a read-only
313+
// code memory) and the value of PC register (that is, the location of
314+
// this instruction), so the produced value is not attacker-controlled.
311315
return Inst.getOperand(0).getReg();
312316
default:
313317
return getNoRegister();
314318
}
315319
}
316320

317-
std::pair<MCPhysReg, MCPhysReg>
318-
analyzeSafeAddressArithmetics(const MCInst &Inst) const override {
321+
std::optional<std::pair<MCPhysReg, MCPhysReg>>
322+
analyzeAddressArithmeticsForPtrAuth(const MCInst &Inst) const override {
319323
switch (Inst.getOpcode()) {
320324
default:
321-
return std::make_pair(getNoRegister(), getNoRegister());
325+
return std::nullopt;
322326
case AArch64::ADDXri:
323327
case AArch64::SUBXri:
328+
// The immediate addend is encoded into the instruction itself, so it is
329+
// not attacker-controlled under Pointer Authentication threat model.
324330
return std::make_pair(Inst.getOperand(0).getReg(),
325331
Inst.getOperand(1).getReg());
326332
case AArch64::ORRXrs:
327333
// "mov Xd, Xm" is equivalent to "orr Xd, XZR, Xm, lsl #0"
328334
if (Inst.getOperand(1).getReg() != AArch64::XZR ||
329335
Inst.getOperand(3).getImm() != 0)
330-
return std::make_pair(getNoRegister(), getNoRegister());
336+
return std::nullopt;
331337

332338
return std::make_pair(Inst.getOperand(0).getReg(),
333339
Inst.getOperand(2).getReg());

bolt/test/binary-analysis/AArch64/gs-pauth-address-materialization.s

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe
1+
// -Wl,--no-relax prevents converting ADRP+ADD pairs into NOP+ADR.
2+
// RUN: %clang %cflags -march=armv8.3-a -Wl,--no-relax %s -o %t.exe
23
// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
34

45
// Test various patterns that should or should not be considered safe
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
if "AArch64" not in config.root.targets:
22
config.unsupported = True
33

4-
# -Wl,--no-relax prevents converting ADRP+ADD pairs into NOP+ADR.
5-
flags = "--target=aarch64-linux-gnu -nostartfiles -nostdlib -ffreestanding -Wl,--no-relax"
4+
flags = "--target=aarch64-linux-gnu -nostartfiles -nostdlib -ffreestanding"
65

76
config.substitutions.insert(0, ("%cflags", f"%cflags {flags}"))
87
config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}"))

0 commit comments

Comments
 (0)