summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lib/CodeGen
diff options
context:
space:
mode:
authormortimer <mortimer@openbsd.org>2018-06-06 00:14:29 +0000
committermortimer <mortimer@openbsd.org>2018-06-06 00:14:29 +0000
commite688c2b0648a80551cf7353d9f455c7cbb98f13c (patch)
treebb3f8b6975fe82bca012e40729fe5e7d66f07427 /gnu/llvm/lib/CodeGen
parentMove pluart(4) to dev/fdt. (diff)
downloadwireguard-openbsd-e688c2b0648a80551cf7353d9f455c7cbb98f13c.tar.xz
wireguard-openbsd-e688c2b0648a80551cf7353d9f455c7cbb98f13c.zip
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the effect that the integrity of the return address is protected, and function return instructions are harder to use in ROP gadgets. On function entry the return address is combined with a per-function random cookie and stored in the stack frame. The integrity of this value is verified before function return, and if this check fails, the program aborts. In this way RETGUARD is an improved stack protector, since the cookies are per-function. The verification routine is constructed such that the binary space immediately before each ret instruction is padded with int03 instructions, which makes these return instructions difficult to use in ROP gadgets. In the kernel, this has the effect of removing approximately 50% of total ROP gadgets, and 15% of unique ROP gadgets compared to the 6.3 release kernel. Function epilogues are essentially gadget free, leaving only the polymorphic gadgets that result from jumping into the instruction stream partway through other instructions. Work to remove these gadgets will continue through other mechanisms. Remaining work includes adding this mechanism to assembly routines, which must be done by hand. Many thanks to all those who helped test and provide feedback, especially deaadt, tb, espie and naddy. ok deraadt@
Diffstat (limited to 'gnu/llvm/lib/CodeGen')
-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
4 files changed, 102 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());