summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/lib')
-rw-r--r--gnu/llvm/lib/CodeGen/CMakeLists.txt1
-rw-r--r--gnu/llvm/lib/CodeGen/PrologEpilogInserter.cpp40
-rw-r--r--gnu/llvm/lib/CodeGen/ReturnProtectorPass.cpp61
-rw-r--r--gnu/llvm/lib/CodeGen/TargetPassConfig.cpp2
-rw-r--r--gnu/llvm/lib/Target/X86/X86FrameLowering.cpp198
-rw-r--r--gnu/llvm/lib/Target/X86/X86FrameLowering.h13
-rw-r--r--gnu/llvm/lib/Target/X86/X86InstrCompiler.td15
-rw-r--r--gnu/llvm/lib/Target/X86/X86MCInstLower.cpp10
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: