]>
git.ipfire.org Git - thirdparty/kernel/linux.git/blob - kernel/cfi.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Clang Control Flow Integrity (CFI) error handling.
5 * Copyright (C) 2022 Google LLC
10 enum bug_trap_type
report_cfi_failure(struct pt_regs
*regs
, unsigned long addr
,
11 unsigned long *target
, u32 type
)
14 pr_err("CFI failure at %pS (target: %pS; expected type: 0x%08x)\n",
15 (void *)addr
, (void *)*target
, type
);
17 pr_err("CFI failure at %pS (no target information)\n",
20 if (IS_ENABLED(CONFIG_CFI_PERMISSIVE
)) {
21 __warn(NULL
, 0, (void *)addr
, 0, regs
, NULL
);
22 return BUG_TRAP_TYPE_WARN
;
25 return BUG_TRAP_TYPE_BUG
;
28 #ifdef CONFIG_ARCH_USES_CFI_TRAPS
29 static inline unsigned long trap_address(s32
*p
)
31 return (unsigned long)((long)p
+ (long)*p
);
34 static bool is_trap(unsigned long addr
, s32
*start
, s32
*end
)
38 for (p
= start
; p
< end
; ++p
) {
39 if (trap_address(p
) == addr
)
47 /* Populates `kcfi_trap(_end)?` fields in `struct module`. */
48 void module_cfi_finalize(const Elf_Ehdr
*hdr
, const Elf_Shdr
*sechdrs
,
54 mod
->kcfi_traps
= NULL
;
55 mod
->kcfi_traps_end
= NULL
;
57 secstrings
= (char *)hdr
+ sechdrs
[hdr
->e_shstrndx
].sh_offset
;
59 for (i
= 1; i
< hdr
->e_shnum
; i
++) {
60 if (strcmp(secstrings
+ sechdrs
[i
].sh_name
, "__kcfi_traps"))
63 mod
->kcfi_traps
= (s32
*)sechdrs
[i
].sh_addr
;
64 mod
->kcfi_traps_end
= (s32
*)(sechdrs
[i
].sh_addr
+ sechdrs
[i
].sh_size
);
69 static bool is_module_cfi_trap(unsigned long addr
)
74 rcu_read_lock_sched_notrace();
76 mod
= __module_address(addr
);
78 found
= is_trap(addr
, mod
->kcfi_traps
, mod
->kcfi_traps_end
);
80 rcu_read_unlock_sched_notrace();
84 #else /* CONFIG_MODULES */
85 static inline bool is_module_cfi_trap(unsigned long addr
)
89 #endif /* CONFIG_MODULES */
91 extern s32 __start___kcfi_traps
[];
92 extern s32 __stop___kcfi_traps
[];
94 bool is_cfi_trap(unsigned long addr
)
96 if (is_trap(addr
, __start___kcfi_traps
, __stop___kcfi_traps
))
99 return is_module_cfi_trap(addr
);
101 #endif /* CONFIG_ARCH_USES_CFI_TRAPS */