| From f958bd2314d117f8c29f4821401bc1925bc2e5ef Mon Sep 17 00:00:00 2001 |
| From: Sean Christopherson <sean.j.christopherson@intel.com> |
| Date: Mon, 9 Dec 2019 12:19:31 -0800 |
| Subject: KVM: x86: Fix potential put_fpu() w/o load_fpu() on MPX platform |
| |
| From: Sean Christopherson <sean.j.christopherson@intel.com> |
| |
| commit f958bd2314d117f8c29f4821401bc1925bc2e5ef upstream. |
| |
| Unlike most state managed by XSAVE, MPX is initialized to zero on INIT. |
| Because INITs are usually recognized in the context of a VCPU_RUN call, |
| kvm_vcpu_reset() puts the guest's FPU so that the FPU state is resident |
| in memory, zeros the MPX state, and reloads FPU state to hardware. But, |
| in the unlikely event that an INIT is recognized during |
| kvm_arch_vcpu_ioctl_get_mpstate() via kvm_apic_accept_events(), |
| kvm_vcpu_reset() will call kvm_put_guest_fpu() without a preceding |
| kvm_load_guest_fpu() and corrupt the guest's FPU state (and possibly |
| userspace's FPU state as well). |
| |
| Given that MPX is being removed from the kernel[*], fix the bug with the |
| simple-but-ugly approach of loading the guest's FPU during |
| KVM_GET_MP_STATE. |
| |
| [*] See commit f240652b6032b ("x86/mpx: Remove MPX APIs"). |
| |
| Fixes: f775b13eedee2 ("x86,kvm: move qemu/guest FPU switching out to vcpu_run") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/x86.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -8235,6 +8235,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(stru |
| struct kvm_mp_state *mp_state) |
| { |
| vcpu_load(vcpu); |
| + if (kvm_mpx_supported()) |
| + kvm_load_guest_fpu(vcpu); |
| |
| kvm_apic_accept_events(vcpu); |
| if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED && |
| @@ -8243,6 +8245,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(stru |
| else |
| mp_state->mp_state = vcpu->arch.mp_state; |
| |
| + if (kvm_mpx_supported()) |
| + kvm_put_guest_fpu(vcpu); |
| vcpu_put(vcpu); |
| return 0; |
| } |