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"
23#include "llvm/IR/Module.h"
24#include <iterator>
25
26using namespace llvm;
27
28#define DEBUG_TYPE "x86-win-fixup-bscheck"
29
30namespace {
31
32class X86WinFixupBufferSecurityCheckPass : public MachineFunctionPass {
33public:
34 static char ID;
35
36 X86WinFixupBufferSecurityCheckPass() : MachineFunctionPass(ID) {}
37
38 StringRef getPassName() const override {
39 return "X86 Windows Fixup Buffer Security Check";
40 }
41
42 bool runOnMachineFunction(MachineFunction &MF) override;
43
44 std::pair<MachineBasicBlock *, MachineInstr *>
45 getSecurityCheckerBasicBlock(MachineFunction &MF);
46
47 void getGuardCheckSequence(MachineBasicBlock *CurMBB, MachineInstr *CheckCall,
48 MachineInstr *SeqMI[5]);
49
50 void SplitBasicBlock(MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
52
53 void FinishBlock(MachineBasicBlock *MBB);
54
55 void FinishFunction(MachineBasicBlock *FailMBB, MachineBasicBlock *NewRetMBB);
56
57 std::pair<MachineInstr *, MachineInstr *>
58 CreateFailCheckSequence(MachineBasicBlock *CurMBB, MachineBasicBlock *FailMBB,
59 MachineInstr *SeqMI[5]);
60};
61} // end anonymous namespace
62
63char X86WinFixupBufferSecurityCheckPass::ID = 0;
64
65INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE,
66 false, false)
67
69 return new X86WinFixupBufferSecurityCheckPass();
70}
71
72void X86WinFixupBufferSecurityCheckPass::SplitBasicBlock(
73 MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
75 NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplitIt, CurMBB->end());
76}
77
78std::pair<MachineBasicBlock *, MachineInstr *>
79X86WinFixupBufferSecurityCheckPass::getSecurityCheckerBasicBlock(
80 MachineFunction &MF) {
82
83 for (auto &MBB : llvm::reverse(MF)) {
84 for (RBegin = MBB.rbegin(), REnd = MBB.rend(); RBegin != REnd; ++RBegin) {
85 auto &MI = *RBegin;
86 if (MI.getOpcode() == X86::CALL64pcrel32 &&
87 MI.getNumExplicitOperands() == 1) {
88 auto MO = MI.getOperand(0);
89 if (MO.isGlobal()) {
90 auto Callee = dyn_cast<Function>(MO.getGlobal());
91 if (Callee && Callee->getName() == "__security_check_cookie") {
92 return std::make_pair(&MBB, &MI);
93 break;
94 }
95 }
96 }
97 }
98 }
99 return std::make_pair(nullptr, nullptr);
100}
101
102void X86WinFixupBufferSecurityCheckPass::getGuardCheckSequence(
103 MachineBasicBlock *CurMBB, MachineInstr *CheckCall,
104 MachineInstr *SeqMI[5]) {
105
106 MachineBasicBlock::iterator UIt(CheckCall);
108 // Seq From StackUp to Stack Down Is fixed.
109 // ADJCALLSTACKUP64
110 ++UIt;
111 SeqMI[4] = &*UIt;
112
113 // CALL __security_check_cookie
114 SeqMI[3] = CheckCall;
115
116 // COPY function slot cookie
117 ++DIt;
118 SeqMI[2] = &*DIt;
119
120 // ADJCALLSTACKDOWN64
121 ++DIt;
122 SeqMI[1] = &*DIt;
123
125 for (; XIt != CurMBB->rbegin(); ++XIt) {
126 auto &CI = *XIt;
127 if ((CI.getOpcode() == X86::XOR64_FP) || (CI.getOpcode() == X86::XOR32_FP))
128 break;
129 }
130 SeqMI[0] = &*XIt;
131}
132
133std::pair<MachineInstr *, MachineInstr *>
134X86WinFixupBufferSecurityCheckPass::CreateFailCheckSequence(
135 MachineBasicBlock *CurMBB, MachineBasicBlock *FailMBB,
136 MachineInstr *SeqMI[5]) {
137
138 auto MF = CurMBB->getParent();
139
140 Module &M = *MF->getFunction().getParent();
141 GlobalVariable *GV = M.getGlobalVariable("__security_cookie");
142 assert(GV && " Security Cookie was not installed!");
143
145
146 MachineInstr *GuardXor = SeqMI[0];
147 MachineBasicBlock::iterator InsertPt(GuardXor);
148 ++InsertPt;
149
150 // Compare security_Cookie with XOR_Val, if not same, we have violation
151 auto CMI = BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::CMP64rm))
152 .addReg(GuardXor->getOperand(0).getReg())
153 .addReg(X86::RIP)
154 .addImm(1)
155 .addReg(X86::NoRegister)
157 .addReg(X86::NoRegister);
158
159 BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JCC_1))
160 .addMBB(FailMBB)
162
163 auto JMI = BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JMP_1));
164
165 return std::make_pair(CMI.getInstr(), JMI.getInstr());
166}
167
168void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) {
169 LivePhysRegs LiveRegs;
170 computeAndAddLiveIns(LiveRegs, *MBB);
171}
172
173void X86WinFixupBufferSecurityCheckPass::FinishFunction(
174 MachineBasicBlock *FailMBB, MachineBasicBlock *NewRetMBB) {
175 FailMBB->getParent()->RenumberBlocks();
176 // FailMBB includes call to MSCV RT where is __security_check_cookie
177 // function is called. This function uses regcall and it expects cookie
178 // value from stack slot.( even if this is modified)
179 // Before going further we compute back livein for this block to make sure
180 // it is live and provided.
181 FinishBlock(FailMBB);
182 FinishBlock(NewRetMBB);
183}
184
185bool X86WinFixupBufferSecurityCheckPass::runOnMachineFunction(
186 MachineFunction &MF) {
187 bool Changed = false;
188 const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
189
190 if (!(STI.isTargetWindowsItanium() || STI.isTargetWindowsMSVC()))
191 return Changed;
192
193 // Check if security cookie was installed or not
194 Module &M = *MF.getFunction().getParent();
195 GlobalVariable *GV = M.getGlobalVariable("__security_cookie");
196 if (!GV)
197 return Changed;
198
200
201 // Check if security check cookie was installed or not
202 auto [CurMBB, CheckCall] = getSecurityCheckerBasicBlock(MF);
203
204 if (!CheckCall)
205 return Changed;
206
209
210 MF.insert(MF.end(), NewRetMBB);
211 MF.insert(MF.end(), FailMBB);
212
213 MachineInstr *SeqMI[5];
214 getGuardCheckSequence(CurMBB, CheckCall, SeqMI);
215 // MachineInstr * GuardXor = SeqMI[0];
216
217 auto FailSeqRange = CreateFailCheckSequence(CurMBB, FailMBB, SeqMI);
218 MachineInstrBuilder JMI(MF, FailSeqRange.second);
219
220 // After Inserting JMP_1, we can not have two terminators
221 // in same block, split CurrentMBB after JMP_1
222 MachineBasicBlock::iterator SplitIt(SeqMI[4]);
223 ++SplitIt;
224 SplitBasicBlock(CurMBB, NewRetMBB, SplitIt);
225
226 // Fill up Failure Routine, move Fail Check Squence from CurMBB to FailMBB
227 MachineBasicBlock::iterator U1It(SeqMI[1]);
228 MachineBasicBlock::iterator U2It(SeqMI[4]);
229 ++U2It;
230 FailMBB->splice(FailMBB->end(), CurMBB, U1It, U2It);
231 BuildMI(*FailMBB, FailMBB->end(), DebugLoc(), TII->get(X86::INT3));
232
233 // Move left over instruction after StackUp
234 // from Current Basic BLocks into New Return Block
235 JMI.addMBB(NewRetMBB);
236 MachineBasicBlock::iterator SplicePt(JMI.getInstr());
237 ++SplicePt;
238 if (SplicePt != CurMBB->end())
239 NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplicePt);
240
241 // Restructure Basic Blocks
242 CurMBB->addSuccessor(NewRetMBB);
243 CurMBB->addSuccessor(FailMBB);
244
245 FinishFunction(FailMBB, NewRetMBB);
246 return !Changed;
247}
MachineBasicBlock & MBB
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Module.h This file contains the declarations for the Module class.
#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:579
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:50
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:419
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.