1103 lines · 27.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Based on arch/arm/kernel/traps.c * * Copyright (C) 1995-2009 Russell King * Copyright (C) 2012 ARM Ltd. */ #include <linux/bug.h>#include <linux/context_tracking.h>#include <linux/signal.h>#include <linux/kallsyms.h>#include <linux/kprobes.h>#include <linux/spinlock.h>#include <linux/uaccess.h>#include <linux/hardirq.h>#include <linux/kdebug.h>#include <linux/module.h>#include <linux/kexec.h>#include <linux/delay.h>#include <linux/efi.h>#include <linux/init.h>#include <linux/sched/signal.h>#include <linux/sched/debug.h>#include <linux/sched/task_stack.h>#include <linux/sizes.h>#include <linux/syscalls.h>#include <linux/mm_types.h>#include <linux/kasan.h>#include <linux/ubsan.h>#include <linux/cfi.h> #include <asm/atomic.h>#include <asm/bug.h>#include <asm/cpufeature.h>#include <asm/daifflags.h>#include <asm/debug-monitors.h>#include <asm/efi.h>#include <asm/esr.h>#include <asm/exception.h>#include <asm/extable.h>#include <asm/insn.h>#include <asm/kprobes.h>#include <asm/text-patching.h>#include <asm/traps.h>#include <asm/smp.h>#include <asm/stack_pointer.h>#include <asm/stacktrace.h>#include <asm/system_misc.h>#include <asm/sysreg.h> static bool __kprobes __check_eq(unsigned long pstate){	return (pstate & PSR_Z_BIT) != 0;} static bool __kprobes __check_ne(unsigned long pstate){	return (pstate & PSR_Z_BIT) == 0;} static bool __kprobes __check_cs(unsigned long pstate){	return (pstate & PSR_C_BIT) != 0;} static bool __kprobes __check_cc(unsigned long pstate){	return (pstate & PSR_C_BIT) == 0;} static bool __kprobes __check_mi(unsigned long pstate){	return (pstate & PSR_N_BIT) != 0;} static bool __kprobes __check_pl(unsigned long pstate){	return (pstate & PSR_N_BIT) == 0;} static bool __kprobes __check_vs(unsigned long pstate){	return (pstate & PSR_V_BIT) != 0;} static bool __kprobes __check_vc(unsigned long pstate){	return (pstate & PSR_V_BIT) == 0;} static bool __kprobes __check_hi(unsigned long pstate){	pstate &= ~(pstate >> 1);	/* PSR_C_BIT &= ~PSR_Z_BIT */	return (pstate & PSR_C_BIT) != 0;} static bool __kprobes __check_ls(unsigned long pstate){	pstate &= ~(pstate >> 1);	/* PSR_C_BIT &= ~PSR_Z_BIT */	return (pstate & PSR_C_BIT) == 0;} static bool __kprobes __check_ge(unsigned long pstate){	pstate ^= (pstate << 3);	/* PSR_N_BIT ^= PSR_V_BIT */	return (pstate & PSR_N_BIT) == 0;} static bool __kprobes __check_lt(unsigned long pstate){	pstate ^= (pstate << 3);	/* PSR_N_BIT ^= PSR_V_BIT */	return (pstate & PSR_N_BIT) != 0;} static bool __kprobes __check_gt(unsigned long pstate){	/*PSR_N_BIT ^= PSR_V_BIT */	unsigned long temp = pstate ^ (pstate << 3); 	temp |= (pstate << 1);	/*PSR_N_BIT |= PSR_Z_BIT */	return (temp & PSR_N_BIT) == 0;} static bool __kprobes __check_le(unsigned long pstate){	/*PSR_N_BIT ^= PSR_V_BIT */	unsigned long temp = pstate ^ (pstate << 3); 	temp |= (pstate << 1);	/*PSR_N_BIT |= PSR_Z_BIT */	return (temp & PSR_N_BIT) != 0;} static bool __kprobes __check_al(unsigned long pstate){	return true;} /* * Note that the ARMv8 ARM calls condition code 0b1111 "nv", but states that * it behaves identically to 0b1110 ("al"). */pstate_check_t * const aarch32_opcode_cond_checks[16] = {	__check_eq, __check_ne, __check_cs, __check_cc,	__check_mi, __check_pl, __check_vs, __check_vc,	__check_hi, __check_ls, __check_ge, __check_lt,	__check_gt, __check_le, __check_al, __check_al}; int show_unhandled_signals = 0; void dump_kernel_instr(unsigned long kaddr){	char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;	int i; 	if (!is_ttbr1_addr(kaddr))		return; 	for (i = -4; i < 1; i++) {		unsigned int val, bad; 		bad = aarch64_insn_read(&((u32 *)kaddr)[i], &val); 		if (!bad)			p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val);		else			p += sprintf(p, i == 0 ? "(????????) " : "???????? ");	} 	printk(KERN_EMERG "Code: %s\n", str);} #define S_SMP " SMP" static int __die(const char *str, long err, struct pt_regs *regs){	static int die_counter;	int ret;	unsigned long addr = instruction_pointer(regs); 	pr_emerg("Internal error: %s: %016lx [#%d] " S_SMP "\n",		 str, err, ++die_counter); 	/* trap and error numbers are mostly meaningless on ARM */	ret = notify_die(DIE_OOPS, str, regs, err, 0, SIGSEGV);	if (ret == NOTIFY_STOP)		return ret; 	print_modules();	show_regs(regs); 	if (user_mode(regs))		return ret; 	dump_kernel_instr(addr); 	return ret;} static DEFINE_RAW_SPINLOCK(die_lock); /* * This function is protected against re-entrancy. */void die(const char *str, struct pt_regs *regs, long err){	int ret;	unsigned long flags; 	raw_spin_lock_irqsave(&die_lock, flags); 	oops_enter(); 	console_verbose();	bust_spinlocks(1);	ret = __die(str, err, regs); 	if (regs && kexec_should_crash(current))		crash_kexec(regs); 	bust_spinlocks(0);	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);	oops_exit(); 	if (in_interrupt())		panic("%s: Fatal exception in interrupt", str);	if (panic_on_oops)		panic("%s: Fatal exception", str); 	raw_spin_unlock_irqrestore(&die_lock, flags); 	if (ret != NOTIFY_STOP)		make_task_dead(SIGSEGV);} static void arm64_show_signal(int signo, const char *str){	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,				      DEFAULT_RATELIMIT_BURST);	struct task_struct *tsk = current;	unsigned long esr = tsk->thread.fault_code;	struct pt_regs *regs = task_pt_regs(tsk); 	/* Leave if the signal won't be shown */	if (!show_unhandled_signals ||	    !unhandled_signal(tsk, signo) ||	    !__ratelimit(&rs))		return; 	pr_info("%s[%d]: unhandled exception: ", tsk->comm, task_pid_nr(tsk));	if (esr)		pr_cont("%s, ESR 0x%016lx, ", esr_get_class_string(esr), esr); 	pr_cont("%s", str);	print_vma_addr(KERN_CONT " in ", regs->pc);	pr_cont("\n");	__show_regs(regs);} void arm64_force_sig_fault(int signo, int code, unsigned long far,			   const char *str){	arm64_show_signal(signo, str);	if (signo == SIGKILL)		force_sig(SIGKILL);	else		force_sig_fault(signo, code, (void __user *)far);} void arm64_force_sig_fault_pkey(unsigned long far, const char *str, int pkey){	arm64_show_signal(SIGSEGV, str);	force_sig_pkuerr((void __user *)far, pkey);} void arm64_force_sig_mceerr(int code, unsigned long far, short lsb,			    const char *str){	arm64_show_signal(SIGBUS, str);	force_sig_mceerr(code, (void __user *)far, lsb);} void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far,				       const char *str){	arm64_show_signal(SIGTRAP, str);	force_sig_ptrace_errno_trap(errno, (void __user *)far);} void arm64_notify_die(const char *str, struct pt_regs *regs,		      int signo, int sicode, unsigned long far,		      unsigned long err){	if (user_mode(regs)) {		WARN_ON(regs != current_pt_regs());		current->thread.fault_address = 0;		current->thread.fault_code = err; 		arm64_force_sig_fault(signo, sicode, far, str);	} else {		die(str, regs, err);	}} #ifdef CONFIG_COMPAT#define PSTATE_IT_1_0_SHIFT	25#define PSTATE_IT_1_0_MASK	(0x3 << PSTATE_IT_1_0_SHIFT)#define PSTATE_IT_7_2_SHIFT	10#define PSTATE_IT_7_2_MASK	(0x3f << PSTATE_IT_7_2_SHIFT) static u32 compat_get_it_state(struct pt_regs *regs){	u32 it, pstate = regs->pstate; 	it  = (pstate & PSTATE_IT_1_0_MASK) >> PSTATE_IT_1_0_SHIFT;	it |= ((pstate & PSTATE_IT_7_2_MASK) >> PSTATE_IT_7_2_SHIFT) << 2; 	return it;} static void compat_set_it_state(struct pt_regs *regs, u32 it){	u32 pstate_it; 	pstate_it  = (it << PSTATE_IT_1_0_SHIFT) & PSTATE_IT_1_0_MASK;	pstate_it |= ((it >> 2) << PSTATE_IT_7_2_SHIFT) & PSTATE_IT_7_2_MASK; 	regs->pstate &= ~PSR_AA32_IT_MASK;	regs->pstate |= pstate_it;} static void advance_itstate(struct pt_regs *regs){	u32 it; 	/* ARM mode */	if (!(regs->pstate & PSR_AA32_T_BIT) ||	    !(regs->pstate & PSR_AA32_IT_MASK))		return; 	it  = compat_get_it_state(regs); 	/*	 * If this is the last instruction of the block, wipe the IT	 * state. Otherwise advance it.	 */	if (!(it & 7))		it = 0;	else		it = (it & 0xe0) | ((it << 1) & 0x1f); 	compat_set_it_state(regs, it);}#elsestatic void advance_itstate(struct pt_regs *regs){}#endif void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size){	regs->pc += size; 	/*	 * If we were single stepping, we want to get the step exception after	 * we return from the trap.	 */	if (user_mode(regs))		user_fastforward_single_step(current); 	if (compat_user_mode(regs))		advance_itstate(regs);	else		regs->pstate &= ~PSR_BTYPE_MASK;} static int user_insn_read(struct pt_regs *regs, u32 *insnp){	u32 instr;	unsigned long pc = instruction_pointer(regs); 	if (compat_thumb_mode(regs)) {		/* 16-bit Thumb instruction */		__le16 instr_le;		if (get_user(instr_le, (__le16 __user *)pc))			return -EFAULT;		instr = le16_to_cpu(instr_le);		if (aarch32_insn_is_wide(instr)) {			u32 instr2; 			if (get_user(instr_le, (__le16 __user *)(pc + 2)))				return -EFAULT;			instr2 = le16_to_cpu(instr_le);			instr = (instr << 16) | instr2;		}	} else {		/* 32-bit ARM instruction */		__le32 instr_le;		if (get_user(instr_le, (__le32 __user *)pc))			return -EFAULT;		instr = le32_to_cpu(instr_le);	} 	*insnp = instr;	return 0;} void force_signal_inject(int signal, int code, unsigned long address, unsigned long err){	const char *desc;	struct pt_regs *regs = current_pt_regs(); 	if (WARN_ON(!user_mode(regs)))		return; 	switch (signal) {	case SIGILL:		desc = "undefined instruction";		break;	case SIGSEGV:		desc = "illegal memory access";		break;	default:		desc = "unknown or unrecoverable error";		break;	} 	/* Force signals we don't understand to SIGKILL */	if (WARN_ON(signal != SIGKILL &&		    siginfo_layout(signal, code) != SIL_FAULT)) {		signal = SIGKILL;	} 	arm64_notify_die(desc, regs, signal, code, address, err);} /* * Set up process info to signal segmentation fault - called on access error. */void arm64_notify_segfault(unsigned long addr){	int code; 	mmap_read_lock(current->mm);	if (find_vma(current->mm, untagged_addr(addr)) == NULL)		code = SEGV_MAPERR;	else		code = SEGV_ACCERR;	mmap_read_unlock(current->mm); 	force_signal_inject(SIGSEGV, code, addr, 0);} void do_el0_undef(struct pt_regs *regs, unsigned long esr){	u32 insn; 	/* check for AArch32 breakpoint instructions */	if (try_handle_aarch32_break(regs))		return; 	if (user_insn_read(regs, &insn))		goto out_err; 	if (try_emulate_mrs(regs, insn))		return; 	if (try_emulate_armv8_deprecated(regs, insn))		return; out_err:	force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);} void do_el1_undef(struct pt_regs *regs, unsigned long esr){	u32 insn; 	if (aarch64_insn_read((void *)regs->pc, &insn))		goto out_err; 	if (try_emulate_el1_ssbs(regs, insn))		return; out_err:	die("Oops - Undefined instruction", regs, esr);} void do_el0_bti(struct pt_regs *regs){	force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);} void do_el1_bti(struct pt_regs *regs, unsigned long esr){	if (efi_runtime_fixup_exception(regs, "BTI violation")) {		regs->pstate &= ~PSR_BTYPE_MASK;		return;	}

Lines 1–500 of 1103.