mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-14 05:49:55 +00:00
Since FineIBT performs checking at the destination, it is weaker against attacks that can construct arbitrary executable memory contents. As such, some system builders want to run with FineIBT disabled by default. Allow the "cfi=kcfi" boot param mode to be selectable through Kconfig via the newly introduced CONFIG_CFI_AUTO_DEFAULT. Reviewed-by: Sami Tolvanen <samitolvanen@google.com> Reviewed-by: Nathan Chancellor <nathan@kernel.org> Tested-by: Nathan Chancellor <nathan@kernel.org> Link: https://lore.kernel.org/r/20240501000218.work.998-kees@kernel.org Signed-off-by: Kees Cook <kees@kernel.org>
147 lines
2.5 KiB
C
147 lines
2.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_X86_CFI_H
|
|
#define _ASM_X86_CFI_H
|
|
|
|
/*
|
|
* Clang Control Flow Integrity (CFI) support.
|
|
*
|
|
* Copyright (C) 2022 Google LLC
|
|
*/
|
|
#include <linux/bug.h>
|
|
#include <asm/ibt.h>
|
|
|
|
/*
|
|
* An overview of the various calling conventions...
|
|
*
|
|
* Traditional:
|
|
*
|
|
* foo:
|
|
* ... code here ...
|
|
* ret
|
|
*
|
|
* direct caller:
|
|
* call foo
|
|
*
|
|
* indirect caller:
|
|
* lea foo(%rip), %r11
|
|
* ...
|
|
* call *%r11
|
|
*
|
|
*
|
|
* IBT:
|
|
*
|
|
* foo:
|
|
* endbr64
|
|
* ... code here ...
|
|
* ret
|
|
*
|
|
* direct caller:
|
|
* call foo / call foo+4
|
|
*
|
|
* indirect caller:
|
|
* lea foo(%rip), %r11
|
|
* ...
|
|
* call *%r11
|
|
*
|
|
*
|
|
* kCFI:
|
|
*
|
|
* __cfi_foo:
|
|
* movl $0x12345678, %eax
|
|
* # 11 nops when CONFIG_CALL_PADDING
|
|
* foo:
|
|
* endbr64 # when IBT
|
|
* ... code here ...
|
|
* ret
|
|
*
|
|
* direct call:
|
|
* call foo # / call foo+4 when IBT
|
|
*
|
|
* indirect call:
|
|
* lea foo(%rip), %r11
|
|
* ...
|
|
* movl $(-0x12345678), %r10d
|
|
* addl -4(%r11), %r10d # -15 when CONFIG_CALL_PADDING
|
|
* jz 1f
|
|
* ud2
|
|
* 1:call *%r11
|
|
*
|
|
*
|
|
* FineIBT (builds as kCFI + CALL_PADDING + IBT + RETPOLINE and runtime patches into):
|
|
*
|
|
* __cfi_foo:
|
|
* endbr64
|
|
* subl 0x12345678, %r10d
|
|
* jz foo
|
|
* ud2
|
|
* nop
|
|
* foo:
|
|
* osp nop3 # was endbr64
|
|
* ... code here ...
|
|
* ret
|
|
*
|
|
* direct caller:
|
|
* call foo / call foo+4
|
|
*
|
|
* indirect caller:
|
|
* lea foo(%rip), %r11
|
|
* ...
|
|
* movl $0x12345678, %r10d
|
|
* subl $16, %r11
|
|
* nop4
|
|
* call *%r11
|
|
*
|
|
*/
|
|
enum cfi_mode {
|
|
CFI_AUTO, /* FineIBT if hardware has IBT, otherwise kCFI */
|
|
CFI_OFF, /* Taditional / IBT depending on .config */
|
|
CFI_KCFI, /* Optionally CALL_PADDING, IBT, RETPOLINE */
|
|
CFI_FINEIBT, /* see arch/x86/kernel/alternative.c */
|
|
};
|
|
|
|
extern enum cfi_mode cfi_mode;
|
|
|
|
struct pt_regs;
|
|
|
|
#ifdef CONFIG_CFI_CLANG
|
|
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
|
|
#define __bpfcall
|
|
extern u32 cfi_bpf_hash;
|
|
extern u32 cfi_bpf_subprog_hash;
|
|
|
|
static inline int cfi_get_offset(void)
|
|
{
|
|
switch (cfi_mode) {
|
|
case CFI_FINEIBT:
|
|
return 16;
|
|
case CFI_KCFI:
|
|
if (IS_ENABLED(CONFIG_CALL_PADDING))
|
|
return 16;
|
|
return 5;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
#define cfi_get_offset cfi_get_offset
|
|
|
|
extern u32 cfi_get_func_hash(void *func);
|
|
|
|
#else
|
|
static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
|
|
{
|
|
return BUG_TRAP_TYPE_NONE;
|
|
}
|
|
#define cfi_bpf_hash 0U
|
|
#define cfi_bpf_subprog_hash 0U
|
|
static inline u32 cfi_get_func_hash(void *func)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_CFI_CLANG */
|
|
|
|
#if HAS_KERNEL_IBT == 1
|
|
#define CFI_NOSEAL(x) asm(IBT_NOSEAL(__stringify(x)))
|
|
#endif
|
|
|
|
#endif /* _ASM_X86_CFI_H */
|