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