File Index
Files and directories
Sign in
FILE

cfi.c

File preview with syntax highlighting.

linux-6.19.14/arch/x86/kernel/cfi.c C
  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 */
 16static 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    -<pos>(%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(buffer, (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(buffer, (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, 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 */
 68enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
 69{
 70	unsigned long target, addr = regs->ip;
 71	u32 type;
 72
 73	switch (cfi_mode) {
 74	case CFI_KCFI:
 75		if (!is_cfi_trap(addr))
 76			return BUG_TRAP_TYPE_NONE;
 77
 78		if (!decode_cfi_insn(regs, &target, &type))
 79			return report_cfi_failure_noaddr(regs, addr);
 80
 81		break;
 82
 83	case CFI_FINEIBT:
 84		if (!decode_fineibt_insn(regs, &target, &type))
 85			return BUG_TRAP_TYPE_NONE;
 86
 87		break;
 88
 89	default:
 90		return BUG_TRAP_TYPE_NONE;
 91	}
 92
 93	return report_cfi_failure(regs, addr, &target, type);
 94}
 95
 96/*
 97 * Ensure that __kcfi_typeid_ symbols are emitted for functions that may
 98 * not be indirectly called with all configurations.
 99 */
100__ADDRESSABLE(__memcpy)
~/ Read-only file preview.