Skip to content

Commit f577508

Browse files
sean-jcgregkh
authored andcommitted
x86/fpu: Clear XSTATE_BV[i] in guest XSAVE state whenever XFD[i]=1
commit b45f721 upstream. When loading guest XSAVE state via KVM_SET_XSAVE, and when updating XFD in response to a guest WRMSR, clear XFD-disabled features in the saved (or to be restored) XSTATE_BV to ensure KVM doesn't attempt to load state for features that are disabled via the guest's XFD. Because the kernel executes XRSTOR with the guest's XFD, saving XSTATE_BV[i]=1 with XFD[i]=1 will cause XRSTOR to #NM and panic the kernel. E.g. if fpu_update_guest_xfd() sets XFD without clearing XSTATE_BV: ------------[ cut here ]------------ WARNING: arch/x86/kernel/traps.c:1524 at exc_device_not_available+0x101/0x110, CPU#29: amx_test/848 Modules linked in: kvm_intel kvm irqbypass CPU: 29 UID: 1000 PID: 848 Comm: amx_test Not tainted 6.19.0-rc2-ffa07f7fd437-x86_amx_nm_xfd_non_init-vm #171 NONE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:exc_device_not_available+0x101/0x110 Call Trace: <TASK> asm_exc_device_not_available+0x1a/0x20 RIP: 0010:restore_fpregs_from_fpstate+0x36/0x90 switch_fpu_return+0x4a/0xb0 kvm_arch_vcpu_ioctl_run+0x1245/0x1e40 [kvm] kvm_vcpu_ioctl+0x2c3/0x8f0 [kvm] __x64_sys_ioctl+0x8f/0xd0 do_syscall_64+0x62/0x940 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> ---[ end trace 0000000000000000 ]--- This can happen if the guest executes WRMSR(MSR_IA32_XFD) to set XFD[18] = 1, and a host IRQ triggers kernel_fpu_begin() prior to the vmexit handler's call to fpu_update_guest_xfd(). and if userspace stuffs XSTATE_BV[i]=1 via KVM_SET_XSAVE: ------------[ cut here ]------------ WARNING: arch/x86/kernel/traps.c:1524 at exc_device_not_available+0x101/0x110, CPU#14: amx_test/867 Modules linked in: kvm_intel kvm irqbypass CPU: 14 UID: 1000 PID: 867 Comm: amx_test Not tainted 6.19.0-rc2-2dace9faccd6-x86_amx_nm_xfd_non_init-vm #168 NONE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:exc_device_not_available+0x101/0x110 Call Trace: <TASK> asm_exc_device_not_available+0x1a/0x20 RIP: 0010:restore_fpregs_from_fpstate+0x36/0x90 fpu_swap_kvm_fpstate+0x6b/0x120 kvm_load_guest_fpu+0x30/0x80 [kvm] kvm_arch_vcpu_ioctl_run+0x85/0x1e40 [kvm] kvm_vcpu_ioctl+0x2c3/0x8f0 [kvm] __x64_sys_ioctl+0x8f/0xd0 do_syscall_64+0x62/0x940 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> ---[ end trace 0000000000000000 ]--- The new behavior is consistent with the AMX architecture. Per Intel's SDM, XSAVE saves XSTATE_BV as '0' for components that are disabled via XFD (and non-compacted XSAVE saves the initial configuration of the state component): If XSAVE, XSAVEC, XSAVEOPT, or XSAVES is saving the state component i, the instruction does not generate #NM when XCR0[i] = IA32_XFD[i] = 1; instead, it operates as if XINUSE[i] = 0 (and the state component was in its initial state): it saves bit i of XSTATE_BV field of the XSAVE header as 0; in addition, XSAVE saves the initial configuration of the state component (the other instructions do not save state component i). Alternatively, KVM could always do XRSTOR with XFD=0, e.g. by using a constant XFD based on the set of enabled features when XSAVEing for a struct fpu_guest. However, having XSTATE_BV[i]=1 for XFD-disabled features can only happen in the above interrupt case, or in similar scenarios involving preemption on preemptible kernels, because fpu_swap_kvm_fpstate()'s call to save_fpregs_to_fpstate() saves the outgoing FPU state with the current XFD; and that is (on all but the first WRMSR to XFD) the guest XFD. Therefore, XFD can only go out of sync with XSTATE_BV in the above interrupt case, or in similar scenarios involving preemption on preemptible kernels, and it we can consider it (de facto) part of KVM ABI that KVM_GET_XSAVE returns XSTATE_BV[i]=0 for XFD-disabled features. Reported-by: Paolo Bonzini <pbonzini@redhat.com> Cc: stable@vger.kernel.org Fixes: 820a6ee ("kvm: x86: Add emulation for IA32_XFD", 2022-01-14) Signed-off-by: Sean Christopherson <seanjc@google.com> [Move clearing of XSTATE_BV from fpu_copy_uabi_to_guest_fpstate to kvm_vcpu_ioctl_x86_set_xsave. - Paolo] Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d6bb046 commit f577508

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

arch/x86/kernel/fpu/core.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,29 @@ EXPORT_SYMBOL_GPL(fpu_enable_guest_xfd_features);
294294
#ifdef CONFIG_X86_64
295295
void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd)
296296
{
297+
struct fpstate *fpstate = guest_fpu->fpstate;
298+
297299
fpregs_lock();
298-
guest_fpu->fpstate->xfd = xfd;
299-
if (guest_fpu->fpstate->in_use)
300-
xfd_update_state(guest_fpu->fpstate);
300+
301+
/*
302+
* KVM's guest ABI is that setting XFD[i]=1 *can* immediately revert the
303+
* save state to its initial configuration. Likewise, KVM_GET_XSAVE does
304+
* the same as XSAVE and returns XSTATE_BV[i]=0 whenever XFD[i]=1.
305+
*
306+
* If the guest's FPU state is in hardware, just update XFD: the XSAVE
307+
* in fpu_swap_kvm_fpstate will clear XSTATE_BV[i] whenever XFD[i]=1.
308+
*
309+
* If however the guest's FPU state is NOT resident in hardware, clear
310+
* disabled components in XSTATE_BV now, or a subsequent XRSTOR will
311+
* attempt to load disabled components and generate #NM _in the host_.
312+
*/
313+
if (xfd && test_thread_flag(TIF_NEED_FPU_LOAD))
314+
fpstate->regs.xsave.header.xfeatures &= ~xfd;
315+
316+
fpstate->xfd = xfd;
317+
if (fpstate->in_use)
318+
xfd_update_state(fpstate);
319+
301320
fpregs_unlock();
302321
}
303322
EXPORT_SYMBOL_GPL(fpu_update_guest_xfd);
@@ -405,6 +424,13 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
405424
if (ustate->xsave.header.xfeatures & ~xcr0)
406425
return -EINVAL;
407426

427+
/*
428+
* Disabled features must be in their initial state, otherwise XRSTOR
429+
* causes an exception.
430+
*/
431+
if (WARN_ON_ONCE(ustate->xsave.header.xfeatures & kstate->xfd))
432+
return -EINVAL;
433+
408434
/*
409435
* Nullify @vpkru to preserve its current value if PKRU's bit isn't set
410436
* in the header. KVM's odd ABI is to leave PKRU untouched in this

arch/x86/kvm/x86.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5625,9 +5625,18 @@ static int kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
56255625
static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
56265626
struct kvm_xsave *guest_xsave)
56275627
{
5628+
union fpregs_state *xstate = (union fpregs_state *)guest_xsave->region;
5629+
56285630
if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
56295631
return vcpu->kvm->arch.has_protected_state ? -EINVAL : 0;
56305632

5633+
/*
5634+
* For backwards compatibility, do not expect disabled features to be in
5635+
* their initial state. XSTATE_BV[i] must still be cleared whenever
5636+
* XFD[i]=1, or XRSTOR would cause a #NM.
5637+
*/
5638+
xstate->xsave.header.xfeatures &= ~vcpu->arch.guest_fpu.fpstate->xfd;
5639+
56315640
return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu,
56325641
guest_xsave->region,
56335642
kvm_caps.supported_xcr0,

0 commit comments

Comments
 (0)