File Index
Files and directories
Sign in
FILE

extable.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm64/mm/extable.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Based on arch/arm/mm/extable.c
  4 */
  5
  6#include <linux/bitfield.h>
  7#include <linux/extable.h>
  8#include <linux/uaccess.h>
  9
 10#include <asm/asm-extable.h>
 11#include <asm/esr.h>
 12#include <asm/ptrace.h>
 13
 14static bool cpy_faulted_on_uaccess(const struct exception_table_entry *ex,
 15				   unsigned long esr)
 16{
 17	bool uaccess_is_write = FIELD_GET(EX_DATA_UACCESS_WRITE, ex->data);
 18	bool fault_on_write = esr & ESR_ELx_WNR;
 19
 20	return uaccess_is_write == fault_on_write;
 21}
 22
 23bool insn_may_access_user(unsigned long addr, unsigned long esr)
 24{
 25	const struct exception_table_entry *ex = search_exception_tables(addr);
 26
 27	if (!ex)
 28		return false;
 29
 30	switch (ex->type) {
 31	case EX_TYPE_UACCESS_CPY:
 32		return cpy_faulted_on_uaccess(ex, esr);
 33	default:
 34		return true;
 35	}
 36}
 37
 38static inline unsigned long
 39get_ex_fixup(const struct exception_table_entry *ex)
 40{
 41	return ((unsigned long)&ex->fixup + ex->fixup);
 42}
 43
 44static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
 45					struct pt_regs *regs)
 46{
 47	int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
 48	int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
 49
 50	pt_regs_write_reg(regs, reg_err, -EFAULT);
 51	pt_regs_write_reg(regs, reg_zero, 0);
 52
 53	regs->pc = get_ex_fixup(ex);
 54	return true;
 55}
 56
 57static bool ex_handler_uaccess_cpy(const struct exception_table_entry *ex,
 58				   struct pt_regs *regs, unsigned long esr)
 59{
 60	/* Do not fix up faults on kernel memory accesses */
 61	if (!cpy_faulted_on_uaccess(ex, esr))
 62		return false;
 63
 64	regs->pc = get_ex_fixup(ex);
 65	return true;
 66}
 67
 68static bool
 69ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
 70				  struct pt_regs *regs)
 71{
 72	int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data);
 73	int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
 74	unsigned long data, addr, offset;
 75
 76	addr = pt_regs_read_reg(regs, reg_addr);
 77
 78	offset = addr & 0x7UL;
 79	addr &= ~0x7UL;
 80
 81	data = *(unsigned long*)addr;
 82
 83#ifndef __AARCH64EB__
 84	data >>= 8 * offset;
 85#else
 86	data <<= 8 * offset;
 87#endif
 88
 89	pt_regs_write_reg(regs, reg_data, data);
 90
 91	regs->pc = get_ex_fixup(ex);
 92	return true;
 93}
 94
 95bool fixup_exception(struct pt_regs *regs, unsigned long esr)
 96{
 97	const struct exception_table_entry *ex;
 98
 99	ex = search_exception_tables(instruction_pointer(regs));
100	if (!ex)
101		return false;
102
103	switch (ex->type) {
104	case EX_TYPE_BPF:
105		return ex_handler_bpf(ex, regs);
106	case EX_TYPE_UACCESS_ERR_ZERO:
107	case EX_TYPE_KACCESS_ERR_ZERO:
108		return ex_handler_uaccess_err_zero(ex, regs);
109	case EX_TYPE_UACCESS_CPY:
110		return ex_handler_uaccess_cpy(ex, regs, esr);
111	case EX_TYPE_LOAD_UNALIGNED_ZEROPAD:
112		return ex_handler_load_unaligned_zeropad(ex, regs);
113	}
114
115	BUG();
116}
~/ Read-only file preview.