Skip to content

Commit

Permalink
Merge tag 'x86-urgent-2024-12-29' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/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
  • Loading branch information
Linus Torvalds committed Dec 29, 2024
2 parents f65832a + 2783497 commit 6cbc4b2
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
30 changes: 30 additions & 0 deletions arch/x86/kernel/cet.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,34 @@ static void do_user_cp_fault(struct pt_regs *regs, unsigned long error_code)

static __ro_after_init bool ibt_fatal = true;

/*
* By definition, all missing-ENDBRANCH #CPs are a result of WFE && !ENDBR.
*
* For the kernel IBT no ENDBR selftest where #CPs are deliberately triggered,
* the WFE state of the interrupted context needs to be cleared to let execution
* continue. Otherwise when the CPU resumes from the instruction that just
* caused the previous #CP, another missing-ENDBRANCH #CP is raised and the CPU
* enters a dead loop.
*
* This is not a problem with IDT because it doesn't preserve WFE and IRET doesn't
* set WFE. But FRED provides space on the entry stack (in an expanded CS area)
* to save and restore the WFE state, thus the WFE state is no longer clobbered,
* so software must clear it.
*/
static void ibt_clear_fred_wfe(struct pt_regs *regs)
{
/*
* No need to do any FRED checks.
*
* For IDT event delivery, the high-order 48 bits of CS are pushed
* as 0s into the stack, and later IRET ignores these bits.
*
* For FRED, a test to check if fred_cs.wfe is set would be dropped
* by compilers.
*/
regs->fred_cs.wfe = 0;
}

static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code)
{
if ((error_code & CP_EC) != CP_ENDBR) {
Expand All @@ -90,13 +118,15 @@ static void do_kernel_cp_fault(struct pt_regs *regs, unsigned long error_code)

if (unlikely(regs->ip == (unsigned long)&ibt_selftest_noendbr)) {
regs->ax = 0;
ibt_clear_fred_wfe(regs);
return;
}

pr_err("Missing ENDBR: %pS\n", (void *)instruction_pointer(regs));
if (!ibt_fatal) {
printk(KERN_DEFAULT CUT_HERE);
__warn(__FILE__, __LINE__, (void *)regs->ip, TAINT_WARN, regs, NULL);
ibt_clear_fred_wfe(regs);
return;
}
BUG();
Expand Down
4 changes: 1 addition & 3 deletions drivers/virt/coco/tdx-guest/tdx-guest.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,8 @@ static void *alloc_quote_buf(void)
if (!addr)
return NULL;

if (set_memory_decrypted((unsigned long)addr, count)) {
free_pages_exact(addr, len);
if (set_memory_decrypted((unsigned long)addr, count))
return NULL;
}

return addr;
}
Expand Down

0 comments on commit 6cbc4b2

Please sign in to comment.