xref: /linux/arch/riscv/kernel/cfi.c (revision 5ccaeedb489b41ce6cb857d0de488992746be282)
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