1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
//===---- X86KCFI.cpp - Implements 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 file implements KCFI indirect call checking.
//
//===----------------------------------------------------------------------===//
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#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"
using namespace llvm;
#define DEBUG_TYPE "x86-kcfi"
#define X86_KCFI_PASS_NAME "Insert KCFI indirect call checks"
STATISTIC(NumKCFIChecksAdded, "Number of indirect call checks added");
namespace {
class X86KCFI : public MachineFunctionPass {
public:
static char ID;
X86KCFI() : MachineFunctionPass(ID) {}
StringRef getPassName() const override { return X86_KCFI_PASS_NAME; }
bool runOnMachineFunction(MachineFunction &MF) override;
private:
/// Machine instruction info used throughout the class.
const X86InstrInfo *TII = 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 X86KCFI::ID = 0;
} // end anonymous namespace
INITIALIZE_PASS(X86KCFI, DEBUG_TYPE, X86_KCFI_PASS_NAME, false, false)
FunctionPass *llvm::createX86KCFIPass() { return new X86KCFI(); }
bool X86KCFI::emitCheck(MachineBasicBlock &MBB,
MachineBasicBlock::instr_iterator MBBI) const {
assert(TII && "Target instruction info 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");
MachineFunction &MF = *MBB.getParent();
// If the call target is a memory operand, unfold it and use R11 for the
// call, so KCFI_CHECK won't have to recompute the address.
switch (MBBI->getOpcode()) {
case X86::CALL64m:
case X86::CALL64m_NT:
case X86::TAILJMPm64:
case X86::TAILJMPm64_REX: {
MachineBasicBlock::instr_iterator OrigCall = MBBI;
SmallVector<MachineInstr *, 2> NewMIs;
if (!TII->unfoldMemoryOperand(MF, *OrigCall, X86::R11, /*UnfoldLoad=*/true,
/*UnfoldStore=*/false, NewMIs))
report_fatal_error("Failed to unfold memory operand for a KCFI check");
for (auto *NewMI : NewMIs)
MBBI = MBB.insert(OrigCall, NewMI);
assert(MBBI->isCall() &&
"Unexpected instruction after memory operand unfolding");
if (OrigCall->shouldUpdateCallSiteInfo())
MF.moveCallSiteInfo(&*OrigCall, &*MBBI);
MBBI->setCFIType(MF, OrigCall->getCFIType());
OrigCall->eraseFromParent();
break;
}
default:
break;
}
MachineInstr *Check =
BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(X86::KCFI_CHECK))
.getInstr();
MachineOperand &Target = MBBI->getOperand(0);
switch (MBBI->getOpcode()) {
case X86::CALL64r:
case X86::CALL64r_NT:
case X86::TAILJMPr64:
case X86::TAILJMPr64_REX:
assert(Target.isReg() && "Unexpected target operand for an indirect call");
Check->addOperand(MachineOperand::CreateReg(Target.getReg(), false));
Target.setIsRenamable(false);
break;
case X86::CALL64pcrel32:
case X86::TAILJMPd64:
assert(Target.isSymbol() && "Unexpected target operand for a direct call");
// X86TargetLowering::EmitLoweredIndirectThunk always uses r11 for
// 64-bit indirect thunk calls.
assert(StringRef(Target.getSymbolName()).endswith("_r11") &&
"Unexpected register for an indirect thunk call");
Check->addOperand(MachineOperand::CreateReg(X86::R11, false));
break;
default:
llvm_unreachable("Unexpected CFI call opcode");
}
Check->addOperand(MachineOperand::CreateImm(MBBI->getCFIType()));
MBBI->setCFIType(MF, 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 X86KCFI::runOnMachineFunction(MachineFunction &MF) {
const Module *M = MF.getMMI().getModule();
if (!M->getModuleFlag("kcfi"))
return false;
const auto &SubTarget = MF.getSubtarget<X86Subtarget>();
TII = SubTarget.getInstrInfo();
bool Changed = false;
for (MachineBasicBlock &MBB : MF) {
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;
}
|