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