Patch "x86/nmi: Fix out-of-order NMI nesting checks & false positive warning" has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    x86/nmi: Fix out-of-order NMI nesting checks & false positive warning

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     x86-nmi-fix-out-of-order-nmi-nesting-checks-false-po.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 278ccb53f53b5ecd868cb980b55bc30aca53e97d
Author: Paul E. McKenney <paulmck@xxxxxxxxxx>
Date:   Wed Oct 11 11:40:16 2023 -0700

    x86/nmi: Fix out-of-order NMI nesting checks & false positive warning
    
    [ Upstream commit f44075ecafb726830e63d33fbca29413149eeeb8 ]
    
    The ->idt_seq and ->recv_jiffies variables added by:
    
      1a3ea611fc10 ("x86/nmi: Accumulate NMI-progress evidence in exc_nmi()")
    
    ... place the exit-time check of the bottom bit of ->idt_seq after the
    this_cpu_dec_return() that re-enables NMI nesting.  This can result in
    the following sequence of events on a given CPU in kernels built with
    CONFIG_NMI_CHECK_CPU=y:
    
      o   An NMI arrives, and ->idt_seq is incremented to an odd number.
          In addition, nmi_state is set to NMI_EXECUTING==1.
    
      o   The NMI is processed.
    
      o   The this_cpu_dec_return(nmi_state) zeroes nmi_state and returns
          NMI_EXECUTING==1, thus opting out of the "goto nmi_restart".
    
      o   Another NMI arrives and ->idt_seq is incremented to an even
          number, triggering the warning.  But all is just fine, at least
          assuming we don't get so many closely spaced NMIs that the stack
          overflows or some such.
    
    Experience on the fleet indicates that the MTBF of this false positive
    is about 70 years.  Or, for those who are not quite that patient, the
    MTBF appears to be about one per week per 4,000 systems.
    
    Fix this false-positive warning by moving the "nmi_restart" label before
    the initial ->idt_seq increment/check and moving the this_cpu_dec_return()
    to follow the final ->idt_seq increment/check.  This way, all nested NMIs
    that get past the NMI_NOT_RUNNING check get a clean ->idt_seq slate.
    And if they don't get past that check, they will set nmi_state to
    NMI_LATCHED, which will cause the this_cpu_dec_return(nmi_state)
    to restart.
    
    Fixes: 1a3ea611fc10 ("x86/nmi: Accumulate NMI-progress evidence in exc_nmi()")
    Reported-by: Chris Mason <clm@xxxxxx>
    Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
    Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx>
    Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
    Cc: Andy Lutomirski <luto@xxxxxxxxxx>
    Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
    Link: https://lore.kernel.org/r/0cbff831-6e3d-431c-9830-ee65ee7787ff@paulmck-laptop
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index a0c551846b35f..4766b6bed4439 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -507,12 +507,13 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
 	}
 	this_cpu_write(nmi_state, NMI_EXECUTING);
 	this_cpu_write(nmi_cr2, read_cr2());
+
+nmi_restart:
 	if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) {
 		WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1);
 		WARN_ON_ONCE(!(nsp->idt_seq & 0x1));
 		WRITE_ONCE(nsp->recv_jiffies, jiffies);
 	}
-nmi_restart:
 
 	/*
 	 * Needs to happen before DR7 is accessed, because the hypervisor can
@@ -548,16 +549,16 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
 
 	if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
 		write_cr2(this_cpu_read(nmi_cr2));
-	if (this_cpu_dec_return(nmi_state))
-		goto nmi_restart;
-
-	if (user_mode(regs))
-		mds_user_clear_cpu_buffers();
 	if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) {
 		WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1);
 		WARN_ON_ONCE(nsp->idt_seq & 0x1);
 		WRITE_ONCE(nsp->recv_jiffies, jiffies);
 	}
+	if (this_cpu_dec_return(nmi_state))
+		goto nmi_restart;
+
+	if (user_mode(regs))
+		mds_user_clear_cpu_buffers();
 }
 
 #if IS_ENABLED(CONFIG_KVM_INTEL)



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux