Skip to content

Commit c42406c

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 TODO: - Add tests. Pull Request: llvm#133533
1 parent 69b1202 commit c42406c

File tree

1 file changed

+165
-15
lines changed

1 file changed

+165
-15
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 165 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;
@@ -209,6 +212,10 @@ class AArch64AsmPrinter : public AsmPrinter {
209212
// authenticating)
210213
void LowerLOADgotAUTH(const MachineInstr &MI);
211214

215+
const MCExpr *emitPAuthRelocationAsIRelative(
216+
const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
217+
bool HasAddressDiversity, bool IsDSOLocal);
218+
212219
/// tblgen'erated driver function for lowering simple MI->MC
213220
/// pseudo instructions.
214221
bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
@@ -2225,6 +2232,146 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
22252232
EmitToStreamer(*OutStreamer, BRInst);
22262233
}
22272234

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

22372384
auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
22382385

2239-
// If we can't understand the referenced ConstantExpr, there's nothing
2240-
// else we can do: emit an error.
2241-
if (!BaseGVB) {
2242-
BaseGV->getContext().emitError(
2243-
"cannot resolve target base/addend of ptrauth constant");
2244-
return nullptr;
2386+
const MCExpr *Sym;
2387+
if (BaseGVB) {
2388+
// If there is an addend, turn that into the appropriate MCExpr.
2389+
Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2390+
if (Offset.sgt(0))
2391+
Sym = MCBinaryExpr::createAdd(
2392+
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2393+
else if (Offset.slt(0))
2394+
Sym = MCBinaryExpr::createSub(
2395+
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2396+
} else {
2397+
Sym = MCConstantExpr::create(Offset.getSExtValue(), Ctx);
22452398
}
22462399

2247-
// If there is an addend, turn that into the appropriate MCExpr.
2248-
const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2249-
if (Offset.sgt(0))
2250-
Sym = MCBinaryExpr::createAdd(
2251-
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2252-
else if (Offset.slt(0))
2253-
Sym = MCBinaryExpr::createSub(
2254-
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2255-
22562400
uint64_t KeyID = CPA.getKey()->getZExtValue();
22572401
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
22582402
// AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2270,6 +2414,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22702414
Disc = 0;
22712415
}
22722416

2417+
// Check if we need to represent this with an IRELATIVE and emit it if so.
2418+
if (auto *IFuncSym = emitPAuthRelocationAsIRelative(
2419+
Sym, Disc, AArch64PACKey::ID(KeyID), CPA.hasAddressDiscriminator(),
2420+
BaseGVB && BaseGVB->isDSOLocal()))
2421+
return IFuncSym;
2422+
22732423
// Finally build the complete @AUTH expr.
22742424
return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
22752425
CPA.hasAddressDiscriminator(), Ctx);

0 commit comments

Comments
 (0)