diff options
Diffstat (limited to 'gnu/llvm/lib')
| -rw-r--r-- | gnu/llvm/lib/CodeGen/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | gnu/llvm/lib/CodeGen/PrologEpilogInserter.cpp | 40 | ||||
| -rw-r--r-- | gnu/llvm/lib/CodeGen/ReturnProtectorPass.cpp | 61 | ||||
| -rw-r--r-- | gnu/llvm/lib/CodeGen/TargetPassConfig.cpp | 2 | ||||
| -rw-r--r-- | gnu/llvm/lib/Target/X86/X86FrameLowering.cpp | 198 | ||||
| -rw-r--r-- | gnu/llvm/lib/Target/X86/X86FrameLowering.h | 13 | ||||
| -rw-r--r-- | gnu/llvm/lib/Target/X86/X86InstrCompiler.td | 15 | ||||
| -rw-r--r-- | gnu/llvm/lib/Target/X86/X86MCInstLower.cpp | 10 |
8 files changed, 338 insertions, 2 deletions
diff --git a/gnu/llvm/lib/CodeGen/CMakeLists.txt b/gnu/llvm/lib/CodeGen/CMakeLists.txt index 865de4f47af..42e91978782 100644 --- a/gnu/llvm/lib/CodeGen/CMakeLists.txt +++ b/gnu/llvm/lib/CodeGen/CMakeLists.txt @@ -120,6 +120,7 @@ add_llvm_library(LLVMCodeGen RegUsageInfoCollector.cpp RegUsageInfoPropagate.cpp ResetMachineFunctionPass.cpp + ReturnProtectorPass.cpp SafeStack.cpp SafeStackColoring.cpp SafeStackLayout.cpp diff --git a/gnu/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/gnu/llvm/lib/CodeGen/PrologEpilogInserter.cpp index a8d8ad8ac7d..529fa7406a5 100644 --- a/gnu/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/gnu/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -175,6 +175,10 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { const TargetRegisterInfo *TRI = Fn.getSubtarget().getRegisterInfo(); const TargetFrameLowering *TFI = Fn.getSubtarget().getFrameLowering(); + // Set Return Protector in the frame + if (F.hasFnAttribute("ret-protector")) + Fn.getFrameInfo().setReturnProtector(true); + RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : nullptr; FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn); FrameIndexEliminationScavenging = (RS && !FrameIndexVirtualScavenging) || @@ -209,6 +213,19 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { if (!F.hasFnAttribute(Attribute::Naked)) insertPrologEpilogCode(Fn); + // Add Return Protectors if using them + if (Fn.getFrameInfo().hasReturnProtector()) { + std::vector<MachineBasicBlock *> ReturnBlocks; + bool insertedGuard = false; + for (auto &MBB: Fn) + if (MBB.isReturnBlock()) + ReturnBlocks.push_back(&MBB); + for (MachineBasicBlock *MBB: ReturnBlocks) + insertedGuard |= TFI->insertReturnProtectorEpilogue(Fn, *MBB); + if (insertedGuard) + TFI->insertReturnProtectorPrologue(Fn, Fn.front()); + } + // Replace all MO_FrameIndex operands with physical register references // and actual offsets. // @@ -293,7 +310,8 @@ void PEI::calculateCallFrameInfo(MachineFunction &Fn) { /// Compute the sets of entry and return blocks for saving and restoring /// callee-saved registers, and placing prolog and epilog code. void PEI::calculateSaveRestoreBlocks(MachineFunction &Fn) { - const MachineFrameInfo &MFI = Fn.getFrameInfo(); + MachineFrameInfo &MFI = Fn.getFrameInfo(); + const TargetFrameLowering *TFI = Fn.getSubtarget().getFrameLowering(); // Even when we do not change any CSR, we still want to insert the // prologue and epilogue of the function. @@ -309,7 +327,18 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &Fn) { // epilogue. if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock()) RestoreBlocks.push_back(RestoreBlock); - return; + + // If we are adding return protectors ensure we can find a free register + if (MFI.hasReturnProtector() && + !TFI->determineReturnProtectorTempRegister(Fn, SaveBlocks, RestoreBlocks)) { + // Shrinkwrapping will prevent finding a free register + SaveBlocks.clear(); + RestoreBlocks.clear(); + MFI.setSavePoint(nullptr); + MFI.setRestorePoint(nullptr); + } else { + return; + } } // Save refs to entry and return blocks. @@ -320,6 +349,9 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &Fn) { if (MBB.isReturnBlock()) RestoreBlocks.push_back(&MBB); } + + if (MFI.hasReturnProtector()) + TFI->determineReturnProtectorTempRegister(Fn, SaveBlocks, RestoreBlocks); } static void assignCalleeSavedSpillSlots(MachineFunction &F, @@ -341,6 +373,10 @@ static void assignCalleeSavedSpillSlots(MachineFunction &F, const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering(); MachineFrameInfo &MFI = F.getFrameInfo(); + + if (MFI.hasReturnProtectorTempRegister()) + CSI.push_back(CalleeSavedInfo(MFI.getReturnProtectorTempRegister())); + if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI)) { // If target doesn't implement this, use generic code. diff --git a/gnu/llvm/lib/CodeGen/ReturnProtectorPass.cpp b/gnu/llvm/lib/CodeGen/ReturnProtectorPass.cpp new file mode 100644 index 00000000000..c4f8cb4f1b1 --- /dev/null +++ b/gnu/llvm/lib/CodeGen/ReturnProtectorPass.cpp @@ -0,0 +1,61 @@ +//===- ReturnProtectorPass.cpp - Set up rteurn protectors -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass sets up functions for return protectors. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/Passes.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "return-protector" + +STATISTIC(NumSymbols, "Counts number of cookie symbols added"); + +namespace { + struct ReturnProtector : public FunctionPass { + static char ID; + ReturnProtector() : FunctionPass(ID) {} + + bool runOnFunction(Function &F) override { + if (F.hasFnAttribute("ret-protector")) { + // Create a symbol for the cookie + Module *M = F.getParent(); + std::hash<std::string> hasher; + std::string cookiename = "__retguard_" + std::to_string(hasher((M->getName() + F.getName()).str()) % 4000); + Type *cookietype = Type::getInt8PtrTy(M->getContext()); + GlobalVariable *cookie = dyn_cast_or_null<GlobalVariable>( + M->getOrInsertGlobal(cookiename, cookietype)); + cookie->setInitializer(Constant::getNullValue(cookietype)); + cookie->setLinkage(GlobalVariable::WeakAnyLinkage); + cookie->setVisibility(GlobalValue::HiddenVisibility); + cookie->setSection(".openbsd.randomdata"); + cookie->setExternallyInitialized(true); + F.addFnAttr("ret-protector-cookie", cookiename); + NumSymbols++; + } + return false; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + } + }; +} + +char ReturnProtector::ID = 0; +INITIALIZE_PASS(ReturnProtector, "return-protector", "Return Protector Pass", + false, false) +FunctionPass *llvm::createReturnProtectorPass() { return new ReturnProtector(); } + diff --git a/gnu/llvm/lib/CodeGen/TargetPassConfig.cpp b/gnu/llvm/lib/CodeGen/TargetPassConfig.cpp index 3e6ad3eeef0..04f60eca18b 100644 --- a/gnu/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/gnu/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -688,6 +688,8 @@ void TargetPassConfig::addISelPrepare() { if (requiresCodeGenSCCOrder()) addPass(new DummyCGSCCPass); + addPass(createReturnProtectorPass()); + // Add both the safe stack and the stack protection passes: each of them will // only protect functions that have corresponding attributes. addPass(createSafeStackPass()); diff --git a/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp b/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp index 11808f8995f..16acc7ea459 100644 --- a/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -3059,3 +3059,201 @@ void X86FrameLowering::processFunctionBeforeFrameFinalized( UnwindHelpFI) .addImm(-2); } + +static void markUsedRegsInSuccessors(MachineBasicBlock &MBB, + SmallSet<unsigned, 16> &Used, + SmallSet<int, 24> &Visited) { + int BBNum = MBB.getNumber(); + if (Visited.count(BBNum)) + return; + + // Mark all the registers used + for (auto &MBBI : MBB.instrs()) + for (auto &MBBIOp : MBBI.operands()) + if (MBBIOp.isReg()) + Used.insert(MBBIOp.getReg()); + // Mark this MBB as visited + Visited.insert(BBNum); + // Recurse over all successors + for (auto &SuccMBB : MBB.successors()) + markUsedRegsInSuccessors(*SuccMBB, Used, Visited); +} + +static inline bool opcodeIsRealReturn(unsigned opcode) { + switch (opcode) { + case X86::RET: + case X86::RETL: + case X86::RETQ: + case X86::RETW: + case X86::RETIL: + case X86::RETIQ: + case X86::RETIW: + case X86::LRETL: + case X86::LRETQ: + case X86::LRETW: + case X86::LRETIL: + case X86::LRETIQ: + case X86::LRETIW: + return true; + default: + return false; + } +} +static inline bool needsReturnProtector(MachineFunction &MF) { + for (auto &MBB : MF) + for (auto &T : MBB.terminators()) + if (opcodeIsRealReturn(T.getOpcode())) + return true; + return false; +} + +bool X86FrameLowering::determineReturnProtectorTempRegister(MachineFunction &MF, + const SmallVector<MachineBasicBlock *, 4> &SaveBlocks, + const SmallVector<MachineBasicBlock *, 4> &RestoreBlocks) const { + + MachineFrameInfo &MFI = MF.getFrameInfo(); + + if (!MFI.hasReturnProtector() || !needsReturnProtector(MF)) + return true; + + // CSR spills happen at the beginning of this block + std::vector<unsigned> TempRegs; + SmallSet<unsigned, 16> Used; + SmallSet<int, 24> Visited; + const Function &F = MF.getFunction(); + + TempRegs = {X86::R11, X86::R10}; + if (!F.isVarArg()) { + // We can use any of the caller saved unused arg registers + switch (F.arg_size()) { + case 0: TempRegs.push_back(X86::RDI); + case 1: TempRegs.push_back(X86::RSI); + case 2: // RDX is the 2nd return register + case 3: TempRegs.push_back(X86::RCX); + case 4: TempRegs.push_back(X86::R8); + case 5: TempRegs.push_back(X86::R9); + default: break; + } + } + + // so we can mark it as visited because anything past it is safe + for(auto &SB : SaveBlocks) + Visited.insert(SB->getNumber()); + + // CSR Restores happen at the end of restore blocks, before any terminators, + // so we need to search restores for MBB terminators, and any successor BBs. + for (auto &RB : RestoreBlocks) { + for (auto &RBI : RB->terminators()) + for (auto &RBIOp : RBI.operands()) + if (RBIOp.isReg()) + Used.insert(RBIOp.getReg()); + for (auto &SuccMBB : RB->successors()) + markUsedRegsInSuccessors(*SuccMBB, Used, Visited); + } + + // Now we iterate from the front to find code paths that + // bypass save blocks and land on return blocks + markUsedRegsInSuccessors(MF.front(), Used, Visited); + + // Now we have gathered all the regs used outside the frame save / restore, + // so we can see if we have a free reg to use for the retguard cookie. + for (unsigned Reg : TempRegs) { + bool canUse = true; + for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) { + if (Used.count(*AI)) { + // Reg is used somewhere, so we cannot use it + canUse = false; + break; + } + } + if (canUse) { + MFI.setReturnProtectorTempRegister(Reg); + break; + } + } + + // return whether or not we set a register + return MFI.hasReturnProtectorTempRegister(); +} + +void X86FrameLowering::insertReturnProtectorPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const +{ + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + if (!MFI.hasReturnProtector() || !MFI.hasReturnProtectorTempRegister()) + return; + + unsigned CFIIndex; + MachineBasicBlock::instr_iterator MBBI = MBB.instr_begin(); + DebugLoc MBBDL = MBB.findDebugLoc(MBBI); + const Function &Fn = MF.getFunction(); + const Module *M = Fn.getParent(); + GlobalVariable *cookie; + unsigned XORRM, MOVRM, SP, REG, IP; + + XORRM = X86::XOR64rm; + MOVRM = X86::MOV64rm; + SP = X86::RSP; + REG = MFI.getReturnProtectorTempRegister(); + IP = X86::RIP; + + cookie = dyn_cast_or_null<GlobalVariable>(M->getGlobalVariable( + Fn.getFnAttribute("ret-protector-cookie").getValueAsString(), + Type::getInt8PtrTy(M->getContext()))); + MBB.addLiveIn(REG); + BuildMI(MBB, MBBI, MBBDL, TII.get(MOVRM), REG) + .addReg(IP) + .addImm(0) + .addReg(0) + .addGlobalAddress(cookie) + .addReg(0); + addDirectMem(BuildMI(MBB, MBBI, MBBDL, TII.get(XORRM), REG).addReg(REG), SP); +} + +bool X86FrameLowering::insertReturnProtectorEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const +{ + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + if (!MFI.hasReturnProtector() || !MFI.hasReturnProtectorTempRegister()) + return false; + + const Function &Fn = MF.getFunction(); + const Module *M = Fn.getParent(); + std::vector<MachineInstr *> returns; + GlobalVariable *cookie; + unsigned XORRM, CMPRM, SP, REG, IP; + + XORRM = X86::XOR64rm; + CMPRM = X86::CMP64rm; + SP = X86::RSP; + REG = MFI.getReturnProtectorTempRegister(); + IP = X86::RIP; + + for (auto &MI : MBB.terminators()) + if (opcodeIsRealReturn(MI.getOpcode())) + returns.push_back(&MI); + + if (returns.empty()) + return false; + + for (auto &MI : returns) { + const DebugLoc &DL = MI->getDebugLoc(); + cookie = dyn_cast_or_null<GlobalVariable>(M->getGlobalVariable( + Fn.getFnAttribute("ret-protector-cookie").getValueAsString(), + Type::getInt8PtrTy(M->getContext()))); + MBB.addLiveIn(REG); + addDirectMem(BuildMI(MBB, MI, DL, TII.get(XORRM), REG).addReg(REG), SP); + BuildMI(MBB, MI, DL, TII.get(CMPRM)) + .addReg(REG) + .addReg(IP) + .addImm(0) + .addReg(0) + .addGlobalAddress(cookie) + .addReg(0); + BuildMI(MBB, MI, DL, TII.get(X86::RETGUARD_JMP_TRAP)); + } + return true; +} diff --git a/gnu/llvm/lib/Target/X86/X86FrameLowering.h b/gnu/llvm/lib/Target/X86/X86FrameLowering.h index 909319fc18f..5938b36dbd7 100644 --- a/gnu/llvm/lib/Target/X86/X86FrameLowering.h +++ b/gnu/llvm/lib/Target/X86/X86FrameLowering.h @@ -68,6 +68,19 @@ public: void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + /// determineReturnProtectorTempRegister - find a free register for the + /// return protector cookie calculation. + virtual bool determineReturnProtectorTempRegister(MachineFunction &MF, + const SmallVector<MachineBasicBlock *, 4> &SaveBlocks, + const SmallVector<MachineBasicBlock *, 4> &RestoreBlocks) const override; + + + /// Insert Return Protector instrumentation prologue / epilogue + void insertReturnProtectorPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const override; + bool insertReturnProtectorEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const override; + void adjustForSegmentedStacks(MachineFunction &MF, MachineBasicBlock &PrologueMBB) const override; diff --git a/gnu/llvm/lib/Target/X86/X86InstrCompiler.td b/gnu/llvm/lib/Target/X86/X86InstrCompiler.td index d66d9258e96..34b20cba9aa 100644 --- a/gnu/llvm/lib/Target/X86/X86InstrCompiler.td +++ b/gnu/llvm/lib/Target/X86/X86InstrCompiler.td @@ -267,6 +267,21 @@ def MORESTACK_RET_RESTORE_R10 : I<0, Pseudo, (outs), (ins), } //===----------------------------------------------------------------------===// +// Pseudo instruction used by retguard + +// This is lowered to a JE 2; INT3; INT3. Prior to this pseudo should be a +// compare instruction to ensure the retguard cookie is correct. +// We use a pseudo here in order to avoid splitting the BB just before the return. +// Splitting the BB and inserting a JE_1 over a new INT3 BB occasionally +// resulted in incorrect code when a value from a byte register (CL) was +// used as a return value. When emitted as a split BB, the single byte +// register would sometimes be widened to 4 bytes, which would corrupt +// the return value (ie mov %ecx, %eax instead of mov %cl, %al). +let isCodeGenOnly = 1, Uses = [EFLAGS] in { +def RETGUARD_JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>; +} + +//===----------------------------------------------------------------------===// // Alias Instructions //===----------------------------------------------------------------------===// diff --git a/gnu/llvm/lib/Target/X86/X86MCInstLower.cpp b/gnu/llvm/lib/Target/X86/X86MCInstLower.cpp index 5f0ada2d6d1..8f1259cb6a9 100644 --- a/gnu/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/gnu/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -1623,6 +1623,16 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { .addReg(X86::RAX)); return; + case X86::RETGUARD_JMP_TRAP: { + MCSymbol *RGSuccSym = OutContext.createTempSymbol(); + const MCExpr *RGSuccExpr = MCSymbolRefExpr::create(RGSuccSym, OutContext); + EmitAndCountInstruction(MCInstBuilder(X86::JE_1).addExpr(RGSuccExpr)); + EmitAndCountInstruction(MCInstBuilder(X86::INT3)); + EmitAndCountInstruction(MCInstBuilder(X86::INT3)); + OutStreamer->EmitLabel(RGSuccSym); + return; + } + case X86::SEH_PushReg: case X86::SEH_SaveReg: case X86::SEH_SaveXMM: |
