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