LLVM 20.0.0git
X86WinFixupBufferSecurityCheck.cpp
Go to the documentation of this file.
1//===- X86WinFixupBufferSecurityCheck.cpp Fix Buffer Security Check Call -===//
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// Buffer Security Check implementation inserts windows specific callback into
9// code. On windows, __security_check_cookie call gets call everytime function
10// is return without fixup. Since this function is defined in runtime library,
11// it incures cost of call in dll which simply does comparison and returns most
12// time. With Fixup, We selective move to call in DLL only if comparison fails.
13//===----------------------------------------------------------------------===//
14
15#include "X86.h"
16#include "X86FrameLowering.h"
17#include "X86InstrInfo.h"
18#include "X86Subtarget.h"
22#include "llvm/IR/Module.h"
23
24using namespace llvm;
25
26#define DEBUG_TYPE "x86-win-fixup-bscheck"
27
28namespace {
29
30class X86WinFixupBufferSecurityCheckPass : public MachineFunctionPass {
31public:
32 static char ID;
33
34 X86WinFixupBufferSecurityCheckPass() : MachineFunctionPass(ID) {}
35
36 StringRef getPassName() const override {
37 return "X86 Windows Fixup Buffer Security Check";
38 }
39
40 bool runOnMachineFunction(MachineFunction &MF) override;
41
42 std::pair<MachineBasicBlock *, MachineInstr *>
43 getSecurityCheckerBasicBlock(MachineFunction &MF);
44
45 void getGuardCheckSequence(MachineBasicBlock *CurMBB, MachineInstr *CheckCall,
46 MachineInstr *SeqMI[5]);
47
48 void SplitBasicBlock(MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
50
51 void FinishBlock(MachineBasicBlock *MBB);
52
53 void FinishFunction(MachineBasicBlock *FailMBB, MachineBasicBlock *NewRetMBB);
54
55 std::pair<MachineInstr *, MachineInstr *>
56 CreateFailCheckSequence(MachineBasicBlock *CurMBB, MachineBasicBlock *FailMBB,
57 MachineInstr *SeqMI[5]);
58};
59} // end anonymous namespace
60
61char X86WinFixupBufferSecurityCheckPass::ID = 0;
62
63INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE,
64 false, false)
65
67 return new X86WinFixupBufferSecurityCheckPass();
68}
69
70void X86WinFixupBufferSecurityCheckPass::SplitBasicBlock(
71 MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
73 NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplitIt, CurMBB->end());
74}
75
76std::pair<MachineBasicBlock *, MachineInstr *>
77X86WinFixupBufferSecurityCheckPass::getSecurityCheckerBasicBlock(
78 MachineFunction &MF) {
80
81 for (auto &MBB : llvm::reverse(MF)) {
82 for (RBegin = MBB.rbegin(), REnd = MBB.rend(); RBegin != REnd; ++RBegin) {
83 auto &MI = *RBegin;
84 if (MI.getOpcode() == X86::CALL64pcrel32 &&
85 MI.getNumExplicitOperands() == 1) {
86 auto MO = MI.getOperand(0);
87 if (MO.isGlobal()) {
88 auto Callee = dyn_cast<Function>(MO.getGlobal());
89 if (Callee && Callee->getName() == "__security_check_cookie") {
90 return std::make_pair(&MBB, &MI);
91 break;
92 }
93 }
94 }
95 }
96 }
97 return std::make_pair(nullptr, nullptr);
98}
99
100void X86WinFixupBufferSecurityCheckPass::getGuardCheckSequence(
101 MachineBasicBlock *CurMBB, MachineInstr *CheckCall,
102 MachineInstr *SeqMI[5]) {
103
104 MachineBasicBlock::iterator UIt(CheckCall);
106 // Seq From StackUp to Stack Down Is fixed.
107 // ADJCALLSTACKUP64
108 ++UIt;
109 SeqMI[4] = &*UIt;
110
111 // CALL __security_check_cookie
112 SeqMI[3] = CheckCall;
113
114 // COPY function slot cookie
115 ++DIt;
116 SeqMI[2] = &*DIt;
117
118 // ADJCALLSTACKDOWN64
119 ++DIt;
120 SeqMI[1] = &*DIt;
121
123 for (; XIt != CurMBB->rbegin(); ++XIt) {
124 auto &CI = *XIt;
125 if ((CI.getOpcode() == X86::XOR64_FP) || (CI.getOpcode() == X86::XOR32_FP))
126 break;
127 }
128 SeqMI[0] = &*XIt;
129}
130
131std::pair<MachineInstr *, MachineInstr *>
132X86WinFixupBufferSecurityCheckPass::CreateFailCheckSequence(
133 MachineBasicBlock *CurMBB, MachineBasicBlock *FailMBB,
134 MachineInstr *SeqMI[5]) {
135
136 auto MF = CurMBB->getParent();
137
138 Module &M = *MF->getFunction().getParent();
139 GlobalVariable *GV = M.getGlobalVariable("__security_cookie");
140 assert(GV && " Security Cookie was not installed!");
141
143
144 MachineInstr *GuardXor = SeqMI[0];
145 MachineBasicBlock::iterator InsertPt(GuardXor);
146 ++InsertPt;
147
148 // Compare security_Cookie with XOR_Val, if not same, we have violation
149 auto CMI = BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::CMP64rm))
150 .addReg(GuardXor->getOperand(0).getReg())
151 .addReg(X86::RIP)
152 .addImm(1)
153 .addReg(X86::NoRegister)
155 .addReg(X86::NoRegister);
156
157 BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JCC_1))
158 .addMBB(FailMBB)
160
161 auto JMI = BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JMP_1));
162
163 return std::make_pair(CMI.getInstr(), JMI.getInstr());
164}
165
166void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) {
167 LivePhysRegs LiveRegs;
168 computeAndAddLiveIns(LiveRegs, *MBB);
169}
170
171void X86WinFixupBufferSecurityCheckPass::FinishFunction(
172 MachineBasicBlock *FailMBB, MachineBasicBlock *NewRetMBB) {
173 FailMBB->getParent()->RenumberBlocks();
174 // FailMBB includes call to MSCV RT where is __security_check_cookie
175 // function is called. This function uses regcall and it expects cookie
176 // value from stack slot.( even if this is modified)
177 // Before going further we compute back livein for this block to make sure
178 // it is live and provided.
179 FinishBlock(FailMBB);
180 FinishBlock(NewRetMBB);
181}
182
183bool X86WinFixupBufferSecurityCheckPass::runOnMachineFunction(
184 MachineFunction &MF) {
185 bool Changed = false;
186 const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
187
188 if (!(STI.isTargetWindowsItanium() || STI.isTargetWindowsMSVC()))
189 return Changed;
190
191 // Check if security cookie was installed or not
192 Module &M = *MF.getFunction().getParent();
193 GlobalVariable *GV = M.getGlobalVariable("__security_cookie");
194 if (!GV)
195 return Changed;
196
198
199 // Check if security check cookie was installed or not
200 auto [CurMBB, CheckCall] = getSecurityCheckerBasicBlock(MF);
201
202 if (!CheckCall)
203 return Changed;
204
207
208 MF.insert(MF.end(), NewRetMBB);
209 MF.insert(MF.end(), FailMBB);
210
211 MachineInstr *SeqMI[5];
212 getGuardCheckSequence(CurMBB, CheckCall, SeqMI);
213 // MachineInstr * GuardXor = SeqMI[0];
214
215 auto FailSeqRange = CreateFailCheckSequence(CurMBB, FailMBB, SeqMI);
216 MachineInstrBuilder JMI(MF, FailSeqRange.second);
217
218 // After Inserting JMP_1, we can not have two terminators
219 // in same block, split CurrentMBB after JMP_1
220 MachineBasicBlock::iterator SplitIt(SeqMI[4]);
221 ++SplitIt;
222 SplitBasicBlock(CurMBB, NewRetMBB, SplitIt);
223
224 // Fill up Failure Routine, move Fail Check Squence from CurMBB to FailMBB
225 MachineBasicBlock::iterator U1It(SeqMI[1]);
226 MachineBasicBlock::iterator U2It(SeqMI[4]);
227 ++U2It;
228 FailMBB->splice(FailMBB->end(), CurMBB, U1It, U2It);
229 BuildMI(*FailMBB, FailMBB->end(), DebugLoc(), TII->get(X86::INT3));
230
231 // Move left over instruction after StackUp
232 // from Current Basic BLocks into New Return Block
233 JMI.addMBB(NewRetMBB);
234 MachineBasicBlock::iterator SplicePt(JMI.getInstr());
235 ++SplicePt;
236 if (SplicePt != CurMBB->end())
237 NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplicePt);
238
239 // Restructure Basic Blocks
240 CurMBB->addSuccessor(NewRetMBB);
241 CurMBB->addSuccessor(FailMBB);
242
243 FinishFunction(FailMBB, NewRetMBB);
244 return !Changed;
245}
MachineBasicBlock & MBB
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A debug info location.
Definition: DebugLoc.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:656
A set of physical registers with utility functions to track liveness when walking backward/forward th...
Definition: LivePhysRegs.h:52
reverse_iterator rend()
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
reverse_iterator rbegin()
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
void RenumberBlocks(MachineBasicBlock *MBBFrom=nullptr)
RenumberBlocks - This discards all of the MachineBasicBlock numbers and recomputes them.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
Definition: MachineInstr.h:69
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:585
Register getReg() const
getReg - Returns the register number.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
TargetInstrInfo - Interface to description of machine instruction set.
virtual const TargetInstrInfo * getInstrInfo() const
bool isTargetWindowsMSVC() const
Definition: X86Subtarget.h:300
bool isTargetWindowsItanium() const
Definition: X86Subtarget.h:316
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
void computeAndAddLiveIns(LivePhysRegs &LiveRegs, MachineBasicBlock &MBB)
Convenience function combining computeLiveIns() and addLiveIns().
FunctionPass * createX86WinFixupBufferSecurityCheckPass()
Return a pass that transform inline buffer security check into seperate bb.