[PATCH 04/45] KVM: x86/emulate: Check TSS busy-bit writes during task switches
From: Paolo Bonzini
Date: Mon Nov 02 2026 - 15:47:07 EST
Task switching ignores failures when clearing the old TSS descriptor's
busy bit and setting the new descriptor's busy bit. A memory attribute
restriction can therefore drop either write while the task switch
continues with inconsistent descriptor state.
Check both writes and stop the task switch on failure. Memory attribute
faults reach the existing emulation-failure exit in kvm_task_switch().
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
arch/x86/kvm/emulate.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c1b21282187f..711794592c2c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2925,7 +2925,9 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */
- write_segment_descriptor(ctxt, old_tss_sel, &curr_tss_desc);
+ ret = write_segment_descriptor(ctxt, old_tss_sel, &curr_tss_desc);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
}
if (reason == TASK_SWITCH_IRET)
@@ -2949,7 +2951,9 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
if (reason != TASK_SWITCH_IRET) {
next_tss_desc.type |= (1 << 1); /* set busy flag */
- write_segment_descriptor(ctxt, tss_selector, &next_tss_desc);
+ ret = write_segment_descriptor(ctxt, tss_selector, &next_tss_desc);
+ if (ret != X86EMUL_CONTINUE)
+ return ret;
}
ops->set_cr(ctxt, 0, ops->get_cr(ctxt, 0) | X86_CR0_TS);
--
2.52.0