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