Kernel Control Flow Integrity

Control flow integrity (CFI) is a security mechanism that disallows changes to the original control flow graph of a compiled binary, making it significantly harder to perform such attacks.

In Android 9, we enabled LLVM's implementation of CFI in more components and also in the kernel. System CFI is on by default, but you need to enable kernel CFI.

LLVM's CFI requires compiling with Link-Time Optimization (LTO). LTO preserves the LLVM bitcode representation of object files until link-time, which allows the compiler to better reason about what optimizations can be performed. Enabling LTO reduces the size of the final binary and improves performance, but increases compile time. In testing on Android, the combination of LTO and CFI results in negligible overhead to code size and performance; in a few cases both improved.

For more technical details about CFI and how other forward-control checks are handled, see the LLVM design documentation.

Implementation

Support for kernel CFI exists in Android common kernel versions 4.9 and 4.14. If your kernel is based on version 4.9 or 4.14 and you build with Clang, then you can enable it. To enable kCFI, you need to copy over the relevant patches and update your kernel config file.

Copy kCFI patches

Add these changes to your kernel:

Enable kCFI

After you've copied over the relevant changes, you need to enable the kCFI in your kernel config file, such as /kernel/PROJECT/+/BRANCH/arch/arm64/configs/PROJECT_defconfig.

To enable kCFI, add these lines:

CONFIG_LTO_CLANG=y
CONFIG_CFI_CLANG=y

Troubleshooting

After enabling, work through any type mismatch errors that may exist with their drivers. An indirect function call through an incompatible function pointer trips CFI. When a CFI failure is detected, the kernel prints out a warning that includes both the function that was called and the stacktrace that led to the failure. Correct this by ensuring function pointers always have the same type as the function that's called.

To assist in debugging CFI failures, enable CONFIG_CFI_PERMISSIVE, which prints out a warning instead of causing a kernel panic. Permissive mode must not be used in production.

Validation

Currently, there are no CTS test specifically for CFI. Instead, make sure that CTS tests pass with or without CFI enabled to verify that CFI isn't impacting the device.