From f030656c681846133b00e8fe9b0f2104f533836b Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 6 Jul 2020 22:13:33 +0800 Subject: [PATCH] x86/mce: fixup exception only for the correct mces fix #29415191 commit 1df73b2131e3b33d518609769636b41ce00212de upstream the severity grading code returns in_kernel_recov error context for errors which have happened in kernel space but from which the kernel can recover. whether the recovery can happen is determined by the exception table entry having as handler ex_handler_fault() and which has been declared at build time using _asm_extable_fault(). in_kernel_recov is used in mce_severity_intel() to lookup the corresponding error severity in the severities table. however, the mapping back from error severity to whether the error is in_kernel_recov is ambiguous and in the very paranoid case - which might not be possible right now - but be better safe than sorry later, an exception fixup could be attempted for another mce whose address is in the exception table and has the proper severity. which would be unfortunate, to say the least. therefore, mark such mces explicitly as mce_in_kernel_recov so that the recovery attempt is done only for them. document the whole handling, while at it, as it is not trivial. reported-by: thomas gleixner signed-off-by: borislav petkov tested-by: tony luck link: https://lkml.kernel.org/r/20200407163414.18058-10-bp@alien8.de Signed-off-by: Youquan Song Signed-off-by: Wetp Zhang Reviewed-by: Artie Ding --- arch/x86/include/asm/mce.h | 1 + arch/x86/kernel/cpu/mcheck/mce-severity.c | 6 +++++- arch/x86/kernel/cpu/mcheck/mce.c | 15 +++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index d9b3fd38a1ca..40592a86eda1 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -131,6 +131,7 @@ #define MCE_HANDLED_NFIT BIT_ULL(3) #define MCE_HANDLED_EDAC BIT_ULL(4) #define MCE_HANDLED_MCELOG BIT_ULL(5) +#define MCE_IN_KERNEL_RECOV BIT_ULL(6) /* * This structure contains all data related to the MCE log. Also diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index bd0bf4bfc792..8893ca7e448b 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -217,8 +217,12 @@ static int error_context(struct mce *m) { if ((m->cs & 3) == 3) return IN_USER; - if (mc_recoverable(m->mcgstatus) && ex_has_fault_handler(m->ip)) + + if (mc_recoverable(m->mcgstatus) && ex_has_fault_handler(m->ip)) { + m->kflags |= MCE_IN_KERNEL_RECOV; return IN_KERNEL_RECOV; + } + return IN_KERNEL; } diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 44add3cd1fe9..bad25e99dd8f 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1359,8 +1359,19 @@ void do_machine_check(struct pt_regs *regs, long error_code) current->mce_kill_me.func = kill_me_now; task_work_add(current, ¤t->mce_kill_me, true); } else { - if (!fixup_exception(regs, X86_TRAP_MC)) - mce_panic("Failed kernel mode recovery", &m, NULL); + /* + * Handle an MCE which has happened in kernel space but from + * which the kernel can recover: ex_has_fault_handler() has + * already verified that the rIP at which the error happened is + * a rIP from which the kernel can recover (by jumping to + * recovery code specified in _ASM_EXTABLE_FAULT()) and the + * corresponding exception handler which would do that is the + * proper one. + */ + if (m.kflags & MCE_IN_KERNEL_RECOV) { + if (!fixup_exception(regs, X86_TRAP_MC)) + mce_panic("Failed kernel mode recovery", &m, msg); + } } out_ist: -- GitLab