LLVM  14.0.0git
X86IndirectThunks.cpp
Go to the documentation of this file.
1 //==- X86IndirectThunks.cpp - Construct indirect call/jump thunks for x86 --=//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 ///
10 /// Pass that injects an MI thunk that is used to lower indirect calls in a way
11 /// that prevents speculation on some x86 processors and can be used to mitigate
12 /// security vulnerabilities due to targeted speculative execution and side
13 /// channels such as CVE-2017-5715.
14 ///
15 /// Currently supported thunks include:
16 /// - Retpoline -- A RET-implemented trampoline that lowers indirect calls
17 /// - LVI Thunk -- A CALL/JMP-implemented thunk that forces load serialization
18 /// before making an indirect call/jump
19 ///
20 /// Note that the reason that this is implemented as a MachineFunctionPass and
21 /// not a ModulePass is that ModulePasses at this point in the LLVM X86 pipeline
22 /// serialize all transformations, which can consume lots of memory.
23 ///
24 /// TODO(chandlerc): All of this code could use better comments and
25 /// documentation.
26 ///
27 //===----------------------------------------------------------------------===//
28 
29 #include "X86.h"
30 #include "X86InstrBuilder.h"
31 #include "X86Subtarget.h"
36 #include "llvm/CodeGen/Passes.h"
38 #include "llvm/IR/IRBuilder.h"
39 #include "llvm/IR/Instructions.h"
40 #include "llvm/IR/Module.h"
42 #include "llvm/Support/Debug.h"
45 
46 using namespace llvm;
47 
48 #define DEBUG_TYPE "x86-retpoline-thunks"
49 
50 static const char RetpolineNamePrefix[] = "__llvm_retpoline_";
51 static const char R11RetpolineName[] = "__llvm_retpoline_r11";
52 static const char EAXRetpolineName[] = "__llvm_retpoline_eax";
53 static const char ECXRetpolineName[] = "__llvm_retpoline_ecx";
54 static const char EDXRetpolineName[] = "__llvm_retpoline_edx";
55 static const char EDIRetpolineName[] = "__llvm_retpoline_edi";
56 
57 static const char LVIThunkNamePrefix[] = "__llvm_lvi_thunk_";
58 static const char R11LVIThunkName[] = "__llvm_lvi_thunk_r11";
59 
60 namespace {
61 struct RetpolineThunkInserter : ThunkInserter<RetpolineThunkInserter> {
62  const char *getThunkPrefix() { return RetpolineNamePrefix; }
63  bool mayUseThunk(const MachineFunction &MF) {
64  const auto &STI = MF.getSubtarget<X86Subtarget>();
65  return (STI.useRetpolineIndirectCalls() ||
66  STI.useRetpolineIndirectBranches()) &&
68  }
69  void insertThunks(MachineModuleInfo &MMI);
70  void populateThunk(MachineFunction &MF);
71 };
72 
73 struct LVIThunkInserter : ThunkInserter<LVIThunkInserter> {
74  const char *getThunkPrefix() { return LVIThunkNamePrefix; }
75  bool mayUseThunk(const MachineFunction &MF) {
76  return MF.getSubtarget<X86Subtarget>().useLVIControlFlowIntegrity();
77  }
78  void insertThunks(MachineModuleInfo &MMI) {
79  createThunkFunction(MMI, R11LVIThunkName);
80  }
81  void populateThunk(MachineFunction &MF) {
82  assert (MF.size() == 1);
83  MachineBasicBlock *Entry = &MF.front();
84  Entry->clear();
85 
86  // This code mitigates LVI by replacing each indirect call/jump with a
87  // direct call/jump to a thunk that looks like:
88  // ```
89  // lfence
90  // jmpq *%r11
91  // ```
92  // This ensures that if the value in register %r11 was loaded from memory,
93  // then the value in %r11 is (architecturally) correct prior to the jump.
94  const TargetInstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
95  BuildMI(&MF.front(), DebugLoc(), TII->get(X86::LFENCE));
96  BuildMI(&MF.front(), DebugLoc(), TII->get(X86::JMP64r)).addReg(X86::R11);
97  MF.front().addLiveIn(X86::R11);
98  }
99 };
100 
101 class X86IndirectThunks : public MachineFunctionPass {
102 public:
103  static char ID;
104 
105  X86IndirectThunks() : MachineFunctionPass(ID) {}
106 
107  StringRef getPassName() const override { return "X86 Indirect Thunks"; }
108 
109  bool doInitialization(Module &M) override;
110  bool runOnMachineFunction(MachineFunction &MF) override;
111 
112 private:
113  std::tuple<RetpolineThunkInserter, LVIThunkInserter> TIs;
114 
115  // FIXME: When LLVM moves to C++17, these can become folds
116  template <typename... ThunkInserterT>
117  static void initTIs(Module &M,
118  std::tuple<ThunkInserterT...> &ThunkInserters) {
119  (void)std::initializer_list<int>{
120  (std::get<ThunkInserterT>(ThunkInserters).init(M), 0)...};
121  }
122  template <typename... ThunkInserterT>
123  static bool runTIs(MachineModuleInfo &MMI, MachineFunction &MF,
124  std::tuple<ThunkInserterT...> &ThunkInserters) {
125  bool Modified = false;
126  (void)std::initializer_list<int>{
127  Modified |= std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)...};
128  return Modified;
129  }
130 };
131 
132 } // end anonymous namespace
133 
134 void RetpolineThunkInserter::insertThunks(MachineModuleInfo &MMI) {
136  createThunkFunction(MMI, R11RetpolineName);
137  else
140  createThunkFunction(MMI, Name);
141 }
142 
143 void RetpolineThunkInserter::populateThunk(MachineFunction &MF) {
144  bool Is64Bit = MF.getTarget().getTargetTriple().getArch() == Triple::x86_64;
145  Register ThunkReg;
146  if (Is64Bit) {
147  assert(MF.getName() == "__llvm_retpoline_r11" &&
148  "Should only have an r11 thunk on 64-bit targets");
149 
150  // __llvm_retpoline_r11:
151  // callq .Lr11_call_target
152  // .Lr11_capture_spec:
153  // pause
154  // lfence
155  // jmp .Lr11_capture_spec
156  // .align 16
157  // .Lr11_call_target:
158  // movq %r11, (%rsp)
159  // retq
160  ThunkReg = X86::R11;
161  } else {
162  // For 32-bit targets we need to emit a collection of thunks for various
163  // possible scratch registers as well as a fallback that uses EDI, which is
164  // normally callee saved.
165  // __llvm_retpoline_eax:
166  // calll .Leax_call_target
167  // .Leax_capture_spec:
168  // pause
169  // jmp .Leax_capture_spec
170  // .align 16
171  // .Leax_call_target:
172  // movl %eax, (%esp) # Clobber return addr
173  // retl
174  //
175  // __llvm_retpoline_ecx:
176  // ... # Same setup
177  // movl %ecx, (%esp)
178  // retl
179  //
180  // __llvm_retpoline_edx:
181  // ... # Same setup
182  // movl %edx, (%esp)
183  // retl
184  //
185  // __llvm_retpoline_edi:
186  // ... # Same setup
187  // movl %edi, (%esp)
188  // retl
189  if (MF.getName() == EAXRetpolineName)
190  ThunkReg = X86::EAX;
191  else if (MF.getName() == ECXRetpolineName)
192  ThunkReg = X86::ECX;
193  else if (MF.getName() == EDXRetpolineName)
194  ThunkReg = X86::EDX;
195  else if (MF.getName() == EDIRetpolineName)
196  ThunkReg = X86::EDI;
197  else
198  llvm_unreachable("Invalid thunk name on x86-32!");
199  }
200 
201  const TargetInstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
202  assert (MF.size() == 1);
203  MachineBasicBlock *Entry = &MF.front();
204  Entry->clear();
205 
206  MachineBasicBlock *CaptureSpec =
207  MF.CreateMachineBasicBlock(Entry->getBasicBlock());
208  MachineBasicBlock *CallTarget =
209  MF.CreateMachineBasicBlock(Entry->getBasicBlock());
210  MCSymbol *TargetSym = MF.getContext().createTempSymbol();
211  MF.push_back(CaptureSpec);
212  MF.push_back(CallTarget);
213 
214  const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32;
215  const unsigned RetOpc = Is64Bit ? X86::RET64 : X86::RET32;
216 
217  Entry->addLiveIn(ThunkReg);
218  BuildMI(Entry, DebugLoc(), TII->get(CallOpc)).addSym(TargetSym);
219 
220  // The MIR verifier thinks that the CALL in the entry block will fall through
221  // to CaptureSpec, so mark it as the successor. Technically, CaptureTarget is
222  // the successor, but the MIR verifier doesn't know how to cope with that.
223  Entry->addSuccessor(CaptureSpec);
224 
225  // In the capture loop for speculation, we want to stop the processor from
226  // speculating as fast as possible. On Intel processors, the PAUSE instruction
227  // will block speculation without consuming any execution resources. On AMD
228  // processors, the PAUSE instruction is (essentially) a nop, so we also use an
229  // LFENCE instruction which they have advised will stop speculation as well
230  // with minimal resource utilization. We still end the capture with a jump to
231  // form an infinite loop to fully guarantee that no matter what implementation
232  // of the x86 ISA, speculating this code path never escapes.
233  BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::PAUSE));
234  BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::LFENCE));
235  BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::JMP_1)).addMBB(CaptureSpec);
236  CaptureSpec->setHasAddressTaken();
237  CaptureSpec->addSuccessor(CaptureSpec);
238 
239  CallTarget->addLiveIn(ThunkReg);
240  CallTarget->setHasAddressTaken();
241  CallTarget->setAlignment(Align(16));
242 
243  // Insert return address clobber
244  const unsigned MovOpc = Is64Bit ? X86::MOV64mr : X86::MOV32mr;
245  const Register SPReg = Is64Bit ? X86::RSP : X86::ESP;
246  addRegOffset(BuildMI(CallTarget, DebugLoc(), TII->get(MovOpc)), SPReg, false,
247  0)
248  .addReg(ThunkReg);
249 
250  CallTarget->back().setPreInstrSymbol(MF, TargetSym);
251  BuildMI(CallTarget, DebugLoc(), TII->get(RetOpc));
252 }
253 
255  return new X86IndirectThunks();
256 }
257 
258 char X86IndirectThunks::ID = 0;
259 
260 bool X86IndirectThunks::doInitialization(Module &M) {
261  initTIs(M, TIs);
262  return false;
263 }
264 
265 bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
266  LLVM_DEBUG(dbgs() << getPassName() << '\n');
267  auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
268  return runTIs(MMI, MF, TIs);
269 }
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::MCSymbol
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
X86Subtarget.h
llvm::MachineFunction::getContext
MCContext & getContext() const
Definition: MachineFunction.h:586
X86InstrBuilder.h
R11RetpolineName
static const char R11RetpolineName[]
Definition: X86IndirectThunks.cpp:51
llvm::N86::EDI
@ EDI
Definition: X86MCTargetDesc.h:51
llvm::X86Subtarget
Definition: X86Subtarget.h:52
llvm::MachineFunctionPass
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Definition: MachineFunctionPass.h:30
llvm::createX86IndirectThunksPass
FunctionPass * createX86IndirectThunksPass()
This pass creates the thunks for the retpoline feature.
Definition: X86IndirectThunks.cpp:254
Module.h
llvm::Triple::x86_64
@ x86_64
Definition: Triple.h:84
llvm::addRegOffset
static const MachineInstrBuilder & addRegOffset(const MachineInstrBuilder &MIB, unsigned Reg, bool isKill, int Offset)
addRegOffset - This function is used to add a memory reference of the form [Reg + Offset],...
Definition: X86InstrBuilder.h:157
EDXRetpolineName
static const char EDXRetpolineName[]
Definition: X86IndirectThunks.cpp:54
llvm::MachineBasicBlock::back
MachineInstr & back()
Definition: MachineBasicBlock.h:248
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::MachineBasicBlock::addSuccessor
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
Definition: MachineBasicBlock.cpp:750
CommandLine.h
llvm::MachineFunction::front
const MachineBasicBlock & front() const
Definition: MachineFunction.h:828
X86.h
llvm::TargetInstrInfo
TargetInstrInfo - Interface to description of machine instruction set.
Definition: TargetInstrInfo.h:97
TargetMachine.h
llvm::MachineInstrBuilder::addMBB
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Definition: MachineInstrBuilder.h:146
llvm::N86::ESP
@ ESP
Definition: X86MCTargetDesc.h:51
EAXRetpolineName
static const char EAXRetpolineName[]
Definition: X86IndirectThunks.cpp:52
llvm::N86::EAX
@ EAX
Definition: X86MCTargetDesc.h:51
llvm::MachineModuleInfo::getTarget
const LLVMTargetMachine & getTarget() const
Definition: MachineModuleInfo.h:165
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:129
llvm::MachineFunction::size
unsigned size() const
Definition: MachineFunction.h:826
llvm::MachineModuleInfo
This class contains meta information specific to a module.
Definition: MachineModuleInfo.h:78
IndirectThunks.h
LoopDeletionResult::Modified
@ Modified
llvm::MachineInstr::setPreInstrSymbol
void setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol)
Set a symbol that will be emitted just prior to the instruction itself.
Definition: MachineInstr.cpp:478
llvm::N86::EDX
@ EDX
Definition: X86MCTargetDesc.h:51
Align
uint64_t Align
Definition: ELFObjHandler.cpp:83
llvm::Triple::getArch
ArchType getArch() const
Get the parsed architecture type of this triple.
Definition: Triple.h:312
llvm::N86::ECX
@ ECX
Definition: X86MCTargetDesc.h:51
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:95
llvm::MachineBasicBlock::setAlignment
void setAlignment(Align A)
Set alignment of the basic block.
Definition: MachineBasicBlock.h:522
Passes.h
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:634
llvm::MachineFunction::push_back
void push_back(MachineBasicBlock *MBB)
Definition: MachineFunction.h:833
llvm::MachineFunction::CreateMachineBasicBlock
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *bb=nullptr)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
Definition: MachineFunction.cpp:415
TargetPassConfig.h
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:542
EDIRetpolineName
static const char EDIRetpolineName[]
Definition: X86IndirectThunks.cpp:55
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MachineBasicBlock::setHasAddressTaken
void setHasAddressTaken()
Set this block to reflect that it potentially is the target of an indirect branch.
Definition: MachineBasicBlock.h:215
MachineModuleInfo.h
llvm::MachineInstrBuilder::addReg
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Definition: MachineInstrBuilder.h:97
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
llvm::MachineFunction
Definition: MachineFunction.h:234
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
llvm::MCContext::createTempSymbol
MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Definition: MCContext.cpp:303
llvm::Register
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
llvm::MachineBasicBlock::addLiveIn
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
Definition: MachineBasicBlock.h:367
R11LVIThunkName
static const char R11LVIThunkName[]
Definition: X86IndirectThunks.cpp:58
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
llvm::MachineFunction::getTarget
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Definition: MachineFunction.h:630
RetpolineNamePrefix
static const char RetpolineNamePrefix[]
Definition: X86IndirectThunks.cpp:50
llvm::ThunkInserter
Definition: IndirectThunks.h:24
llvm::X86Subtarget::useRetpolineExternalThunk
bool useRetpolineExternalThunk() const
Definition: X86Subtarget.h:789
Instructions.h
llvm::MachineInstrBuilder::addSym
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
Definition: MachineInstrBuilder.h:267
MachineInstrBuilder.h
llvm::BuildMI
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
Definition: MachineInstrBuilder.h:328
ECXRetpolineName
static const char ECXRetpolineName[]
Definition: X86IndirectThunks.cpp:53
llvm::TargetMachine::getTargetTriple
const Triple & getTargetTriple() const
Definition: TargetMachine.h:129
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:298
llvm::DebugLoc
A debug info location.
Definition: DebugLoc.h:33
raw_ostream.h
MachineFunction.h
LVIThunkNamePrefix
static const char LVIThunkNamePrefix[]
Definition: X86IndirectThunks.cpp:57
Debug.h
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38