106c3fb27SDimitry Andric //===---- KCFI.cpp - Implements Kernel Control-Flow Integrity (KCFI) ------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric // 906c3fb27SDimitry Andric // This pass implements Kernel Control-Flow Integrity (KCFI) indirect call 1006c3fb27SDimitry Andric // check lowering. For each call instruction with a cfi-type attribute, it 1106c3fb27SDimitry Andric // emits an arch-specific check before the call, and bundles the check and 1206c3fb27SDimitry Andric // the call to prevent unintentional modifications. 1306c3fb27SDimitry Andric // 1406c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1506c3fb27SDimitry Andric 1606c3fb27SDimitry Andric #include "llvm/ADT/Statistic.h" 1706c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 1806c3fb27SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 1906c3fb27SDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h" 2006c3fb27SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 2106c3fb27SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 2206c3fb27SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 2306c3fb27SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 24*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 2506c3fb27SDimitry Andric #include "llvm/InitializePasses.h" 2606c3fb27SDimitry Andric 2706c3fb27SDimitry Andric using namespace llvm; 2806c3fb27SDimitry Andric 2906c3fb27SDimitry Andric #define DEBUG_TYPE "kcfi" 3006c3fb27SDimitry Andric #define KCFI_PASS_NAME "Insert KCFI indirect call checks" 3106c3fb27SDimitry Andric 3206c3fb27SDimitry Andric STATISTIC(NumKCFIChecksAdded, "Number of indirect call checks added"); 3306c3fb27SDimitry Andric 3406c3fb27SDimitry Andric namespace { 3506c3fb27SDimitry Andric class KCFI : public MachineFunctionPass { 3606c3fb27SDimitry Andric public: 3706c3fb27SDimitry Andric static char ID; 3806c3fb27SDimitry Andric 3906c3fb27SDimitry Andric KCFI() : MachineFunctionPass(ID) {} 4006c3fb27SDimitry Andric 4106c3fb27SDimitry Andric StringRef getPassName() const override { return KCFI_PASS_NAME; } 4206c3fb27SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 4306c3fb27SDimitry Andric 4406c3fb27SDimitry Andric private: 4506c3fb27SDimitry Andric /// Machine instruction info used throughout the class. 4606c3fb27SDimitry Andric const TargetInstrInfo *TII = nullptr; 4706c3fb27SDimitry Andric 4806c3fb27SDimitry Andric /// Target lowering for arch-specific parts. 4906c3fb27SDimitry Andric const TargetLowering *TLI = nullptr; 5006c3fb27SDimitry Andric 5106c3fb27SDimitry Andric /// Emits a KCFI check before an indirect call. 5206c3fb27SDimitry Andric /// \returns true if the check was added and false otherwise. 5306c3fb27SDimitry Andric bool emitCheck(MachineBasicBlock &MBB, 5406c3fb27SDimitry Andric MachineBasicBlock::instr_iterator I) const; 5506c3fb27SDimitry Andric }; 5606c3fb27SDimitry Andric 5706c3fb27SDimitry Andric char KCFI::ID = 0; 5806c3fb27SDimitry Andric } // end anonymous namespace 5906c3fb27SDimitry Andric 6006c3fb27SDimitry Andric INITIALIZE_PASS(KCFI, DEBUG_TYPE, KCFI_PASS_NAME, false, false) 6106c3fb27SDimitry Andric 6206c3fb27SDimitry Andric FunctionPass *llvm::createKCFIPass() { return new KCFI(); } 6306c3fb27SDimitry Andric 6406c3fb27SDimitry Andric bool KCFI::emitCheck(MachineBasicBlock &MBB, 6506c3fb27SDimitry Andric MachineBasicBlock::instr_iterator MBBI) const { 6606c3fb27SDimitry Andric assert(TII && "Target instruction info was not initialized"); 6706c3fb27SDimitry Andric assert(TLI && "Target lowering was not initialized"); 6806c3fb27SDimitry Andric 6906c3fb27SDimitry Andric // If the call instruction is bundled, we can only emit a check safely if 7006c3fb27SDimitry Andric // it's the first instruction in the bundle. 7106c3fb27SDimitry Andric if (MBBI->isBundled() && !std::prev(MBBI)->isBundle()) 7206c3fb27SDimitry Andric report_fatal_error("Cannot emit a KCFI check for a bundled call"); 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric // Emit a KCFI check for the call instruction at MBBI. The implementation 7506c3fb27SDimitry Andric // must unfold memory operands if applicable. 7606c3fb27SDimitry Andric MachineInstr *Check = TLI->EmitKCFICheck(MBB, MBBI, TII); 7706c3fb27SDimitry Andric 7806c3fb27SDimitry Andric // Clear the original call's CFI type. 7906c3fb27SDimitry Andric assert(MBBI->isCall() && "Unexpected instruction type"); 8006c3fb27SDimitry Andric MBBI->setCFIType(*MBB.getParent(), 0); 8106c3fb27SDimitry Andric 8206c3fb27SDimitry Andric // If not already bundled, bundle the check and the call to prevent 8306c3fb27SDimitry Andric // further changes. 8406c3fb27SDimitry Andric if (!MBBI->isBundled()) 8506c3fb27SDimitry Andric finalizeBundle(MBB, Check->getIterator(), std::next(MBBI->getIterator())); 8606c3fb27SDimitry Andric 8706c3fb27SDimitry Andric ++NumKCFIChecksAdded; 8806c3fb27SDimitry Andric return true; 8906c3fb27SDimitry Andric } 9006c3fb27SDimitry Andric 9106c3fb27SDimitry Andric bool KCFI::runOnMachineFunction(MachineFunction &MF) { 92*0fca6ea1SDimitry Andric const Module *M = MF.getFunction().getParent(); 9306c3fb27SDimitry Andric if (!M->getModuleFlag("kcfi")) 9406c3fb27SDimitry Andric return false; 9506c3fb27SDimitry Andric 9606c3fb27SDimitry Andric const auto &SubTarget = MF.getSubtarget(); 9706c3fb27SDimitry Andric TII = SubTarget.getInstrInfo(); 9806c3fb27SDimitry Andric TLI = SubTarget.getTargetLowering(); 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric bool Changed = false; 10106c3fb27SDimitry Andric for (MachineBasicBlock &MBB : MF) { 10206c3fb27SDimitry Andric // Use instr_iterator because we don't want to skip bundles. 10306c3fb27SDimitry Andric for (MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), 10406c3fb27SDimitry Andric MIE = MBB.instr_end(); 10506c3fb27SDimitry Andric MII != MIE; ++MII) { 10606c3fb27SDimitry Andric if (MII->isCall() && MII->getCFIType()) 10706c3fb27SDimitry Andric Changed |= emitCheck(MBB, MII); 10806c3fb27SDimitry Andric } 10906c3fb27SDimitry Andric } 11006c3fb27SDimitry Andric 11106c3fb27SDimitry Andric return Changed; 11206c3fb27SDimitry Andric } 113