|  | //===---- KCFI.cpp - Implements Kernel Control-Flow Integrity (KCFI) ------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This pass implements Kernel Control-Flow Integrity (KCFI) indirect call | 
|  | // check lowering. For each call instruction with a cfi-type attribute, it | 
|  | // emits an arch-specific check before the call, and bundles the check and | 
|  | // the call to prevent unintentional modifications. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/MachineInstrBundle.h" | 
|  | #include "llvm/CodeGen/MachineModuleInfo.h" | 
|  | #include "llvm/CodeGen/TargetInstrInfo.h" | 
|  | #include "llvm/CodeGen/TargetLowering.h" | 
|  | #include "llvm/CodeGen/TargetSubtargetInfo.h" | 
|  | #include "llvm/InitializePasses.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "kcfi" | 
|  | #define KCFI_PASS_NAME "Insert KCFI indirect call checks" | 
|  |  | 
|  | STATISTIC(NumKCFIChecksAdded, "Number of indirect call checks added"); | 
|  |  | 
|  | namespace { | 
|  | class KCFI : public MachineFunctionPass { | 
|  | public: | 
|  | static char ID; | 
|  |  | 
|  | KCFI() : MachineFunctionPass(ID) {} | 
|  |  | 
|  | StringRef getPassName() const override { return KCFI_PASS_NAME; } | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | private: | 
|  | /// Machine instruction info used throughout the class. | 
|  | const TargetInstrInfo *TII = nullptr; | 
|  |  | 
|  | /// Target lowering for arch-specific parts. | 
|  | const TargetLowering *TLI = nullptr; | 
|  |  | 
|  | /// Emits a KCFI check before an indirect call. | 
|  | /// \returns true if the check was added and false otherwise. | 
|  | bool emitCheck(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::instr_iterator I) const; | 
|  | }; | 
|  |  | 
|  | char KCFI::ID = 0; | 
|  | } // end anonymous namespace | 
|  |  | 
|  | INITIALIZE_PASS(KCFI, DEBUG_TYPE, KCFI_PASS_NAME, false, false) | 
|  |  | 
|  | FunctionPass *llvm::createKCFIPass() { return new KCFI(); } | 
|  |  | 
|  | bool KCFI::emitCheck(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::instr_iterator MBBI) const { | 
|  | assert(TII && "Target instruction info was not initialized"); | 
|  | assert(TLI && "Target lowering was not initialized"); | 
|  |  | 
|  | // If the call instruction is bundled, we can only emit a check safely if | 
|  | // it's the first instruction in the bundle. | 
|  | if (MBBI->isBundled() && !std::prev(MBBI)->isBundle()) | 
|  | report_fatal_error("Cannot emit a KCFI check for a bundled call"); | 
|  |  | 
|  | // Emit a KCFI check for the call instruction at MBBI. The implementation | 
|  | // must unfold memory operands if applicable. | 
|  | MachineInstr *Check = TLI->EmitKCFICheck(MBB, MBBI, TII); | 
|  |  | 
|  | // Clear the original call's CFI type. | 
|  | assert(MBBI->isCall() && "Unexpected instruction type"); | 
|  | MBBI->setCFIType(*MBB.getParent(), 0); | 
|  |  | 
|  | // If not already bundled, bundle the check and the call to prevent | 
|  | // further changes. | 
|  | if (!MBBI->isBundled()) | 
|  | finalizeBundle(MBB, Check->getIterator(), std::next(MBBI->getIterator())); | 
|  |  | 
|  | ++NumKCFIChecksAdded; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool KCFI::runOnMachineFunction(MachineFunction &MF) { | 
|  | const Module *M = MF.getMMI().getModule(); | 
|  | if (!M->getModuleFlag("kcfi")) | 
|  | return false; | 
|  |  | 
|  | const auto &SubTarget = MF.getSubtarget(); | 
|  | TII = SubTarget.getInstrInfo(); | 
|  | TLI = SubTarget.getTargetLowering(); | 
|  |  | 
|  | bool Changed = false; | 
|  | for (MachineBasicBlock &MBB : MF) { | 
|  | // Use instr_iterator because we don't want to skip bundles. | 
|  | for (MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), | 
|  | MIE = MBB.instr_end(); | 
|  | MII != MIE; ++MII) { | 
|  | if (MII->isCall() && MII->getCFIType()) | 
|  | Changed |= emitCheck(MBB, MII); | 
|  | } | 
|  | } | 
|  |  | 
|  | return Changed; | 
|  | } |