From: Greg Kroah-Hartman Date: Fri, 7 Aug 2026 05:56:00 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v5.10.264~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=669cf2149e9dd030ea99e2e648b69e962859819a;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: 0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch series x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch --- diff --git a/queue-5.15/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch b/queue-5.15/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch new file mode 100644 index 0000000000..afec3f7702 --- /dev/null +++ b/queue-5.15/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch @@ -0,0 +1,206 @@ +From f19f5591cdb62ad54643e98622666630f878f6d0 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 7 Aug 2026 07:51:25 +0200 +Subject: [PATCH] Revert "x86/bugs: Make Safe-RET robust against interrupt + injection" + +This reverts commit 9c0b8105e919be5208c81d5516a194a28c58fe1e which is +commit 7e7f81cf6f5ca3311e526308f55d7c54d3ba71f9 upstream. + +It was incorrect, a more correct fix will be applied next. + +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -941,8 +941,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) + +@@ -1047,9 +1045,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__ + + /* +@@ -245,14 +201,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 +@@ -534,10 +482,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 +@@ -3397,42 +3397,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 +@@ -112,24 +112,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) + +@@ -244,14 +230,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.15/series b/queue-5.15/series new file mode 100644 index 0000000000..d493245b5a --- /dev/null +++ b/queue-5.15/series @@ -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.15/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch b/queue-5.15/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch new file mode 100644 index 0000000000..4408bd9c56 --- /dev/null +++ b/queue-5.15/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch @@ -0,0 +1,233 @@ +From af5bb96acf3804268827e99010993483224ef8e9 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Thu, 6 Aug 2026 06:29:10 -0700 +Subject: x86/bugs: Make Safe-RET robust against interrupt injection + +From: "Borislav Petkov (AMD)" + +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 +Signed-off-by: David Kaplan +Signed-off-by: Borislav Petkov (AMD) +Signed-off-by: Wenkuan Wang +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -941,6 +941,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) + +@@ -1045,6 +1047,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 +@@ -201,6 +201,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 +@@ -273,6 +281,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); ++ + #ifdef CONFIG_X86_64 + extern void clear_bhb_loop(void); + #endif +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -3397,3 +3397,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 + #include + #include ++#include + #include + #include + #include +@@ -112,13 +113,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 ; +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 /* CONFIG_CPU_SRSO */ ++ + .section .text..__x86.return_thunk + + SYM_CODE_START(srso_alias_return_thunk) +@@ -230,8 +303,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 */