Skip to content

Commit 43fd622

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 29c4e5e commit 43fd622

File tree

1 file changed

+163
-15
lines changed

1 file changed

+163
-15
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 163 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "llvm/MC/MCSectionMachO.h"
5555
#include "llvm/MC/MCStreamer.h"
5656
#include "llvm/MC/MCSymbol.h"
57+
#include "llvm/MC/MCValue.h"
5758
#include "llvm/MC/TargetRegistry.h"
5859
#include "llvm/Support/Casting.h"
5960
#include "llvm/Support/CommandLine.h"
@@ -84,6 +85,7 @@ class AArch64AsmPrinter : public AsmPrinter {
8485
bool EnableImportCallOptimization = false;
8586
DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
8687
SectionToImportedFunctionCalls;
88+
unsigned PAuthIFuncNextUniqueID = 1;
8789

8890
public:
8991
AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
@@ -191,6 +193,10 @@ class AArch64AsmPrinter : public AsmPrinter {
191193
// authenticating)
192194
void LowerLOADgotAUTH(const MachineInstr &MI);
193195

196+
const MCExpr *emitPAuthRelocationAsIRelative(
197+
const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
198+
bool HasAddressDiversity, bool IsDSOLocal);
199+
194200
/// tblgen'erated driver function for lowering simple MI->MC
195201
/// pseudo instructions.
196202
bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
@@ -2218,6 +2224,145 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
22182224
EmitToStreamer(*OutStreamer, BRInst);
22192225
}
22202226

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

22302375
auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
22312376

2232-
// If we can't understand the referenced ConstantExpr, there's nothing
2233-
// else we can do: emit an error.
2234-
if (!BaseGVB) {
2235-
BaseGV->getContext().emitError(
2236-
"cannot resolve target base/addend of ptrauth constant");
2237-
return nullptr;
2377+
const MCExpr *Sym;
2378+
if (BaseGVB) {
2379+
// If there is an addend, turn that into the appropriate MCExpr.
2380+
Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2381+
if (Offset.sgt(0))
2382+
Sym = MCBinaryExpr::createAdd(
2383+
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2384+
else if (Offset.slt(0))
2385+
Sym = MCBinaryExpr::createSub(
2386+
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2387+
} else {
2388+
Sym = MCConstantExpr::create(Offset.getSExtValue(), Ctx);
22382389
}
22392390

2240-
// If there is an addend, turn that into the appropriate MCExpr.
2241-
const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
2242-
if (Offset.sgt(0))
2243-
Sym = MCBinaryExpr::createAdd(
2244-
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
2245-
else if (Offset.slt(0))
2246-
Sym = MCBinaryExpr::createSub(
2247-
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
2248-
22492391
uint64_t KeyID = CPA.getKey()->getZExtValue();
22502392
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
22512393
// AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2259,6 +2401,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22592401
report_fatal_error("AArch64 PAC Discriminator '" + Twine(Disc) +
22602402
"' out of range [0, 0xFFFF]");
22612403

2404+
// Check if we need to represent this with an IRELATIVE and emit it if so.
2405+
if (auto *IFuncSym = emitPAuthRelocationAsIRelative(
2406+
Sym, Disc, AArch64PACKey::ID(KeyID), CPA.hasAddressDiscriminator(),
2407+
BaseGVB && BaseGVB->isDSOLocal()))
2408+
return IFuncSym;
2409+
22622410
// Finally build the complete @AUTH expr.
22632411
return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
22642412
CPA.hasAddressDiscriminator(), Ctx);

0 commit comments

Comments
 (0)