Merge tag 'x86-urgent-2024-12-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Ingo Molnar:

- Fix a hang in the "kernel IBT no ENDBR" self-test that may trigger
on FRED systems, caused by incomplete FRED state cleanup in the
#CP fault handler

- Improve TDX (Coco VM) guest unrecoverable error handling to not
potentially leak decrypted memory

* tag 'x86-urgent-2024-12-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
virt: tdx-guest: Just leak decrypted memory on unrecoverable errors
x86/fred: Clear WFE in missing-ENDBRANCH #CPs

Changed files
+31 -3
arch
x86
kernel
drivers
virt
coco
tdx-guest
+30
arch/x86/kernel/cet.c
··· 81 81 82 82 static __ro_after_init bool ibt_fatal = true; 83 83 84 + /* 85 + * By definition, all missing-ENDBRANCH #CPs are a result of WFE && !ENDBR. 86 + * 87 + * For the kernel IBT no ENDBR selftest where #CPs are deliberately triggered, 88 + * the WFE state of the interrupted context needs to be cleared to let execution 89 + * continue. Otherwise when the CPU resumes from the instruction that just 90 + * caused the previous #CP, another missing-ENDBRANCH #CP is raised and the CPU 91 + * enters a dead loop. 92 + * 93 + * This is not a problem with IDT because it doesn't preserve WFE and IRET doesn't 94 + * set WFE. But FRED provides space on the entry stack (in an expanded CS area) 95 + * to save and restore the WFE state, thus the WFE state is no longer clobbered, 96 + * so software must clear it. 97 + */ 98 + static void ibt_clear_fred_wfe(struct pt_regs *regs) 99 + { 100 + /* 101 + * No need to do any FRED checks. 102 + * 103 + * For IDT event delivery, the high-order 48 bits of CS are pushed 104 + * as 0s into the stack, and later IRET ignores these bits. 105 + * 106 + * For FRED, a test to check if fred_cs.wfe is set would be dropped 107 + * by compilers. 108 + */ 109 + regs->fred_cs.wfe = 0; 110 + } 111 + 84 112 static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code) 85 113 { 86 114 if ((error_code & CP_EC) != CP_ENDBR) { ··· 118 90 119 91 if (unlikely(regs->ip == (unsigned long)&ibt_selftest_noendbr)) { 120 92 regs->ax = 0; 93 + ibt_clear_fred_wfe(regs); 121 94 return; 122 95 } 123 96 ··· 126 97 if (!ibt_fatal) { 127 98 printk(KERN_DEFAULT CUT_HERE); 128 99 __warn(__FILE__, __LINE__, (void *)regs->ip, TAINT_WARN, regs, NULL); 100 + ibt_clear_fred_wfe(regs); 129 101 return; 130 102 } 131 103 BUG();
+1 -3
drivers/virt/coco/tdx-guest/tdx-guest.c
··· 124 124 if (!addr) 125 125 return NULL; 126 126 127 - if (set_memory_decrypted((unsigned long)addr, count)) { 128 - free_pages_exact(addr, len); 127 + if (set_memory_decrypted((unsigned long)addr, count)) 129 128 return NULL; 130 - } 131 129 132 130 return addr; 133 131 }