summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2015-07-15 12:15:56 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2015-07-15 12:15:56 +0000
commit6fccf95aadba3c5aec1f41723ceae6168d64ac80 (patch)
treee95a8dc2c6a71a3d05197d3b6720f78b57073b70
parent3bed68cfc7c7f336e4ae1f48798ceb3e60e6c888 (diff)
downloadbcm5719-llvm-6fccf95aadba3c5aec1f41723ceae6168d64ac80.tar.gz
bcm5719-llvm-6fccf95aadba3c5aec1f41723ceae6168d64ac80.zip
CodeGen: Improve CFI type blacklisting mechanism.
We now use the sanitizer special case list to decide which types to blacklist. We also support a special blacklist entry for types with a uuid attribute, which are generally COM types whose virtual tables are defined externally. Differential Revision: http://reviews.llvm.org/D11096 llvm-svn: 242286
-rw-r--r--clang/docs/ControlFlowIntegrity.rst52
-rw-r--r--clang/lib/CodeGen/CGClass.cpp9
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp8
-rw-r--r--clang/lib/Driver/SanitizerArgs.cpp2
-rw-r--r--clang/test/CodeGenCXX/cfi-blacklist.cpp30
5 files changed, 74 insertions, 27 deletions
diff --git a/clang/docs/ControlFlowIntegrity.rst b/clang/docs/ControlFlowIntegrity.rst
index ce1c37bcd40..b043d24a142 100644
--- a/clang/docs/ControlFlowIntegrity.rst
+++ b/clang/docs/ControlFlowIntegrity.rst
@@ -41,11 +41,9 @@ derived class of the static type of the object used to make the call.
This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
For this scheme to work, all translation units containing the definition
-of a virtual member function (whether inline or not) must be compiled
-with ``-fsanitize=cfi-vcall`` enabled and be statically linked into the
-program. Classes in the C++ standard library (under namespace ``std``) are
-exempted from checking, and therefore programs may be linked against a
-pre-built standard library, but this may change in the future.
+of a virtual member function (whether inline or not), other than members
+of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
+``-fsanitize=cfi-vcall`` enabled and be statically linked into the program.
Performance
~~~~~~~~~~~
@@ -85,15 +83,13 @@ If a program as a matter of policy forbids the second type of cast, that
restriction can normally be enforced. However it may in some cases be necessary
for a function to perform a forbidden cast to conform with an external API
(e.g. the ``allocate`` member function of a standard library allocator). Such
-functions may be blacklisted using a :doc:`SanitizerSpecialCaseList`.
+functions may be :ref:`blacklisted <cfi-blacklist>`.
For this scheme to work, all translation units containing the definition
-of a virtual member function (whether inline or not) must be compiled with
+of a virtual member function (whether inline or not), other than members
+of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
``-fsanitize=cfi-derived-cast`` or ``-fsanitize=cfi-unrelated-cast`` enabled
-and be statically linked into the program. Classes in the C++ standard library
-(under namespace ``std``) are exempted from checking, and therefore programs
-may be linked against a pre-built standard library, but this may change in
-the future.
+and be statically linked into the program.
Non-Virtual Member Function Call Checking
-----------------------------------------
@@ -106,11 +102,9 @@ polymorphic class type. This CFI scheme can be enabled on its own using
``-fsanitize=cfi-nvcall``.
For this scheme to work, all translation units containing the definition
-of a virtual member function (whether inline or not) must be compiled
-with ``-fsanitize=cfi-nvcall`` enabled and be statically linked into the
-program. Classes in the C++ standard library (under namespace ``std``) are
-exempted from checking, and therefore programs may be linked against a
-pre-built standard library, but this may change in the future.
+of a virtual member function (whether inline or not), other than members
+of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
+``-fsanitize=cfi-nvcall`` enabled and be statically linked into the program.
.. _cfi-strictness:
@@ -129,6 +123,32 @@ member functions on class instances with specific properties that works under
most compilers and should not have security implications, so we allow it by
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
+.. _cfi-blacklist:
+
+Blacklist
+---------
+
+A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
+source files, functions and types using the ``src``, ``fun`` and ``type``
+entity types.
+
+In addition, if a type has a ``uuid`` attribute and the blacklist contains
+the type entry ``attr:uuid``, CFI checks are suppressed for that type. This
+allows all COM types to be easily blacklisted, which is useful as COM types
+are typically defined outside of the linked program.
+
+.. code-block:: bash
+
+ # Suppress checking for code in a file.
+ src:bad_file.cpp
+ src:bad_header.h
+ # Ignore all functions with names containing MyFooBar.
+ fun:*MyFooBar*
+ # Ignore all types in the standard library.
+ type:std::*
+ # Ignore all types with a uuid attribute.
+ type:attr:uuid
+
Design
------
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index c49f182c21d..9c18b860920 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2190,15 +2190,6 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
if (!ClassDecl->isCompleteDefinition() || !ClassDecl->isDynamicClass())
return;
- SmallString<64> MangledName;
- llvm::raw_svector_ostream Out(MangledName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(T.getUnqualifiedType(),
- Out);
-
- // Blacklist based on the mangled type.
- if (CGM.getContext().getSanitizerBlacklist().isBlacklistedType(Out.str()))
- return;
-
if (!SanOpts.has(SanitizerKind::CFICastStrict))
ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index e36051c2053..373009e8bf9 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -841,8 +841,12 @@ void CodeGenModule::EmitDeferredVTables() {
}
bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) {
- // FIXME: Make this user configurable.
- return RD->isInStdNamespace();
+ if (RD->hasAttr<UuidAttr>() &&
+ getContext().getSanitizerBlacklist().isBlacklistedType("attr:uuid"))
+ return true;
+
+ return getContext().getSanitizerBlacklist().isBlacklistedType(
+ RD->getQualifiedNameAsString());
}
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index c3ad8ef9c1e..3b3984c7197 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -90,6 +90,8 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
BlacklistFile = "tsan_blacklist.txt";
else if (Kinds & DataFlow)
BlacklistFile = "dfsan_abilist.txt";
+ else if (Kinds & CFI)
+ BlacklistFile = "cfi_blacklist.txt";
if (BlacklistFile) {
clang::SmallString<64> Path(D.ResourceDir);
diff --git a/clang/test/CodeGenCXX/cfi-blacklist.cpp b/clang/test/CodeGenCXX/cfi-blacklist.cpp
new file mode 100644
index 00000000000..32ed05bcc52
--- /dev/null
+++ b/clang/test/CodeGenCXX/cfi-blacklist.cpp
@@ -0,0 +1,30 @@
+// RUN: echo "type:attr:uuid" > %t.txt
+// RUN: %clang_cc1 -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOUUID %s
+// RUN: echo "type:std::*" > %t.txt
+// RUN: %clang_cc1 -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+
+struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) S1 {
+ virtual void f();
+};
+
+namespace std {
+
+struct S2 {
+ virtual void f();
+};
+
+}
+
+// CHECK: define{{.*}}s1f
+// NOSTD: llvm.bitset.test
+// NOUUID-NOT: llvm.bitset.test
+void s1f(S1 *s1) {
+ s1->f();
+}
+
+// CHECK: define{{.*}}s2f
+// NOSTD-NOT: llvm.bitset.test
+// NOUUID: llvm.bitset.test
+void s2f(std::S2 *s2) {
+ s2->f();
+}
OpenPOWER on IntegriCloud