xref: /llvm-project/llvm/lib/Target/X86/X86WinFixupBufferSecurityCheck.cpp (revision dfe43bd1ca46c59399b7cbbf81b09256232e27f9)
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/IR/Module.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "x86-win-fixup-bscheck"
27 
28 namespace {
29 
30 class X86WinFixupBufferSecurityCheckPass : public MachineFunctionPass {
31 public:
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,
49                        MachineBasicBlock::iterator SplitIt);
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 
61 char X86WinFixupBufferSecurityCheckPass::ID = 0;
62 
63 INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE,
64                 false, false)
65 
66 FunctionPass *llvm::createX86WinFixupBufferSecurityCheckPass() {
67   return new X86WinFixupBufferSecurityCheckPass();
68 }
69 
70 void X86WinFixupBufferSecurityCheckPass::SplitBasicBlock(
71     MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB,
72     MachineBasicBlock::iterator SplitIt) {
73   NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplitIt, CurMBB->end());
74 }
75 
76 std::pair<MachineBasicBlock *, MachineInstr *>
77 X86WinFixupBufferSecurityCheckPass::getSecurityCheckerBasicBlock(
78     MachineFunction &MF) {
79   MachineBasicBlock::reverse_iterator RBegin, REnd;
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 
100 void X86WinFixupBufferSecurityCheckPass::getGuardCheckSequence(
101     MachineBasicBlock *CurMBB, MachineInstr *CheckCall,
102     MachineInstr *SeqMI[5]) {
103 
104   MachineBasicBlock::iterator UIt(CheckCall);
105   MachineBasicBlock::reverse_iterator DIt(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 
122   MachineBasicBlock::reverse_iterator XIt(SeqMI[1]);
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 
131 std::pair<MachineInstr *, MachineInstr *>
132 X86WinFixupBufferSecurityCheckPass::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 
142   const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
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)
154                  .addGlobalAddress(GV)
155                  .addReg(X86::NoRegister);
156 
157   BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JCC_1))
158       .addMBB(FailMBB)
159       .addImm(X86::COND_NE);
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 
166 void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) {
167   LivePhysRegs LiveRegs;
168   computeAndAddLiveIns(LiveRegs, *MBB);
169 }
170 
171 void 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 
183 bool 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 
197   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
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 
205   MachineBasicBlock *FailMBB = MF.CreateMachineBasicBlock();
206   MachineBasicBlock *NewRetMBB = MF.CreateMachineBasicBlock();
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 }
246