287 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
| ======================
 | |
| Control Flow Integrity
 | |
| ======================
 | |
| 
 | |
| .. toctree::
 | |
|    :hidden:
 | |
| 
 | |
|    ControlFlowIntegrityDesign
 | |
| 
 | |
| .. contents::
 | |
|    :local:
 | |
| 
 | |
| Introduction
 | |
| ============
 | |
| 
 | |
| Clang includes an implementation of a number of control flow integrity (CFI)
 | |
| schemes, which are designed to abort the program upon detecting certain forms
 | |
| of undefined behavior that can potentially allow attackers to subvert the
 | |
| 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``.
 | |
| 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.
 | |
| 
 | |
| The compiler will only produce CFI checks for a class if it can infer hidden
 | |
| LTO visibility for that class. LTO visibility is a property of a class that
 | |
| is inferred from flags and attributes. For more details, see the documentation
 | |
| for :doc:`LTO visibility <LTOVisibility>`.
 | |
| 
 | |
| The ``-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}`` flags
 | |
| require that a ``-fvisibility=`` flag also be specified. This is because the
 | |
| default visibility setting is ``-fvisibility=default``, which would disable
 | |
| CFI checks for classes without visibility attributes. Most users will want
 | |
| to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
 | |
| 
 | |
| Experimental support for :ref:`cross-DSO control flow integrity
 | |
| <cfi-cross-dso>` exists that does not require classes to have hidden LTO
 | |
| visibility. 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
 | |
| 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), 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
 | |
| web browser. Another good performance benchmark for this mechanism is the
 | |
| virtual-call-heavy SPEC 2006 xalancbmk.
 | |
| 
 | |
| 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
 | |
| of the pointee type of the cast. The checks are currently only introduced
 | |
| where the class being casted to is a polymorphic class.
 | |
| 
 | |
| Bad casts are not in themselves control flow integrity violations, but they
 | |
| can also create security vulnerabilities, and the implementation uses many
 | |
| of the same mechanisms.
 | |
| 
 | |
| There are two types of bad cast that may be forbidden: bad casts
 | |
| from a base class to a derived class (which can be checked with
 | |
| ``-fsanitize=cfi-derived-cast``), and bad casts from a pointer of
 | |
| type ``void*`` or another unrelated type (which can be checked with
 | |
| ``-fsanitize=cfi-unrelated-cast``).
 | |
| 
 | |
| The difference between these two types of casts is that the first is defined
 | |
| by the C++ standard to produce an undefined value, while the second is not
 | |
| in itself undefined behavior (it is well defined to cast the pointer back
 | |
| to its original type) unless the object is uninitialized and the cast is a
 | |
| ``static_cast`` (see C++14 [basic.life]p5).
 | |
| 
 | |
| 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 :ref:`blacklisted <cfi-blacklist>`.
 | |
| 
 | |
| For this scheme to work, all translation units containing the definition
 | |
| 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.
 | |
| 
 | |
| 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
 | |
| must be a derived class of the static type of the object used to make the
 | |
| call. The checks are currently only introduced where the object is of a
 | |
| 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), 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
 | |
| destructor, it will have the same layout and virtual function semantics as
 | |
| its base. By default, casts to such classes are checked as if they were made
 | |
| to the least derived such class.
 | |
| 
 | |
| Casting an instance of a base class to such a derived class is technically
 | |
| undefined behavior, but it is a relatively common hack for introducing
 | |
| 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.
 | |
| 
 | |
| .. 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::*
 | |
| 
 | |
| .. _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``.
 | |
| 
 | |
| Normally, CFI checks will only be performed for classes that have hidden LTO
 | |
| visibility. With this flag enabled, the compiler will emit cross-DSO CFI
 | |
| checks for all classes, except for those which appear in the CFI blacklist
 | |
| or which use a ``no_sanitize`` attribute.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| `Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM <http://www.pcc.me.uk/~peter/acad/usenix14.pdf>`_.
 | |
| Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway,
 | |
| Úlfar Erlingsson, Luis Lozano, Geoff Pike.
 |