1 //===-- X86RetClean.cpp - Clean Retaddr off stack upon function return ----===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 /// This file defines a function pass that clears the ret-address from
11 /// the top of the stack, immediately upon return to the caller, the goal
12 /// is remove this subtle but powerful info-leak which hints at the
13 /// address space location of the lower level libraries.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "X86.h"
18 #include "X86InstrBuilder.h"
19 #include "X86InstrInfo.h"
20 #include "X86MachineFunctionInfo.h"
21 #include "X86Subtarget.h"
22 #include "X86TargetMachine.h"
23 #include "llvm/CodeGen/MachineFunction.h"
24 #include "llvm/CodeGen/MachineFunctionPass.h"
25 #include "llvm/CodeGen/MachineInstrBuilder.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 #include "llvm/CodeGen/Passes.h"
28 #include "llvm/MC/MCAsmInfo.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/raw_ostream.h"
32 using namespace llvm;
33 
34 #define RETCLEAN_DESC "X86 Ret Clean"
35 #define RETCLEAN_NAME "x86-ret-clean"
36 
37 #define DEBUG_TYPE RETCLEAN_NAME
38 
39 // Toggle with cc1 option: -mllvm -x86-ret-clean=<true|false>
40 static cl::opt<bool> RetClean(
41     "x86-ret-clean", cl::Hidden,
42     cl::desc("clean return address off stack after call"),
43     cl::init(false));
44 
45 namespace {
46 class RetCleanPass : public MachineFunctionPass {
47 
48 public:
49   static char ID;
50 
getPassName() const51   StringRef getPassName() const override { return RETCLEAN_DESC; }
52 
RetCleanPass()53   RetCleanPass()
54       : MachineFunctionPass(ID) {}
55 
56   /// Loop over all the instructions and replace ret with ret+clean
57   bool runOnMachineFunction(MachineFunction &MF) override;
58 
getRequiredProperties() const59   MachineFunctionProperties getRequiredProperties() const override {
60     return MachineFunctionProperties().set(
61         MachineFunctionProperties::Property::NoVRegs);
62   }
63 
64 private:
65   bool fixupInstruction(MachineFunction &MF, MachineBasicBlock &MBB,
66                         MachineInstr &MI);
67 };
68 char RetCleanPass::ID = 0;
69 } // namespace
70 
createX86RetCleanPass()71 FunctionPass *llvm::createX86RetCleanPass() {
72   return new RetCleanPass();
73 }
74 
fixupInstruction(MachineFunction & MF,MachineBasicBlock & MBB,MachineInstr & MI)75 bool RetCleanPass::fixupInstruction(MachineFunction &MF,
76                                MachineBasicBlock &MBB,
77                                MachineInstr &MI) {
78 
79   const X86InstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
80   bool Is64Bit = MF.getTarget().getTargetTriple().getArch() == Triple::x86_64;
81   unsigned Opc = Is64Bit ? X86::MOV64mi32 : X86::MOV32mi;
82   unsigned Offset = Is64Bit ? -8 : -4;
83   Register SPReg = Is64Bit ? X86::RSP : X86::ESP;
84 
85   // add "movq $0, -8(%rsp)" (or similar) in caller, to clear the
86   // ret-addr info-leak off the stack
87   addRegOffset(BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(Opc)),
88     SPReg, false, Offset)
89     .addImm(0);
90   return true;
91 }
92 
runOnMachineFunction(MachineFunction & MF)93 bool RetCleanPass::runOnMachineFunction(MachineFunction &MF) {
94   if (!RetClean)
95     return false;
96 
97   bool modified = false;
98 
99   // If a setjmp-like function is called by this function, we should not clean
100   if (MF.exposesReturnsTwice())
101     return false;
102 
103   for (auto &MBB : MF) {
104     std::vector<MachineInstr*> fixups;
105     bool foundcall = false;
106 
107     for (auto &MI : MBB) {
108       if (MI.isCall()) {
109         foundcall = true;	// queue the insert before the next MI
110       } else if (foundcall) {
111          fixups.push_back(&MI);
112          foundcall = false;
113       }
114     }
115     for (auto *fixup : fixups)
116       modified |= fixupInstruction(MF, MBB, *fixup);
117   }
118   return modified;
119 }
120