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.h> |
8 | #include <asm/insn.h> |
9 | |
10 | /* |
11 | * Returns the target address and the expected type when regs->epc points |
12 | * to a compiler-generated CFI trap. |
13 | */ |
14 | static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, |
15 | u32 *type) |
16 | { |
17 | unsigned long *regs_ptr = (unsigned long *)regs; |
18 | int rs1_num; |
19 | u32 insn; |
20 | |
21 | *target = *type = 0; |
22 | |
23 | /* |
24 | * The compiler generates the following instruction sequence |
25 | * for indirect call checks: |
26 | * |
27 | * lw t1, -4(<reg>) |
28 | * lui t2, <hi20> |
29 | * addiw t2, t2, <lo12> |
30 | * beq t1, t2, .Ltmp1 |
31 | * ebreak ; <- regs->epc |
32 | * .Ltmp1: |
33 | * jalr <reg> |
34 | * |
35 | * We can read the expected type and the target address from the |
36 | * registers passed to the beq/jalr instructions. |
37 | */ |
38 | if (get_kernel_nofault(insn, (void *)regs->epc - 4)) |
39 | return false; |
40 | if (!riscv_insn_is_beq(insn)) |
41 | return false; |
42 | |
43 | *type = (u32)regs_ptr[RV_EXTRACT_RS1_REG(insn)]; |
44 | |
45 | if (get_kernel_nofault(insn, (void *)regs->epc) || |
46 | get_kernel_nofault(insn, (void *)regs->epc + GET_INSN_LENGTH(insn))) |
47 | return false; |
48 | |
49 | if (riscv_insn_is_jalr(insn)) |
50 | rs1_num = RV_EXTRACT_RS1_REG(insn); |
51 | else if (riscv_insn_is_c_jalr(insn)) |
52 | rs1_num = RVC_EXTRACT_C2_RS1_REG(insn); |
53 | else |
54 | return false; |
55 | |
56 | *target = regs_ptr[rs1_num]; |
57 | |
58 | return true; |
59 | } |
60 | |
61 | /* |
62 | * Checks if the ebreak trap is because of a CFI failure, and handles the trap |
63 | * if needed. Returns a bug_trap_type value similarly to report_bug. |
64 | */ |
65 | enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) |
66 | { |
67 | unsigned long target; |
68 | u32 type; |
69 | |
70 | if (!is_cfi_trap(addr: regs->epc)) |
71 | return BUG_TRAP_TYPE_NONE; |
72 | |
73 | if (!decode_cfi_insn(regs, target: &target, type: &type)) |
74 | return report_cfi_failure_noaddr(regs, regs->epc); |
75 | |
76 | return report_cfi_failure(regs, regs->epc, &target, type); |
77 | } |
78 | |
79 | #ifdef CONFIG_CFI_CLANG |
80 | struct bpf_insn; |
81 | |
82 | /* Must match bpf_func_t / DEFINE_BPF_PROG_RUN() */ |
83 | extern unsigned int __bpf_prog_runX(const void *ctx, |
84 | const struct bpf_insn *insn); |
85 | |
86 | /* |
87 | * Force a reference to the external symbol so the compiler generates |
88 | * __kcfi_typid. |
89 | */ |
90 | __ADDRESSABLE(__bpf_prog_runX); |
91 | |
92 | /* u32 __ro_after_init cfi_bpf_hash = __kcfi_typeid___bpf_prog_runX; */ |
93 | asm ( |
94 | " .pushsection .data..ro_after_init,\"aw\",@progbits \n" |
95 | " .type cfi_bpf_hash,@object \n" |
96 | " .globl cfi_bpf_hash \n" |
97 | " .p2align 2, 0x0 \n" |
98 | "cfi_bpf_hash: \n" |
99 | " .word __kcfi_typeid___bpf_prog_runX \n" |
100 | " .size cfi_bpf_hash, 4 \n" |
101 | " .popsection \n" |
102 | ); |
103 | |
104 | /* Must match bpf_callback_t */ |
105 | extern u64 __bpf_callback_fn(u64, u64, u64, u64, u64); |
106 | |
107 | __ADDRESSABLE(__bpf_callback_fn); |
108 | |
109 | /* u32 __ro_after_init cfi_bpf_subprog_hash = __kcfi_typeid___bpf_callback_fn; */ |
110 | asm ( |
111 | " .pushsection .data..ro_after_init,\"aw\",@progbits \n" |
112 | " .type cfi_bpf_subprog_hash,@object \n" |
113 | " .globl cfi_bpf_subprog_hash \n" |
114 | " .p2align 2, 0x0 \n" |
115 | "cfi_bpf_subprog_hash: \n" |
116 | " .word __kcfi_typeid___bpf_callback_fn \n" |
117 | " .size cfi_bpf_subprog_hash, 4 \n" |
118 | " .popsection \n" |
119 | ); |
120 | |
121 | u32 cfi_get_func_hash(void *func) |
122 | { |
123 | u32 hash; |
124 | |
125 | if (get_kernel_nofault(hash, func - cfi_get_offset())) |
126 | return 0; |
127 | |
128 | return hash; |
129 | } |
130 | #endif |
131 | |