xref: /openbmc/qemu/docs/devel/control-flow-integrity.rst (revision d45a5270d075ea589f0b0ddcf963a5fea1f500ac)
1a1118243SDaniele Buono============================
2a1118243SDaniele BuonoControl-Flow Integrity (CFI)
3a1118243SDaniele Buono============================
4a1118243SDaniele Buono
5a1118243SDaniele BuonoThis document describes the current control-flow integrity (CFI) mechanism in
6a1118243SDaniele BuonoQEMU. How it can be enabled, its benefits and deficiencies, and how it affects
7a1118243SDaniele Buononew and existing code in QEMU
8a1118243SDaniele Buono
9a1118243SDaniele BuonoBasics
10a1118243SDaniele Buono------
11a1118243SDaniele Buono
12a1118243SDaniele BuonoCFI is a hardening technique that focusing on guaranteeing that indirect
13a1118243SDaniele Buonofunction calls have not been altered by an attacker.
14a1118243SDaniele BuonoThe type used in QEMU is a forward-edge control-flow integrity that ensures
15a1118243SDaniele Buonofunction calls performed through function pointers, always call a "compatible"
16a1118243SDaniele Buonofunction. A compatible function is a function with the same signature of the
17a1118243SDaniele Buonofunction pointer declared in the source code.
18a1118243SDaniele Buono
19a1118243SDaniele BuonoThis type of CFI is entirely compiler-based and relies on the compiler knowing
20a1118243SDaniele Buonothe signature of every function and every function pointer used in the code.
21a1118243SDaniele BuonoAs of now, the only compiler that provides support for CFI is Clang.
22a1118243SDaniele Buono
23a1118243SDaniele BuonoCFI is best used on production binaries, to protect against unknown attack
24a1118243SDaniele Buonovectors.
25a1118243SDaniele Buono
26a1118243SDaniele BuonoIn case of a CFI violation (i.e. call to a non-compatible function) QEMU will
27a1118243SDaniele Buonoterminate abruptly, to stop the possible attack.
28a1118243SDaniele Buono
29a1118243SDaniele BuonoBuilding with CFI
30a1118243SDaniele Buono-----------------
31a1118243SDaniele Buono
32a1118243SDaniele BuonoNOTE: CFI requires the use of link-time optimization. Therefore, when CFI is
33a1118243SDaniele Buonoselected, LTO will be automatically enabled.
34a1118243SDaniele Buono
35a1118243SDaniele BuonoTo build with CFI, the minimum requirement is Clang 6+. If you
36a1118243SDaniele Buonoare planning to also enable fuzzing, then Clang 11+ is needed (more on this
37a1118243SDaniele Buonolater).
38a1118243SDaniele Buono
39a1118243SDaniele BuonoGiven the use of LTO, a version of AR that supports LLVM IR is required.
40a1118243SDaniele BuonoThe easies way of doing this is by selecting the AR provided by LLVM::
41a1118243SDaniele Buono
42*04a25211SSerge Guelton AR=llvm-ar-9 CC=clang-9 CXX=clang++-9 /path/to/configure --enable-cfi
43a1118243SDaniele Buono
44a1118243SDaniele BuonoCFI is enabled on every binary produced.
45a1118243SDaniele Buono
46a1118243SDaniele BuonoIf desired, an additional flag to increase the verbosity of the output in case
47a1118243SDaniele Buonoof a CFI violation is offered (``--enable-debug-cfi``).
48a1118243SDaniele Buono
49a1118243SDaniele BuonoUsing QEMU built with CFI
50a1118243SDaniele Buono-------------------------
51a1118243SDaniele Buono
52a1118243SDaniele BuonoA binary with CFI will work exactly like a standard binary. In case of a CFI
53a1118243SDaniele Buonoviolation, the binary will terminate with an illegal instruction signal.
54a1118243SDaniele Buono
55a1118243SDaniele BuonoIncompatible code with CFI
56a1118243SDaniele Buono--------------------------
57a1118243SDaniele Buono
58a1118243SDaniele BuonoAs mentioned above, CFI is entirely compiler-based and therefore relies on
59a1118243SDaniele Buonocompile-time knowledge of the code. This means that, while generally supported
60a1118243SDaniele Buonofor most code, some specific use pattern can break CFI compatibility, and
61a1118243SDaniele Buonocreate false-positives. The two main patterns that can cause issues are:
62a1118243SDaniele Buono
63a1118243SDaniele Buono* Just-in-time compiled code: since such code is created at runtime, the jump
64a1118243SDaniele Buono  to the buffer containing JIT code will fail.
65a1118243SDaniele Buono
66a1118243SDaniele Buono* Libraries loaded dynamically, e.g. with dlopen/dlsym, since the library was
67a1118243SDaniele Buono  not known at compile time.
68a1118243SDaniele Buono
69a1118243SDaniele BuonoCurrent areas of QEMU that are not entirely compatible with CFI are:
70a1118243SDaniele Buono
71a1118243SDaniele Buono1. TCG, since the idea of TCG is to pre-compile groups of instructions at
72a1118243SDaniele Buono   runtime to speed-up interpretation, quite similarly to a JIT compiler
73a1118243SDaniele Buono
74a1118243SDaniele Buono2. TCI, where the interpreter has to interpret the generic *call* operation
75a1118243SDaniele Buono
76a1118243SDaniele Buono3. Plugins, since a plugin is implemented as an external library
77a1118243SDaniele Buono
78a1118243SDaniele Buono4. Modules, since they are implemented as an external library
79a1118243SDaniele Buono
80a1118243SDaniele Buono5. Directly calling signal handlers from the QEMU source code, since the
81a1118243SDaniele Buono   signal handler may have been provided by an external library or even plugged
82a1118243SDaniele Buono   at runtime.
83a1118243SDaniele Buono
84a1118243SDaniele BuonoDisabling CFI for a specific function
85a1118243SDaniele Buono-------------------------------------
86a1118243SDaniele Buono
87a1118243SDaniele BuonoIf you are working on function that is performing a call using an
88a1118243SDaniele Buonoincompatible way, as described before, you can selectively disable CFI checks
89a1118243SDaniele Buonofor such function by using the decorator ``QEMU_DISABLE_CFI`` at function
90a1118243SDaniele Buonodefinition, and add an explanation on why the function is not compatible
91a1118243SDaniele Buonowith CFI. An example of the use of ``QEMU_DISABLE_CFI`` is provided here::
92a1118243SDaniele Buono
93a1118243SDaniele Buono	/*
94a1118243SDaniele Buono	 * Disable CFI checks.
95a1118243SDaniele Buono	 * TCG creates binary blobs at runtime, with the transformed code.
96a1118243SDaniele Buono	 * A TB is a blob of binary code, created at runtime and called with an
97a1118243SDaniele Buono	 * indirect function call. Since such function did not exist at compile time,
98a1118243SDaniele Buono	 * the CFI runtime has no way to verify its signature and would fail.
99a1118243SDaniele Buono	 * TCG is not considered a security-sensitive part of QEMU so this does not
100a1118243SDaniele Buono	 * affect the impact of CFI in environment with high security requirements
101a1118243SDaniele Buono	 */
102a1118243SDaniele Buono	QEMU_DISABLE_CFI
103a1118243SDaniele Buono	static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
104a1118243SDaniele Buono
105a1118243SDaniele BuonoNOTE: CFI needs to be disabled at the **caller** function, (i.e. a compatible
106a1118243SDaniele Buonocfi function that calls a non-compatible one), since the check is performed
107a1118243SDaniele Buonowhen the function call is performed.
108a1118243SDaniele Buono
109a1118243SDaniele BuonoCFI and fuzzing
110a1118243SDaniele Buono---------------
111a1118243SDaniele Buono
112a1118243SDaniele BuonoThere is generally no advantage of using CFI and fuzzing together, because
113a1118243SDaniele Buonothey target different environments (production for CFI, debug for fuzzing).
114a1118243SDaniele Buono
115a1118243SDaniele BuonoCFI could be used in conjunction with fuzzing to identify a broader set of
116a1118243SDaniele Buonobugs that may not end immediately in a segmentation fault or triggering
117a1118243SDaniele Buonoan assertion. However, other sanitizers such as address and ub sanitizers
118a1118243SDaniele Buonocan identify such bugs in a more precise way than CFI.
119a1118243SDaniele Buono
120a1118243SDaniele BuonoThere is, however, an interesting use case in using CFI in conjunction with
121a1118243SDaniele Buonofuzzing, that is to make sure that CFI is not triggering any false positive
122a1118243SDaniele Buonoin remote-but-possible parts of the code.
123a1118243SDaniele Buono
124a1118243SDaniele BuonoCFI can be enabled with fuzzing, but with some caveats:
125a1118243SDaniele Buono1. Fuzzing relies on the linker performing function wrapping at link-time.
126a1118243SDaniele BuonoThe standard BFD linker does not support function wrapping when LTO is
127a1118243SDaniele Buonoalso enabled. The workaround is to use LLVM's lld linker.
128a1118243SDaniele Buono2. Fuzzing also relies on a custom linker script, which is only supported by
129a1118243SDaniele Buonolld with version 11+.
130a1118243SDaniele Buono
131a1118243SDaniele BuonoIn other words, to compile with fuzzing and CFI, clang 11+ is required, and
132a1118243SDaniele Buonolld needs to be used as a linker::
133a1118243SDaniele Buono
134*04a25211SSerge Guelton AR=llvm-ar-11 CC=clang-11 CXX=clang++-11 /path/to/configure --enable-cfi \
135a1118243SDaniele Buono                           -enable-fuzzing --extra-ldflags="-fuse-ld=lld"
136a1118243SDaniele Buono
137a1118243SDaniele Buonoand then, compile the fuzzers as usual.
138