Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/KCFI.cpp
35269 views
//===-- KCFI.cpp - Generic KCFI operand bundle lowering ---------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This pass emits generic KCFI indirect call checks for targets that don't9// support lowering KCFI operand bundles in the back-end.10//11//===----------------------------------------------------------------------===//1213#include "llvm/Transforms/Instrumentation/KCFI.h"14#include "llvm/ADT/Statistic.h"15#include "llvm/IR/Constants.h"16#include "llvm/IR/DiagnosticInfo.h"17#include "llvm/IR/DiagnosticPrinter.h"18#include "llvm/IR/Function.h"19#include "llvm/IR/GlobalObject.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"2829using namespace llvm;3031#define DEBUG_TYPE "kcfi"3233STATISTIC(NumKCFIChecks, "Number of kcfi operands transformed into checks");3435namespace {36class DiagnosticInfoKCFI : public DiagnosticInfo {37const Twine &Msg;3839public:40DiagnosticInfoKCFI(const Twine &DiagMsg,41DiagnosticSeverity Severity = DS_Error)42: DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}43void print(DiagnosticPrinter &DP) const override { DP << Msg; }44};45} // namespace4647PreservedAnalyses KCFIPass::run(Function &F, FunctionAnalysisManager &AM) {48Module &M = *F.getParent();49if (!M.getModuleFlag("kcfi"))50return PreservedAnalyses::all();5152// Find call instructions with KCFI operand bundles.53SmallVector<CallInst *> KCFICalls;54for (Instruction &I : instructions(F)) {55if (auto *CI = dyn_cast<CallInst>(&I))56if (CI->getOperandBundle(LLVMContext::OB_kcfi))57KCFICalls.push_back(CI);58}5960if (KCFICalls.empty())61return PreservedAnalyses::all();6263LLVMContext &Ctx = M.getContext();64// patchable-function-prefix emits nops between the KCFI type identifier65// and the function start. As we don't know the size of the emitted nops,66// don't allow this attribute with generic lowering.67if (F.hasFnAttribute("patchable-function-prefix"))68Ctx.diagnose(69DiagnosticInfoKCFI("-fpatchable-function-entry=N,M, where M>0 is not "70"compatible with -fsanitize=kcfi on this target"));7172IntegerType *Int32Ty = Type::getInt32Ty(Ctx);73MDNode *VeryUnlikelyWeights = MDBuilder(Ctx).createUnlikelyBranchWeights();74Triple T(M.getTargetTriple());7576for (CallInst *CI : KCFICalls) {77// Get the expected hash value.78const uint32_t ExpectedHash =79cast<ConstantInt>(CI->getOperandBundle(LLVMContext::OB_kcfi)->Inputs[0])80->getZExtValue();8182// Drop the KCFI operand bundle.83CallBase *Call = CallBase::removeOperandBundle(CI, LLVMContext::OB_kcfi,84CI->getIterator());85assert(Call != CI);86Call->copyMetadata(*CI);87CI->replaceAllUsesWith(Call);88CI->eraseFromParent();8990if (!Call->isIndirectCall())91continue;9293// Emit a check and trap if the target hash doesn't match.94IRBuilder<> Builder(Call);95Value *FuncPtr = Call->getCalledOperand();96// ARM uses the least significant bit of the function pointer to select97// between ARM and Thumb modes for the callee. Instructions are always98// at least 16-bit aligned, so clear the LSB before we compute the hash99// location.100if (T.isARM() || T.isThumb()) {101FuncPtr = Builder.CreateIntToPtr(102Builder.CreateAnd(Builder.CreatePtrToInt(FuncPtr, Int32Ty),103ConstantInt::get(Int32Ty, -2)),104FuncPtr->getType());105}106Value *HashPtr = Builder.CreateConstInBoundsGEP1_32(Int32Ty, FuncPtr, -1);107Value *Test = Builder.CreateICmpNE(Builder.CreateLoad(Int32Ty, HashPtr),108ConstantInt::get(Int32Ty, ExpectedHash));109Instruction *ThenTerm =110SplitBlockAndInsertIfThen(Test, Call, false, VeryUnlikelyWeights);111Builder.SetInsertPoint(ThenTerm);112Builder.CreateCall(Intrinsic::getDeclaration(&M, Intrinsic::debugtrap));113++NumKCFIChecks;114}115116return PreservedAnalyses::none();117}118119120