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