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
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,
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
63char X86WinFixupBufferSecurityCheckPass::ID = 0;
64
65INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE,
66 false, false)
67
68FunctionPass *llvm::createX86WinFixupBufferSecurityCheckPass() {
69 return new X86WinFixupBufferSecurityCheckPass();
70}
71
72void X86WinFixupBufferSecurityCheckPass::SplitBasicBlock(
73 MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
74 MachineBasicBlock::iterator SplitIt) {
75 NewRetMBB->splice(Where: NewRetMBB->end(), Other: CurMBB, From: SplitIt, To: CurMBB->end());
76}
77
78std::pair<MachineBasicBlock *, MachineInstr *>
79X86WinFixupBufferSecurityCheckPass::getSecurityCheckerBasicBlock(
80 MachineFunction &MF) {
81 MachineBasicBlock::reverse_iterator RBegin, REnd;
82
83 for (auto &MBB : llvm::reverse(C&: 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(i: 0);
89 if (MO.isGlobal()) {
90 auto Callee = dyn_cast<Function>(Val: MO.getGlobal());
91 if (Callee && Callee->getName() == "__security_check_cookie") {
92 return std::make_pair(x: &MBB, y: &MI);
93 break;
94 }
95 }
96 }
97 }
98 }
99 return std::make_pair(x: nullptr, y: nullptr);
100}
101
102void 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
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(Name: "__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(BB&: *CurMBB, I: InsertPt, MIMD: DebugLoc(), MCID: TII->get(Opcode: X86::CMP64rm))
152 .addReg(RegNo: GuardXor->getOperand(i: 0).getReg())
153 .addReg(RegNo: X86::RIP)
154 .addImm(Val: 1)
155 .addReg(RegNo: X86::NoRegister)
156 .addGlobalAddress(GV)
157 .addReg(RegNo: X86::NoRegister);
158
159 BuildMI(BB&: *CurMBB, I: InsertPt, MIMD: DebugLoc(), MCID: TII->get(Opcode: X86::JCC_1))
160 .addMBB(MBB: FailMBB)
161 .addImm(Val: X86::COND_NE);
162
163 auto JMI = BuildMI(BB&: *CurMBB, I: InsertPt, MIMD: DebugLoc(), MCID: TII->get(Opcode: X86::JMP_1));
164
165 return std::make_pair(x: CMI.getInstr(), y: JMI.getInstr());
166}
167
168void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) {
169 LivePhysRegs LiveRegs;
170 computeAndAddLiveIns(LiveRegs, MBB&: *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(MBB: FailMBB);
182 FinishBlock(MBB: 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(Name: "__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(MBBI: MF.end(), MBB: NewRetMBB);
211 MF.insert(MBBI: MF.end(), MBB: 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(Where: FailMBB->end(), Other: CurMBB, From: U1It, To: U2It);
231 BuildMI(BB&: *FailMBB, I: FailMBB->end(), MIMD: DebugLoc(), MCID: TII->get(Opcode: X86::INT3));
232
233 // Move left over instruction after StackUp
234 // from Current Basic BLocks into New Return Block
235 JMI.addMBB(MBB: NewRetMBB);
236 MachineBasicBlock::iterator SplicePt(JMI.getInstr());
237 ++SplicePt;
238 if (SplicePt != CurMBB->end())
239 NewRetMBB->splice(Where: NewRetMBB->end(), Other: CurMBB, From: SplicePt);
240
241 // Restructure Basic Blocks
242 CurMBB->addSuccessor(Succ: NewRetMBB);
243 CurMBB->addSuccessor(Succ: FailMBB);
244
245 FinishFunction(FailMBB, NewRetMBB);
246 return !Changed;
247}
248