diff options
Diffstat (limited to 'docs/ControlFlowIntegrity.rst')
-rw-r--r-- | docs/ControlFlowIntegrity.rst | 194 |
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. |