]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Aug 2026 05:55:46 +0000 (07:55 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Aug 2026 05:55:46 +0000 (07:55 +0200)
added patches:
0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch
series
x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch

queue-5.10/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch [new file with mode: 0644]
queue-5.10/series [new file with mode: 0644]
queue-5.10/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch [new file with mode: 0644]

diff --git a/queue-5.10/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch b/queue-5.10/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch
new file mode 100644 (file)
index 0000000..79fe4b4
--- /dev/null
@@ -0,0 +1,206 @@
+From 2c77bb87d3bb24b2ef98e12371ad8551e894c4b0 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Fri, 7 Aug 2026 07:53:29 +0200
+Subject: [PATCH] Revert "x86/bugs: Make Safe-RET robust against interrupt
+ injection"
+
+This reverts commit 9de1a49e8f1fbf7c372902573a27a97d4ab4d0af which is
+commit 7e7f81cf6f5ca3311e526308f55d7c54d3ba71f9 upstream.
+
+It was incorrect, a more correct fix will be applied next.
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/entry/entry_64.S            |    5 ---
+ arch/x86/include/asm/nospec-branch.h |   56 -----------------------------------
+ arch/x86/kernel/cpu/bugs.c           |   39 ------------------------
+ arch/x86/lib/retpoline.S             |   20 ------------
+ 4 files changed, 120 deletions(-)
+
+--- a/arch/x86/entry/entry_64.S
++++ b/arch/x86/entry/entry_64.S
+@@ -971,8 +971,6 @@ SYM_CODE_START_LOCAL(paranoid_entry)
+       IBRS_ENTER save_reg=%r15
+       UNTRAIN_RET
+-      HANDLE_INTR_SAFERET 8(%rsp)
+-
+       RET
+ SYM_CODE_END(paranoid_entry)
+@@ -1080,9 +1078,6 @@ SYM_CODE_START_LOCAL(error_entry)
+       movl    %ecx, %eax                      /* zero extend */
+       cmpq    %rax, RIP+8(%rsp)
+       je      .Lbstep_iret
+-
+-      HANDLE_INTR_SAFERET 8(%rsp)
+-
+       cmpq    $.Lgs_change, RIP+8(%rsp)
+       jne     .Lerror_entry_done_lfence
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -87,50 +87,6 @@
+       add     $(BITS_PER_LONG/8), %_ASM_SP;           \
+       lfence;
+-/*
+- * Helper for detecting if an interrupt occurred at an unsafe location within
+- * Safe-RET.  If Safe-RET is interrupted after the CALL or LEA the RSB may get
+- * poisoned by the interrupt handler.
+- *
+- * The Safe-RET sequence is:
+- *
+- * CALL
+- * LEA 8(%RSP), %RSP
+- * RET
+- *
+- * The two CMPs below check whether RIP points to after the CALL or after the
+- * LEA.
+- *
+- * The LFENCE below is to address this particular speculation case:
+- *
+- * 1. Userspace runs and poisons the BTB around the safe-RET routine
+- *
+- * 2. Userspace triggers some kind of exception
+- *
+- * 3. Kernel executes error_entry() and mis-speculates the branch into thinking
+- *    it actually came from kernel space
+- *
+- * 4. The kernel then further mis-speculates that the exception occurred due
+- *    to an interrupted safe-RET
+- *
+- * 5. The handle_interrupted_saferet() routine speculatively executes and
+- *    speculatively does a safe-RET. But this is unsafe since it was never
+- *    untrained.
+- *
+- * The LFENCE fixes this by ensuring step 5 is never reached speculatively.
+- * Note that this LFENCE only occurs if safe-RET was actually interrupted (so
+- * it's outside of the normal path).
+- */
+-#define __HANDLE_INTR_SAFERET(name, pt_regs)          \
+-      cmpq    $(name), RIP+pt_regs;                   \
+-      jb      1f;                                     \
+-      cmpq    $(name)+5, RIP+pt_regs;                 \
+-      ja      1f;                                     \
+-      lfence;                                         \
+-      leaq    pt_regs, %rdi;                          \
+-      call    handle_interrupted_saferet;             \
+-      1:
+-
+ #ifdef __ASSEMBLY__
+ /*
+@@ -234,14 +190,6 @@
+ #endif
+ .endm
+-.macro HANDLE_INTR_SAFERET pt_regs
+-#ifdef CONFIG_MITIGATION_SRSO
+-      ALTERNATIVE_2 "", \
+-      __stringify(__HANDLE_INTR_SAFERET(srso_safe_ret, \pt_regs)), X86_FEATURE_SRSO, \
+-      __stringify(__HANDLE_INTR_SAFERET(srso_alias_safe_ret, \pt_regs)), X86_FEATURE_SRSO_ALIAS
+-#endif
+-.endm
+-
+ /*
+  * Macro to execute VERW insns that mitigate transient data sampling
+  * attacks such as MDS or TSA. On affected systems a microcode update
+@@ -501,10 +449,6 @@ static __always_inline void x86_idle_cle
+               x86_clear_cpu_buffers();
+ }
+-void srso_safe_ret(void);
+-void srso_alias_safe_ret(void);
+-void handle_interrupted_saferet(struct pt_regs *regs);
+-
+ #endif /* __ASSEMBLY__ */
+ #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -3238,42 +3238,3 @@ ssize_t cpu_show_vmscape(struct device *
+       return cpu_show_common(dev, attr, buf, X86_BUG_VMSCAPE);
+ }
+ #endif
+-
+-#ifdef CONFIG_MITIGATION_SRSO
+-/*
+- * Called during exception/interrupt entry if interrupted during the
+- * safe-RET sequence.  The safe-RET sequence consists of 3 instructions:
+- *
+- *    CALL
+- *    LEA 8(%RSP), %RSP
+- *    RET
+- *
+- * An interrupt after the CALL or after the LEA could potentially lead
+- * to branch predictor poisoning and results in the sequence not being
+- * able to be safely resumed.
+- *
+- * Therefore, modify the regs state as if the remaining part of the
+- * safe-RET sequence executed so the interrupt returns back to the
+- * desired return target, instead of the to the safe-RET sequence.
+- */
+-void noinstr handle_interrupted_saferet(struct pt_regs *regs)
+-{
+-      unsigned long rip = regs->ip;
+-
+-      if (rip == (unsigned long) srso_safe_ret ||
+-          rip == (unsigned long) srso_alias_safe_ret) {
+-          /* Modify stack pointer as if LEA executed: */
+-          regs->sp += 8;
+-      }
+-
+-      /*
+-       * Adjust registers as if RET executed:
+-       *
+-       * 1. Read the return address off the stack and into rIP:
+-       */
+-      regs->ip = *(unsigned long *)(regs->sp);
+-
+-      /* 2. Pop rIP off the stack: */
+-      regs->sp += 8;
+-}
+-#endif /* CONFIG_MITIGATION_SRSO */
+--- a/arch/x86/lib/retpoline.S
++++ b/arch/x86/lib/retpoline.S
+@@ -113,24 +113,10 @@ __EXPORT_THUNK(srso_alias_untrain_ret)
+ #endif
+ SYM_START(srso_alias_safe_ret, SYM_L_GLOBAL, SYM_A_NONE)
+-
+-      /*
+-       * Tell objtool that those are not function pointers referenced by
+-       * __HANDLE_INTR_SAFERET(). Below too.
+-       */
+-      ANNOTATE_NOENDBR
+-
+-      /*
+-       * Safe-RET sequence. If you need to change it, adjust
+-       * handle_interrupted_saferet() too.
+-       */
+       lea 8(%_ASM_SP), %_ASM_SP
+       UNWIND_HINT_FUNC
+-
+-      ANNOTATE_NOENDBR
+       ANNOTATE_UNRET_SAFE
+       ret
+-      /* End of Safe-RET sequence */
+       int3
+ SYM_FUNC_END(srso_alias_safe_ret)
+@@ -245,14 +231,8 @@ SYM_START(srso_untrain_ret, SYM_L_GLOBAL
+  * the stack.
+  */
+ SYM_INNER_LABEL(srso_safe_ret, SYM_L_GLOBAL)
+-      /*
+-       * Safe-RET sequence. If you need to change it, adjust
+-       * handle_interrupted_saferet() too.
+-       */
+       lea 8(%_ASM_SP), %_ASM_SP
+       ret
+-      /* End of Safe-RET sequence */
+-
+       int3
+       int3
+       /* end of movabs */
diff --git a/queue-5.10/series b/queue-5.10/series
new file mode 100644 (file)
index 0000000..d493245
--- /dev/null
@@ -0,0 +1,2 @@
+0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch
+x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch
diff --git a/queue-5.10/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch b/queue-5.10/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch
new file mode 100644 (file)
index 0000000..88a2aee
--- /dev/null
@@ -0,0 +1,233 @@
+From 0778a5399a9dde7b1d547d07d7058597c28e5330 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Wed, 29 Jul 2026 19:35:27 -0700
+Subject: x86/bugs: Make Safe-RET robust against interrupt injection
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+An attacker injecting interrupts while the Safe-RET mitigation executes
+on machines affected by SRSO can neutralize the safe return sequence,
+potentially leading to data leakage through speculative execution.
+
+Fixup register state as if the Safe-RET sequence executed successfully
+by "emulating" it, in a manner of speaking, and avoid executing a RET
+instruction after returning from the interrupt.
+
+Co-developed-by: David Kaplan <David.Kaplan@amd.com>
+Signed-off-by: David Kaplan <David.Kaplan@amd.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Signed-off-by: Wenkuan Wang <Wenkuan.Wang@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/entry/entry_64.S            |    5 ++
+ arch/x86/include/asm/nospec-branch.h |   13 +++++
+ arch/x86/kernel/cpu/bugs.c           |   39 +++++++++++++++++
+ arch/x86/lib/retpoline.S             |   79 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 136 insertions(+)
+
+--- a/arch/x86/entry/entry_64.S
++++ b/arch/x86/entry/entry_64.S
+@@ -971,6 +971,8 @@ SYM_CODE_START_LOCAL(paranoid_entry)
+       IBRS_ENTER save_reg=%r15
+       UNTRAIN_RET
++      HANDLE_INTR_SAFERET 8(%rsp)
++
+       RET
+ SYM_CODE_END(paranoid_entry)
+@@ -1078,6 +1080,9 @@ SYM_CODE_START_LOCAL(error_entry)
+       movl    %ecx, %eax                      /* zero extend */
+       cmpq    %rax, RIP+8(%rsp)
+       je      .Lbstep_iret
++
++      HANDLE_INTR_SAFERET 8(%rsp)
++
+       cmpq    $.Lgs_change, RIP+8(%rsp)
+       jne     .Lerror_entry_done_lfence
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -190,6 +190,14 @@
+ #endif
+ .endm
++.macro HANDLE_INTR_SAFERET pt_regs
++#ifdef CONFIG_CPU_SRSO
++      ALTERNATIVE_2 "",                                                       \
++                    "call __handle_intr_saferet", X86_FEATURE_SRSO,           \
++                    "call __handle_intr_saferet_alias", X86_FEATURE_SRSO_ALIAS
++#endif
++.endm
++
+ /*
+  * Macro to execute VERW insns that mitigate transient data sampling
+  * attacks such as MDS or TSA. On affected systems a microcode update
+@@ -249,6 +257,11 @@ extern void srso_alias_untrain_ret(void)
+ extern void entry_untrain_ret(void);
+ extern void entry_ibpb(void);
++struct pt_regs;
++void srso_safe_ret(void);
++void srso_alias_safe_ret(void);
++void handle_interrupted_saferet(struct pt_regs *regs);
++
+ extern void (*x86_return_thunk)(void);
+ #ifdef CONFIG_RETPOLINE
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -3238,3 +3238,42 @@ ssize_t cpu_show_vmscape(struct device *
+       return cpu_show_common(dev, attr, buf, X86_BUG_VMSCAPE);
+ }
+ #endif
++
++#ifdef CONFIG_CPU_SRSO
++/*
++ * Called during exception/interrupt entry if interrupted during the
++ * safe-RET sequence.  The safe-RET sequence consists of 3 instructions:
++ *
++ *    CALL
++ *    LEA 8(%RSP), %RSP
++ *    RET
++ *
++ * An interrupt after the CALL or after the LEA could potentially lead
++ * to branch predictor poisoning and results in the sequence not being
++ * able to be safely resumed.
++ *
++ * Therefore, modify the regs state as if the remaining part of the
++ * safe-RET sequence executed so the interrupt returns back to the
++ * desired return target, instead of the to the safe-RET sequence.
++ */
++void noinstr handle_interrupted_saferet(struct pt_regs *regs)
++{
++      unsigned long rip = regs->ip;
++
++      if (rip == (unsigned long) srso_safe_ret ||
++          rip == (unsigned long) srso_alias_safe_ret) {
++              /* Modify stack pointer as if LEA executed: */
++              regs->sp += 8;
++      }
++
++      /*
++       * Adjust registers as if RET executed:
++       *
++       * 1. Read the return address off the stack and into rIP:
++       */
++      regs->ip = *(unsigned long *)(regs->sp);
++
++      /* 2. Pop rIP off the stack: */
++      regs->sp += 8;
++}
++#endif /* CONFIG_CPU_SRSO */
+--- a/arch/x86/lib/retpoline.S
++++ b/arch/x86/lib/retpoline.S
+@@ -7,6 +7,7 @@
+ #include <asm/alternative.h>
+ #include <asm/export.h>
+ #include <asm/nospec-branch.h>
++#include <asm/ptrace-abi.h>
+ #include <asm/unwind_hints.h>
+ #include <asm/frame.h>
+ #include <asm/nops.h>
+@@ -113,13 +114,85 @@ __EXPORT_THUNK(srso_alias_untrain_ret)
+ #endif
+ SYM_START(srso_alias_safe_ret, SYM_L_GLOBAL, SYM_A_NONE)
++
++      /*
++       * Tell objtool that those are not function pointers referenced by
++       * __handle_intr_saferet() / __handle_intr_saferet_alias(). Below too.
++       */
++      ANNOTATE_NOENDBR
++
++      /*
++       * Safe-RET sequence. If you need to change it, adjust
++       * handle_interrupted_saferet() too.
++       */
+       lea 8(%_ASM_SP), %_ASM_SP
+       UNWIND_HINT_FUNC
++
++      ANNOTATE_NOENDBR
+       ANNOTATE_UNRET_SAFE
+       ret
++      /* End of Safe-RET sequence */
+       int3
+ SYM_FUNC_END(srso_alias_safe_ret)
++#ifdef CONFIG_CPU_SRSO
++      .pushsection .noinstr.text, "ax"
++
++/*
++ * Out-of-line helpers for HANDLE_INTR_SAFERET.
++ *
++ * Called via ALTERNATIVE_2 from paranoid_entry / error_entry. There is one
++ * entry per SRSO variant so that each only checks its own Safe-RET range,
++ * mirroring the upstream per-feature ALTERNATIVE_2:
++ *
++ *   X86_FEATURE_SRSO       -> __handle_intr_saferet       (srso_safe_ret)
++ *   X86_FEATURE_SRSO_ALIAS -> __handle_intr_saferet_alias (srso_alias_safe_ret)
++ *
++ * If the interrupted RIP falls within the 5-byte Safe-RET sequence, emulate
++ * the remainder of the sequence by calling handle_interrupted_saferet().
++ *
++ * Stack layout on entry (CALL pushed return address):
++ *   pt_regs base at 16(%rsp), RIP field at RIP+16(%rsp)
++ *   (RIP is the pt_regs RIP offset (128) from <asm/ptrace-abi.h>; +16 = 8 for
++ *    pt_regs base at 8(%rsp) at the call site + 8 for the CALL return address)
++ *
++ * The pt_regs pointer is loaded into %rdi *before* FRAME_BEGIN so the 16(%rsp)
++ * offset does not depend on CONFIG_FRAME_POINTER (which would push %rbp and
++ * shift %rsp). FRAME_BEGIN/FRAME_END set up a frame pointer so the call to
++ * handle_interrupted_saferet() does not trip objtool's frame-pointer check on
++ * CONFIG_FRAME_POINTER builds; both are no-ops otherwise.
++ *
++ * Both entries are emitted from one macro: @safe_ret is the label at the start
++ * of the 5-byte Safe-RET sequence whose range the interrupted RIP is tested
++ * against; \@ yields a unique local label per macro instantiation.
++ */
++.macro HANDLE_INTR_SAFERET_FN name safe_ret
++SYM_FUNC_START(\name)
++      UNWIND_HINT_FUNC
++
++      /* Load pt_regs pointer before FRAME_BEGIN adjusts %rsp. */
++      leaq    16(%rsp), %rdi
++      FRAME_BEGIN
++
++      /* Check range: [\safe_ret, \safe_ret + 5] */
++      cmpq    $\safe_ret, RIP(%rdi)
++      jb      .Ldone_\@
++      cmpq    $\safe_ret + 5, RIP(%rdi)
++      ja      .Ldone_\@
++      lfence
++      call    handle_interrupted_saferet
++.Ldone_\@:
++      FRAME_END
++      RET
++SYM_FUNC_END(\name)
++.endm
++
++HANDLE_INTR_SAFERET_FN __handle_intr_saferet     srso_safe_ret
++HANDLE_INTR_SAFERET_FN __handle_intr_saferet_alias srso_alias_safe_ret
++
++      .popsection
++#endif
++
+       .section .text..__x86.return_thunk
+ SYM_CODE_START(srso_alias_return_thunk)
+@@ -231,8 +304,14 @@ SYM_START(srso_untrain_ret, SYM_L_GLOBAL
+  * the stack.
+  */
+ SYM_INNER_LABEL(srso_safe_ret, SYM_L_GLOBAL)
++      /*
++       * Safe-RET sequence. If you need to change it, adjust
++       * handle_interrupted_saferet() too.
++       */
+       lea 8(%_ASM_SP), %_ASM_SP
+       ret
++      /* End of Safe-RET sequence */
++
+       int3
+       int3
+       /* end of movabs */