|
48 | 48 | #include "clang/CodeGen/ConstantInitBuilder.h"
|
49 | 49 | #include "clang/Frontend/FrontendDiagnostic.h"
|
50 | 50 | #include "llvm/ADT/STLExtras.h"
|
| 51 | +#include "llvm/ADT/StringExtras.h" |
51 | 52 | #include "llvm/ADT/StringSwitch.h"
|
52 | 53 | #include "llvm/ADT/Triple.h"
|
53 | 54 | #include "llvm/Analysis/TargetLibraryInfo.h"
|
|
67 | 68 | #include "llvm/Support/MD5.h"
|
68 | 69 | #include "llvm/Support/TimeProfiler.h"
|
69 | 70 | #include "llvm/Support/X86TargetParser.h"
|
| 71 | +#include "llvm/Support/xxhash.h" |
70 | 72 |
|
71 | 73 | using namespace clang;
|
72 | 74 | using namespace CodeGen;
|
@@ -577,6 +579,8 @@ void CodeGenModule::Release() {
|
577 | 579 | CodeGenFunction(*this).EmitCfiCheckFail();
|
578 | 580 | CodeGenFunction(*this).EmitCfiCheckStub();
|
579 | 581 | }
|
| 582 | + if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) |
| 583 | + finalizeKCFITypes(); |
580 | 584 | emitAtAvailableLinkGuard();
|
581 | 585 | if (Context.getTargetInfo().getTriple().isWasm())
|
582 | 586 | EmitMainVoidAlias();
|
@@ -759,6 +763,9 @@ void CodeGenModule::Release() {
|
759 | 763 | CodeGenOpts.SanitizeCfiCanonicalJumpTables);
|
760 | 764 | }
|
761 | 765 |
|
| 766 | + if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) |
| 767 | + getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1); |
| 768 | + |
762 | 769 | if (CodeGenOpts.CFProtectionReturn &&
|
763 | 770 | Target.checkCFProtectionReturnSupported(getDiags())) {
|
764 | 771 | // Indicate that we want to instrument return control flow protection.
|
@@ -1669,6 +1676,20 @@ llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
|
1669 | 1676 | return llvm::ConstantInt::get(Int64Ty, llvm::MD5Hash(MDS->getString()));
|
1670 | 1677 | }
|
1671 | 1678 |
|
| 1679 | +llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) { |
| 1680 | + if (auto *FnType = T->getAs<FunctionProtoType>()) |
| 1681 | + T = getContext().getFunctionType( |
| 1682 | + FnType->getReturnType(), FnType->getParamTypes(), |
| 1683 | + FnType->getExtProtoInfo().withExceptionSpec(EST_None)); |
| 1684 | + |
| 1685 | + std::string OutName; |
| 1686 | + llvm::raw_string_ostream Out(OutName); |
| 1687 | + getCXXABI().getMangleContext().mangleTypeName(T, Out); |
| 1688 | + |
| 1689 | + return llvm::ConstantInt::get(Int32Ty, |
| 1690 | + static_cast<uint32_t>(llvm::xxHash64(OutName))); |
| 1691 | +} |
| 1692 | + |
1672 | 1693 | void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
|
1673 | 1694 | const CGFunctionInfo &Info,
|
1674 | 1695 | llvm::Function *F, bool IsThunk) {
|
@@ -2287,6 +2308,57 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
|
2287 | 2308 | F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
|
2288 | 2309 | }
|
2289 | 2310 |
|
| 2311 | +void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) { |
| 2312 | + if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) |
| 2313 | + return; |
| 2314 | + |
| 2315 | + llvm::LLVMContext &Ctx = F->getContext(); |
| 2316 | + llvm::MDBuilder MDB(Ctx); |
| 2317 | + F->setMetadata(llvm::LLVMContext::MD_kcfi_type, |
| 2318 | + llvm::MDNode::get( |
| 2319 | + Ctx, MDB.createConstant(CreateKCFITypeId(FD->getType())))); |
| 2320 | +} |
| 2321 | + |
| 2322 | +static bool allowKCFIIdentifier(StringRef Name) { |
| 2323 | + // KCFI type identifier constants are only necessary for external assembly |
| 2324 | + // functions, which means it's safe to skip unusual names. Subset of |
| 2325 | + // MCAsmInfo::isAcceptableChar() and MCAsmInfoXCOFF::isAcceptableChar(). |
| 2326 | + return llvm::all_of(Name, [](const char &C) { |
| 2327 | + return llvm::isAlnum(C) || C == '_' || C == '.'; |
| 2328 | + }); |
| 2329 | +} |
| 2330 | + |
| 2331 | +void CodeGenModule::finalizeKCFITypes() { |
| 2332 | + llvm::Module &M = getModule(); |
| 2333 | + for (auto &F : M.functions()) { |
| 2334 | + // Remove KCFI type metadata from non-address-taken local functions. |
| 2335 | + bool AddressTaken = F.hasAddressTaken(); |
| 2336 | + if (!AddressTaken && F.hasLocalLinkage()) |
| 2337 | + F.eraseMetadata(llvm::LLVMContext::MD_kcfi_type); |
| 2338 | + |
| 2339 | + // Generate a constant with the expected KCFI type identifier for all |
| 2340 | + // address-taken function declarations to support annotating indirectly |
| 2341 | + // called assembly functions. |
| 2342 | + if (!AddressTaken || !F.isDeclaration()) |
| 2343 | + continue; |
| 2344 | + |
| 2345 | + const llvm::ConstantInt *Type; |
| 2346 | + if (const llvm::MDNode *MD = F.getMetadata(llvm::LLVMContext::MD_kcfi_type)) |
| 2347 | + Type = llvm::mdconst::extract<llvm::ConstantInt>(MD->getOperand(0)); |
| 2348 | + else |
| 2349 | + continue; |
| 2350 | + |
| 2351 | + StringRef Name = F.getName(); |
| 2352 | + if (!allowKCFIIdentifier(Name)) |
| 2353 | + continue; |
| 2354 | + |
| 2355 | + std::string Asm = (".weak __kcfi_typeid_" + Name + "\n.set __kcfi_typeid_" + |
| 2356 | + Name + ", " + Twine(Type->getZExtValue()) + "\n") |
| 2357 | + .str(); |
| 2358 | + M.appendModuleInlineAsm(Asm); |
| 2359 | + } |
| 2360 | +} |
| 2361 | + |
2290 | 2362 | void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
2291 | 2363 | bool IsIncompleteFunction,
|
2292 | 2364 | bool IsThunk) {
|
@@ -2369,6 +2441,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
|
2369 | 2441 | !CodeGenOpts.SanitizeCfiCanonicalJumpTables)
|
2370 | 2442 | CreateFunctionTypeMetadataForIcall(FD, F);
|
2371 | 2443 |
|
| 2444 | + if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) |
| 2445 | + setKCFIType(FD, F); |
| 2446 | + |
2372 | 2447 | if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
|
2373 | 2448 | getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
|
2374 | 2449 |
|
|
0 commit comments