/* 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 #include /* * 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_DEFAULT, /* 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 */