1*06c3fb27SDimitry Andric //===---- KCFI.cpp - Implements Kernel Control-Flow Integrity (KCFI) ------===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric // 9*06c3fb27SDimitry Andric // This pass implements Kernel Control-Flow Integrity (KCFI) indirect call 10*06c3fb27SDimitry Andric // check lowering. For each call instruction with a cfi-type attribute, it 11*06c3fb27SDimitry Andric // emits an arch-specific check before the call, and bundles the check and 12*06c3fb27SDimitry Andric // the call to prevent unintentional modifications. 13*06c3fb27SDimitry Andric // 14*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 15*06c3fb27SDimitry Andric 16*06c3fb27SDimitry Andric #include "llvm/ADT/Statistic.h" 17*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 18*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 19*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h" 20*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 21*06c3fb27SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 22*06c3fb27SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 23*06c3fb27SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 24*06c3fb27SDimitry Andric #include "llvm/InitializePasses.h" 25*06c3fb27SDimitry Andric 26*06c3fb27SDimitry Andric using namespace llvm; 27*06c3fb27SDimitry Andric 28*06c3fb27SDimitry Andric #define DEBUG_TYPE "kcfi" 29*06c3fb27SDimitry Andric #define KCFI_PASS_NAME "Insert KCFI indirect call checks" 30*06c3fb27SDimitry Andric 31*06c3fb27SDimitry Andric STATISTIC(NumKCFIChecksAdded, "Number of indirect call checks added"); 32*06c3fb27SDimitry Andric 33*06c3fb27SDimitry Andric namespace { 34*06c3fb27SDimitry Andric class KCFI : public MachineFunctionPass { 35*06c3fb27SDimitry Andric public: 36*06c3fb27SDimitry Andric static char ID; 37*06c3fb27SDimitry Andric 38*06c3fb27SDimitry Andric KCFI() : MachineFunctionPass(ID) {} 39*06c3fb27SDimitry Andric 40*06c3fb27SDimitry Andric StringRef getPassName() const override { return KCFI_PASS_NAME; } 41*06c3fb27SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 42*06c3fb27SDimitry Andric 43*06c3fb27SDimitry Andric private: 44*06c3fb27SDimitry Andric /// Machine instruction info used throughout the class. 45*06c3fb27SDimitry Andric const TargetInstrInfo *TII = nullptr; 46*06c3fb27SDimitry Andric 47*06c3fb27SDimitry Andric /// Target lowering for arch-specific parts. 48*06c3fb27SDimitry Andric const TargetLowering *TLI = nullptr; 49*06c3fb27SDimitry Andric 50*06c3fb27SDimitry Andric /// Emits a KCFI check before an indirect call. 51*06c3fb27SDimitry Andric /// \returns true if the check was added and false otherwise. 52*06c3fb27SDimitry Andric bool emitCheck(MachineBasicBlock &MBB, 53*06c3fb27SDimitry Andric MachineBasicBlock::instr_iterator I) const; 54*06c3fb27SDimitry Andric }; 55*06c3fb27SDimitry Andric 56*06c3fb27SDimitry Andric char KCFI::ID = 0; 57*06c3fb27SDimitry Andric } // end anonymous namespace 58*06c3fb27SDimitry Andric 59*06c3fb27SDimitry Andric INITIALIZE_PASS(KCFI, DEBUG_TYPE, KCFI_PASS_NAME, false, false) 60*06c3fb27SDimitry Andric 61*06c3fb27SDimitry Andric FunctionPass *llvm::createKCFIPass() { return new KCFI(); } 62*06c3fb27SDimitry Andric 63*06c3fb27SDimitry Andric bool KCFI::emitCheck(MachineBasicBlock &MBB, 64*06c3fb27SDimitry Andric MachineBasicBlock::instr_iterator MBBI) const { 65*06c3fb27SDimitry Andric assert(TII && "Target instruction info was not initialized"); 66*06c3fb27SDimitry Andric assert(TLI && "Target lowering was not initialized"); 67*06c3fb27SDimitry Andric 68*06c3fb27SDimitry Andric // If the call instruction is bundled, we can only emit a check safely if 69*06c3fb27SDimitry Andric // it's the first instruction in the bundle. 70*06c3fb27SDimitry Andric if (MBBI->isBundled() && !std::prev(MBBI)->isBundle()) 71*06c3fb27SDimitry Andric report_fatal_error("Cannot emit a KCFI check for a bundled call"); 72*06c3fb27SDimitry Andric 73*06c3fb27SDimitry Andric // Emit a KCFI check for the call instruction at MBBI. The implementation 74*06c3fb27SDimitry Andric // must unfold memory operands if applicable. 75*06c3fb27SDimitry Andric MachineInstr *Check = TLI->EmitKCFICheck(MBB, MBBI, TII); 76*06c3fb27SDimitry Andric 77*06c3fb27SDimitry Andric // Clear the original call's CFI type. 78*06c3fb27SDimitry Andric assert(MBBI->isCall() && "Unexpected instruction type"); 79*06c3fb27SDimitry Andric MBBI->setCFIType(*MBB.getParent(), 0); 80*06c3fb27SDimitry Andric 81*06c3fb27SDimitry Andric // If not already bundled, bundle the check and the call to prevent 82*06c3fb27SDimitry Andric // further changes. 83*06c3fb27SDimitry Andric if (!MBBI->isBundled()) 84*06c3fb27SDimitry Andric finalizeBundle(MBB, Check->getIterator(), std::next(MBBI->getIterator())); 85*06c3fb27SDimitry Andric 86*06c3fb27SDimitry Andric ++NumKCFIChecksAdded; 87*06c3fb27SDimitry Andric return true; 88*06c3fb27SDimitry Andric } 89*06c3fb27SDimitry Andric 90*06c3fb27SDimitry Andric bool KCFI::runOnMachineFunction(MachineFunction &MF) { 91*06c3fb27SDimitry Andric const Module *M = MF.getMMI().getModule(); 92*06c3fb27SDimitry Andric if (!M->getModuleFlag("kcfi")) 93*06c3fb27SDimitry Andric return false; 94*06c3fb27SDimitry Andric 95*06c3fb27SDimitry Andric const auto &SubTarget = MF.getSubtarget(); 96*06c3fb27SDimitry Andric TII = SubTarget.getInstrInfo(); 97*06c3fb27SDimitry Andric TLI = SubTarget.getTargetLowering(); 98*06c3fb27SDimitry Andric 99*06c3fb27SDimitry Andric bool Changed = false; 100*06c3fb27SDimitry Andric for (MachineBasicBlock &MBB : MF) { 101*06c3fb27SDimitry Andric // Use instr_iterator because we don't want to skip bundles. 102*06c3fb27SDimitry Andric for (MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), 103*06c3fb27SDimitry Andric MIE = MBB.instr_end(); 104*06c3fb27SDimitry Andric MII != MIE; ++MII) { 105*06c3fb27SDimitry Andric if (MII->isCall() && MII->getCFIType()) 106*06c3fb27SDimitry Andric Changed |= emitCheck(MBB, MII); 107*06c3fb27SDimitry Andric } 108*06c3fb27SDimitry Andric } 109*06c3fb27SDimitry Andric 110*06c3fb27SDimitry Andric return Changed; 111*06c3fb27SDimitry Andric } 112