Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751909AbdHVRjw (ORCPT ); Tue, 22 Aug 2017 13:39:52 -0400 Received: from mail-qt0-f193.google.com ([209.85.216.193]:35240 "EHLO mail-qt0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751852AbdHVRjs (ORCPT ); Tue, 22 Aug 2017 13:39:48 -0400 MIME-Version: 1.0 In-Reply-To: References: From: oliver yang Date: Wed, 23 Aug 2017 01:39:47 +0800 Message-ID: Subject: Fwd: [PATCH] x86/nmi/64: avoid passing user space rsp of pt_regs to nmi handler To: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by nfs id v7MHdu9o005133 Content-Length: 4356 Lines: 127 Copied linux-kernel, as my email got rejected by the alias. ---------- Forwarded message ---------- From: yang oliver Date: 2017-08-23 1:09 GMT+08:00 Subject: [PATCH] x86/nmi/64: avoid passing user space rsp of pt_regs to nmi handler To: "tglx@linutronix.de" , "mingo@redhat.com" , "hpa@zytor.com" , "luto@kernel.org" , "x86@kernel.org" 抄送: "rostedt@goodmis.org" , "jpoimboe@redhat.com" , "linux-kernel@vger.kernel.org" , Yong Yang From: Yong Yang While NMI interrupts the very beginning of SYSCALL, the rsp could be still user space address without loading kernel address. Then the pt_regs constructed by the NMI entry point could have a user space rsp. If a NMI handler tried to dump stack by using this rsp, it can cause the kernel panic. This patch tries to check the rsp saved in outermost frame, and will do another copy for pt_regs. If the rsp of outermost frame is from user space, then use the kernel address of the rsp as the member of pt_regs. Signed-off-by: Yong Yang --- arch/x86/entry/entry_64.S | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index d271fb7..dc85452 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -1298,7 +1298,13 @@ ENTRY(nmi) * | outermost CS } Copied to "iret" frame on each | * | outermost RIP } iteration. | * +---------------------------------------------------------+ - * | pt_regs | + * | pt_regs SS } initialized in first_nmi; | + * | pt_regs Return RSP } will not be changed before | + * | pt_regs RFLAGS } NMI processing is done. | + * | pt_regs CS } Passed to do_nmi for NMI handler. | + * | pt_regs RIP } User space RSP could be replaced. | + * +---------------------------------------------------------+ + * | pt_regs (remaining registers) | * +---------------------------------------------------------+ * * The "original" frame is used by hardware. Before re-enabling @@ -1394,9 +1400,6 @@ nested_nmi_out: INTERRUPT_RETURN first_nmi: - /* Restore rdx. */ - movq (%rsp), %rdx - /* Make room for "NMI executing". */ pushq $0 @@ -1408,6 +1411,24 @@ first_nmi: pushq 11*8(%rsp) .endr + /* Copy the "outermost" frame to pt_regs frame */ + pushq 16*8(%rsp) + movq $__PAGE_OFFSET, %rdx + cmpq 16*8(%rsp), %rdx /* kernel rsp? */ + jbe 2f + /* Save user RSP to avoid pt_regs->rsp got referenced by NMI handler */ + pushq %rsp + jmp 3f +2: + pushq 16*8(%rsp) +3: + .rept 3 + pushq 16*8(%rsp) + .endr + + /* Restore rdx. */ + movq 16*8(%rsp), %rdx + /* Everything up to here is safe from nested NMIs */ #ifdef CONFIG_DEBUG_ENTRY @@ -1441,18 +1462,18 @@ repeat_nmi: * gsbase if needed before we call do_nmi. "NMI executing" * is zero. */ - movq $1, 10*8(%rsp) /* Set "NMI executing". */ + movq $1, 15*8(%rsp) /* Set "NMI executing". */ /* * Copy the "outermost" frame to the "iret" frame. NMIs that nest * here must not modify the "iret" frame while we're writing to * it or it will end up containing garbage. */ - addq $(10*8), %rsp + addq $(15*8), %rsp .rept 5 pushq -6*8(%rsp) .endr - subq $(5*8), %rsp + subq $(10*8), %rsp end_repeat_nmi: /* @@ -1486,7 +1507,7 @@ nmi_restore: RESTORE_C_REGS /* Point RSP at the "iret" frame. */ - REMOVE_PT_GPREGS_FROM_STACK 6*8 + REMOVE_PT_GPREGS_FROM_STACK 11*8 /* * Clear "NMI executing". Set DF first so that we can easily -- 1.8.3.1 -- ------------------ Oliver Yang