1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_X86_CFI_H 3 #define _ASM_X86_CFI_H 4 5 /* 6 * Clang Control Flow Integrity (CFI) support. 7 * 8 * Copyright (C) 2022 Google LLC 9 */ 10 #include <linux/bug.h> 11 #include <asm/ibt.h> 12 13 /* 14 * An overview of the various calling conventions... 15 * 16 * Traditional: 17 * 18 * foo: 19 * ... code here ... 20 * ret 21 * 22 * direct caller: 23 * call foo 24 * 25 * indirect caller: 26 * lea foo(%rip), %r11 27 * ... 28 * call *%r11 29 * 30 * 31 * IBT: 32 * 33 * foo: 34 * endbr64 35 * ... code here ... 36 * ret 37 * 38 * direct caller: 39 * call foo / call foo+4 40 * 41 * indirect caller: 42 * lea foo(%rip), %r11 43 * ... 44 * call *%r11 45 * 46 * 47 * kCFI: 48 * 49 * __cfi_foo: 50 * movl $0x12345678, %eax 51 * # 11 nops when CONFIG_CALL_PADDING 52 * foo: 53 * endbr64 # when IBT 54 * ... code here ... 55 * ret 56 * 57 * direct call: 58 * call foo # / call foo+4 when IBT 59 * 60 * indirect call: 61 * lea foo(%rip), %r11 62 * ... 63 * movl $(-0x12345678), %r10d 64 * addl -4(%r11), %r10d # -15 when CONFIG_CALL_PADDING 65 * jz 1f 66 * ud2 67 * 1:call *%r11 68 * 69 * 70 * FineIBT (builds as kCFI + CALL_PADDING + IBT + RETPOLINE and runtime patches into): 71 * 72 * __cfi_foo: 73 * endbr64 74 * subl 0x12345678, %r10d 75 * jz foo 76 * ud2 77 * nop 78 * foo: 79 * osp nop3 # was endbr64 80 * ... code here ... 81 * ret 82 * 83 * direct caller: 84 * call foo / call foo+4 85 * 86 * indirect caller: 87 * lea foo(%rip), %r11 88 * ... 89 * movl $0x12345678, %r10d 90 * subl $16, %r11 91 * nop4 92 * call *%r11 93 * 94 */ 95 enum cfi_mode { 96 CFI_AUTO, /* FineIBT if hardware has IBT, otherwise kCFI */ 97 CFI_OFF, /* Taditional / IBT depending on .config */ 98 CFI_KCFI, /* Optionally CALL_PADDING, IBT, RETPOLINE */ 99 CFI_FINEIBT, /* see arch/x86/kernel/alternative.c */ 100 }; 101 102 extern enum cfi_mode cfi_mode; 103 104 struct pt_regs; 105 106 #ifdef CONFIG_CFI_CLANG 107 enum bug_trap_type handle_cfi_failure(struct pt_regs *regs); 108 #define __bpfcall 109 extern u32 cfi_bpf_hash; 110 extern u32 cfi_bpf_subprog_hash; 111 112 static inline int cfi_get_offset(void) 113 { 114 switch (cfi_mode) { 115 case CFI_FINEIBT: 116 return 16; 117 case CFI_KCFI: 118 if (IS_ENABLED(CONFIG_CALL_PADDING)) 119 return 16; 120 return 5; 121 default: 122 return 0; 123 } 124 } 125 #define cfi_get_offset cfi_get_offset 126 127 extern u32 cfi_get_func_hash(void *func); 128 129 #else 130 static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) 131 { 132 return BUG_TRAP_TYPE_NONE; 133 } 134 #define cfi_bpf_hash 0U 135 #define cfi_bpf_subprog_hash 0U 136 static inline u32 cfi_get_func_hash(void *func) 137 { 138 return 0; 139 } 140 #endif /* CONFIG_CFI_CLANG */ 141 142 #if HAS_KERNEL_IBT == 1 143 #define CFI_NOSEAL(x) asm(IBT_NOSEAL(__stringify(x))) 144 #endif 145 146 #endif /* _ASM_X86_CFI_H */ 147