On Thu, Mar 11, 2021 at 04:49:03PM -0800, Sami Tolvanen wrote: > This change adds support for Clang’s forward-edge Control Flow > Integrity (CFI) checking. With CONFIG_CFI_CLANG, the compiler > injects a runtime check before each indirect function call to ensure > the target is a valid function with the correct static type. This > restricts possible call targets and makes it more difficult for > an attacker to exploit bugs that allow the modification of stored > function pointers. For more details, see: > > https://clang.llvm.org/docs/ControlFlowIntegrity.html > > Clang requires CONFIG_LTO_CLANG to be enabled with CFI to gain > visibility to possible call targets. Kernel modules are supported > with Clang’s cross-DSO CFI mode, which allows checking between > independently compiled components. > > With CFI enabled, the compiler injects a __cfi_check() function into > the kernel and each module for validating local call targets. For > cross-module calls that cannot be validated locally, the compiler > calls the global __cfi_slowpath_diag() function, which determines > the target module and calls the correct __cfi_check() function. This > patch includes a slowpath implementation that uses __module_address() > to resolve call targets, and with CONFIG_CFI_CLANG_SHADOW enabled, a > shadow map that speeds up module look-ups by ~3x. > > Clang implements indirect call checking using jump tables and > offers two methods of generating them. With canonical jump tables, > the compiler renames each address-taken function to <function>.cfi > and points the original symbol to a jump table entry, which passes > __cfi_check() validation. This isn’t compatible with stand-alone > assembly code, which the compiler doesn’t instrument, and would > result in indirect calls to assembly code to fail. Therefore, we > default to using non-canonical jump tables instead, where the compiler > generates a local jump table entry <function>.cfi_jt for each > address-taken function, and replaces all references to the function > with the address of the jump table entry. > > Note that because non-canonical jump table addresses are local > to each component, they break cross-module function address > equality. Specifically, the address of a global function will be > different in each module, as it's replaced with the address of a local > jump table entry. If this address is passed to a different module, > it won’t match the address of the same function taken there. This > may break code that relies on comparing addresses passed from other > components. > > CFI checking can be disabled in a function with the __nocfi attribute. > Additionally, CFI can be disabled for an entire compilation unit by > filtering out CC_FLAGS_CFI. > > By default, CFI failures result in a kernel panic to stop a potential > exploit. CONFIG_CFI_PERMISSIVE enables a permissive mode, where the > kernel prints out a rate-limited warning instead, and allows execution > to continue. This option is helpful for locating type mismatches, but > should only be enabled during development. > > Signed-off-by: Sami Tolvanen <samitolvanen@xxxxxxxxxx> Reviewed-by: Kees Cook <keescook@xxxxxxxxxxxx> -- Kees Cook