Release 4.14 arch/x86/kernel/traps.c
/*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
* Handle hardware traps and faults.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/context_tracking.h>
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
#include <linux/spinlock.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <linux/kgdb.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/ptrace.h>
#include <linux/uprobes.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kexec.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/bug.h>
#include <linux/nmi.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/io.h>
#if defined(CONFIG_EDAC)
#include <linux/edac.h>
#endif
#include <asm/kmemcheck.h>
#include <asm/stacktrace.h>
#include <asm/processor.h>
#include <asm/debugreg.h>
#include <linux/atomic.h>
#include <asm/text-patching.h>
#include <asm/ftrace.h>
#include <asm/traps.h>
#include <asm/desc.h>
#include <asm/fpu/internal.h>
#include <asm/mce.h>
#include <asm/fixmap.h>
#include <asm/mach_traps.h>
#include <asm/alternative.h>
#include <asm/fpu/xstate.h>
#include <asm/trace/mpx.h>
#include <asm/mpx.h>
#include <asm/vm86.h>
#ifdef CONFIG_X86_64
#include <asm/x86_init.h>
#include <asm/pgalloc.h>
#include <asm/proto.h>
#else
#include <asm/processor-flags.h>
#include <asm/setup.h>
#include <asm/proto.h>
#endif
DECLARE_BITMAP(used_vectors, NR_VECTORS);
static inline void cond_local_irq_enable(struct pt_regs *regs)
{
if (regs->flags & X86_EFLAGS_IF)
local_irq_enable();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Harvey Harrison | 12 | 52.17% | 1 | 20.00% |
Alexander van Heukelum | 7 | 30.43% | 1 | 20.00% |
Linus Torvalds (pre-git) | 2 | 8.70% | 1 | 20.00% |
Alexander Kuleshov | 1 | 4.35% | 1 | 20.00% |
Jan Beulich | 1 | 4.35% | 1 | 20.00% |
Total | 23 | 100.00% | 5 | 100.00% |
static inline void cond_local_irq_disable(struct pt_regs *regs)
{
if (regs->flags & X86_EFLAGS_IF)
local_irq_disable();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexander van Heukelum | 22 | 95.65% | 1 | 50.00% |
Alexander Kuleshov | 1 | 4.35% | 1 | 50.00% |
Total | 23 | 100.00% | 2 | 100.00% |
/*
* In IST context, we explicitly disable preemption. This serves two
* purposes: it makes it much less likely that we would accidentally
* schedule in IST context and it will force a warning if we somehow
* manage to schedule by accident.
*/
void ist_enter(struct pt_regs *regs)
{
if (user_mode(regs)) {
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
} else {
/*
* We might have interrupted pretty much anything. In
* fact, if we're a machine check, we can even interrupt
* NMI processing. We don't want in_nmi() to return true,
* but we need to notify RCU.
*/
rcu_nmi_enter();
}
preempt_disable();
/* This code is a bit fragile. Test it. */
RCU_LOCKDEP_WARN(!rcu_is_watching(), "ist_enter didn't work");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 44 | 91.67% | 6 | 75.00% |
Paul E. McKenney | 2 | 4.17% | 1 | 12.50% |
Linus Torvalds | 2 | 4.17% | 1 | 12.50% |
Total | 48 | 100.00% | 8 | 100.00% |
void ist_exit(struct pt_regs *regs)
{
preempt_enable_no_resched();
if (!user_mode(regs))
rcu_nmi_exit();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 24 | 100.00% | 4 | 100.00% |
Total | 24 | 100.00% | 4 | 100.00% |
/**
* ist_begin_non_atomic() - begin a non-atomic section in an IST exception
* @regs: regs passed to the IST exception handler
*
* IST exception handlers normally cannot schedule. As a special
* exception, if the exception interrupted userspace code (i.e.
* user_mode(regs) would return true) and the exception was not
* a double fault, it can be safe to schedule. ist_begin_non_atomic()
* begins a non-atomic section within an ist_enter()/ist_exit() region.
* Callers are responsible for enabling interrupts themselves inside
* the non-atomic section, and callers must call ist_end_non_atomic()
* before ist_exit().
*/
void ist_begin_non_atomic(struct pt_regs *regs)
{
BUG_ON(!user_mode(regs));
/*
* Sanity check: we need to be on the normal thread stack. This
* will catch asm bugs and any attempt to use ist_preempt_enable
* from double_fault.
*/
BUG_ON((unsigned long)(current_top_of_stack() -
current_stack_pointer) >= THREAD_SIZE);
preempt_enable_no_resched();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 39 | 100.00% | 5 | 100.00% |
Total | 39 | 100.00% | 5 | 100.00% |
/**
* ist_end_non_atomic() - begin a non-atomic section in an IST exception
*
* Ends a non-atomic section started with ist_begin_non_atomic().
*/
void ist_end_non_atomic(void)
{
preempt_disable();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 10 | 100.00% | 2 | 100.00% |
Total | 10 | 100.00% | 2 | 100.00% |
int is_valid_bugaddr(unsigned long addr)
{
unsigned short ud;
if (addr < TASK_SIZE_MAX)
return 0;
if (probe_kernel_address((unsigned short *)addr, ud))
return 0;
return ud == INSN_UD0 || ud == INSN_UD2;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Peter Zijlstra | 48 | 100.00% | 1 | 100.00% |
Total | 48 | 100.00% | 1 | 100.00% |
int fixup_bug(struct pt_regs *regs, int trapnr)
{
if (trapnr != X86_TRAP_UD)
return 0;
switch (report_bug(regs->ip, regs)) {
case BUG_TRAP_TYPE_NONE:
case BUG_TRAP_TYPE_BUG:
break;
case BUG_TRAP_TYPE_WARN:
regs->ip += LEN_UD0;
return 1;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Peter Zijlstra | 57 | 100.00% | 1 | 100.00% |
Total | 57 | 100.00% | 1 | 100.00% |
static nokprobe_inline int
do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
struct pt_regs *regs, long error_code)
{
if (v8086_mode(regs)) {
/*
* Traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
* On nmi (interrupt 2), do_trap should not be called.
*/
if (trapnr < X86_TRAP_UD) {
if (!handle_vm86_trap((struct kernel_vm86_regs *) regs,
error_code, trapnr))
return 0;
}
return -1;
}
if (!user_mode(regs)) {
if (fixup_exception(regs, trapnr))
return 0;
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = trapnr;
die(str, regs, error_code);
}
return -1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Frédéric Weisbecker | 73 | 60.83% | 1 | 8.33% |
Linus Torvalds (pre-git) | 27 | 22.50% | 2 | 16.67% |
Linus Torvalds | 5 | 4.17% | 1 | 8.33% |
Peter Zijlstra | 3 | 2.50% | 1 | 8.33% |
Andrew Lutomirski | 3 | 2.50% | 1 | 8.33% |
Vincent Hanquez | 2 | 1.67% | 1 | 8.33% |
Tony Luck | 2 | 1.67% | 1 | 8.33% |
Alexander van Heukelum | 2 | 1.67% | 1 | 8.33% |
Masami Hiramatsu | 1 | 0.83% | 1 | 8.33% |
Kees Cook | 1 | 0.83% | 1 | 8.33% |
Ingo Molnar | 1 | 0.83% | 1 | 8.33% |
Total | 120 | 100.00% | 12 | 100.00% |
static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr,
siginfo_t *info)
{
unsigned long siaddr;
int sicode;
switch (trapnr) {
default:
return SEND_SIG_PRIV;
case X86_TRAP_DE:
sicode = FPE_INTDIV;
siaddr = uprobe_get_trap_addr(regs);
break;
case X86_TRAP_UD:
sicode = ILL_ILLOPN;
siaddr = uprobe_get_trap_addr(regs);
break;
case X86_TRAP_AC:
sicode = BUS_ADRALN;
siaddr = 0;
break;
}
info->si_signo = signr;
info->si_errno = 0;
info->si_code = sicode;
info->si_addr = (void __user *)siaddr;
return info;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 113 | 100.00% | 3 | 100.00% |
Total | 113 | 100.00% | 3 | 100.00% |
static void
do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
long error_code, siginfo_t *info)
{
struct task_struct *tsk = current;
if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
return;
/*
* We want error_code and trap_nr set for userspace faults and
* kernelspace faults which result in die(), but not
* kernelspace faults which are fixed up. die() gives the
* process no chance to handle the signal and notice the
* kernel fault information, so that won't result in polluting
* the information about previously queued, but not yet
* delivered, faults. See also do_general_protection below.
*/
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = trapnr;
if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
printk_ratelimit()) {
pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx",
tsk->comm, tsk->pid, str,
regs->ip, regs->sp, error_code);
print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n");
}
force_sig_info(signr, info ?: SEND_SIG_PRIV, tsk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexander van Heukelum | 53 | 38.69% | 1 | 11.11% |
Frédéric Weisbecker | 51 | 37.23% | 1 | 11.11% |
Andi Kleen | 15 | 10.95% | 1 | 11.11% |
Linus Torvalds (pre-git) | 10 | 7.30% | 2 | 22.22% |
Oleg Nesterov | 3 | 2.19% | 1 | 11.11% |
Joe Perches | 2 | 1.46% | 1 | 11.11% |
Srikar Dronamraju | 2 | 1.46% | 1 | 11.11% |
Markus Trippelsdorf | 1 | 0.73% | 1 | 11.11% |
Total | 137 | 100.00% | 9 | 100.00% |
NOKPROBE_SYMBOL(do_trap);
static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
unsigned long trapnr, int signr)
{
siginfo_t info;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
/*
* WARN*()s end up here; fix them up before we call the
* notifier chain.
*/
if (!user_mode(regs) && fixup_bug(regs, trapnr))
return;
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) !=
NOTIFY_STOP) {
cond_local_irq_enable(regs);
do_trap(trapnr, signr, str, regs, error_code,
fill_trap_info(regs, signr, trapnr, &info));
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 78 | 74.29% | 2 | 28.57% |
Alexander Shishkin | 17 | 16.19% | 1 | 14.29% |
Andrew Lutomirski | 7 | 6.67% | 2 | 28.57% |
Linus Torvalds | 2 | 1.90% | 1 | 14.29% |
Alexander Kuleshov | 1 | 0.95% | 1 | 14.29% |
Total | 105 | 100.00% | 7 | 100.00% |
#define DO_ERROR(trapnr, signr, str, name) \
dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
{ \
do_error_trap(regs, error_code, str, trapnr, signr); \
}
DO_ERROR(X86_TRAP_DE, SIGFPE, "divide error", divide_error)
DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow)
DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op)
DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun)
DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present)
DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment)
DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check)
#ifdef CONFIG_VMAP_STACK
__visible void __noreturn handle_stack_overflow(const char *message,
struct pt_regs *regs,
unsigned long fault_address)
{
printk(KERN_EMERG "BUG: stack guard page was hit at %p (stack is %p..%p)\n",
(void *)fault_address, current->stack,
(char *)current->stack + THREAD_SIZE - 1);
die(message, regs, 0);
/* Be absolutely certain we don't return. */
panic(message);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 64 | 100.00% | 2 | 100.00% |
Total | 64 | 100.00% | 2 | 100.00% |
#endif
#ifdef CONFIG_X86_64
/* Runs on IST stack */
dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
{
static const char str[] = "double fault";
struct task_struct *tsk = current;
#ifdef CONFIG_VMAP_STACK
unsigned long cr2;
#endif
#ifdef CONFIG_X86_ESPFIX64
extern unsigned char native_irq_return_iret[];
/*
* If IRET takes a non-IST fault on the espfix64 stack, then we
* end up promoting it to a doublefault. In that case, modify
* the stack to make it look like we just entered the #GP
* handler from user space, similar to bad_iret.
*
* No need for ist_enter here because we don't use RCU.
*/
if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY &&
regs->cs == __KERNEL_CS &&
regs->ip == (unsigned long)native_irq_return_iret)
{
struct pt_regs *normal_regs = task_pt_regs(current);
/* Fake a #GP(0) from userspace. */
memmove(&normal_regs->ip, (void *)regs->sp, 5*8);
normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */
regs->ip = (unsigned long)general_protection;
regs->sp = (unsigned long)&normal_regs->orig_ax;
return;
}
#endif
ist_enter(regs);
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_DF;
#ifdef CONFIG_VMAP_STACK
/*
* If we overflow the stack into a guard page, the CPU will fail
* to deliver #PF and will send #DF instead. Similarly, if we
* take any non-IST exception while too close to the bottom of
* the stack, the processor will get a page fault while
* delivering the exception and will generate a double fault.
*
* According to the SDM (footnote in 6.15 under "Interrupt 14 -
* Page-Fault Exception (#PF):
*
* Processors update CR2 whenever a page fault is detected. If a
* second page fault occurs while an earlier page fault is being
* deliv- ered, the faulting linear address of the second fault will
* overwrite the contents of CR2 (replacing the previous
* address). These updates to CR2 occur even if the page fault
* results in a double fault or occurs during the delivery of a
* double fault.
*
* The logic below has a small possibility of incorrectly diagnosing
* some errors as stack overflows. For example, if the IDT or GDT
* gets corrupted such that #GP delivery fails due to a bad descriptor
* causing #GP and we hit this condition while CR2 coincidentally
* points to the stack guard page, we'll think we overflowed the
* stack. Given that we're going to panic one way or another
* if this happens, this isn't necessarily worth fixing.
*
* If necessary, we could improve the test by only diagnosing
* a stack overflow if the saved RSP points within 47 bytes of
* the bottom of the stack: if RSP == tsk_stack + 48 and we
* take an exception, the stack is already aligned and there
* will be enough room SS, RSP, RFLAGS, CS, RIP, and a
* possible error code, so a stack overflow would *not* double
* fault. With any less space left, exception delivery could
* fail, and, as a practical matter, we've overflowed the
* stack even if the actual trigger for the double fault was
* something else.
*/
cr2 = read_cr2();
if ((unsigned long)task_stack_page(tsk) - 1 - cr2 < PAGE_SIZE)
handle_stack_overflow("kernel stack overflow (double-fault)", regs, cr2);
#endif
#ifdef CONFIG_DOUBLEFAULT
df_debug(regs, error_code);
#endif
/*
* This is always a kernel trap and never fixable (and thus must
* never return).
*/
for (;;)
die(str, regs, error_code);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 157 | 64.08% | 3 | 33.33% |
Alexander van Heukelum | 71 | 28.98% | 1 | 11.11% |
Borislav Petkov | 12 | 4.90% | 1 | 11.11% |
Kees Cook | 2 | 0.82% | 1 | 11.11% |
Srikar Dronamraju | 1 | 0.41% | 1 | 11.11% |
Ingo Molnar | 1 | 0.41% | 1 | 11.11% |
Frédéric Weisbecker | 1 | 0.41% | 1 | 11.11% |
Total | 245 | 100.00% | 9 | 100.00% |
#endif
dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
{
const struct mpx_bndcsr *bndcsr;
siginfo_t *info;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
if (notify_die(DIE_TRAP, "bounds", regs, error_code,
X86_TRAP_BR, SIGSEGV) == NOTIFY_STOP)
return;
cond_local_irq_enable(regs);
if (!user_mode(regs))
die("bounds", regs, error_code);
if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
/* The exception is not from Intel MPX */
goto exit_trap;
}
/*
* We need to look at BNDSTATUS to resolve this exception.
* A NULL here might mean that it is in its 'init state',
* which is all zeros which indicates MPX was not
* responsible for the exception.
*/
bndcsr = get_xsave_field_ptr(XFEATURE_MASK_BNDCSR);
if (!bndcsr)
goto exit_trap;
trace_bounds_exception_mpx(bndcsr);
/*
* The error code field of the BNDSTATUS register communicates status
* information of a bound range exception #BR or operation involving
* bound directory.
*/
switch (bndcsr->bndstatus & MPX_BNDSTA_ERROR_CODE) {
case 2: /* Bound directory has invalid entry. */
if (mpx_handle_bd_fault())
goto exit_trap;
break; /* Success, it was handled */
case 1: /* Bound violation. */
info = mpx_generate_siginfo(regs);
if (IS_ERR(info)) {
/*
* We failed to decode the MPX instruction. Act as if
* the exception was not caused by MPX.
*/
goto exit_trap;
}
/*
* Success, we decoded the instruction and retrieved
* an 'info' containing the address being accessed
* which caused the exception. This information
* allows and application to possibly handle the
* #BR exception itself.
*/
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info);
kfree(info);
break;
case 0: /* No exception caused by Intel MPX operations. */
goto exit_trap;
default:
die("bounds", regs, error_code);
}
return;
exit_trap:
/*
* This path out is for all the cases where we could not
* handle the exception in some way (like allocating a
* table or telling userspace about it. We will also end
* up here if the kernel has MPX turned off at compile
* time..
*/
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dave Hansen | 206 | 94.93% | 6 | 46.15% |
Andrew Lutomirski | 7 | 3.23% | 4 | 30.77% |
Linus Torvalds | 2 | 0.92% | 1 | 7.69% |
Alexander Kuleshov | 1 | 0.46% | 1 | 7.69% |
Dan Carpenter | 1 | 0.46% | 1 | 7.69% |
Total | 217 | 100.00% | 13 | 100.00% |
dotraplinkage void
do_general_protection(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
cond_local_irq_enable(regs);
if (v8086_mode(regs)) {
local_irq_enable();
handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
return;
}
tsk = current;
if (!user_mode(regs)) {
if (fixup_exception(regs, X86_TRAP_GP))
return;
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_GP;
if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
die("general protection fault", regs, error_code);
return;
}
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_GP;
if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
printk_ratelimit()) {
pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx",
tsk->comm, task_pid_nr(tsk),
regs->ip, regs->sp, error_code);
print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n");
}
force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Frédéric Weisbecker | 72 | 34.78% | 3 | 9.68% |
Linus Torvalds (pre-git) | 37 | 17.87% | 5 | 16.13% |
Masoud Asgharifard Sharbiani | 28 | 13.53% | 1 | 3.23% |
Alexander van Heukelum | 19 | 9.18% | 3 | 9.68% |
Andi Kleen | 16 | 7.73% | 1 | 3.23% |
Andrew Lutomirski | 11 | 5.31% | 4 | 12.90% |
Ingo Molnar | 4 | 1.93% | 3 | 9.68% |
Alexey Dobriyan | 3 | 1.45% | 1 | 3.23% |
Oleg Nesterov | 3 | 1.45% | 1 | 3.23% |
Linus Torvalds | 2 | 0.97% | 1 | 3.23% |
Joe Perches | 2 | 0.97% | 1 | 3.23% |
Tony Luck | 2 | 0.97% | 1 | 3.23% |
H. Peter Anvin | 2 | 0.97% | 1 | 3.23% |
Vincent Hanquez | 2 | 0.97% | 1 | 3.23% |
Srikar Dronamraju | 1 | 0.48% | 1 | 3.23% |
Alexander Kuleshov | 1 | 0.48% | 1 | 3.23% |
Markus Trippelsdorf | 1 | 0.48% | 1 | 3.23% |
Kees Cook | 1 | 0.48% | 1 | 3.23% |
Total | 207 | 100.00% | 31 | 100.00% |
NOKPROBE_SYMBOL(do_general_protection);
/* May run on IST stack. */
dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
{
#ifdef CONFIG_DYNAMIC_FTRACE
/*
* ftrace must be first, everything else may cause a recursive crash.
* See note by declaration of modifying_ftrace_code in ftrace.c
*/
if (unlikely(atomic_read(&modifying_ftrace_code)) &&
ftrace_int3_handler(regs))
return;
#endif
if (poke_int3_handler(regs))
return;
ist_enter(regs);
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
SIGTRAP) == NOTIFY_STOP)
goto exit;
#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
#ifdef CONFIG_KPROBES
if (kprobe_int3_handler(regs))
goto exit;
#endif
if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
SIGTRAP) == NOTIFY_STOP)
goto exit;
/*
* Let others (NMI) know that the debug stack is in use
* as we may switch to the interrupt stack.
*/
debug_stack_usage_inc();
cond_local_irq_enable(regs);
do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
cond_local_irq_disable(regs);
debug_stack_usage_dec();
exit:
ist_exit(regs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Prasanna S. Panchamukhi | 44 | 26.83% | 2 | 10.00% |
Steven Rostedt | 31 | 18.90% | 3 | 15.00% |
Jason Wessel | 22 | 13.41% | 1 | 5.00% |
Masami Hiramatsu | 16 | 9.76% | 2 | 10.00% |
Andrew Lutomirski | 13 | 7.93% | 3 | 15.00% |
Alexander van Heukelum | 11 | 6.71% | 3 | 15.00% |
Frédéric Weisbecker | 11 | 6.71% | 1 | 5.00% |
Jiri Kosina | 8 | 4.88% | 1 | 5.00% |
Kees Cook | 3 | 1.83% | 1 | 5.00% |
Alexander Kuleshov | 2 | 1.22% | 1 | 5.00% |
Linus Torvalds | 2 | 1.22% | 1 | 5.00% |
Stas Sergeev | 1 | 0.61% | 1 | 5.00% |
Total | 164 | 100.00% | 20 | 100.00% |
NOKPROBE_SYMBOL(do_int3);
#ifdef CONFIG_X86_64
/*
* Help handler running on IST stack to switch off the IST stack if the
* interrupted code was in user mode. The actual stack switch is done in
* entry_64.S
*/
asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs)
{
struct pt_regs *regs = task_pt_regs(current);
*regs = *eregs;
return regs;
}
NOKPROBE_SYMBOL(sync_regs);
struct bad_iret_stack {
void *error_entry_ret;
struct pt_regs regs;
};
asmlinkage __visible notrace
struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
{
/*
* This is called from entry_64.S early in handling a fault
* caused by a bad iret to user mode. To handle the fault
* correctly, we want move our stack frame to task_pt_regs
* and we want to pretend that the exception came from the
* iret target.
*/
struct bad_iret_stack *new_stack =
container_of(task_pt_regs(current),
struct bad_iret_stack, regs);
/* Copy the IRET target to the new stack. */
memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8);
/* Copy the remainder of the stack from the current stack. */
memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip));
BUG_ON(!user_mode(&new_stack->regs));
return new_stack;
}
NOKPROBE_SYMBOL(fixup_bad_iret);
#endif
static bool is_sysenter_singlestep(struct pt_regs *regs)
{
/*
* We don't try for precision here. If we're anywhere in the region of
* code that can be single-stepped in the SYSENTER entry path, then
* assume that this is a useless single-step trap due to SYSENTER
* being invoked with TF set. (We don't know in advance exactly
* which instructions will be hit because BTF could plausibly
* be set.)
*/
#ifdef CONFIG_X86_32
return (regs->ip - (unsigned long)__begin_SYSENTER_singlestep_region) <
(unsigned long)__end_SYSENTER_singlestep_region -
(unsigned long)__begin_SYSENTER_singlestep_region;
#elif defined(CONFIG_IA32_EMULATION)
return (regs->ip - (unsigned long)entry_SYSENTER_compat) <
(unsigned long)__end_entry_SYSENTER_compat -
(unsigned long)entry_SYSENTER_compat;
#else
return false;
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 78 | 100.00% | 1 | 100.00% |
Total | 78 | 100.00% | 1 | 100.00% |
/*
* Our handling of the processor debug registers is non-trivial.
* We do not clear them on entry and exit from the kernel. Therefore
* it is possible to get a watchpoint trap here from inside the kernel.
* However, the code in ./ptrace.c has ensured that the user can
* only set watchpoints on userspace addresses. Therefore the in-kernel
* watchpoint trap can only occur in code which is reading/writing
* from user space. Such code must not hold kernel locks (since it
* can equally take a page fault), therefore it is safe to call
* force_sig_info even though that claims and releases locks.
*
* Code in ./signal.c ensures that the debug control register
* is restored before we deliver any signal, and therefore that
* user code runs with the correct debug control register even though
* we clear it here.
*
* Being careful here means that we don't have to be as careful in a
* lot of more complicated places (task switching can be a bit lazy
* about restoring all the debug state, and ptrace doesn't have to
* find every occurrence of the TF bit that could be saved away even
* by user code)
*
* May run on IST stack.
*/
dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk = current;
int user_icebp = 0;
unsigned long dr6;
int si_code;
ist_enter(regs);
get_debugreg(dr6, 6);
/*
* The Intel SDM says:
*
* Certain debug exceptions may clear bits 0-3. The remaining
* contents of the DR6 register are never cleared by the
* processor. To avoid confusion in identifying debug
* exceptions, debug handlers should clear the register before
* returning to the interrupted task.
*
* Keep it simple: clear DR6 immediately.
*/
set_debugreg(0, 6);
/* Filter out all the reserved bits which are preset to 1 */
dr6 &= ~DR6_RESERVED;
/*
* The SDM says "The processor clears the BTF flag when it
* generates a debug exception." Clear TIF_BLOCKSTEP to keep
* TIF_BLOCKSTEP in sync with the hardware BTF flag.
*/
clear_tsk_thread_flag(tsk, TIF_BLOCKSTEP);
if (unlikely(!user_mode(regs) && (dr6 & DR_STEP) &&
is_sysenter_singlestep(regs))) {
dr6 &= ~DR_STEP;
if (!dr6)
goto exit;
/*
* else we might have gotten a single-step trap and hit a
* watchpoint at the same time, in which case we should fall
* through and handle the watchpoint.
*/
}
/*
* If dr6 has no reason to give us about the origin of this trap,
* then it's very likely the result of an icebp/int01 trap.
* User wants a sigtrap for that.
*/
if (!dr6 && user_mode(regs))
user_icebp = 1;
/* Catch kmemcheck conditions! */
if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
goto exit;
/* Store the virtualized DR6 value */
tsk->thread.debugreg6 = dr6;
#ifdef CONFIG_KPROBES
if (kprobe_debug_handler(regs))
goto exit;
#endif
if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code,
SIGTRAP) == NOTIFY_STOP)
goto exit;
/*
* Let others (NMI) know that the debug stack is in use
* as we may switch to the interrupt stack.
*/
debug_stack_usage_inc();
/* It's safe to allow irq's after DR6 has been saved */
cond_local_irq_enable(regs);
if (v8086_mode(regs)) {
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code,
X86_TRAP_DB);
cond_local_irq_disable(regs);
debug_stack_usage_dec();
goto exit;
}
if (WARN_ON_ONCE((dr6 & DR_STEP) && !user_mode(regs))) {
/*
* Historical junk that used to handle SYSENTER single-stepping.
* This should be unreachable now. If we survive for a while
* without anyone hitting this warning, we'll turn this into
* an oops.
*/
tsk->thread.debugreg6 &= ~DR_STEP;
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
regs->flags &= ~X86_EFLAGS_TF;
}
si_code = get_si_code(tsk->thread.debugreg6);
if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp)
send_sigtrap(tsk, regs, error_code, si_code);
cond_local_irq_disable(regs);
debug_stack_usage_dec();
exit:
#if defined(CONFIG_X86_32)
/*
* This is the most likely code path that involves non-trivial use
* of the SYSENTER stack. Check that we haven't overrun it.
*/
WARN(this_cpu_read(cpu_tss.SYSENTER_stack_canary) != STACK_END_MAGIC,
"Overran or corrupted SYSENTER stack\n");
#endif
ist_exit(regs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 92 | 26.29% | 7 | 17.95% |
K.Prasad | 80 | 22.86% | 3 | 7.69% |
Linus Torvalds (pre-git) | 43 | 12.29% | 6 | 15.38% |
Frédéric Weisbecker | 35 | 10.00% | 2 | 5.13% |
Prasanna S. Panchamukhi | 18 | 5.14% | 2 | 5.13% |
Masami Hiramatsu | 17 | 4.86% | 3 | 7.69% |
Alexander van Heukelum | 11 | 3.14% | 1 | 2.56% |
Steven Rostedt | 10 | 2.86% | 1 | 2.56% |
Vegard Nossum | 10 | 2.86% | 1 | 2.56% |
Ingo Molnar | 7 | 2.00% | 4 | 10.26% |
Linus Torvalds | 7 | 2.00% | 1 | 2.56% |
Bart Oldeman | 4 | 1.14% | 1 | 2.56% |
Srinivasa D S | 3 | 0.86% | 1 | 2.56% |
Jamie Lokier | 3 | 0.86% | 1 | 2.56% |
Alexander Kuleshov | 3 | 0.86% | 1 | 2.56% |
Rusty Russell | 3 | 0.86% | 1 | 2.56% |
Vincent Hanquez | 2 | 0.57% | 1 | 2.56% |
H. Peter Anvin | 1 | 0.29% | 1 | 2.56% |
Kees Cook | 1 | 0.29% | 1 | 2.56% |
Total | 350 | 100.00% | 39 | 100.00% |
NOKPROBE_SYMBOL(do_debug);
/*
* Note that we play around with the 'TS' bit in an attempt to get
* the correct behaviour even in the presence of the asynchronous
* IRQ13 behaviour
*/
static void math_error(struct pt_regs *regs, int error_code, int trapnr)
{
struct task_struct *task = current;
struct fpu *fpu = &task->thread.fpu;
siginfo_t info;
char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" :
"simd exception";
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, SIGFPE) == NOTIFY_STOP)
return;
cond_local_irq_enable(regs);
if (!user_mode(regs)) {
if (!fixup_exception(regs, trapnr)) {
task->thread.error_code = error_code;
task->thread.trap_nr = trapnr;
die(str, regs, error_code);
}
return;
}
/*
* Save the info for the exception handler and clear the error.
*/
fpu__save(fpu);
task->thread.trap_nr = trapnr;
task->thread.error_code = error_code;
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_addr = (void __user *)uprobe_get_trap_addr(regs);
info.si_code = fpu__exception_code(fpu, trapnr);
/* Retry when we get spurious exceptions: */
if (!info.si_code)
return;
force_sig_info(SIGFPE, &info, task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Brian Gerst | 73 | 35.78% | 2 | 8.33% |
Linus Torvalds (pre-git) | 50 | 24.51% | 9 | 37.50% |
Alexander van Heukelum | 41 | 20.10% | 1 | 4.17% |
Ingo Molnar | 22 | 10.78% | 3 | 12.50% |
H. Peter Anvin | 7 | 3.43% | 2 | 8.33% |
Oleg Nesterov | 4 | 1.96% | 2 | 8.33% |
Tony Luck | 2 | 0.98% | 1 | 4.17% |
Srikar Dronamraju | 2 | 0.98% | 1 | 4.17% |
Kees Cook | 1 | 0.49% | 1 | 4.17% |
Andrew Lutomirski | 1 | 0.49% | 1 | 4.17% |
Alexander Kuleshov | 1 | 0.49% | 1 | 4.17% |
Total | 204 | 100.00% | 24 | 100.00% |
dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
{
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
math_error(regs, error_code, X86_TRAP_MF);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 18 | 56.25% | 2 | 20.00% |
Andrew Lutomirski | 5 | 15.62% | 2 | 20.00% |
Alexander van Heukelum | 4 | 12.50% | 2 | 20.00% |
Frédéric Weisbecker | 2 | 6.25% | 2 | 20.00% |
Linus Torvalds | 2 | 6.25% | 1 | 10.00% |
Kees Cook | 1 | 3.12% | 1 | 10.00% |
Total | 32 | 100.00% | 10 | 100.00% |
dotraplinkage void
do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
{
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
math_error(regs, error_code, X86_TRAP_XF);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 13 | 40.62% | 1 | 9.09% |
Andrew Lutomirski | 5 | 15.62% | 2 | 18.18% |
Alexander van Heukelum | 4 | 12.50% | 2 | 18.18% |
Alexander Nyberg | 4 | 12.50% | 1 | 9.09% |
Linus Torvalds | 2 | 6.25% | 1 | 9.09% |
Frédéric Weisbecker | 2 | 6.25% | 2 | 18.18% |
Brian Gerst | 1 | 3.12% | 1 | 9.09% |
Kees Cook | 1 | 3.12% | 1 | 9.09% |
Total | 32 | 100.00% | 11 | 100.00% |
dotraplinkage void
do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
{
cond_local_irq_enable(regs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 13 | 68.42% | 1 | 25.00% |
Alexander van Heukelum | 5 | 26.32% | 2 | 50.00% |
Alexander Kuleshov | 1 | 5.26% | 1 | 25.00% |
Total | 19 | 100.00% | 4 | 100.00% |
dotraplinkage void
do_device_not_available(struct pt_regs *regs, long error_code)
{
unsigned long cr0;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
#ifdef CONFIG_MATH_EMULATION
if (!boot_cpu_has(X86_FEATURE_FPU) && (read_cr0() & X86_CR0_EM)) {
struct math_emu_info info = { };
cond_local_irq_enable(regs);
info.regs = regs;
math_emulate(&info);
return;
}
#endif
/* This should not happen. */
cr0 = read_cr0();
if (WARN(cr0 & X86_CR0_TS, "CR0.TS was set")) {
/* Try to fix it up and carry on. */
write_cr0(cr0 & ~X86_CR0_TS);
} else {
/*
* Something terrible happened, and we're better off trying
* to kill the task than getting stuck in a never-ending
* loop of #NM faults.
*/
die("unexpected #NM exception", regs, error_code);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 50 | 43.86% | 4 | 26.67% |
Alexander van Heukelum | 37 | 32.46% | 3 | 20.00% |
Tejun Heo | 14 | 12.28% | 1 | 6.67% |
Brian Gerst | 5 | 4.39% | 2 | 13.33% |
Ingo Molnar | 3 | 2.63% | 1 | 6.67% |
Linus Torvalds | 2 | 1.75% | 1 | 6.67% |
Frédéric Weisbecker | 2 | 1.75% | 2 | 13.33% |
Alexander Kuleshov | 1 | 0.88% | 1 | 6.67% |
Total | 114 | 100.00% | 15 | 100.00% |
NOKPROBE_SYMBOL(do_device_not_available);
#ifdef CONFIG_X86_32
dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
{
siginfo_t info;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
local_irq_enable();
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_BADSTK;
info.si_addr = NULL;
if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) {
do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
&info);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexander van Heukelum | 75 | 83.33% | 2 | 22.22% |
Andrew Lutomirski | 5 | 5.56% | 2 | 22.22% |
Frédéric Weisbecker | 5 | 5.56% | 2 | 22.22% |
Linus Torvalds | 2 | 2.22% | 1 | 11.11% |
Kees Cook | 2 | 2.22% | 1 | 11.11% |
Hannes Eder | 1 | 1.11% | 1 | 11.11% |
Total | 90 | 100.00% | 9 | 100.00% |
#endif
void __init trap_init(void)
{
idt_setup_traps();
/*
* Set the IDT descriptor to a fixed read-only location, so that the
* "sidt" instruction will not leak the location of the kernel, and
* to defend the IDT against arbitrary memory write vulnerabilities.
* It will be reloaded in cpu_init() */
__set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
idt_descr.address = fix_to_virt(FIX_RO_IDT);
/*
* Should be a barrier for any external CPU state:
*/
cpu_init();
idt_setup_ist_traps();
x86_init.irqs.trap_init();
idt_setup_debugidt_traps();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kees Cook | 22 | 44.00% | 1 | 7.14% |
Linus Torvalds (pre-git) | 13 | 26.00% | 5 | 35.71% |
Thomas Gleixner | 11 | 22.00% | 4 | 28.57% |
Wang Nan | 1 | 2.00% | 1 | 7.14% |
Rusty Russell | 1 | 2.00% | 1 | 7.14% |
Ingo Molnar | 1 | 2.00% | 1 | 7.14% |
Steven Rostedt | 1 | 2.00% | 1 | 7.14% |
Total | 50 | 100.00% | 14 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Lutomirski | 741 | 24.04% | 24 | 12.83% |
Alexander van Heukelum | 436 | 14.14% | 19 | 10.16% |
Linus Torvalds (pre-git) | 328 | 10.64% | 31 | 16.58% |
Frédéric Weisbecker | 257 | 8.34% | 6 | 3.21% |
Dave Hansen | 215 | 6.97% | 6 | 3.21% |
Oleg Nesterov | 207 | 6.71% | 7 | 3.74% |
Peter Zijlstra | 108 | 3.50% | 1 | 0.53% |
Brian Gerst | 83 | 2.69% | 5 | 2.67% |
K.Prasad | 80 | 2.59% | 3 | 1.60% |
Ingo Molnar | 69 | 2.24% | 15 | 8.02% |
Prasanna S. Panchamukhi | 66 | 2.14% | 3 | 1.60% |
Masami Hiramatsu | 62 | 2.01% | 3 | 1.60% |
Kees Cook | 48 | 1.56% | 3 | 1.60% |
Steven Rostedt | 45 | 1.46% | 4 | 2.14% |
Linus Torvalds | 34 | 1.10% | 5 | 2.67% |
Andi Kleen | 34 | 1.10% | 4 | 2.14% |
Masoud Asgharifard Sharbiani | 28 | 0.91% | 1 | 0.53% |
Jason Wessel | 25 | 0.81% | 1 | 0.53% |
Alexander Shishkin | 17 | 0.55% | 1 | 0.53% |
Tejun Heo | 14 | 0.45% | 1 | 0.53% |
Thomas Gleixner | 14 | 0.45% | 4 | 2.14% |
Vegard Nossum | 13 | 0.42% | 1 | 0.53% |
Alexander Kuleshov | 13 | 0.42% | 1 | 0.53% |
Harvey Harrison | 12 | 0.39% | 1 | 0.53% |
Borislav Petkov | 12 | 0.39% | 1 | 0.53% |
Joe Perches | 11 | 0.36% | 1 | 0.53% |
Jiri Kosina | 11 | 0.36% | 1 | 0.53% |
Dave Jiang | 11 | 0.36% | 1 | 0.53% |
H. Peter Anvin | 10 | 0.32% | 3 | 1.60% |
Alexander Nyberg | 7 | 0.23% | 2 | 1.07% |
Yinghai Lu | 7 | 0.23% | 1 | 0.53% |
Vincent Hanquez | 6 | 0.19% | 2 | 1.07% |
Tony Luck | 6 | 0.19% | 1 | 0.53% |
Rusty Russell | 6 | 0.19% | 3 | 1.60% |
Srikar Dronamraju | 6 | 0.19% | 1 | 0.53% |
Jan Beulich | 5 | 0.16% | 2 | 1.07% |
Bart Oldeman | 4 | 0.13% | 1 | 0.53% |
Hidetoshi Seto | 3 | 0.10% | 1 | 0.53% |
Srinivasa D S | 3 | 0.10% | 1 | 0.53% |
Alexey Dobriyan | 3 | 0.10% | 1 | 0.53% |
Jeremy Fitzhardinge | 3 | 0.10% | 1 | 0.53% |
Jamie Lokier | 3 | 0.10% | 1 | 0.53% |
Daniel Jacobowitz | 2 | 0.06% | 1 | 0.53% |
Dave Jones | 2 | 0.06% | 1 | 0.53% |
Andrew Morton | 2 | 0.06% | 1 | 0.53% |
Markus Trippelsdorf | 2 | 0.06% | 1 | 0.53% |
Paul E. McKenney | 2 | 0.06% | 1 | 0.53% |
Arun Sharma | 1 | 0.03% | 1 | 0.53% |
Hannes Eder | 1 | 0.03% | 1 | 0.53% |
Chuck Ebbert | 1 | 0.03% | 1 | 0.53% |
Stas Sergeev | 1 | 0.03% | 1 | 0.53% |
Dan Carpenter | 1 | 0.03% | 1 | 0.53% |
Paul Gortmaker | 1 | 0.03% | 1 | 0.53% |
Wang Nan | 1 | 0.03% | 1 | 0.53% |
Total | 3083 | 100.00% | 187 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.