94 lines
4.4 KiB
ReStructuredText
94 lines
4.4 KiB
ReStructuredText
|
==============================================
|
||
|
Control Flow Verification Tool Design Document
|
||
|
==============================================
|
||
|
|
||
|
.. contents::
|
||
|
:local:
|
||
|
|
||
|
Objective
|
||
|
=========
|
||
|
|
||
|
This document provides an overview of an external tool to verify the protection
|
||
|
mechanisms implemented by Clang's *Control Flow Integrity* (CFI) schemes
|
||
|
(``-fsanitize=cfi``). This tool, provided a binary or DSO, should infer whether
|
||
|
indirect control flow operations are protected by CFI, and should output these
|
||
|
results in a human-readable form.
|
||
|
|
||
|
This tool should also be added as part of Clang's continuous integration testing
|
||
|
framework, where modifications to the compiler ensure that CFI protection
|
||
|
schemes are still present in the final binary.
|
||
|
|
||
|
Location
|
||
|
========
|
||
|
|
||
|
This tool will be present as a part of the LLVM toolchain, and will reside in
|
||
|
the "/llvm/tools/llvm-cfi-verify" directory, relative to the LLVM trunk. It will
|
||
|
be tested in two methods:
|
||
|
|
||
|
- Unit tests to validate code sections, present in
|
||
|
"/llvm/unittests/tools/llvm-cfi-verify".
|
||
|
- Integration tests, present in "/llvm/tools/clang/test/LLVMCFIVerify". These
|
||
|
integration tests are part of clang as part of a continuous integration
|
||
|
framework, ensuring updates to the compiler that reduce CFI coverage on
|
||
|
indirect control flow instructions are identified.
|
||
|
|
||
|
Background
|
||
|
==========
|
||
|
|
||
|
This tool will continuously validate that CFI directives are properly
|
||
|
implemented around all indirect control flows by analysing the output machine
|
||
|
code. The analysis of machine code is important as it ensures that any bugs
|
||
|
present in linker or compiler do not subvert CFI protections in the final
|
||
|
shipped binary.
|
||
|
|
||
|
Unprotected indirect control flow instructions will be flagged for manual
|
||
|
review. These unexpected control flows may simply have not been accounted for in
|
||
|
the compiler implementation of CFI (e.g. indirect jumps to facilitate switch
|
||
|
statements may not be fully protected).
|
||
|
|
||
|
It may be possible in the future to extend this tool to flag unnecessary CFI
|
||
|
directives (e.g. CFI directives around a static call to a non-polymorphic base
|
||
|
type). This type of directive has no security implications, but may present
|
||
|
performance impacts.
|
||
|
|
||
|
Design Ideas
|
||
|
============
|
||
|
|
||
|
This tool will disassemble binaries and DSO's from their machine code format and
|
||
|
analyse the disassembled machine code. The tool will inspect virtual calls and
|
||
|
indirect function calls. This tool will also inspect indirect jumps, as inlined
|
||
|
functions and jump tables should also be subject to CFI protections. Non-virtual
|
||
|
calls (``-fsanitize=cfi-nvcall``) and cast checks (``-fsanitize=cfi-*cast*``)
|
||
|
are not implemented due to a lack of information provided by the bytecode.
|
||
|
|
||
|
The tool would operate by searching for indirect control flow instructions in
|
||
|
the disassembly. A control flow graph would be generated from a small buffer of
|
||
|
the instructions surrounding the 'target' control flow instruction. If the
|
||
|
target instruction is branched-to, the fallthrough of the branch should be the
|
||
|
CFI trap (on x86, this is a ``ud2`` instruction). If the target instruction is
|
||
|
the fallthrough (i.e. immediately succeeds) of a conditional jump, the
|
||
|
conditional jump target should be the CFI trap. If an indirect control flow
|
||
|
instruction does not conform to one of these formats, the target will be noted
|
||
|
as being CFI-unprotected.
|
||
|
|
||
|
Note that in the second case outlined above (where the target instruction is the
|
||
|
fallthrough of a conditional jump), if the target represents a vcall that takes
|
||
|
arguments, these arguments may be pushed to the stack after the branch but
|
||
|
before the target instruction. In these cases, a secondary 'spill graph' in
|
||
|
constructed, to ensure the register argument used by the indirect jump/call is
|
||
|
not spilled from the stack at any point in the interim period. If there are no
|
||
|
spills that affect the target register, the target is marked as CFI-protected.
|
||
|
|
||
|
Other Design Notes
|
||
|
~~~~~~~~~~~~~~~~~~
|
||
|
|
||
|
Only machine code sections that are marked as executable will be subject to this
|
||
|
analysis. Non-executable sections do not require analysis as any execution
|
||
|
present in these sections has already violated the control flow integrity.
|
||
|
|
||
|
Suitable extensions may be made at a later date to include analysis for indirect
|
||
|
control flow operations across DSO boundaries. Currently, these CFI features are
|
||
|
only experimental with an unstable ABI, making them unsuitable for analysis.
|
||
|
|
||
|
The tool currently only supports the x86, x86_64, and AArch64 architectures.
|