162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Clang Control Flow Integrity (CFI) support.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2022 Google LLC
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <asm/cfi.h>
862306a36Sopenharmony_ci#include <asm/insn.h>
962306a36Sopenharmony_ci#include <asm/insn-eval.h>
1062306a36Sopenharmony_ci#include <linux/string.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci * Returns the target address and the expected type when regs->ip points
1462306a36Sopenharmony_ci * to a compiler-generated CFI trap.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_cistatic bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
1762306a36Sopenharmony_ci			    u32 *type)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	char buffer[MAX_INSN_SIZE];
2062306a36Sopenharmony_ci	struct insn insn;
2162306a36Sopenharmony_ci	int offset = 0;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	*target = *type = 0;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	/*
2662306a36Sopenharmony_ci	 * The compiler generates the following instruction sequence
2762306a36Sopenharmony_ci	 * for indirect call checks:
2862306a36Sopenharmony_ci	 *
2962306a36Sopenharmony_ci	 *   movl    -<id>, %r10d       ; 6 bytes
3062306a36Sopenharmony_ci	 *   addl    -4(%reg), %r10d    ; 4 bytes
3162306a36Sopenharmony_ci	 *   je      .Ltmp1             ; 2 bytes
3262306a36Sopenharmony_ci	 *   ud2                        ; <- regs->ip
3362306a36Sopenharmony_ci	 *   .Ltmp1:
3462306a36Sopenharmony_ci	 *
3562306a36Sopenharmony_ci	 * We can decode the expected type and the target address from the
3662306a36Sopenharmony_ci	 * movl/addl instructions.
3762306a36Sopenharmony_ci	 */
3862306a36Sopenharmony_ci	if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 12, MAX_INSN_SIZE))
3962306a36Sopenharmony_ci		return false;
4062306a36Sopenharmony_ci	if (insn_decode_kernel(&insn, &buffer[offset]))
4162306a36Sopenharmony_ci		return false;
4262306a36Sopenharmony_ci	if (insn.opcode.value != 0xBA)
4362306a36Sopenharmony_ci		return false;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	*type = -(u32)insn.immediate.value;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 6, MAX_INSN_SIZE))
4862306a36Sopenharmony_ci		return false;
4962306a36Sopenharmony_ci	if (insn_decode_kernel(&insn, &buffer[offset]))
5062306a36Sopenharmony_ci		return false;
5162306a36Sopenharmony_ci	if (insn.opcode.value != 0x3)
5262306a36Sopenharmony_ci		return false;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* Read the target address from the register. */
5562306a36Sopenharmony_ci	offset = insn_get_modrm_rm_off(&insn, regs);
5662306a36Sopenharmony_ci	if (offset < 0)
5762306a36Sopenharmony_ci		return false;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	*target = *(unsigned long *)((void *)regs + offset);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return true;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * Checks if a ud2 trap is because of a CFI failure, and handles the trap
6662306a36Sopenharmony_ci * if needed. Returns a bug_trap_type value similarly to report_bug.
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_cienum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	unsigned long target;
7162306a36Sopenharmony_ci	u32 type;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!is_cfi_trap(regs->ip))
7462306a36Sopenharmony_ci		return BUG_TRAP_TYPE_NONE;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (!decode_cfi_insn(regs, &target, &type))
7762306a36Sopenharmony_ci		return report_cfi_failure_noaddr(regs, regs->ip);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return report_cfi_failure(regs, regs->ip, &target, type);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * Ensure that __kcfi_typeid_ symbols are emitted for functions that may
8462306a36Sopenharmony_ci * not be indirectly called with all configurations.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ci__ADDRESSABLE(__memcpy)
87