From 3ea36b4450e616888fcefdb02ff548ed6ba1cc47 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 7 Aug 2026 07:42:56 +0200 Subject: [PATCH] 6.6-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 --- ...Make-Safe-RET-robust-against-interru.patch | 216 +++++++++++++++++ queue-6.6/series | 2 + ...t-robust-against-interrupt-injection.patch | 228 ++++++++++++++++++ 3 files changed, 446 insertions(+) create mode 100644 queue-6.6/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch create mode 100644 queue-6.6/series create mode 100644 queue-6.6/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch diff --git a/queue-6.6/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch b/queue-6.6/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch new file mode 100644 index 0000000000..d6b1d7c52b --- /dev/null +++ b/queue-6.6/0001-Revert-x86-bugs-Make-Safe-RET-robust-against-interru.patch @@ -0,0 +1,216 @@ +From 9670ee468a0c5335c92aeae6a662b97360968887 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 7 Aug 2026 07:41:07 +0200 +Subject: [PATCH] Revert "x86/bugs: Make Safe-RET robust against interrupt + injection" + +This reverts commit 608c8f5dccaaf8b8d2b28c0fbdd439d144be62b0 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 | 8 ----- + arch/x86/include/asm/nospec-branch.h | 56 ----------------------------------- + arch/x86/kernel/cpu/bugs.c | 39 ------------------------ + arch/x86/lib/retpoline.S | 20 ------------ + 4 files changed, 1 insertion(+), 122 deletions(-) + +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -976,8 +976,6 @@ SYM_CODE_START(paranoid_entry) + IBRS_ENTER save_reg=%r15 + UNTRAIN_RET_FROM_CALL + +- HANDLE_INTR_SAFERET 8(%rsp) +- + RET + SYM_CODE_END(paranoid_entry) + +@@ -1080,11 +1078,6 @@ SYM_CODE_START(error_entry) + movl %ecx, %eax /* zero extend */ + cmpq %rax, RIP+8(%rsp) + je .Lbstep_iret +- +- VALIDATE_UNRET_END +- +- HANDLE_INTR_SAFERET 8(%rsp) +- + cmpq $.Lgs_change, RIP+8(%rsp) + jne .Lerror_entry_done_lfence + +@@ -1103,6 +1096,7 @@ SYM_CODE_START(error_entry) + FENCE_SWAPGS_KERNEL_ENTRY + CALL_DEPTH_ACCOUNT + leaq 8(%rsp), %rax /* return pt_regs pointer */ ++ VALIDATE_UNRET_END + RET + + .Lbstep_iret: +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -186,50 +186,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__ + + /* +@@ -359,14 +315,6 @@ + #define UNTRAIN_RET_FROM_CALL \ + __UNTRAIN_RET X86_FEATURE_ENTRY_IBPB, __stringify(RESET_CALL_DEPTH_FROM_CALL) + +-.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 CALL_DEPTH_ACCOUNT + #ifdef CONFIG_CALL_DEPTH_TRACKING +@@ -701,10 +649,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 +@@ -3489,42 +3489,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 +@@ -161,24 +161,10 @@ __EXPORT_THUNK(srso_alias_untrain_ret) + + .pushsection .text..__x86.rethunk_safe + 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) + +@@ -213,14 +199,8 @@ SYM_START(srso_untrain_ret, SYM_L_LOCAL, + * 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-6.6/series b/queue-6.6/series new file mode 100644 index 0000000000..d493245b5a --- /dev/null +++ b/queue-6.6/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-6.6/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch b/queue-6.6/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch new file mode 100644 index 0000000000..ac056f9fb2 --- /dev/null +++ b/queue-6.6/x86-bugs-make-safe-ret-robust-against-interrupt-injection.patch @@ -0,0 +1,228 @@ +From f89da9b198bc7944feb2dcceca2987b763cc22f1 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Tue, 2 Jun 2026 21:26:44 -0700 +Subject: x86/bugs: Make Safe-RET robust against interrupt injection + +From: "Borislav Petkov (AMD)" + +commit 7e7f81cf6f5ca3311e526308f55d7c54d3ba71f9 upstream. + +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: Greg Kroah-Hartman +--- + arch/x86/entry/entry_64.S | 8 ++++ + arch/x86/include/asm/nospec-branch.h | 59 +++++++++++++++++++++++++++++++++++ + arch/x86/kernel/cpu/bugs.c | 39 +++++++++++++++++++++++ + arch/x86/lib/retpoline.S | 20 +++++++++++ + 4 files changed, 125 insertions(+), 1 deletion(-) + +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -976,6 +976,8 @@ SYM_CODE_START(paranoid_entry) + IBRS_ENTER save_reg=%r15 + UNTRAIN_RET_FROM_CALL + ++ HANDLE_INTR_SAFERET 8(%rsp) ++ + RET + SYM_CODE_END(paranoid_entry) + +@@ -1078,6 +1080,11 @@ SYM_CODE_START(error_entry) + movl %ecx, %eax /* zero extend */ + cmpq %rax, RIP+8(%rsp) + je .Lbstep_iret ++ ++ VALIDATE_UNRET_END ++ ++ HANDLE_INTR_SAFERET 8(%rsp) ++ + cmpq $.Lgs_change, RIP+8(%rsp) + jne .Lerror_entry_done_lfence + +@@ -1096,7 +1103,6 @@ SYM_CODE_START(error_entry) + FENCE_SWAPGS_KERNEL_ENTRY + CALL_DEPTH_ACCOUNT + leaq 8(%rsp), %rax /* return pt_regs pointer */ +- VALIDATE_UNRET_END + RET + + .Lbstep_iret: +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -186,6 +186,53 @@ + 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). ++ * ++ * (The 128 below is RIP offset, used as a naked number here for ease of ++ * backporting). ++ */ ++#define __HANDLE_INTR_SAFERET(name, pt_regs) \ ++ cmpq $(name), 128+pt_regs; \ ++ jb 1f; \ ++ cmpq $(name)+5, 128+pt_regs; \ ++ ja 1f; \ ++ lfence; \ ++ leaq pt_regs, %rdi; \ ++ call handle_interrupted_saferet; \ ++ 1: ++ + #ifdef __ASSEMBLY__ + + /* +@@ -315,6 +362,14 @@ + #define UNTRAIN_RET_FROM_CALL \ + __UNTRAIN_RET X86_FEATURE_ENTRY_IBPB, __stringify(RESET_CALL_DEPTH_FROM_CALL) + ++.macro HANDLE_INTR_SAFERET pt_regs ++#ifdef CONFIG_CPU_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 CALL_DEPTH_ACCOUNT + #ifdef CONFIG_CALL_DEPTH_TRACKING +@@ -649,6 +704,10 @@ 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 +@@ -3489,3 +3489,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 +@@ -161,10 +161,24 @@ __EXPORT_THUNK(srso_alias_untrain_ret) + + .pushsection .text..__x86.rethunk_safe + 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) + +@@ -199,8 +213,14 @@ SYM_START(srso_untrain_ret, SYM_L_LOCAL, + * 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 */ -- 2.47.3