summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2015-02-20 20:30:56 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2015-02-20 20:30:56 +0000
commita4ccff32818c05c9f2d7a2a6503866d13636b664 (patch)
treed0853e78880e850956141ea043fecb36250e5842 /clang/lib/CodeGen
parente6909c8e8ba07acb5e6366186fe186c91054e93c (diff)
downloadbcm5719-llvm-a4ccff32818c05c9f2d7a2a6503866d13636b664.tar.gz
bcm5719-llvm-a4ccff32818c05c9f2d7a2a6503866d13636b664.zip
Implement Control Flow Integrity for virtual calls.
This patch introduces the -fsanitize=cfi-vptr flag, which enables a control flow integrity scheme that checks that virtual calls take place using a vptr of the correct dynamic type. More details in the new docs/ControlFlowIntegrity.rst file. It also introduces the -fsanitize=cfi flag, which is currently a synonym for -fsanitize=cfi-vptr, but will eventually cover all CFI checks implemented in Clang. Differential Revision: http://reviews.llvm.org/D7424 llvm-svn: 230055
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGClass.cpp33
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp61
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h3
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h5
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp4
5 files changed, 106 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 524697cd230..66ab6152c21 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -24,6 +24,7 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -2087,6 +2088,38 @@ llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
return VTable;
}
+void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXMethodDecl *MD,
+ llvm::Value *VTable) {
+ if (!SanOpts.has(SanitizerKind::CFIVptr))
+ return;
+
+ const CXXRecordDecl *RD = MD->getParent();
+ // FIXME: Add blacklisting scheme.
+ if (RD->isInStdNamespace())
+ return;
+
+ std::string OutName;
+ llvm::raw_string_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXVTableBitSet(RD, Out);
+
+ llvm::Value *BitSetName = llvm::MetadataAsValue::get(
+ getLLVMContext(), llvm::MDString::get(getLLVMContext(), Out.str()));
+
+ llvm::Value *BitSetTest = Builder.CreateCall2(
+ CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
+ Builder.CreateBitCast(VTable, CGM.Int8PtrTy), BitSetName);
+
+ llvm::BasicBlock *ContBlock = createBasicBlock("vtable.check.cont");
+ llvm::BasicBlock *TrapBlock = createBasicBlock("vtable.check.trap");
+
+ Builder.CreateCondBr(BitSetTest, ContBlock, TrapBlock);
+
+ EmitBlock(TrapBlock);
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
+ Builder.CreateUnreachable();
+
+ EmitBlock(ContBlock);
+}
// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
// quite what we want.
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 77244677650..14116e498ee 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -669,6 +669,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
VTLayout->getNumVTableThunks(), RTTI);
VTable->setInitializer(Init);
+ CGM.EmitVTableBitSetEntries(VTable, *VTLayout.get());
+
return VTable;
}
@@ -837,3 +839,62 @@ void CodeGenModule::EmitDeferredVTables() {
"deferred extra v-tables during v-table emission?");
DeferredVTables.clear();
}
+
+void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
+ const VTableLayout &VTLayout) {
+ if (!LangOpts.Sanitize.has(SanitizerKind::CFIVptr))
+ return;
+
+ llvm::Metadata *VTableMD = llvm::ConstantAsMetadata::get(VTable);
+
+ std::vector<llvm::MDTuple *> BitsetEntries;
+ // Create a bit set entry for each address point.
+ for (auto &&AP : VTLayout.getAddressPoints()) {
+ // FIXME: Add blacklisting scheme.
+ if (AP.first.getBase()->isInStdNamespace())
+ continue;
+
+ std::string OutName;
+ llvm::raw_string_ostream Out(OutName);
+ getCXXABI().getMangleContext().mangleCXXVTableBitSet(AP.first.getBase(),
+ Out);
+
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ uint64_t AddrPointOffset = AP.second * PointerWidth.getQuantity();
+
+ llvm::Metadata *BitsetOps[] = {
+ llvm::MDString::get(getLLVMContext(), Out.str()),
+ VTableMD,
+ llvm::ConstantAsMetadata::get(
+ llvm::ConstantInt::get(Int64Ty, AddrPointOffset))};
+ llvm::MDTuple *BitsetEntry =
+ llvm::MDTuple::get(getLLVMContext(), BitsetOps);
+ BitsetEntries.push_back(BitsetEntry);
+ }
+
+ // Sort the bit set entries for determinism.
+ std::sort(BitsetEntries.begin(), BitsetEntries.end(), [](llvm::MDTuple *T1,
+ llvm::MDTuple *T2) {
+ StringRef S1 = cast<llvm::MDString>(T1->getOperand(0))->getString();
+ StringRef S2 = cast<llvm::MDString>(T2->getOperand(0))->getString();
+ if (S1 < S2)
+ return true;
+ if (S1 != S2)
+ return false;
+
+ uint64_t Offset1 = cast<llvm::ConstantInt>(
+ cast<llvm::ConstantAsMetadata>(T1->getOperand(2))
+ ->getValue())->getZExtValue();
+ uint64_t Offset2 = cast<llvm::ConstantInt>(
+ cast<llvm::ConstantAsMetadata>(T2->getOperand(2))
+ ->getValue())->getZExtValue();
+ assert(Offset1 != Offset2);
+ return Offset1 < Offset2;
+ });
+
+ llvm::NamedMDNode *BitsetsMD =
+ getModule().getOrInsertNamedMetadata("llvm.bitsets");
+ for (auto BitsetEntry : BitsetEntries)
+ BitsetsMD->addOperand(BitsetEntry);
+}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index b52ba8ab964..7571332af06 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1346,6 +1346,9 @@ public:
/// to by This.
llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty);
+ /// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable.
+ /// If vptr CFI is enabled, emit a check that VTable is valid.
+ void EmitVTablePtrCheckForCall(const CXXMethodDecl *MD, llvm::Value *VTable);
/// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
/// expr can be devirtualized.
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 7daa0932e1a..6902d1917a6 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1103,6 +1103,11 @@ public:
/// \param D Threadprivate declaration.
void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
+ /// Emit bit set entries for the given vtable using the given layout if
+ /// vptr CFI is enabled.
+ void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
+ const VTableLayout &VTLayout);
+
private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 14a2890b29c..e580969ce5b 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1281,6 +1281,8 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
DC->getParent()->isTranslationUnit())
EmitFundamentalRTTIDescriptors();
+
+ CGM.EmitVTableBitSetEntries(VTable, VTLayout);
}
llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
@@ -1372,6 +1374,8 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
Ty = Ty->getPointerTo()->getPointerTo();
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
+ CGF.EmitVTablePtrCheckForCall(cast<CXXMethodDecl>(GD.getDecl()), VTable);
+
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
llvm::Value *VFuncPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
OpenPOWER on IntegriCloud