Skip to content

Commit 4bf047a

Browse files
committed
CodeGen: Optionally emit PAuth relocations as IRELATIVE relocations.
This supports the following use cases: - ConstantPtrAuth expressions that are unrepresentable using standard PAuth relocations such as expressions involving an integer operand or deactivation symbols. - libc implementations that do not support PAuth relocations. For more information see the RFC: https://discourse.llvm.org/t/rfc-structure-protection-a-family-of-uaf-mitigation-techniques/85555 Pull Request: llvm#133533
1 parent 8799f58 commit 4bf047a

File tree

3 files changed

+241
-16
lines changed

3 files changed

+241
-16
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 162 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@
4949
#include "llvm/IR/Module.h"
5050
#include "llvm/MC/MCAsmInfo.h"
5151
#include "llvm/MC/MCContext.h"
52+
#include "llvm/MC/MCExpr.h"
5253
#include "llvm/MC/MCInst.h"
5354
#include "llvm/MC/MCInstBuilder.h"
5455
#include "llvm/MC/MCSectionELF.h"
5556
#include "llvm/MC/MCSectionMachO.h"
5657
#include "llvm/MC/MCStreamer.h"
5758
#include "llvm/MC/MCSymbol.h"
59+
#include "llvm/MC/MCValue.h"
5860
#include "llvm/MC/TargetRegistry.h"
5961
#include "llvm/Support/Casting.h"
6062
#include "llvm/Support/CommandLine.h"
@@ -95,6 +97,7 @@ class AArch64AsmPrinter : public AsmPrinter {
9597
bool EnableImportCallOptimization = false;
9698
DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
9799
SectionToImportedFunctionCalls;
100+
unsigned PAuthIFuncNextUniqueID = 1;
98101

99102
public:
100103
static char ID;
@@ -212,6 +215,10 @@ class AArch64AsmPrinter : public AsmPrinter {
212215
// authenticating)
213216
void LowerLOADgotAUTH(const MachineInstr &MI);
214217

218+
const MCExpr *emitPAuthRelocationAsIRelative(
219+
const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
220+
bool HasAddressDiversity, bool IsDSOLocal);
221+
215222
/// tblgen'erated driver function for lowering simple MI->MC
216223
/// pseudo instructions.
217224
bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
@@ -2259,6 +2266,143 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
22592266
EmitToStreamer(*OutStreamer, BRInst);
22602267
}
22612268

2269+
static void emitAddress(MCStreamer &Streamer, MCRegister Reg,
2270+
const MCExpr *Expr, bool DSOLocal,
2271+
const MCSubtargetInfo &STI) {
2272+
MCValue Val;
2273+
if (!Expr->evaluateAsRelocatable(Val, nullptr))
2274+
report_fatal_error("emitAddress could not evaluate");
2275+
if (DSOLocal) {
2276+
Streamer.emitInstruction(
2277+
MCInstBuilder(AArch64::ADRP)
2278+
.addReg(Reg)
2279+
.addExpr(MCSpecifierExpr::create(Expr, AArch64::S_ABS_PAGE,
2280+
Streamer.getContext())),
2281+
STI);
2282+
Streamer.emitInstruction(
2283+
MCInstBuilder(AArch64::ADDXri)
2284+
.addReg(Reg)
2285+
.addReg(Reg)
2286+
.addExpr(MCSpecifierExpr::create(Expr, AArch64::S_LO12,
2287+
Streamer.getContext()))
2288+
.addImm(0),
2289+
STI);
2290+
} else {
2291+
auto *SymRef = MCSymbolRefExpr::create(Val.getAddSym(), Streamer.getContext());
2292+
Streamer.emitInstruction(
2293+
MCInstBuilder(AArch64::ADRP)
2294+
.addReg(Reg)
2295+
.addExpr(MCSpecifierExpr::create(SymRef, AArch64::S_GOT_PAGE,
2296+
Streamer.getContext())),
2297+
STI);
2298+
Streamer.emitInstruction(
2299+
MCInstBuilder(AArch64::LDRXui)
2300+
.addReg(Reg)
2301+
.addReg(Reg)
2302+
.addExpr(MCSpecifierExpr::create(SymRef, AArch64::S_GOT_LO12,
2303+
Streamer.getContext())),
2304+
STI);
2305+
if (Val.getConstant())
2306+
Streamer.emitInstruction(MCInstBuilder(AArch64::ADDXri)
2307+
.addReg(Reg)
2308+
.addReg(Reg)
2309+
.addImm(Val.getConstant())
2310+
.addImm(0),
2311+
STI);
2312+
}
2313+
}
2314+
2315+
static bool targetSupportsPAuthRelocation(const Triple &TT,
2316+
const MCExpr *Target) {
2317+
// No released version of glibc supports PAuth relocations.
2318+
if (TT.isOSGlibc())
2319+
return false;
2320+
2321+
// We emit PAuth constants as IRELATIVE relocations in cases where the
2322+
// constant cannot be represented as a PAuth relocation:
2323+
// 1) The signed value is not a symbol.
2324+
return !isa<MCConstantExpr>(Target);
2325+
}
2326+
2327+
static bool targetSupportsIRelativeRelocation(const Triple &TT) {
2328+
// IFUNCs are ELF-only.
2329+
if (!TT.isOSBinFormatELF())
2330+
return false;
2331+
2332+
// musl doesn't support IFUNCs.
2333+
if (TT.isMusl())
2334+
return false;
2335+
2336+
return true;
2337+
}
2338+
2339+
const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative(
2340+
const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
2341+
bool HasAddressDiversity, bool IsDSOLocal) {
2342+
const Triple &TT = TM.getTargetTriple();
2343+
2344+
// We only emit an IRELATIVE relocation if the target supports IRELATIVE and
2345+
// does not support the kind of PAuth relocation that we are trying to emit.
2346+
if (targetSupportsPAuthRelocation(TT, Target) ||
2347+
!targetSupportsIRelativeRelocation(TT))
2348+
return nullptr;
2349+
2350+
// For now, only the DA key is supported.
2351+
if (KeyID != AArch64PACKey::DA)
2352+
return nullptr;
2353+
2354+
std::unique_ptr<MCSubtargetInfo> STI(
2355+
TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
2356+
assert(STI && "Unable to create subtarget info");
2357+
2358+
MCSymbol *Place = OutStreamer->getContext().createTempSymbol();
2359+
OutStreamer->emitLabel(Place);
2360+
OutStreamer->pushSection();
2361+
2362+
OutStreamer->switchSection(OutStreamer->getContext().getELFSection(
2363+
".text.startup", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
2364+
0, "", true, PAuthIFuncNextUniqueID++, nullptr));
2365+
2366+
MCSymbol *IRelativeSym =
2367+
OutStreamer->getContext().createLinkerPrivateSymbol("pauth_ifunc");
2368+
OutStreamer->emitLabel(IRelativeSym);
2369+
if (isa<MCConstantExpr>(Target)) {
2370+
OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
2371+
.addReg(AArch64::X0)
2372+
.addExpr(Target)
2373+
.addImm(0),
2374+
*STI);
2375+
} else {
2376+
emitAddress(*OutStreamer, AArch64::X0, Target, IsDSOLocal, *STI);
2377+
}
2378+
if (HasAddressDiversity) {
2379+
auto *PlacePlusDisc = MCBinaryExpr::createAdd(
2380+
MCSymbolRefExpr::create(Place, OutStreamer->getContext()),
2381+
MCConstantExpr::create(static_cast<int16_t>(Disc),
2382+
OutStreamer->getContext()),
2383+
OutStreamer->getContext());
2384+
emitAddress(*OutStreamer, AArch64::X1, PlacePlusDisc, /*IsDSOLocal=*/true,
2385+
*STI);
2386+
} else {
2387+
emitMOVZ(AArch64::X1, Disc, 0);
2388+
}
2389+
2390+
// We don't know the subtarget because this is being emitted for a global
2391+
// initializer. Because the performance of IFUNC resolvers is unimportant, we
2392+
// always call the EmuPAC runtime, which will end up using the PAC instruction
2393+
// if the target supports PAC.
2394+
MCSymbol *EmuPAC =
2395+
OutStreamer->getContext().getOrCreateSymbol("__emupac_pacda");
2396+
const MCSymbolRefExpr *EmuPACRef =
2397+
MCSymbolRefExpr::create(EmuPAC, OutStreamer->getContext());
2398+
OutStreamer->emitInstruction(MCInstBuilder(AArch64::B).addExpr(EmuPACRef),
2399+
*STI);
2400+
OutStreamer->popSection();
2401+
2402+
return MCSymbolRefExpr::create(IRelativeSym, AArch64::S_FUNCINIT,
2403+
OutStreamer->getContext());
2404+
}
2405+
22622406
const MCExpr *
22632407
AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22642408
MCContext &Ctx = OutContext;
@@ -2270,23 +2414,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22702414

22712415
auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
22722416

2273-
// If we can't understand the referenced ConstantExpr, there's nothing
2274-
// else we can do: emit an error.
2275-
if (!BaseGVB) {
2276-
BaseGV->getContext().emitError(
2277-
"cannot resolve target base/addend of ptrauth constant");
2278-
return nullptr;
2417+
const MCExpr *Sym;
2418+
if (BaseGVB) {
2419+
// If there is an addend, turn that into the appropriate MCExpr.
2420+
Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2421+
if (Offset.sgt(0))
2422+
Sym = MCBinaryExpr::createAdd(
2423+
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2424+
else if (Offset.slt(0))
2425+
Sym = MCBinaryExpr::createSub(
2426+
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2427+
} else {
2428+
Sym = MCConstantExpr::create(Offset.getSExtValue(), Ctx);
22792429
}
22802430

2281-
// If there is an addend, turn that into the appropriate MCExpr.
2282-
const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2283-
if (Offset.sgt(0))
2284-
Sym = MCBinaryExpr::createAdd(
2285-
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2286-
else if (Offset.slt(0))
2287-
Sym = MCBinaryExpr::createSub(
2288-
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2289-
22902431
uint64_t KeyID = CPA.getKey()->getZExtValue();
22912432
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
22922433
// AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2304,6 +2445,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
23042445
Disc = 0;
23052446
}
23062447

2448+
// Check if we need to represent this with an IRELATIVE and emit it if so.
2449+
if (auto *IFuncSym = emitPAuthRelocationAsIRelative(
2450+
Sym, Disc, AArch64PACKey::ID(KeyID), CPA.hasAddressDiscriminator(),
2451+
BaseGVB && BaseGVB->isDSOLocal()))
2452+
return IFuncSym;
2453+
23072454
// Finally build the complete @AUTH expr.
23082455
return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
23092456
CPA.hasAddressDiscriminator(), Ctx);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
; RUN: llc -mtriple aarch64-linux-gnu -mattr=+pauth -filetype=asm -o - %s | FileCheck %s
2+
3+
; CHECK: nullref:
4+
; CHECK-NEXT: [[PLACE:.*]]:
5+
; CHECK-NEXT: .section .text.startup
6+
; CHECK-NEXT: [[FUNC:.*]]:
7+
; CHECK-NEXT: movz x0, #0
8+
; CHECK-NEXT: mov x1, #1
9+
; CHECK-NEXT: b __emupac_pacda
10+
; CHECK-NEXT: .section .rodata
11+
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
12+
@nullref = constant ptr ptrauth (ptr null, i32 2, i64 1, ptr null), align 8
13+
14+
@dsolocal = external dso_local global i8
15+
16+
; CHECK: dsolocalref:
17+
; CHECK-NEXT: [[PLACE:.*]]:
18+
; CHECK-NEXT: .section .text.startup
19+
; CHECK-NEXT: [[FUNC:.*]]:
20+
; CHECK-NEXT: adrp x0, dsolocal
21+
; CHECK-NEXT: add x0, x0, :lo12:dsolocal
22+
; CHECK-NEXT: mov x1, #2
23+
; CHECK-NEXT: b __emupac_pacda
24+
; CHECK-NEXT: .section .rodata
25+
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
26+
@dsolocalref = constant ptr ptrauth (ptr @dsolocal, i32 2, i64 2, ptr null), align 8
27+
28+
; CHECK: dsolocalref8:
29+
; CHECK-NEXT: [[PLACE:.*]]:
30+
; CHECK-NEXT: .section .text.startup
31+
; CHECK-NEXT: [[FUNC:.*]]:
32+
; CHECK-NEXT: adrp x0, dsolocal+8
33+
; CHECK-NEXT: add x0, x0, :lo12:dsolocal+8
34+
; CHECK-NEXT: mov x1, #3
35+
; CHECK-NEXT: b __emupac_pacda
36+
; CHECK-NEXT: .section .rodata
37+
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
38+
@dsolocalref8 = constant ptr ptrauth (ptr getelementptr (i8, ptr @dsolocal, i64 8), i32 2, i64 3, ptr null), align 8
39+
40+
; CHECK: disc:
41+
; CHECK-NEXT: [[PLACE:.*]]:
42+
; CHECK-NEXT: .section .text.startup
43+
; CHECK-NEXT: [[FUNC:.*]]:
44+
; CHECK-NEXT: adrp x0, dsolocal
45+
; CHECK-NEXT: add x0, x0, :lo12:dsolocal
46+
; CHECK-NEXT: adrp x1, [[PLACE]]
47+
; CHECK-NEXT: add x1, x1, :lo12:[[PLACE]]
48+
; CHECK-NEXT: b __emupac_pacda
49+
; CHECK-NEXT: .section .rodata
50+
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
51+
@disc = constant ptr ptrauth (ptr @dsolocal, i32 2, i64 0, ptr @disc), align 8
52+
53+
@global = external global i8
54+
55+
; CHECK: globalref:
56+
; CHECK-NEXT: [[PLACE:.*]]:
57+
; CHECK-NEXT: .section .text.startup
58+
; CHECK-NEXT: [[FUNC:.*]]:
59+
; CHECK-NEXT: adrp x0, :got:global
60+
; CHECK-NEXT: ldr x0, [x0, :got_lo12:global]
61+
; CHECK-NEXT: mov x1, #4
62+
; CHECK-NEXT: b __emupac_pacda
63+
; CHECK-NEXT: .section .rodata
64+
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
65+
@globalref = constant ptr ptrauth (ptr @global, i32 2, i64 4, ptr null), align 8
66+
67+
; CHECK: globalref8:
68+
; CHECK-NEXT: [[PLACE:.*]]:
69+
; CHECK-NEXT: .section .text.startup
70+
; CHECK-NEXT: [[FUNC:.*]]:
71+
; CHECK-NEXT: adrp x0, :got:global
72+
; CHECK-NEXT: ldr x0, [x0, :got_lo12:global]
73+
; CHECK-NEXT: add x0, x0, #8
74+
; CHECK-NEXT: mov x1, #5
75+
; CHECK-NEXT: b __emupac_pacda
76+
; CHECK-NEXT: .section .rodata
77+
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
78+
@globalref8 = constant ptr ptrauth (ptr getelementptr (i8, ptr @global, i64 8), i32 2, i64 5, ptr null), align 8

llvm/test/CodeGen/AArch64/ptrauth-type-info-vptr-discr.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: llc -mtriple aarch64-linux-gnu -mattr=+pauth -filetype=asm -o - %s | FileCheck --check-prefix=ELF %s
1+
; RUN: llc -mtriple aarch64-linux-musl -mattr=+pauth -filetype=asm -o - %s | FileCheck --check-prefix=ELF %s
22
; RUN: llc -mtriple aarch64-apple-darwin -mattr=+pauth -filetype=asm -o - %s | FileCheck --check-prefix=MACHO %s
33

44
; ELF-LABEL: _ZTI10Disc:

0 commit comments

Comments
 (0)