Skip to content

Commit 6cbc4b2

Browse files
committed
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
2 parents f65832a + 2783497 commit 6cbc4b2

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

arch/x86/kernel/cet.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@ static void do_user_cp_fault(struct pt_regs *regs, unsigned long error_code)
8181

8282
static __ro_after_init bool ibt_fatal = true;
8383

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+
84112
static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code)
85113
{
86114
if ((error_code & CP_EC) != CP_ENDBR) {
@@ -90,13 +118,15 @@ static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code)
90118

91119
if (unlikely(regs->ip == (unsigned long)&ibt_selftest_noendbr)) {
92120
regs->ax = 0;
121+
ibt_clear_fred_wfe(regs);
93122
return;
94123
}
95124

96125
pr_err("Missing ENDBR: %pS\n", (void *)instruction_pointer(regs));
97126
if (!ibt_fatal) {
98127
printk(KERN_DEFAULT CUT_HERE);
99128
__warn(__FILE__, __LINE__, (void *)regs->ip, TAINT_WARN, regs, NULL);
129+
ibt_clear_fred_wfe(regs);
100130
return;
101131
}
102132
BUG();

drivers/virt/coco/tdx-guest/tdx-guest.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,8 @@ static void *alloc_quote_buf(void)
124124
if (!addr)
125125
return NULL;
126126

127-
if (set_memory_decrypted((unsigned long)addr, count)) {
128-
free_pages_exact(addr, len);
127+
if (set_memory_decrypted((unsigned long)addr, count))
129128
return NULL;
130-
}
131129

132130
return addr;
133131
}

0 commit comments

Comments
 (0)