xref: /freebsd/contrib/llvm-project/llvm/lib/Target/X86/X86WinFixupBufferSecurityCheck.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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