Hello tech,

I've been working on llvm/clang some lately, and am experimenting with
the llvm Pass infrastructure. Passes essentially let you perform
arbitrary transforms on the program at various points in the compilation
process.

I've attached a patch that defines a machine function pass that adds:

xor [rsp], rsp

at the start of each function, and before every RET. This means that the
return pointer on the stack is xored with the stack address where it
happens to be. When the function returns, the same transform is applied
again to reverse the process. The consequences of doing this are (a) The
return address is obfuscated on the stack, which mitigates against some
info leaks and (b) All the RETs in the program become hard to use in ROP
gadgets, because the return address is permuted before being popped.
ASLR on the stack makes predicting stack addresses difficult, so if an
attacker is dumping a ROP chain onto the stack that uses these gadgets,
they will need to know the addresses they are writing to on the stack in
order for them to work, which adds an extra hurdle. 

The performance cost here is 2 extra instructions per function call. I
picked rsp to xor with the return address because it is cheap to use,
non-constant, and makes the transform simple and easy to reason about. I
am happy to bikeshed about better choices if people are interested.

I've done some light testing on this, and it seems to work on my test
programs and when I did it to my libc. I am not really sure if this is
interesting enough to warrant more work, but I figured there isn't any
harm in posting it up. So I'm not looking for okays, but figured it
might be interesting to some others on the list.

Todd


diff --git llvm/lib/Target/X86/CMakeLists.txt llvm/lib/Target/X86/CMakeLists.txt
index 9dfd09022bd..dc2d58073fd 100644
--- llvm/lib/Target/X86/CMakeLists.txt
+++ llvm/lib/Target/X86/CMakeLists.txt
@@ -45,6 +45,7 @@ set(sources
   X86MachineFunctionInfo.cpp
   X86OptimizeLEAs.cpp
   X86PadShortFunction.cpp
+  X86GuardStackRet.cpp
   X86RegisterInfo.cpp
   X86SelectionDAGInfo.cpp
   X86ShuffleDecodeConstantPool.cpp
diff --git llvm/lib/Target/X86/X86.h llvm/lib/Target/X86/X86.h
index 2cb80a482d0..4b8a132f648 100644
--- llvm/lib/Target/X86/X86.h
+++ llvm/lib/Target/X86/X86.h
@@ -50,6 +50,10 @@ FunctionPass *createX86IssueVZeroUpperPass();
 /// This will prevent a stall when returning on the Atom.
 FunctionPass *createX86PadShortFunctions();
 
+/// Return a pass that adds xor instructions for return pointers
+/// on the stack
+FunctionPass *createX86GuardStackRet();
+
 /// Return a pass that selectively replaces certain instructions (like add,
 /// sub, inc, dec, some shifts, and some multiplies) by equivalent LEA
 /// instructions, in order to eliminate execution delays in some processors.
diff --git llvm/lib/Target/X86/X86GuardStackRet.cpp 
llvm/lib/Target/X86/X86GuardStackRet.cpp
new file mode 100644
index 00000000000..e7261a85aee
--- /dev/null
+++ llvm/lib/Target/X86/X86GuardStackRet.cpp
@@ -0,0 +1,98 @@
+//===-------- X86GuardStackRet.cpp - xor return pointers -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a pass that will add an xor (rsp), rsp instruction to
+// each function preamble, and before any ret.
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+
+#include "X86.h"
+#include "X86InstrInfo.h"
+#include "X86Subtarget.h"
+#include "X86InstrBuilder.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetInstrInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "x86-guard-ret"
+
+namespace {
+  struct GuardStackRet : public MachineFunctionPass {
+    static char ID;
+    GuardStackRet() : MachineFunctionPass(ID)
+                    , STI(nullptr), TII(nullptr) {}
+
+    bool runOnMachineFunction(MachineFunction &MF) override;
+
+    MachineFunctionProperties getRequiredProperties() const override {
+      return MachineFunctionProperties().set(
+          MachineFunctionProperties::Property::NoVRegs);
+    }
+
+    StringRef getPassName() const override {
+      return "X86 Guard RET Instructions";
+    }
+
+  private:
+    void addXORInst(MachineBasicBlock &MBB, MachineInstr &MI);
+
+    const X86Subtarget *STI;
+    const TargetInstrInfo *TII;
+       bool is64bit;
+  };
+
+  char GuardStackRet::ID = 0;
+}
+
+FunctionPass *llvm::createX86GuardStackRet() {
+  return new GuardStackRet();
+}
+
+/// runOnMachineFunction - Loop over all of the basic blocks, inserting
+//  XORs before each function and each ret
+bool GuardStackRet::runOnMachineFunction(MachineFunction &MF) {
+  STI = &MF.getSubtarget<X86Subtarget>();
+  TII = STI->getInstrInfo();
+  is64bit = STI->is64Bit();
+
+  bool MadeChange = false;
+
+  // Insert XOR blocks at the start of each function and before each RET
+  for (auto &MBB : MF) {
+    for (auto &MI : MBB) {
+         if (MI.isReturn()) {
+                 addXORInst(MBB, MI);
+                 MadeChange = true;
+         }
+    }
+  }
+  if (MadeChange) {
+       addXORInst(MF.front(), MF.front().front());
+  }
+
+  return MadeChange;
+}
+
+/// addXORInst - Add xor (rsp), rsp before the given MBBI
+void GuardStackRet::addXORInst(MachineBasicBlock &MBB, MachineInstr &MI) {
+  unsigned opcode = is64bit ? X86::XOR64mr : X86::XOR32mr;
+  unsigned stackp = is64bit ? X86::RSP     : X86::ESP;
+  addDirectMem(BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(opcode)), stackp)
+                 .addReg(stackp);
+}
diff --git llvm/lib/Target/X86/X86TargetMachine.cpp 
llvm/lib/Target/X86/X86TargetMachine.cpp
index aa5cfc64e9e..e957d2e5642 100644
--- llvm/lib/Target/X86/X86TargetMachine.cpp
+++ llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -402,4 +402,5 @@ void X86PassConfig::addPreEmitPass() {
     addPass(createX86FixupLEAs());
     addPass(createX86EvexToVexInsts());
   }
+  addPass(createX86GuardStackRet());
 }
diff --git usr.bin/clang/libLLVMX86CodeGen/Makefile 
usr.bin/clang/libLLVMX86CodeGen/Makefile
index 9d57d336c56..b23e82241ed 100644
--- usr.bin/clang/libLLVMX86CodeGen/Makefile
+++ usr.bin/clang/libLLVMX86CodeGen/Makefile
@@ -26,6 +26,7 @@ SRCS= X86AsmPrinter.cpp \
        X86MCInstLower.cpp \
        X86MachineFunctionInfo.cpp \
        X86PadShortFunction.cpp \
+       X86GuardStackRet.cpp \
        X86RegisterInfo.cpp \
        X86SelectionDAGInfo.cpp \
        X86ShuffleDecodeConstantPool.cpp \

Reply via email to