summaryrefslogtreecommitdiffstats
path: root/docs/ControlFlowIntegrity.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/ControlFlowIntegrity.rst')
-rw-r--r--docs/ControlFlowIntegrity.rst194
1 files changed, 162 insertions, 32 deletions
diff --git a/docs/ControlFlowIntegrity.rst b/docs/ControlFlowIntegrity.rst
index ce1c37b..780ff88 100644
--- a/docs/ControlFlowIntegrity.rst
+++ b/docs/ControlFlowIntegrity.rst
@@ -20,20 +20,72 @@ program's control flow. These schemes have been optimized for performance,
allowing developers to enable them in release builds.
To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
-As currently implemented, CFI relies on link-time optimization (LTO); so it is
-required to specify ``-flto``, and the linker used must support LTO, for example
-via the `gold plugin`_. To allow the checks to be implemented efficiently,
-the program must be structured such that certain object files are compiled
-with CFI enabled, and are statically linked into the program. This may
-preclude the use of shared libraries in some cases.
-
-Clang currently implements forward-edge CFI for member function calls and
-bad cast checking. More schemes are under development.
+You can also enable a subset of available :ref:`schemes <cfi-schemes>`.
+As currently implemented, all schemes rely on link-time optimization (LTO);
+so it is required to specify ``-flto``, and the linker used must support LTO,
+for example via the `gold plugin`_.
+
+To allow the checks to be implemented efficiently, the program must be
+structured such that certain object files are compiled with CFI
+enabled, and are statically linked into the program. This may preclude
+the use of shared libraries in some cases. Experimental support for
+:ref:`cross-DSO control flow integrity <cfi-cross-dso>` exists that
+does not have these requirements. This cross-DSO support has unstable
+ABI at this time.
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
+.. _cfi-schemes:
+
+Available schemes
+=================
+
+Available schemes are:
+
+ - ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
+ <cfi-strictness>`.
+ - ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
+ dynamic type.
+ - ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
+ unrelated type to the wrong dynamic type.
+ - ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
+ the wrong dynamic type.
+ - ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
+ wrong dynamic type.
+ - ``-fsanitize=cfi-icall``: Indirect call of a function with wrong dynamic
+ type.
+
+You can use ``-fsanitize=cfi`` to enable all the schemes and use
+``-fno-sanitize`` flag to narrow down the set of schemes as desired.
+For example, you can build your program with
+``-fsanitize=cfi -fno-sanitize=cfi-nvcall,cfi-icall``
+to use all schemes except for non-virtual member function call and indirect call
+checking.
+
+Remember that you have to provide ``-flto`` if at least one CFI scheme is
+enabled.
+
+Trapping and Diagnostics
+========================
+
+By default, CFI will abort the program immediately upon detecting a control
+flow integrity violation. You can use the :ref:`-fno-sanitize-trap=
+<controlling-code-generation>` flag to cause CFI to print a diagnostic
+similar to the one below before the program aborts.
+
+.. code-block:: console
+
+ bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
+ 0x000000425a50: note: vtable is of type 'A'
+ 00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
+ ^
+
+If diagnostics are enabled, you can also configure CFI to continue program
+execution instead of aborting by using the :ref:`-fsanitize-recover=
+<controlling-code-generation>` flag.
+
Forward-Edge CFI for Virtual Calls
-----------------------------------
+==================================
This scheme checks that virtual calls take place using a vptr of the correct
dynamic type; that is, the dynamic type of the called object must be a
@@ -41,14 +93,12 @@ 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
-~~~~~~~~~~~
+-----------
A performance overhead of less than 1% has been measured by running the
Dromaeo benchmark suite against an instrumented version of the Chromium
@@ -59,7 +109,7 @@ Note that this scheme has not yet been optimized for binary size; an increase
of up to 15% has been observed for Chromium.
Bad Cast Checking
------------------
+=================
This scheme checks that pointer casts are made to an object of the correct
dynamic type; that is, the dynamic type of the object must be a derived class
@@ -85,18 +135,16 @@ 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
------------------------------------------
+=========================================
This scheme checks that non-virtual calls take place using an object of
the correct dynamic type; that is, the dynamic type of the called object
@@ -106,16 +154,14 @@ 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:
Strictness
-~~~~~~~~~~
+----------
If a class has a single non-virtual base and does not introduce or override
virtual member functions or fields other than an implicitly defined virtual
@@ -129,13 +175,97 @@ 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``.
+Indirect Function Call Checking
+===============================
+
+This scheme checks that function calls take place using a function of the
+correct dynamic type; that is, the dynamic type of the function must match
+the static type used at the call. This CFI scheme can be enabled on its own
+using ``-fsanitize=cfi-icall``.
+
+For this scheme to work, each indirect function call in the program, other
+than calls in :ref:`blacklisted <cfi-blacklist>` functions, must call a
+function which was either compiled with ``-fsanitize=cfi-icall`` enabled,
+or whose address was taken by a function in a translation unit compiled with
+``-fsanitize=cfi-icall``.
+
+If a function in a translation unit compiled with ``-fsanitize=cfi-icall``
+takes the address of a function not compiled with ``-fsanitize=cfi-icall``,
+that address may differ from the address taken by a function in a translation
+unit not compiled with ``-fsanitize=cfi-icall``. This is technically a
+violation of the C and C++ standards, but it should not affect most programs.
+
+Each translation unit compiled with ``-fsanitize=cfi-icall`` must be
+statically linked into the program or shared library, and calls across
+shared library boundaries are handled as if the callee was not compiled with
+``-fsanitize=cfi-icall``.
+
+This scheme is currently only supported on the x86 and x86_64 architectures.
+
+``-fsanitize=cfi-icall`` and ``-fsanitize=function``
+----------------------------------------------------
+
+This tool is similar to ``-fsanitize=function`` in that both tools check
+the types of function calls. However, the two tools occupy different points
+on the design space; ``-fsanitize=function`` is a developer tool designed
+to find bugs in local development builds, whereas ``-fsanitize=cfi-icall``
+is a security hardening mechanism designed to be deployed in release builds.
+
+``-fsanitize=function`` has a higher space and time overhead due to a more
+complex type check at indirect call sites, as well as a need for run-time
+type information (RTTI), which may make it unsuitable for deployment. Because
+of the need for RTTI, ``-fsanitize=function`` can only be used with C++
+programs, whereas ``-fsanitize=cfi-icall`` can protect both C and C++ programs.
+
+On the other hand, ``-fsanitize=function`` conforms more closely with the C++
+standard and user expectations around interaction with shared libraries;
+the identity of function pointers is maintained, and calls across shared
+library boundaries are no different from calls within a single program or
+shared library.
+
+.. _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
+
+.. _cfi-cross-dso:
+
+Shared library support
+======================
+
+Use **-f[no-]sanitize-cfi-cross-dso** to enable the cross-DSO control
+flow integrity mode, which allows all CFI schemes listed above to
+apply across DSO boundaries. As in the regular CFI, each DSO must be
+built with ``-flto``.
+
Design
-------
+======
Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
Publications
-------------
+============
`Control-Flow Integrity: Principles, Implementations, and Applications <http://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
Martin Abadi, Mihai Budiu, Ăšlfar Erlingsson, Jay Ligatti.
OpenPOWER on IntegriCloud