|
@@ -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<llvm::MDString>(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<uint64_t>(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<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(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<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(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
|