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