summaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/cfi.h
blob: 31d19c815f992ca6951833851cb60aa250119e46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* 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 <linux/bug.h>
#include <asm/ibt.h>

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