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