1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Clang Control Flow Integrity (CFI) support. 4 * 5 * Copyright (C) 2023 Google LLC 6 */ 7 #include <linux/cfi_types.h> 8 #include <linux/cfi.h> 9 #include <asm/insn.h> 10 11 /* 12 * Returns the target address and the expected type when regs->epc points 13 * to a compiler-generated CFI trap. 14 */ 15 static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, 16 u32 *type) 17 { 18 unsigned long *regs_ptr = (unsigned long *)regs; 19 int rs1_num; 20 u32 insn; 21 22 *target = *type = 0; 23 24 /* 25 * The compiler generates the following instruction sequence 26 * for indirect call checks: 27 * 28 * lw t1, -4(<reg>) 29 * lui t2, <hi20> 30 * addiw t2, t2, <lo12> 31 * beq t1, t2, .Ltmp1 32 * ebreak ; <- regs->epc 33 * .Ltmp1: 34 * jalr <reg> 35 * 36 * We can read the expected type and the target address from the 37 * registers passed to the beq/jalr instructions. 38 */ 39 if (get_kernel_nofault(insn, (void *)regs->epc - 4)) 40 return false; 41 if (!riscv_insn_is_beq(insn)) 42 return false; 43 44 *type = (u32)regs_ptr[RV_EXTRACT_RS1_REG(insn)]; 45 46 if (get_kernel_nofault(insn, (void *)regs->epc) || 47 get_kernel_nofault(insn, (void *)regs->epc + GET_INSN_LENGTH(insn))) 48 return false; 49 50 if (riscv_insn_is_jalr(insn)) 51 rs1_num = RV_EXTRACT_RS1_REG(insn); 52 else if (riscv_insn_is_c_jalr(insn)) 53 rs1_num = RVC_EXTRACT_C2_RS1_REG(insn); 54 else 55 return false; 56 57 *target = regs_ptr[rs1_num]; 58 59 return true; 60 } 61 62 /* 63 * Checks if the ebreak trap is because of a CFI failure, and handles the trap 64 * if needed. Returns a bug_trap_type value similarly to report_bug. 65 */ 66 enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) 67 { 68 unsigned long target; 69 u32 type; 70 71 if (!is_cfi_trap(regs->epc)) 72 return BUG_TRAP_TYPE_NONE; 73 74 if (!decode_cfi_insn(regs, &target, &type)) 75 return report_cfi_failure_noaddr(regs, regs->epc); 76 77 return report_cfi_failure(regs, regs->epc, &target, type); 78 } 79 80 #ifdef CONFIG_CFI_CLANG 81 struct bpf_insn; 82 83 /* Must match bpf_func_t / DEFINE_BPF_PROG_RUN() */ 84 extern unsigned int __bpf_prog_runX(const void *ctx, 85 const struct bpf_insn *insn); 86 DEFINE_CFI_TYPE(cfi_bpf_hash, __bpf_prog_runX); 87 88 /* Must match bpf_callback_t */ 89 extern u64 __bpf_callback_fn(u64, u64, u64, u64, u64); 90 DEFINE_CFI_TYPE(cfi_bpf_subprog_hash, __bpf_callback_fn); 91 92 u32 cfi_get_func_hash(void *func) 93 { 94 u32 hash; 95 96 if (get_kernel_nofault(hash, func - cfi_get_offset())) 97 return 0; 98 99 return hash; 100 } 101 #endif 102