1 //===-- KCFI.cpp - Generic KCFI operand bundle lowering ---------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass emits generic KCFI indirect call checks for targets that don't
10 // support lowering KCFI operand bundles in the back-end.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Transforms/Instrumentation/KCFI.h"
15 #include "llvm/ADT/Statistic.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/DiagnosticInfo.h"
18 #include "llvm/IR/DiagnosticPrinter.h"
19 #include "llvm/IR/Function.h"
20 #include "llvm/IR/IRBuilder.h"
21 #include "llvm/IR/InstIterator.h"
22 #include "llvm/IR/Instructions.h"
23 #include "llvm/IR/Intrinsics.h"
24 #include "llvm/IR/MDBuilder.h"
25 #include "llvm/IR/Module.h"
26 #include "llvm/Target/TargetMachine.h"
27 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
31 #define DEBUG_TYPE "kcfi"
33 STATISTIC(NumKCFIChecks
, "Number of kcfi operands transformed into checks");
36 class DiagnosticInfoKCFI
: public DiagnosticInfo
{
40 DiagnosticInfoKCFI(const Twine
&DiagMsg
,
41 DiagnosticSeverity Severity
= DS_Error
)
42 : DiagnosticInfo(DK_Linker
, Severity
), Msg(DiagMsg
) {}
43 void print(DiagnosticPrinter
&DP
) const override
{ DP
<< Msg
; }
47 PreservedAnalyses
KCFIPass::run(Function
&F
, FunctionAnalysisManager
&AM
) {
48 Module
&M
= *F
.getParent();
49 if (!M
.getModuleFlag("kcfi"))
50 return PreservedAnalyses::all();
52 // Find call instructions with KCFI operand bundles.
53 SmallVector
<CallInst
*> KCFICalls
;
54 for (Instruction
&I
: instructions(F
)) {
55 if (auto *CI
= dyn_cast
<CallInst
>(&I
))
56 if (CI
->getOperandBundle(LLVMContext::OB_kcfi
))
57 KCFICalls
.push_back(CI
);
60 if (KCFICalls
.empty())
61 return PreservedAnalyses::all();
63 LLVMContext
&Ctx
= M
.getContext();
64 // patchable-function-prefix emits nops between the KCFI type identifier
65 // and the function start. As we don't know the size of the emitted nops,
66 // don't allow this attribute with generic lowering.
67 if (F
.hasFnAttribute("patchable-function-prefix"))
69 DiagnosticInfoKCFI("-fpatchable-function-entry=N,M, where M>0 is not "
70 "compatible with -fsanitize=kcfi on this target"));
72 IntegerType
*Int32Ty
= Type::getInt32Ty(Ctx
);
73 MDNode
*VeryUnlikelyWeights
= MDBuilder(Ctx
).createUnlikelyBranchWeights();
74 Triple
T(M
.getTargetTriple());
76 for (CallInst
*CI
: KCFICalls
) {
77 // Get the expected hash value.
78 const uint32_t ExpectedHash
=
79 cast
<ConstantInt
>(CI
->getOperandBundle(LLVMContext::OB_kcfi
)->Inputs
[0])
82 // Drop the KCFI operand bundle.
83 CallBase
*Call
= CallBase::removeOperandBundle(CI
, LLVMContext::OB_kcfi
,
86 Call
->copyMetadata(*CI
);
87 CI
->replaceAllUsesWith(Call
);
88 CI
->eraseFromParent();
90 if (!Call
->isIndirectCall())
93 // Emit a check and trap if the target hash doesn't match.
94 IRBuilder
<> Builder(Call
);
95 Value
*FuncPtr
= Call
->getCalledOperand();
96 // ARM uses the least significant bit of the function pointer to select
97 // between ARM and Thumb modes for the callee. Instructions are always
98 // at least 16-bit aligned, so clear the LSB before we compute the hash
100 if (T
.isARM() || T
.isThumb()) {
101 FuncPtr
= Builder
.CreateIntToPtr(
102 Builder
.CreateAnd(Builder
.CreatePtrToInt(FuncPtr
, Int32Ty
),
103 ConstantInt::get(Int32Ty
, -2)),
106 Value
*HashPtr
= Builder
.CreateConstInBoundsGEP1_32(Int32Ty
, FuncPtr
, -1);
107 Value
*Test
= Builder
.CreateICmpNE(Builder
.CreateLoad(Int32Ty
, HashPtr
),
108 ConstantInt::get(Int32Ty
, ExpectedHash
));
109 Instruction
*ThenTerm
=
110 SplitBlockAndInsertIfThen(Test
, Call
, false, VeryUnlikelyWeights
);
111 Builder
.SetInsertPoint(ThenTerm
);
112 Builder
.CreateIntrinsic(Intrinsic::debugtrap
, {}, {});
116 return PreservedAnalyses::none();