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 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 63 char X86WinFixupBufferSecurityCheckPass::ID = 0; 64 65 INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE, 66 false, false) 67 68 FunctionPass *llvm::createX86WinFixupBufferSecurityCheckPass() { 69 return new X86WinFixupBufferSecurityCheckPass(); 70 } 71 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 *> 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 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 *> 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 168 void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) { 169 LivePhysRegs LiveRegs; 170 computeAndAddLiveIns(LiveRegs, *MBB); 171 } 172 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 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