cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

traps.c (4340B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/bug.h>
      3#include <linux/io.h>
      4#include <linux/types.h>
      5#include <linux/kdebug.h>
      6#include <linux/signal.h>
      7#include <linux/sched.h>
      8#include <linux/sched/debug.h>
      9#include <linux/sched/task_stack.h>
     10#include <linux/uaccess.h>
     11#include <linux/hardirq.h>
     12#include <linux/kernel.h>
     13#include <linux/kexec.h>
     14#include <linux/sched/signal.h>
     15
     16#include <linux/extable.h>
     17#include <linux/module.h>	/* print_modules */
     18#include <asm/unwinder.h>
     19#include <asm/traps.h>
     20
     21static DEFINE_SPINLOCK(die_lock);
     22
     23void __noreturn die(const char *str, struct pt_regs *regs, long err)
     24{
     25	static int die_counter;
     26
     27	oops_enter();
     28
     29	spin_lock_irq(&die_lock);
     30	console_verbose();
     31	bust_spinlocks(1);
     32
     33	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
     34	print_modules();
     35	show_regs(regs);
     36
     37	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
     38			task_pid_nr(current), task_stack_page(current) + 1);
     39
     40	if (!user_mode(regs) || in_interrupt())
     41		dump_mem("Stack: ", KERN_DEFAULT, regs->regs[15],
     42			THREAD_SIZE + (unsigned long)task_stack_page(current));
     43
     44	notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
     45
     46	bust_spinlocks(0);
     47	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
     48	spin_unlock_irq(&die_lock);
     49	oops_exit();
     50
     51	if (kexec_should_crash(current))
     52		crash_kexec(regs);
     53
     54	if (in_interrupt())
     55		panic("Fatal exception in interrupt");
     56
     57	if (panic_on_oops)
     58		panic("Fatal exception");
     59
     60	make_task_dead(SIGSEGV);
     61}
     62
     63void die_if_kernel(const char *str, struct pt_regs *regs, long err)
     64{
     65	if (!user_mode(regs))
     66		die(str, regs, err);
     67}
     68
     69/*
     70 * try and fix up kernelspace address errors
     71 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
     72 * - kernel/userspace interfaces cause a jump to an appropriate handler
     73 * - other kernel errors are bad
     74 */
     75void die_if_no_fixup(const char *str, struct pt_regs *regs, long err)
     76{
     77	if (!user_mode(regs)) {
     78		const struct exception_table_entry *fixup;
     79		fixup = search_exception_tables(regs->pc);
     80		if (fixup) {
     81			regs->pc = fixup->fixup;
     82			return;
     83		}
     84
     85		die(str, regs, err);
     86	}
     87}
     88
     89#ifdef CONFIG_GENERIC_BUG
     90static void handle_BUG(struct pt_regs *regs)
     91{
     92	const struct bug_entry *bug;
     93	unsigned long bugaddr = regs->pc;
     94	enum bug_trap_type tt;
     95
     96	if (!is_valid_bugaddr(bugaddr))
     97		goto invalid;
     98
     99	bug = find_bug(bugaddr);
    100
    101	/* Switch unwinders when unwind_stack() is called */
    102	if (bug->flags & BUGFLAG_UNWINDER)
    103		unwinder_faulted = 1;
    104
    105	tt = report_bug(bugaddr, regs);
    106	if (tt == BUG_TRAP_TYPE_WARN) {
    107		regs->pc += instruction_size(bugaddr);
    108		return;
    109	}
    110
    111invalid:
    112	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
    113}
    114
    115int is_valid_bugaddr(unsigned long addr)
    116{
    117	insn_size_t opcode;
    118
    119	if (addr < PAGE_OFFSET)
    120		return 0;
    121	if (get_kernel_nofault(opcode, (insn_size_t *)addr))
    122		return 0;
    123	if (opcode == TRAPA_BUG_OPCODE)
    124		return 1;
    125
    126	return 0;
    127}
    128#endif
    129
    130/*
    131 * Generic trap handler.
    132 */
    133BUILD_TRAP_HANDLER(debug)
    134{
    135	TRAP_HANDLER_DECL;
    136
    137	/* Rewind */
    138	regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
    139
    140	if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
    141		       SIGTRAP) == NOTIFY_STOP)
    142		return;
    143
    144	force_sig(SIGTRAP);
    145}
    146
    147/*
    148 * Special handler for BUG() traps.
    149 */
    150BUILD_TRAP_HANDLER(bug)
    151{
    152	TRAP_HANDLER_DECL;
    153
    154	/* Rewind */
    155	regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
    156
    157	if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
    158		       SIGTRAP) == NOTIFY_STOP)
    159		return;
    160
    161#ifdef CONFIG_GENERIC_BUG
    162	if (__kernel_text_address(instruction_pointer(regs))) {
    163		insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
    164		if (insn == TRAPA_BUG_OPCODE)
    165			handle_BUG(regs);
    166		return;
    167	}
    168#endif
    169
    170	force_sig(SIGTRAP);
    171}
    172
    173#ifdef CONFIG_DYNAMIC_FTRACE
    174extern void arch_ftrace_nmi_enter(void);
    175extern void arch_ftrace_nmi_exit(void);
    176#else
    177static inline void arch_ftrace_nmi_enter(void) { }
    178static inline void arch_ftrace_nmi_exit(void) { }
    179#endif
    180
    181BUILD_TRAP_HANDLER(nmi)
    182{
    183	TRAP_HANDLER_DECL;
    184
    185	arch_ftrace_nmi_enter();
    186
    187	nmi_enter();
    188	this_cpu_inc(irq_stat.__nmi_count);
    189
    190	switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
    191	case NOTIFY_OK:
    192	case NOTIFY_STOP:
    193		break;
    194	case NOTIFY_BAD:
    195		die("Fatal Non-Maskable Interrupt", regs, SIGINT);
    196	default:
    197		printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n");
    198		break;
    199	}
    200
    201	nmi_exit();
    202
    203	arch_ftrace_nmi_exit();
    204}