Skip to content

Commit 82c0ec0

Browse files
committed
KVM: x86: Don't emulate task switches when IBT or SHSTK is enabled
Exit to userspace with KVM_INTERNAL_ERROR_EMULATION if the guest triggers task switch emulation with Indirect Branch Tracking or Shadow Stacks enabled, as attempting to do the right thing would require non-trivial effort and complexity, KVM doesn't support emulating CET generally, and it's extremely unlikely that any guest will do task switches while also utilizing CET. Defer taking on the complexity until someone cares enough to put in the time and effort to add support. Per the SDM: If shadow stack is enabled, then the SSP of the task is located at the 4 bytes at offset 104 in the 32-bit TSS and is used by the processor to establish the SSP when a task switch occurs from a task associated with this TSS. Note that the processor does not write the SSP of the task initiating the task switch to the TSS of that task, and instead the SSP of the previous task is pushed onto the shadow stack of the new task. Note, per the SDM's pseudocode on TASK SWITCHING, IBT state for the new privilege level is updated. To keep things simple, check both S_CET and U_CET (again, anyone that wants more precise checking can have the honor of implementing support). Reported-by: Binbin Wu <binbin.wu@linux.intel.com> Closes: https://lore.kernel.org/all/819bd98b-2a60-4107-8e13-41f1e4c706b1@linux.intel.com Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com> Link: https://lore.kernel.org/r/20250919223258.1604852-20-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 57c3db7 commit 82c0ec0

1 file changed

Lines changed: 28 additions & 7 deletions

File tree

arch/x86/kvm/x86.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12175,6 +12175,25 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
1217512175
struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
1217612176
int ret;
1217712177

12178+
if (kvm_is_cr4_bit_set(vcpu, X86_CR4_CET)) {
12179+
u64 u_cet, s_cet;
12180+
12181+
/*
12182+
* Check both User and Supervisor on task switches as inter-
12183+
* privilege level task switches are impacted by CET at both
12184+
* the current privilege level and the new privilege level, and
12185+
* that information is not known at this time. The expectation
12186+
* is that the guest won't require emulation of task switches
12187+
* while using IBT or Shadow Stacks.
12188+
*/
12189+
if (__kvm_emulate_msr_read(vcpu, MSR_IA32_U_CET, &u_cet) ||
12190+
__kvm_emulate_msr_read(vcpu, MSR_IA32_S_CET, &s_cet))
12191+
goto unhandled_task_switch;
12192+
12193+
if ((u_cet | s_cet) & (CET_ENDBR_EN | CET_SHSTK_EN))
12194+
goto unhandled_task_switch;
12195+
}
12196+
1217812197
init_emulate_ctxt(vcpu);
1217912198

1218012199
ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason,
@@ -12184,17 +12203,19 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
1218412203
* Report an error userspace if MMIO is needed, as KVM doesn't support
1218512204
* MMIO during a task switch (or any other complex operation).
1218612205
*/
12187-
if (ret || vcpu->mmio_needed) {
12188-
vcpu->mmio_needed = false;
12189-
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
12190-
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
12191-
vcpu->run->internal.ndata = 0;
12192-
return 0;
12193-
}
12206+
if (ret || vcpu->mmio_needed)
12207+
goto unhandled_task_switch;
1219412208

1219512209
kvm_rip_write(vcpu, ctxt->eip);
1219612210
kvm_set_rflags(vcpu, ctxt->eflags);
1219712211
return 1;
12212+
12213+
unhandled_task_switch:
12214+
vcpu->mmio_needed = false;
12215+
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
12216+
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
12217+
vcpu->run->internal.ndata = 0;
12218+
return 0;
1219812219
}
1219912220
EXPORT_SYMBOL_GPL(kvm_task_switch);
1220012221

0 commit comments

Comments
 (0)