• Sami Tolvanen's avatar
    add support for Clang CFI · cf68fffb
    Sami Tolvanen authored
    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: default avatarSami Tolvanen <samitolvanen@google.com>
    Reviewed-by: default avatarKees Cook <keescook@chromium.org>
    Tested-by: default avatarNathan Chancellor <nathan@kernel.org>
    Signed-off-by: default avatarKees Cook <keescook@chromium.org>
    Link: https://lore.kernel.org/r/20210408182843.1754385-2-samitolvanen@google.com
    cf68fffb
bug.h 7.32 KB