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"
19 #include "llvm/CodeGen/LivePhysRegs.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineRegisterInfo.h"
23 #include "llvm/IR/Module.h"
24 #include <iterator>
25
26 using namespace llvm;
27
28 #define DEBUG_TYPE "x86-win-fixup-bscheck"
29
30 namespace {
31
32 class X86WinFixupBufferSecurityCheckPass : public MachineFunctionPass {
33 public:
34 static char ID;
35
X86WinFixupBufferSecurityCheckPass()36 X86WinFixupBufferSecurityCheckPass() : MachineFunctionPass(ID) {}
37
getPassName() const38 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,
51 MachineBasicBlock::iterator SplitIt);
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
63 char X86WinFixupBufferSecurityCheckPass::ID = 0;
64
INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass,DEBUG_TYPE,DEBUG_TYPE,false,false)65 INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE,
66 false, false)
67
68 FunctionPass *llvm::createX86WinFixupBufferSecurityCheckPass() {
69 return new X86WinFixupBufferSecurityCheckPass();
70 }
71
SplitBasicBlock(MachineBasicBlock * CurMBB,MachineBasicBlock * NewRetMBB,MachineBasicBlock::iterator SplitIt)72 void X86WinFixupBufferSecurityCheckPass::SplitBasicBlock(
73 MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
74 MachineBasicBlock::iterator SplitIt) {
75 NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplitIt, CurMBB->end());
76 }
77
78 std::pair<MachineBasicBlock *, MachineInstr *>
getSecurityCheckerBasicBlock(MachineFunction & MF)79 X86WinFixupBufferSecurityCheckPass::getSecurityCheckerBasicBlock(
80 MachineFunction &MF) {
81 MachineBasicBlock::reverse_iterator RBegin, REnd;
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
getGuardCheckSequence(MachineBasicBlock * CurMBB,MachineInstr * CheckCall,MachineInstr * SeqMI[5])102 void X86WinFixupBufferSecurityCheckPass::getGuardCheckSequence(
103 MachineBasicBlock *CurMBB, MachineInstr *CheckCall,
104 MachineInstr *SeqMI[5]) {
105
106 MachineBasicBlock::iterator UIt(CheckCall);
107 MachineBasicBlock::reverse_iterator DIt(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
124 MachineBasicBlock::reverse_iterator XIt(SeqMI[1]);
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
133 std::pair<MachineInstr *, MachineInstr *>
CreateFailCheckSequence(MachineBasicBlock * CurMBB,MachineBasicBlock * FailMBB,MachineInstr * SeqMI[5])134 X86WinFixupBufferSecurityCheckPass::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
144 const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
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)
156 .addGlobalAddress(GV)
157 .addReg(X86::NoRegister);
158
159 BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JCC_1))
160 .addMBB(FailMBB)
161 .addImm(X86::COND_NE);
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
FinishBlock(MachineBasicBlock * MBB)168 void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) {
169 LivePhysRegs LiveRegs;
170 computeAndAddLiveIns(LiveRegs, *MBB);
171 }
172
FinishFunction(MachineBasicBlock * FailMBB,MachineBasicBlock * NewRetMBB)173 void 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
runOnMachineFunction(MachineFunction & MF)185 bool 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
199 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
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
207 MachineBasicBlock *FailMBB = MF.CreateMachineBasicBlock();
208 MachineBasicBlock *NewRetMBB = MF.CreateMachineBasicBlock();
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 }
248