x86/speculation: Prevent deadlock on ssb_state::lock [Linux 3.16.72]

This Linux kernel change "x86/speculation: Prevent deadlock on ssb_state::lock" is included in the Linux 3.16.72 release. This change is authored by Thomas Gleixner <tglx [at] linutronix.de> on Sun Apr 14 19:51:06 2019 +0200. The commit for this change in Linux stable tree is 13ff2d8 (patch) which is from upstream commit 2f5fb19. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 2f5fb19.

x86/speculation: Prevent deadlock on ssb_state::lock

commit 2f5fb19341883bb6e37da351bc3700489d8506a7 upstream.

Mikhail reported a lockdep splat related to the AMD specific ssb_state
lock:

  CPU0                       CPU1
  lock(&st->lock);
                             local_irq_disable();
                             lock(&(&sighand->siglock)->rlock);
                             lock(&st->lock);
  <Interrupt>
     lock(&(&sighand->siglock)->rlock);

  *** DEADLOCK ***

The connection between sighand->siglock and st->lock comes through seccomp,
which takes st->lock while holding sighand->siglock.

Make sure interrupts are disabled when __speculation_ctrl_update() is
invoked via prctl() -> speculation_ctrl_update(). Add a lockdep assert to
catch future offenders.

Fixes: 1f50ddb4f418 ("x86/speculation: Handle HT correctly on AMD")
Reported-by: Mikhail Gavrilov <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Mikhail Gavrilov <[email protected]>
Cc: Thomas Lendacky <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Ben Hutchings <[email protected]>

There are 8 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/x86/kernel/process.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 074510b..feca78b 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -351,6 +351,8 @@ static __always_inline void __speculation_ctrl_update(unsigned long tifp,
    u64 msr = x86_spec_ctrl_base;
    bool updmsr = false;

+   lockdep_assert_irqs_disabled();
+
    /*
     * If TIF_SSBD is different, select the proper mitigation
     * method. Note that if SSBD mitigation is disabled or permanentely
@@ -402,10 +404,12 @@ static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)

 void speculation_ctrl_update(unsigned long tif)
 {
+   unsigned long flags;
+
    /* Forced update. Make sure all relevant TIF flags are different */
-   preempt_disable();
+   local_irq_save(flags);
    __speculation_ctrl_update(~tif, tif);
-   preempt_enable();
+   local_irq_restore(flags);
 }

 /* Called from seccomp/prctl update */

Leave a Reply

Your email address will not be published. Required fields are marked *