LLVM  16.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"
37 #include "llvm/CodeGen/Passes.h"
39 #include "llvm/IR/IRBuilder.h"
40 #include "llvm/IR/Instructions.h"
41 #include "llvm/IR/Module.h"
43 #include "llvm/Support/Debug.h"
46 
47 using namespace llvm;
48 
49 #define DEBUG_TYPE "x86-retpoline-thunks"
50 
51 static const char RetpolineNamePrefix[] = "__llvm_retpoline_";
52 static const char R11RetpolineName[] = "__llvm_retpoline_r11";
53 static const char EAXRetpolineName[] = "__llvm_retpoline_eax";
54 static const char ECXRetpolineName[] = "__llvm_retpoline_ecx";
55 static const char EDXRetpolineName[] = "__llvm_retpoline_edx";
56 static const char EDIRetpolineName[] = "__llvm_retpoline_edi";
57 
58 static const char LVIThunkNamePrefix[] = "__llvm_lvi_thunk_";
59 static const char R11LVIThunkName[] = "__llvm_lvi_thunk_r11";
60 
61 namespace {
62 struct RetpolineThunkInserter : ThunkInserter<RetpolineThunkInserter> {
63  const char *getThunkPrefix() { return RetpolineNamePrefix; }
64  bool mayUseThunk(const MachineFunction &MF) {
65  const auto &STI = MF.getSubtarget<X86Subtarget>();
66  return (STI.useRetpolineIndirectCalls() ||
67  STI.useRetpolineIndirectBranches()) &&
68  !STI.useRetpolineExternalThunk();
69  }
70  void insertThunks(MachineModuleInfo &MMI);
71  void populateThunk(MachineFunction &MF);
72 };
73 
74 struct LVIThunkInserter : ThunkInserter<LVIThunkInserter> {
75  const char *getThunkPrefix() { return LVIThunkNamePrefix; }
76  bool mayUseThunk(const MachineFunction &MF) {
77  return MF.getSubtarget<X86Subtarget>().useLVIControlFlowIntegrity();
78  }
79  void insertThunks(MachineModuleInfo &MMI) {
80  createThunkFunction(MMI, R11LVIThunkName);
81  }
82  void populateThunk(MachineFunction &MF) {
83  assert (MF.size() == 1);
84  MachineBasicBlock *Entry = &MF.front();
85  Entry->clear();
86 
87  // This code mitigates LVI by replacing each indirect call/jump with a
88  // direct call/jump to a thunk that looks like:
89  // ```
90  // lfence
91  // jmpq *%r11
92  // ```
93  // This ensures that if the value in register %r11 was loaded from memory,
94  // then the value in %r11 is (architecturally) correct prior to the jump.
95  const TargetInstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
96  BuildMI(&MF.front(), DebugLoc(), TII->get(X86::LFENCE));
97  BuildMI(&MF.front(), DebugLoc(), TII->get(X86::JMP64r)).addReg(X86::R11);
98  MF.front().addLiveIn(X86::R11);
99  }
100 };
101 
102 class X86IndirectThunks : public MachineFunctionPass {
103 public:
104  static char ID;
105 
106  X86IndirectThunks() : MachineFunctionPass(ID) {}
107 
108  StringRef getPassName() const override { return "X86 Indirect Thunks"; }
109 
110  bool doInitialization(Module &M) override;
111  bool runOnMachineFunction(MachineFunction &MF) override;
112 
113 private:
114  std::tuple<RetpolineThunkInserter, LVIThunkInserter> TIs;
115 
116  // FIXME: When LLVM moves to C++17, these can become folds
117  template <typename... ThunkInserterT>
118  static void initTIs(Module &M,
119  std::tuple<ThunkInserterT...> &ThunkInserters) {
120  (void)std::initializer_list<int>{
121  (std::get<ThunkInserterT>(ThunkInserters).init(M), 0)...};
122  }
123  template <typename... ThunkInserterT>
124  static bool runTIs(MachineModuleInfo &MMI, MachineFunction &MF,
125  std::tuple<ThunkInserterT...> &ThunkInserters) {
126  bool Modified = false;
127  (void)std::initializer_list<int>{
128  Modified |= std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF)...};
129  return Modified;
130  }
131 };
132 
133 } // end anonymous namespace
134 
135 void RetpolineThunkInserter::insertThunks(MachineModuleInfo &MMI) {
137  createThunkFunction(MMI, R11RetpolineName);
138  else
141  createThunkFunction(MMI, Name);
142 }
143 
144 void RetpolineThunkInserter::populateThunk(MachineFunction &MF) {
145  bool Is64Bit = MF.getTarget().getTargetTriple().getArch() == Triple::x86_64;
146  Register ThunkReg;
147  if (Is64Bit) {
148  assert(MF.getName() == "__llvm_retpoline_r11" &&
149  "Should only have an r11 thunk on 64-bit targets");
150 
151  // __llvm_retpoline_r11:
152  // callq .Lr11_call_target
153  // .Lr11_capture_spec:
154  // pause
155  // lfence
156  // jmp .Lr11_capture_spec
157  // .align 16
158  // .Lr11_call_target:
159  // movq %r11, (%rsp)
160  // retq
161  ThunkReg = X86::R11;
162  } else {
163  // For 32-bit targets we need to emit a collection of thunks for various
164  // possible scratch registers as well as a fallback that uses EDI, which is
165  // normally callee saved.
166  // __llvm_retpoline_eax:
167  // calll .Leax_call_target
168  // .Leax_capture_spec:
169  // pause
170  // jmp .Leax_capture_spec
171  // .align 16
172  // .Leax_call_target:
173  // movl %eax, (%esp) # Clobber return addr
174  // retl
175  //
176  // __llvm_retpoline_ecx:
177  // ... # Same setup
178  // movl %ecx, (%esp)
179  // retl
180  //
181  // __llvm_retpoline_edx:
182  // ... # Same setup
183  // movl %edx, (%esp)
184  // retl
185  //
186  // __llvm_retpoline_edi:
187  // ... # Same setup
188  // movl %edi, (%esp)
189  // retl
190  if (MF.getName() == EAXRetpolineName)
191  ThunkReg = X86::EAX;
192  else if (MF.getName() == ECXRetpolineName)
193  ThunkReg = X86::ECX;
194  else if (MF.getName() == EDXRetpolineName)
195  ThunkReg = X86::EDX;
196  else if (MF.getName() == EDIRetpolineName)
197  ThunkReg = X86::EDI;
198  else
199  llvm_unreachable("Invalid thunk name on x86-32!");
200  }
201 
202  const TargetInstrInfo *TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
203  assert (MF.size() == 1);
204  MachineBasicBlock *Entry = &MF.front();
205  Entry->clear();
206 
207  MachineBasicBlock *CaptureSpec =
208  MF.CreateMachineBasicBlock(Entry->getBasicBlock());
209  MachineBasicBlock *CallTarget =
210  MF.CreateMachineBasicBlock(Entry->getBasicBlock());
211  MCSymbol *TargetSym = MF.getContext().createTempSymbol();
212  MF.push_back(CaptureSpec);
213  MF.push_back(CallTarget);
214 
215  const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32;
216  const unsigned RetOpc = Is64Bit ? X86::RET64 : X86::RET32;
217 
218  Entry->addLiveIn(ThunkReg);
219  BuildMI(Entry, DebugLoc(), TII->get(CallOpc)).addSym(TargetSym);
220 
221  // The MIR verifier thinks that the CALL in the entry block will fall through
222  // to CaptureSpec, so mark it as the successor. Technically, CaptureTarget is
223  // the successor, but the MIR verifier doesn't know how to cope with that.
224  Entry->addSuccessor(CaptureSpec);
225 
226  // In the capture loop for speculation, we want to stop the processor from
227  // speculating as fast as possible. On Intel processors, the PAUSE instruction
228  // will block speculation without consuming any execution resources. On AMD
229  // processors, the PAUSE instruction is (essentially) a nop, so we also use an
230  // LFENCE instruction which they have advised will stop speculation as well
231  // with minimal resource utilization. We still end the capture with a jump to
232  // form an infinite loop to fully guarantee that no matter what implementation
233  // of the x86 ISA, speculating this code path never escapes.
234  BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::PAUSE));
235  BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::LFENCE));
236  BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::JMP_1)).addMBB(CaptureSpec);
237  CaptureSpec->setMachineBlockAddressTaken();
238  CaptureSpec->addSuccessor(CaptureSpec);
239 
240  CallTarget->addLiveIn(ThunkReg);
241  CallTarget->setMachineBlockAddressTaken();
242  CallTarget->setAlignment(Align(16));
243 
244  // Insert return address clobber
245  const unsigned MovOpc = Is64Bit ? X86::MOV64mr : X86::MOV32mr;
246  const Register SPReg = Is64Bit ? X86::RSP : X86::ESP;
247  addRegOffset(BuildMI(CallTarget, DebugLoc(), TII->get(MovOpc)), SPReg, false,
248  0)
249  .addReg(ThunkReg);
250 
251  CallTarget->back().setPreInstrSymbol(MF, TargetSym);
252  BuildMI(CallTarget, DebugLoc(), TII->get(RetOpc));
253 }
254 
256  return new X86IndirectThunks();
257 }
258 
259 char X86IndirectThunks::ID = 0;
260 
261 bool X86IndirectThunks::doInitialization(Module &M) {
262  initTIs(M, TIs);
263  return false;
264 }
265 
266 bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
267  LLVM_DEBUG(dbgs() << getPassName() << '\n');
268  auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
269  return runTIs(MMI, MF, TIs);
270 }
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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
llvm::AArch64PACKey::ID
ID
Definition: AArch64BaseInfo.h:818
X86Subtarget.h
llvm::MachineFunction::getContext
MCContext & getContext() const
Definition: MachineFunction.h:609
X86InstrBuilder.h
R11RetpolineName
static const char R11RetpolineName[]
Definition: X86IndirectThunks.cpp:52
llvm::N86::ECX
@ ECX
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:255
Module.h
llvm::Triple::x86_64
@ x86_64
Definition: Triple.h:86
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:55
llvm::MachineBasicBlock::back
MachineInstr & back()
Definition: MachineBasicBlock.h:285
llvm::N86::EDX
@ EDX
Definition: X86MCTargetDesc.h:51
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:762
CommandLine.h
llvm::MachineFunction::front
const MachineBasicBlock & front() const
Definition: MachineFunction.h:866
X86.h
llvm::TargetInstrInfo
TargetInstrInfo - Interface to description of machine instruction set.
Definition: TargetInstrInfo.h:98
TargetMachine.h
llvm::MachineInstrBuilder::addMBB
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Definition: MachineInstrBuilder.h:146
EAXRetpolineName
static const char EAXRetpolineName[]
Definition: X86IndirectThunks.cpp:53
llvm::MachineModuleInfo::getTarget
const LLVMTargetMachine & getTarget() const
Definition: MachineModuleInfo.h:141
llvm::N86::ESP
@ ESP
Definition: X86MCTargetDesc.h:51
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:125
llvm::MachineFunction::size
unsigned size() const
Definition: MachineFunction.h:864
llvm::MachineModuleInfo
This class contains meta information specific to a module.
Definition: MachineModuleInfo.h:74
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:462
Align
uint64_t Align
Definition: ELFObjHandler.cpp:82
llvm::Triple::getArch
ArchType getArch() const
Get the parsed architecture type of this triple.
Definition: Triple.h:354
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:94
llvm::MachineBasicBlock::setAlignment
void setAlignment(Align A)
Set alignment of the basic block.
Definition: MachineBasicBlock.h:559
Passes.h
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:657
llvm::MachineFunction::push_back
void push_back(MachineBasicBlock *MBB)
Definition: MachineFunction.h:871
llvm::N86::EDI
@ EDI
Definition: X86MCTargetDesc.h:51
llvm::MachineFunction::CreateMachineBasicBlock
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *bb=nullptr)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
Definition: MachineFunction.cpp:439
TargetPassConfig.h
MachineFunctionPass.h
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:567
EDIRetpolineName
static const char EDIRetpolineName[]
Definition: X86IndirectThunks.cpp:56
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:65
llvm::N86::EAX
@ EAX
Definition: X86MCTargetDesc.h:51
llvm::MachineFunction
Definition: MachineFunction.h:257
llvm::MachineBasicBlock::setMachineBlockAddressTaken
void setMachineBlockAddressTaken()
Set this block to indicate that its address is used as something other than the target of a terminato...
Definition: MachineBasicBlock.h:247
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
llvm::MCContext::createTempSymbol
MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Definition: MCContext.cpp:318
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:404
R11LVIThunkName
static const char R11LVIThunkName[]
Definition: X86IndirectThunks.cpp:59
llvm::MachineFunction::getTarget
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Definition: MachineFunction.h:653
RetpolineNamePrefix
static const char RetpolineNamePrefix[]
Definition: X86IndirectThunks.cpp:51
llvm::ThunkInserter
Definition: IndirectThunks.h:24
Instructions.h
llvm::MachineInstrBuilder::addSym
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
Definition: MachineInstrBuilder.h:267
llvm::BuildMI
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
Definition: MachineInstrBuilder.h:357
MachineInstrBuilder.h
ECXRetpolineName
static const char ECXRetpolineName[]
Definition: X86IndirectThunks.cpp:54
llvm::TargetMachine::getTargetTriple
const Triple & getTargetTriple() const
Definition: TargetMachine.h:125
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
llvm::DebugLoc
A debug info location.
Definition: DebugLoc.h:33
raw_ostream.h
MachineFunction.h
LVIThunkNamePrefix
static const char LVIThunkNamePrefix[]
Definition: X86IndirectThunks.cpp:58
Debug.h