Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/kernel/cfi.c
26243 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Clang Control Flow Integrity (CFI) error handling.
4
*
5
* Copyright (C) 2022 Google LLC
6
*/
7
8
#include <linux/bpf.h>
9
#include <linux/cfi_types.h>
10
#include <linux/cfi.h>
11
12
bool cfi_warn __ro_after_init = IS_ENABLED(CONFIG_CFI_PERMISSIVE);
13
14
enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
15
unsigned long *target, u32 type)
16
{
17
if (target)
18
pr_err("CFI failure at %pS (target: %pS; expected type: 0x%08x)\n",
19
(void *)addr, (void *)*target, type);
20
else
21
pr_err("CFI failure at %pS (no target information)\n",
22
(void *)addr);
23
24
if (cfi_warn) {
25
__warn(NULL, 0, (void *)addr, 0, regs, NULL);
26
return BUG_TRAP_TYPE_WARN;
27
}
28
29
return BUG_TRAP_TYPE_BUG;
30
}
31
32
/*
33
* Declare two non-existent functions with types that match bpf_func_t and
34
* bpf_callback_t pointers, and use DEFINE_CFI_TYPE to define type hash
35
* variables for each function type. The cfi_bpf_* variables are used by
36
* arch-specific BPF JIT implementations to ensure indirectly callable JIT
37
* code has matching CFI type hashes.
38
*/
39
extern typeof(*(bpf_func_t)0) __bpf_prog_runX;
40
DEFINE_CFI_TYPE(cfi_bpf_hash, __bpf_prog_runX);
41
42
extern typeof(*(bpf_callback_t)0) __bpf_callback_fn;
43
DEFINE_CFI_TYPE(cfi_bpf_subprog_hash, __bpf_callback_fn);
44
45
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
46
static inline unsigned long trap_address(s32 *p)
47
{
48
return (unsigned long)((long)p + (long)*p);
49
}
50
51
static bool is_trap(unsigned long addr, s32 *start, s32 *end)
52
{
53
s32 *p;
54
55
for (p = start; p < end; ++p) {
56
if (trap_address(p) == addr)
57
return true;
58
}
59
60
return false;
61
}
62
63
#ifdef CONFIG_MODULES
64
/* Populates `kcfi_trap(_end)?` fields in `struct module`. */
65
void module_cfi_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
66
struct module *mod)
67
{
68
char *secstrings;
69
unsigned int i;
70
71
mod->kcfi_traps = NULL;
72
mod->kcfi_traps_end = NULL;
73
74
secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
75
76
for (i = 1; i < hdr->e_shnum; i++) {
77
if (strcmp(secstrings + sechdrs[i].sh_name, "__kcfi_traps"))
78
continue;
79
80
mod->kcfi_traps = (s32 *)sechdrs[i].sh_addr;
81
mod->kcfi_traps_end = (s32 *)(sechdrs[i].sh_addr + sechdrs[i].sh_size);
82
break;
83
}
84
}
85
86
static bool is_module_cfi_trap(unsigned long addr)
87
{
88
struct module *mod;
89
bool found = false;
90
91
guard(rcu)();
92
mod = __module_address(addr);
93
if (mod)
94
found = is_trap(addr, mod->kcfi_traps, mod->kcfi_traps_end);
95
96
return found;
97
}
98
#else /* CONFIG_MODULES */
99
static inline bool is_module_cfi_trap(unsigned long addr)
100
{
101
return false;
102
}
103
#endif /* CONFIG_MODULES */
104
105
extern s32 __start___kcfi_traps[];
106
extern s32 __stop___kcfi_traps[];
107
108
bool is_cfi_trap(unsigned long addr)
109
{
110
if (is_trap(addr, __start___kcfi_traps, __stop___kcfi_traps))
111
return true;
112
113
return is_module_cfi_trap(addr);
114
}
115
#endif /* CONFIG_ARCH_USES_CFI_TRAPS */
116
117