forked from OSchip/llvm-project
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
This commit is contained in:
parent
3bed68cfc7
commit
6fccf95aad
|
@ -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``.
|
This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
|
||||||
|
|
||||||
For this scheme to work, all translation units containing the definition
|
For this scheme to work, all translation units containing the definition
|
||||||
of a virtual member function (whether inline or not) must be compiled
|
of a virtual member function (whether inline or not), other than members
|
||||||
with ``-fsanitize=cfi-vcall`` enabled and be statically linked into the
|
of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
|
||||||
program. Classes in the C++ standard library (under namespace ``std``) are
|
``-fsanitize=cfi-vcall`` enabled and be statically linked into the program.
|
||||||
exempted from checking, and therefore programs may be linked against a
|
|
||||||
pre-built standard library, but this may change in the future.
|
|
||||||
|
|
||||||
Performance
|
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
|
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
|
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
|
(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
|
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
|
``-fsanitize=cfi-derived-cast`` or ``-fsanitize=cfi-unrelated-cast`` enabled
|
||||||
and be statically linked into the program. Classes in the C++ standard library
|
and be statically linked into the program.
|
||||||
(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.
|
|
||||||
|
|
||||||
Non-Virtual Member Function Call Checking
|
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``.
|
``-fsanitize=cfi-nvcall``.
|
||||||
|
|
||||||
For this scheme to work, all translation units containing the definition
|
For this scheme to work, all translation units containing the definition
|
||||||
of a virtual member function (whether inline or not) must be compiled
|
of a virtual member function (whether inline or not), other than members
|
||||||
with ``-fsanitize=cfi-nvcall`` enabled and be statically linked into the
|
of :ref:`blacklisted <cfi-blacklist>` types, must be compiled with
|
||||||
program. Classes in the C++ standard library (under namespace ``std``) are
|
``-fsanitize=cfi-nvcall`` enabled and be statically linked into the program.
|
||||||
exempted from checking, and therefore programs may be linked against a
|
|
||||||
pre-built standard library, but this may change in the future.
|
|
||||||
|
|
||||||
.. _cfi-strictness:
|
.. _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
|
most compilers and should not have security implications, so we allow it by
|
||||||
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
|
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
|
Design
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -2190,15 +2190,6 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
|
||||||
if (!ClassDecl->isCompleteDefinition() || !ClassDecl->isDynamicClass())
|
if (!ClassDecl->isCompleteDefinition() || !ClassDecl->isDynamicClass())
|
||||||
return;
|
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))
|
if (!SanOpts.has(SanitizerKind::CFICastStrict))
|
||||||
ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
|
ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
|
||||||
|
|
||||||
|
|
|
@ -841,8 +841,12 @@ void CodeGenModule::EmitDeferredVTables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) {
|
bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) {
|
||||||
// FIXME: Make this user configurable.
|
if (RD->hasAttr<UuidAttr>() &&
|
||||||
return RD->isInStdNamespace();
|
getContext().getSanitizerBlacklist().isBlacklistedType("attr:uuid"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return getContext().getSanitizerBlacklist().isBlacklistedType(
|
||||||
|
RD->getQualifiedNameAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
||||||
|
|
|
@ -90,6 +90,8 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
|
||||||
BlacklistFile = "tsan_blacklist.txt";
|
BlacklistFile = "tsan_blacklist.txt";
|
||||||
else if (Kinds & DataFlow)
|
else if (Kinds & DataFlow)
|
||||||
BlacklistFile = "dfsan_abilist.txt";
|
BlacklistFile = "dfsan_abilist.txt";
|
||||||
|
else if (Kinds & CFI)
|
||||||
|
BlacklistFile = "cfi_blacklist.txt";
|
||||||
|
|
||||||
if (BlacklistFile) {
|
if (BlacklistFile) {
|
||||||
clang::SmallString<64> Path(D.ResourceDir);
|
clang::SmallString<64> Path(D.ResourceDir);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
Loading…
Reference in New Issue