xref: /linux/arch/x86/include/asm/cfi.h (revision 9591fdb0611dccdeeeeacb99d89f0098737d209b)
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, %eax
75  *   jne.32,pn foo+3
76  * foo:
77  *   nopl -42(%rax)		# was endbr64
78  *   ... code here ...
79  *   ret
80  *
81  * direct caller:
82  *   call foo / call foo+4
83  *
84  * indirect caller:
85  *   lea foo(%rip), %r11
86  *   ...
87  *   movl $0x12345678, %eax
88  *   lea  -0x10(%r11), %r11
89  *   nop5
90  *   call *%r11
91  *
92  */
93 enum cfi_mode {
94 	CFI_AUTO,	/* FineIBT if hardware has IBT, otherwise kCFI */
95 	CFI_OFF,	/* Taditional / IBT depending on .config */
96 	CFI_KCFI,	/* Optionally CALL_PADDING, IBT, RETPOLINE */
97 	CFI_FINEIBT,	/* see arch/x86/kernel/alternative.c */
98 };
99 
100 extern enum cfi_mode cfi_mode;
101 
102 #ifdef CONFIG_FINEIBT_BHI
103 extern bool cfi_bhi;
104 #else
105 #define cfi_bhi (0)
106 #endif
107 
108 typedef u8 bhi_thunk[32];
109 extern bhi_thunk __bhi_args[];
110 extern bhi_thunk __bhi_args_end[];
111 
112 struct pt_regs;
113 
114 #ifdef CONFIG_CFI
115 enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
116 #define __bpfcall
117 
cfi_get_offset(void)118 static inline int cfi_get_offset(void)
119 {
120 	switch (cfi_mode) {
121 	case CFI_FINEIBT:
122 		return 16;
123 	case CFI_KCFI:
124 		if (IS_ENABLED(CONFIG_CALL_PADDING))
125 			return 16;
126 		return 5;
127 	default:
128 		return 0;
129 	}
130 }
131 #define cfi_get_offset cfi_get_offset
132 
133 extern u32 cfi_get_func_hash(void *func);
134 #define cfi_get_func_hash cfi_get_func_hash
135 
136 extern int cfi_get_func_arity(void *func);
137 
138 #ifdef CONFIG_FINEIBT
139 extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
140 #else
141 static inline bool
decode_fineibt_insn(struct pt_regs * regs,unsigned long * target,u32 * type)142 decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
143 {
144 	return false;
145 }
146 
147 #endif
148 
149 #else
handle_cfi_failure(struct pt_regs * regs)150 static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
151 {
152 	return BUG_TRAP_TYPE_NONE;
153 }
cfi_get_func_arity(void * func)154 static inline int cfi_get_func_arity(void *func)
155 {
156 	return 0;
157 }
158 #endif /* CONFIG_CFI */
159 
160 #if HAS_KERNEL_IBT == 1
161 #define CFI_NOSEAL(x)	asm(IBT_NOSEAL(__stringify(x)))
162 #endif
163 
164 #endif /* _ASM_X86_CFI_H */
165