Re: llvm - xor return pointers

2017-08-15 Thread Todd Mortimer
On Tue, Aug 15, 2017 at 05:12:39PM -0700, Ori Bernstein wrote:
> On Sat, 22 Jul 2017 02:25:29 -0400
> Todd Mortimer  wrote:
> 
> > xor [rsp], rsp
> > 
> > at the start of each function, and before every RET.
> 
> Wouldn't this break with alloca() or C99 VLAs?
> %rbp may work better, if the frame pointer is
> retained.

If alloca or C99 VLAs would break with this, than RET is broken with
alloca and C99 VLAs. At the time of the RET, %rsp *must* point to the
return address, or else RET will pop the wrong thing. So as long as we
insert the xor as the first instruction in the function preamble, then
we will xor the return pointer before alloca or VLAs have an opportunity
to modify %rsp, so when we later RET, we can xor it back.

Of course, I am happy to be proven wrong. If you can demonstrate a test
case where this breaks things, then please send it along and we can see
about fixing it. 

Cheers,
Todd



Re: llvm - xor return pointers

2017-08-15 Thread Ori Bernstein
On Sat, 22 Jul 2017 02:25:29 -0400
Todd Mortimer  wrote:

> xor [rsp], rsp
> 
> at the start of each function, and before every RET.

Wouldn't this break with alloca() or C99 VLAs?
%rbp may work better, if the frame pointer is
retained.

-- 
Ori Bernstein 



Re: llvm - xor return pointers

2017-07-22 Thread Theo de Raadt
> Cool stuff.  The downside is that this probably kills doing
> backtraces, making debugging stuff hard.  Unless this also changes the
> DWARF debugging information to reflect the xor operation.  But I'm not
> sure that's possible.

I think it is possible, but some help is probably needed in gdb.

> Having a "constant" (per process) cookie would make things easier for
> debuggers, but also weaken the mechanism.  It might be possible to
> have the kernel initialize such a cookie in the TIB (thread
> information block) that is used for fast access to thread-local
> variables.

Pointless effort I think.  We already have something very similar to
that, which is -fstack-protector-all.  It isn't a SP modification but a
cookie placement, but it doesn't gain any perturbative advantage from
the SP ASLR.



Re: llvm - xor return pointers

2017-07-22 Thread Mark Kettenis
> Date: Sat, 22 Jul 2017 02:25:29 -0400
> From: Todd Mortimer 
> 
> 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.

Cool stuff.  The downside is that this probably kills doing
backtraces, making debugging stuff hard.  Unless this also changes the
DWARF debugging information to reflect the xor operation.  But I'm not
sure that's possible.

Having a "constant" (per process) cookie would make things easier for
debuggers, but also weaken the mechanism.  It might be possible to
have the kernel initialize such a cookie in the TIB (thread
information block) that is used for fast access to thread-local
variables.



llvm - xor return pointers

2017-07-22 Thread Todd Mortimer
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 000..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 
+
+#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 ) override;
+
+MachineFunctionProperties getRequiredProperties() const override {
+  return MachineFunctionProperties().set(
+  MachineFunctionProperties::Property::NoVRegs);
+}
+
+StringRef getPassName() const override {
+  return "X86 Guard RET Instructions";
+}
+
+  private:
+void addXORInst(MachineBasicBlock , MachineInstr );
+
+const X86Subtarget *STI;
+const TargetInstrInfo *TII;
+   bool is64bit;
+  };
+
+  char GuardStackRet::ID = 0;
+}
+
+FunctionPass *llvm::createX86GuardStackRet() {
+  return new GuardStackRet();
+}
+
+/// runOnMachineFunction - Loop over all of the