1*854bbc50SMahesh-Attarde //===- X86WinFixupBufferSecurityCheck.cpp Fix Buffer Security Check Call -===// 2*854bbc50SMahesh-Attarde // 3*854bbc50SMahesh-Attarde // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*854bbc50SMahesh-Attarde // See https://llvm.org/LICENSE.txt for license information. 5*854bbc50SMahesh-Attarde // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*854bbc50SMahesh-Attarde // 7*854bbc50SMahesh-Attarde //===----------------------------------------------------------------------===// 8*854bbc50SMahesh-Attarde // Buffer Security Check implementation inserts windows specific callback into 9*854bbc50SMahesh-Attarde // code. On windows, __security_check_cookie call gets call everytime function 10*854bbc50SMahesh-Attarde // is return without fixup. Since this function is defined in runtime library, 11*854bbc50SMahesh-Attarde // it incures cost of call in dll which simply does comparison and returns most 12*854bbc50SMahesh-Attarde // time. With Fixup, We selective move to call in DLL only if comparison fails. 13*854bbc50SMahesh-Attarde //===----------------------------------------------------------------------===// 14*854bbc50SMahesh-Attarde 15*854bbc50SMahesh-Attarde #include "X86.h" 16*854bbc50SMahesh-Attarde #include "X86FrameLowering.h" 17*854bbc50SMahesh-Attarde #include "X86InstrInfo.h" 18*854bbc50SMahesh-Attarde #include "X86Subtarget.h" 19*854bbc50SMahesh-Attarde #include "llvm/CodeGen/LivePhysRegs.h" 20*854bbc50SMahesh-Attarde #include "llvm/CodeGen/MachineFunctionPass.h" 21*854bbc50SMahesh-Attarde #include "llvm/CodeGen/MachineInstrBuilder.h" 22*854bbc50SMahesh-Attarde #include "llvm/IR/Module.h" 23*854bbc50SMahesh-Attarde 24*854bbc50SMahesh-Attarde using namespace llvm; 25*854bbc50SMahesh-Attarde 26*854bbc50SMahesh-Attarde #define DEBUG_TYPE "x86-win-fixup-bscheck" 27*854bbc50SMahesh-Attarde 28*854bbc50SMahesh-Attarde namespace { 29*854bbc50SMahesh-Attarde 30*854bbc50SMahesh-Attarde class X86WinFixupBufferSecurityCheckPass : public MachineFunctionPass { 31*854bbc50SMahesh-Attarde public: 32*854bbc50SMahesh-Attarde static char ID; 33*854bbc50SMahesh-Attarde 34*854bbc50SMahesh-Attarde X86WinFixupBufferSecurityCheckPass() : MachineFunctionPass(ID) {} 35*854bbc50SMahesh-Attarde 36*854bbc50SMahesh-Attarde StringRef getPassName() const override { 37*854bbc50SMahesh-Attarde return "X86 Windows Fixup Buffer Security Check"; 38*854bbc50SMahesh-Attarde } 39*854bbc50SMahesh-Attarde 40*854bbc50SMahesh-Attarde bool runOnMachineFunction(MachineFunction &MF) override; 41*854bbc50SMahesh-Attarde 42*854bbc50SMahesh-Attarde std::pair<MachineBasicBlock *, MachineInstr *> 43*854bbc50SMahesh-Attarde getSecurityCheckerBasicBlock(MachineFunction &MF); 44*854bbc50SMahesh-Attarde 45*854bbc50SMahesh-Attarde void getGuardCheckSequence(MachineBasicBlock *CurMBB, MachineInstr *CheckCall, 46*854bbc50SMahesh-Attarde MachineInstr *SeqMI[5]); 47*854bbc50SMahesh-Attarde 48*854bbc50SMahesh-Attarde void SplitBasicBlock(MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB, 49*854bbc50SMahesh-Attarde MachineBasicBlock::iterator SplitIt); 50*854bbc50SMahesh-Attarde 51*854bbc50SMahesh-Attarde void FinishBlock(MachineBasicBlock *MBB); 52*854bbc50SMahesh-Attarde 53*854bbc50SMahesh-Attarde void FinishFunction(MachineBasicBlock *FailMBB, MachineBasicBlock *NewRetMBB); 54*854bbc50SMahesh-Attarde 55*854bbc50SMahesh-Attarde std::pair<MachineInstr *, MachineInstr *> 56*854bbc50SMahesh-Attarde CreateFailCheckSequence(MachineBasicBlock *CurMBB, MachineBasicBlock *FailMBB, 57*854bbc50SMahesh-Attarde MachineInstr *SeqMI[5]); 58*854bbc50SMahesh-Attarde }; 59*854bbc50SMahesh-Attarde } // end anonymous namespace 60*854bbc50SMahesh-Attarde 61*854bbc50SMahesh-Attarde char X86WinFixupBufferSecurityCheckPass::ID = 0; 62*854bbc50SMahesh-Attarde 63*854bbc50SMahesh-Attarde INITIALIZE_PASS(X86WinFixupBufferSecurityCheckPass, DEBUG_TYPE, DEBUG_TYPE, 64*854bbc50SMahesh-Attarde false, false) 65*854bbc50SMahesh-Attarde 66*854bbc50SMahesh-Attarde FunctionPass *llvm::createX86WinFixupBufferSecurityCheckPass() { 67*854bbc50SMahesh-Attarde return new X86WinFixupBufferSecurityCheckPass(); 68*854bbc50SMahesh-Attarde } 69*854bbc50SMahesh-Attarde 70*854bbc50SMahesh-Attarde void X86WinFixupBufferSecurityCheckPass::SplitBasicBlock( 71*854bbc50SMahesh-Attarde MachineBasicBlock *CurMBB, MachineBasicBlock *NewRetMBB, 72*854bbc50SMahesh-Attarde MachineBasicBlock::iterator SplitIt) { 73*854bbc50SMahesh-Attarde NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplitIt, CurMBB->end()); 74*854bbc50SMahesh-Attarde } 75*854bbc50SMahesh-Attarde 76*854bbc50SMahesh-Attarde std::pair<MachineBasicBlock *, MachineInstr *> 77*854bbc50SMahesh-Attarde X86WinFixupBufferSecurityCheckPass::getSecurityCheckerBasicBlock( 78*854bbc50SMahesh-Attarde MachineFunction &MF) { 79*854bbc50SMahesh-Attarde MachineBasicBlock::reverse_iterator RBegin, REnd; 80*854bbc50SMahesh-Attarde 81*854bbc50SMahesh-Attarde for (auto &MBB : llvm::reverse(MF)) { 82*854bbc50SMahesh-Attarde for (RBegin = MBB.rbegin(), REnd = MBB.rend(); RBegin != REnd; ++RBegin) { 83*854bbc50SMahesh-Attarde auto &MI = *RBegin; 84*854bbc50SMahesh-Attarde if (MI.getOpcode() == X86::CALL64pcrel32 && 85*854bbc50SMahesh-Attarde MI.getNumExplicitOperands() == 1) { 86*854bbc50SMahesh-Attarde auto MO = MI.getOperand(0); 87*854bbc50SMahesh-Attarde if (MO.isGlobal()) { 88*854bbc50SMahesh-Attarde auto Callee = dyn_cast<Function>(MO.getGlobal()); 89*854bbc50SMahesh-Attarde if (Callee && Callee->getName() == "__security_check_cookie") { 90*854bbc50SMahesh-Attarde return std::make_pair(&MBB, &MI); 91*854bbc50SMahesh-Attarde break; 92*854bbc50SMahesh-Attarde } 93*854bbc50SMahesh-Attarde } 94*854bbc50SMahesh-Attarde } 95*854bbc50SMahesh-Attarde } 96*854bbc50SMahesh-Attarde } 97*854bbc50SMahesh-Attarde return std::make_pair(nullptr, nullptr); 98*854bbc50SMahesh-Attarde } 99*854bbc50SMahesh-Attarde 100*854bbc50SMahesh-Attarde void X86WinFixupBufferSecurityCheckPass::getGuardCheckSequence( 101*854bbc50SMahesh-Attarde MachineBasicBlock *CurMBB, MachineInstr *CheckCall, 102*854bbc50SMahesh-Attarde MachineInstr *SeqMI[5]) { 103*854bbc50SMahesh-Attarde 104*854bbc50SMahesh-Attarde MachineBasicBlock::iterator UIt(CheckCall); 105*854bbc50SMahesh-Attarde MachineBasicBlock::reverse_iterator DIt(CheckCall); 106*854bbc50SMahesh-Attarde // Seq From StackUp to Stack Down Is fixed. 107*854bbc50SMahesh-Attarde // ADJCALLSTACKUP64 108*854bbc50SMahesh-Attarde ++UIt; 109*854bbc50SMahesh-Attarde SeqMI[4] = &*UIt; 110*854bbc50SMahesh-Attarde 111*854bbc50SMahesh-Attarde // CALL __security_check_cookie 112*854bbc50SMahesh-Attarde SeqMI[3] = CheckCall; 113*854bbc50SMahesh-Attarde 114*854bbc50SMahesh-Attarde // COPY function slot cookie 115*854bbc50SMahesh-Attarde ++DIt; 116*854bbc50SMahesh-Attarde SeqMI[2] = &*DIt; 117*854bbc50SMahesh-Attarde 118*854bbc50SMahesh-Attarde // ADJCALLSTACKDOWN64 119*854bbc50SMahesh-Attarde ++DIt; 120*854bbc50SMahesh-Attarde SeqMI[1] = &*DIt; 121*854bbc50SMahesh-Attarde 122*854bbc50SMahesh-Attarde MachineBasicBlock::reverse_iterator XIt(SeqMI[1]); 123*854bbc50SMahesh-Attarde for (; XIt != CurMBB->rbegin(); ++XIt) { 124*854bbc50SMahesh-Attarde auto &CI = *XIt; 125*854bbc50SMahesh-Attarde if ((CI.getOpcode() == X86::XOR64_FP) || (CI.getOpcode() == X86::XOR32_FP)) 126*854bbc50SMahesh-Attarde break; 127*854bbc50SMahesh-Attarde } 128*854bbc50SMahesh-Attarde SeqMI[0] = &*XIt; 129*854bbc50SMahesh-Attarde } 130*854bbc50SMahesh-Attarde 131*854bbc50SMahesh-Attarde std::pair<MachineInstr *, MachineInstr *> 132*854bbc50SMahesh-Attarde X86WinFixupBufferSecurityCheckPass::CreateFailCheckSequence( 133*854bbc50SMahesh-Attarde MachineBasicBlock *CurMBB, MachineBasicBlock *FailMBB, 134*854bbc50SMahesh-Attarde MachineInstr *SeqMI[5]) { 135*854bbc50SMahesh-Attarde 136*854bbc50SMahesh-Attarde auto MF = CurMBB->getParent(); 137*854bbc50SMahesh-Attarde 138*854bbc50SMahesh-Attarde Module &M = *MF->getFunction().getParent(); 139*854bbc50SMahesh-Attarde GlobalVariable *GV = M.getGlobalVariable("__security_cookie"); 140*854bbc50SMahesh-Attarde assert(GV && " Security Cookie was not installed!"); 141*854bbc50SMahesh-Attarde 142*854bbc50SMahesh-Attarde const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); 143*854bbc50SMahesh-Attarde 144*854bbc50SMahesh-Attarde MachineInstr *GuardXor = SeqMI[0]; 145*854bbc50SMahesh-Attarde MachineBasicBlock::iterator InsertPt(GuardXor); 146*854bbc50SMahesh-Attarde ++InsertPt; 147*854bbc50SMahesh-Attarde 148*854bbc50SMahesh-Attarde // Compare security_Cookie with XOR_Val, if not same, we have violation 149*854bbc50SMahesh-Attarde auto CMI = BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::CMP64rm)) 150*854bbc50SMahesh-Attarde .addReg(GuardXor->getOperand(0).getReg()) 151*854bbc50SMahesh-Attarde .addReg(X86::RIP) 152*854bbc50SMahesh-Attarde .addImm(1) 153*854bbc50SMahesh-Attarde .addReg(X86::NoRegister) 154*854bbc50SMahesh-Attarde .addGlobalAddress(GV) 155*854bbc50SMahesh-Attarde .addReg(X86::NoRegister); 156*854bbc50SMahesh-Attarde 157*854bbc50SMahesh-Attarde BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JCC_1)) 158*854bbc50SMahesh-Attarde .addMBB(FailMBB) 159*854bbc50SMahesh-Attarde .addImm(X86::COND_NE); 160*854bbc50SMahesh-Attarde 161*854bbc50SMahesh-Attarde auto JMI = BuildMI(*CurMBB, InsertPt, DebugLoc(), TII->get(X86::JMP_1)); 162*854bbc50SMahesh-Attarde 163*854bbc50SMahesh-Attarde return std::make_pair(CMI.getInstr(), JMI.getInstr()); 164*854bbc50SMahesh-Attarde } 165*854bbc50SMahesh-Attarde 166*854bbc50SMahesh-Attarde void X86WinFixupBufferSecurityCheckPass::FinishBlock(MachineBasicBlock *MBB) { 167*854bbc50SMahesh-Attarde LivePhysRegs LiveRegs; 168*854bbc50SMahesh-Attarde computeAndAddLiveIns(LiveRegs, *MBB); 169*854bbc50SMahesh-Attarde } 170*854bbc50SMahesh-Attarde 171*854bbc50SMahesh-Attarde void X86WinFixupBufferSecurityCheckPass::FinishFunction( 172*854bbc50SMahesh-Attarde MachineBasicBlock *FailMBB, MachineBasicBlock *NewRetMBB) { 173*854bbc50SMahesh-Attarde FailMBB->getParent()->RenumberBlocks(); 174*854bbc50SMahesh-Attarde // FailMBB includes call to MSCV RT where is __security_check_cookie 175*854bbc50SMahesh-Attarde // function is called. This function uses regcall and it expects cookie 176*854bbc50SMahesh-Attarde // value from stack slot.( even if this is modified) 177*854bbc50SMahesh-Attarde // Before going further we compute back livein for this block to make sure 178*854bbc50SMahesh-Attarde // it is live and provided. 179*854bbc50SMahesh-Attarde FinishBlock(FailMBB); 180*854bbc50SMahesh-Attarde FinishBlock(NewRetMBB); 181*854bbc50SMahesh-Attarde } 182*854bbc50SMahesh-Attarde 183*854bbc50SMahesh-Attarde bool X86WinFixupBufferSecurityCheckPass::runOnMachineFunction( 184*854bbc50SMahesh-Attarde MachineFunction &MF) { 185*854bbc50SMahesh-Attarde bool Changed = false; 186*854bbc50SMahesh-Attarde const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>(); 187*854bbc50SMahesh-Attarde 188*854bbc50SMahesh-Attarde if (!(STI.isTargetWindowsItanium() || STI.isTargetWindowsMSVC())) 189*854bbc50SMahesh-Attarde return Changed; 190*854bbc50SMahesh-Attarde 191*854bbc50SMahesh-Attarde // Check if security cookie was installed or not 192*854bbc50SMahesh-Attarde Module &M = *MF.getFunction().getParent(); 193*854bbc50SMahesh-Attarde GlobalVariable *GV = M.getGlobalVariable("__security_cookie"); 194*854bbc50SMahesh-Attarde if (!GV) 195*854bbc50SMahesh-Attarde return Changed; 196*854bbc50SMahesh-Attarde 197*854bbc50SMahesh-Attarde const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 198*854bbc50SMahesh-Attarde 199*854bbc50SMahesh-Attarde // Check if security check cookie was installed or not 200*854bbc50SMahesh-Attarde auto [CurMBB, CheckCall] = getSecurityCheckerBasicBlock(MF); 201*854bbc50SMahesh-Attarde 202*854bbc50SMahesh-Attarde if (!CheckCall) 203*854bbc50SMahesh-Attarde return Changed; 204*854bbc50SMahesh-Attarde 205*854bbc50SMahesh-Attarde MachineBasicBlock *FailMBB = MF.CreateMachineBasicBlock(); 206*854bbc50SMahesh-Attarde MachineBasicBlock *NewRetMBB = MF.CreateMachineBasicBlock(); 207*854bbc50SMahesh-Attarde 208*854bbc50SMahesh-Attarde MF.insert(MF.end(), NewRetMBB); 209*854bbc50SMahesh-Attarde MF.insert(MF.end(), FailMBB); 210*854bbc50SMahesh-Attarde 211*854bbc50SMahesh-Attarde MachineInstr *SeqMI[5]; 212*854bbc50SMahesh-Attarde getGuardCheckSequence(CurMBB, CheckCall, SeqMI); 213*854bbc50SMahesh-Attarde // MachineInstr * GuardXor = SeqMI[0]; 214*854bbc50SMahesh-Attarde 215*854bbc50SMahesh-Attarde auto FailSeqRange = CreateFailCheckSequence(CurMBB, FailMBB, SeqMI); 216*854bbc50SMahesh-Attarde MachineInstrBuilder JMI(MF, FailSeqRange.second); 217*854bbc50SMahesh-Attarde 218*854bbc50SMahesh-Attarde // After Inserting JMP_1, we can not have two terminators 219*854bbc50SMahesh-Attarde // in same block, split CurrentMBB after JMP_1 220*854bbc50SMahesh-Attarde MachineBasicBlock::iterator SplitIt(SeqMI[4]); 221*854bbc50SMahesh-Attarde ++SplitIt; 222*854bbc50SMahesh-Attarde SplitBasicBlock(CurMBB, NewRetMBB, SplitIt); 223*854bbc50SMahesh-Attarde 224*854bbc50SMahesh-Attarde // Fill up Failure Routine, move Fail Check Squence from CurMBB to FailMBB 225*854bbc50SMahesh-Attarde MachineBasicBlock::iterator U1It(SeqMI[1]); 226*854bbc50SMahesh-Attarde MachineBasicBlock::iterator U2It(SeqMI[4]); 227*854bbc50SMahesh-Attarde ++U2It; 228*854bbc50SMahesh-Attarde FailMBB->splice(FailMBB->end(), CurMBB, U1It, U2It); 229*854bbc50SMahesh-Attarde BuildMI(*FailMBB, FailMBB->end(), DebugLoc(), TII->get(X86::INT3)); 230*854bbc50SMahesh-Attarde 231*854bbc50SMahesh-Attarde // Move left over instruction after StackUp 232*854bbc50SMahesh-Attarde // from Current Basic BLocks into New Return Block 233*854bbc50SMahesh-Attarde JMI.addMBB(NewRetMBB); 234*854bbc50SMahesh-Attarde MachineBasicBlock::iterator SplicePt(JMI.getInstr()); 235*854bbc50SMahesh-Attarde ++SplicePt; 236*854bbc50SMahesh-Attarde if (SplicePt != CurMBB->end()) 237*854bbc50SMahesh-Attarde NewRetMBB->splice(NewRetMBB->end(), CurMBB, SplicePt); 238*854bbc50SMahesh-Attarde 239*854bbc50SMahesh-Attarde // Restructure Basic Blocks 240*854bbc50SMahesh-Attarde CurMBB->addSuccessor(NewRetMBB); 241*854bbc50SMahesh-Attarde CurMBB->addSuccessor(FailMBB); 242*854bbc50SMahesh-Attarde 243*854bbc50SMahesh-Attarde FinishFunction(FailMBB, NewRetMBB); 244*854bbc50SMahesh-Attarde return !Changed; 245*854bbc50SMahesh-Attarde } 246