1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Clang Control Flow Integrity (CFI) support. |
4 | * |
5 | * Copyright (C) 2022 Google LLC |
6 | */ |
7 | #include <linux/string.h> |
8 | #include <linux/cfi.h> |
9 | #include <asm/insn.h> |
10 | #include <asm/insn-eval.h> |
11 | |
12 | /* |
13 | * Returns the target address and the expected type when regs->ip points |
14 | * to a compiler-generated CFI trap. |
15 | */ |
16 | static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, |
17 | u32 *type) |
18 | { |
19 | char buffer[MAX_INSN_SIZE]; |
20 | struct insn insn; |
21 | int offset = 0; |
22 | |
23 | *target = *type = 0; |
24 | |
25 | /* |
26 | * The compiler generates the following instruction sequence |
27 | * for indirect call checks: |
28 | * |
29 | * movl -<id>, %r10d ; 6 bytes |
30 | * addl -4(%reg), %r10d ; 4 bytes |
31 | * je .Ltmp1 ; 2 bytes |
32 | * ud2 ; <- regs->ip |
33 | * .Ltmp1: |
34 | * |
35 | * We can decode the expected type and the target address from the |
36 | * movl/addl instructions. |
37 | */ |
38 | if (copy_from_kernel_nofault(dst: buffer, src: (void *)regs->ip - 12, MAX_INSN_SIZE)) |
39 | return false; |
40 | if (insn_decode_kernel(&insn, &buffer[offset])) |
41 | return false; |
42 | if (insn.opcode.value != 0xBA) |
43 | return false; |
44 | |
45 | *type = -(u32)insn.immediate.value; |
46 | |
47 | if (copy_from_kernel_nofault(dst: buffer, src: (void *)regs->ip - 6, MAX_INSN_SIZE)) |
48 | return false; |
49 | if (insn_decode_kernel(&insn, &buffer[offset])) |
50 | return false; |
51 | if (insn.opcode.value != 0x3) |
52 | return false; |
53 | |
54 | /* Read the target address from the register. */ |
55 | offset = insn_get_modrm_rm_off(insn: &insn, regs); |
56 | if (offset < 0) |
57 | return false; |
58 | |
59 | *target = *(unsigned long *)((void *)regs + offset); |
60 | |
61 | return true; |
62 | } |
63 | |
64 | /* |
65 | * Checks if a ud2 trap is because of a CFI failure, and handles the trap |
66 | * if needed. Returns a bug_trap_type value similarly to report_bug. |
67 | */ |
68 | enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) |
69 | { |
70 | unsigned long target; |
71 | u32 type; |
72 | |
73 | if (!is_cfi_trap(addr: regs->ip)) |
74 | return BUG_TRAP_TYPE_NONE; |
75 | |
76 | if (!decode_cfi_insn(regs, target: &target, type: &type)) |
77 | return report_cfi_failure_noaddr(regs, regs->ip); |
78 | |
79 | return report_cfi_failure(regs, regs->ip, &target, type); |
80 | } |
81 | |
82 | /* |
83 | * Ensure that __kcfi_typeid_ symbols are emitted for functions that may |
84 | * not be indirectly called with all configurations. |
85 | */ |
86 | __ADDRESSABLE(__memcpy) |
87 | |