From fd6f92d5cb962a2b72c105dd8440ba831019964c Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 15 Dec 2015 23:00:20 +0000 Subject: Cross-DSO control flow integrity (Clang part). Clang-side cross-DSO CFI. * Adds a command line flag -f[no-]sanitize-cfi-cross-dso. * Links a runtime library when enabled. * Emits __cfi_slowpath calls is bitset test fails. * Emits extra hash-based bitsets for external CFI checks. * Sets a module flag to enable __cfi_check generation during LTO. This mode does not yet support diagnostics. llvm-svn: 255694 --- clang/lib/CodeGen/CodeGenModule.cpp | 102 +++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 18 deletions(-) (limited to 'clang/lib/CodeGen/CodeGenModule.cpp') diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b207bac3dee..3b3fc877bf4 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -53,6 +53,7 @@ #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MD5.h" using namespace clang; using namespace CodeGen; @@ -439,6 +440,11 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth); } + if (CodeGenOpts.SanitizeCfiCrossDso) { + // Indicate that we want cross-DSO control flow integrity checks. + getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1); + } + if (uint32_t PLevel = Context.getLangOpts().PICLevel) { llvm::PICLevel::Level PL = llvm::PICLevel::Default; switch (PLevel) { @@ -736,6 +742,21 @@ void CodeGenModule::setFunctionDLLStorageClass(GlobalDecl GD, llvm::Function *F) F->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass); } +llvm::ConstantInt * +CodeGenModule::CreateCfiIdForTypeMetadata(llvm::Metadata *MD) { + llvm::MDString *MDS = dyn_cast(MD); + if (!MDS) return nullptr; + + llvm::MD5 md5; + llvm::MD5::MD5Result result; + md5.update(MDS->getString()); + md5.final(result); + uint64_t id = 0; + for (int i = 0; i < 8; ++i) + id |= static_cast(result[i]) << (i * 8); + return llvm::ConstantInt::get(Int64Ty, id); +} + void CodeGenModule::setFunctionDefinitionAttributes(const FunctionDecl *D, llvm::Function *F) { setNonAliasAttributes(D, F); @@ -928,6 +949,49 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, } } +void CodeGenModule::CreateFunctionBitSetEntry(const FunctionDecl *FD, + llvm::Function *F) { + // Only if we are checking indirect calls. + if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall)) + return; + + // Non-static class methods are handled via vtable pointer checks elsewhere. + if (isa(FD) && !cast(FD)->isStatic()) + return; + + // Additionally, if building with cross-DSO support... + if (CodeGenOpts.SanitizeCfiCrossDso) { + // Don't emit entries for function declarations. In cross-DSO mode these are + // handled with better precision at run time. + if (!FD->hasBody()) + return; + // Skip available_externally functions. They won't be codegen'ed in the + // current module anyway. + if (getContext().GetGVALinkageForFunction(FD) == GVA_AvailableExternally) + return; + } + + llvm::NamedMDNode *BitsetsMD = + getModule().getOrInsertNamedMetadata("llvm.bitsets"); + + llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType()); + llvm::Metadata *BitsetOps[] = { + MD, llvm::ConstantAsMetadata::get(F), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))}; + BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps)); + + // Emit a hash-based bit set entry for cross-DSO calls. + if (CodeGenOpts.SanitizeCfiCrossDso) { + if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) { + llvm::Metadata *BitsetOps2[] = { + llvm::ConstantAsMetadata::get(TypeId), + llvm::ConstantAsMetadata::get(F), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))}; + BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2)); + } + } +} + void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction, bool IsThunk) { @@ -970,19 +1034,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, F->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoBuiltin); - // If we are checking indirect calls and this is not a non-static member - // function, emit a bit set entry for the function type. - if (LangOpts.Sanitize.has(SanitizerKind::CFIICall) && - !(isa(FD) && !cast(FD)->isStatic())) { - llvm::NamedMDNode *BitsetsMD = - getModule().getOrInsertNamedMetadata("llvm.bitsets"); - - llvm::Metadata *BitsetOps[] = { - CreateMetadataIdentifierForType(FD->getType()), - llvm::ConstantAsMetadata::get(F), - llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))}; - BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps)); - } + CreateFunctionBitSetEntry(FD, F); } void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) { @@ -3874,14 +3926,28 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) { return InternalId; } -llvm::MDTuple *CodeGenModule::CreateVTableBitSetEntry( - llvm::GlobalVariable *VTable, CharUnits Offset, const CXXRecordDecl *RD) { +void CodeGenModule::CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD, + llvm::GlobalVariable *VTable, + CharUnits Offset, + const CXXRecordDecl *RD) { + llvm::Metadata *MD = + CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)); llvm::Metadata *BitsetOps[] = { - CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)), - llvm::ConstantAsMetadata::get(VTable), + MD, llvm::ConstantAsMetadata::get(VTable), llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))}; - return llvm::MDTuple::get(getLLVMContext(), BitsetOps); + BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps)); + + if (CodeGenOpts.SanitizeCfiCrossDso) { + if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) { + llvm::Metadata *BitsetOps2[] = { + llvm::ConstantAsMetadata::get(TypeId), + llvm::ConstantAsMetadata::get(VTable), + llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))}; + BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2)); + } + } } // Fills in the supplied string map with the set of target features for the -- cgit v1.2.3