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