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;
}
|