Re: [RFC PATCH v2 20/21] x86: Add support for CONFIG_CFI_CLANG

Kees Cook
2022-05-14T22:02:57Z

On Fri, May 13, 2022 at 01:21:58PM -0700, Sami Tolvanen wrote:
> With CONFIG_CFI_CLANG, the compiler injects a type preamble
> immediately before each function and a check to validate the target
> function type before indirect calls:
>
> ; type preamble
> __cfi_function:
> int3
> int3
> mov <id>, %eax
> int3
> int3
> function:
> ...
> ; indirect call check
> cmpl    <id>, -6(%r11)
> je .Ltmp1
> ud2
> .Ltmp1:
> call __x86_indirect_thunk_r11
>
> Define the __CFI_TYPE helper macro for manual type annotations in
> assembly code, add error handling for the CFI ud2 traps, and allow
> CONFIG_CFI_CLANG to be selected on x86_64.
>
> Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
> ---
> arch/x86/Kconfig | 2 ++
> arch/x86/include/asm/linkage.h | 12 +++++++
> arch/x86/kernel/traps.c | 60 +++++++++++++++++++++++++++++++++-
> 3 files changed, 73 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 4bed3abf444d..2e73d0792d48 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -108,6 +108,8 @@ config X86
> select ARCH_SUPPORTS_PAGE_TABLE_CHECK if X86_64
> select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
> select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096
> + select ARCH_SUPPORTS_CFI_CLANG if X86_64
> + select ARCH_USES_CFI_TRAPS if X86_64 && CFI_CLANG
> select ARCH_SUPPORTS_LTO_CLANG
> select ARCH_SUPPORTS_LTO_CLANG_THIN
> select ARCH_USE_BUILTIN_BSWAP
> diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
> index 85865f1645bd..0ee4a0af3974 100644
> --- a/arch/x86/include/asm/linkage.h
> +++ b/arch/x86/include/asm/linkage.h
> @@ -25,6 +25,18 @@
> #define RET ret
> #endif
>
> +#ifdef CONFIG_CFI_CLANG
> +#define __CFI_TYPE(name) \
> + .fill 7, 1, 0xCC ASM_NL \
> + SYM_START(__cfi_##name, SYM_L_LOCAL, SYM_A_NONE) \
> + int3 ASM_NL \
> + int3 ASM_NL \
> + mov __kcfi_typeid_##name, %eax ASM_NL \
> + int3 ASM_NL \
> + int3 ASM_NL \
> + SYM_FUNC_END(__cfi_##name)
> +#endif
> +
> #else /* __ASSEMBLY__ */
>
> #ifdef CONFIG_SLS
> diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
> index 1563fb995005..320e257eb4be 100644
> --- a/arch/x86/kernel/traps.c
> +++ b/arch/x86/kernel/traps.c
> @@ -40,6 +40,7 @@
> #include <linux/hardirq.h>
> #include <linux/atomic.h>
> #include <linux/ioasid.h>
> +#include <linux/cfi.h>
>
> #include <asm/stacktrace.h>
> #include <asm/processor.h>
> @@ -295,6 +296,62 @@ static inline void handle_invalid_op(struct pt_regs *regs)
> ILL_ILLOPN, error_get_trap_addr(regs));
> }
>
> +#ifdef CONFIG_CFI_CLANG
> +static void decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
> + unsigned long *type)
> +{
> + char buffer[MAX_INSN_SIZE];
> + struct insn insn;
> + int offset;
> +
> + *target = *type = 0;

Should report_cfi_failure() have some additional hinting for the case
where target/type are zero? Like, "hey, got an inexplicable CFI failure
here, but preamble decode failed. Yikes!"

Reviewed-by: Kees Cook <keescook@chromium.org>

--
Kees Cook