]> git.ipfire.org Git - people/ms/linux.git/commitdiff
KVM: x86: Inject #UD on emulated XSETBV if XSAVES isn't enabled
authorSean Christopherson <seanjc@google.com>
Wed, 24 Aug 2022 03:30:57 +0000 (03:30 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 22 Sep 2022 21:04:20 +0000 (17:04 -0400)
Inject #UD when emulating XSETBV if CR4.OSXSAVE is not set.  This also
covers the "XSAVE not supported" check, as setting CR4.OSXSAVE=1 #GPs if
XSAVE is not supported (and userspace gets to keep the pieces if it
forces incoherent vCPU state).

Add a comment to kvm_emulate_xsetbv() to call out that the CPU checks
CR4.OSXSAVE before checking for intercepts.  AMD'S APM implies that #UD
has priority (says that intercepts are checked before #GP exceptions),
while Intel's SDM says nothing about interception priority.  However,
testing on hardware shows that both AMD and Intel CPUs prioritize the #UD
over interception.

Fixes: 02d4160fbd76 ("x86: KVM: add xsetbv to the emulator")
Cc: stable@vger.kernel.org
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20220824033057.3576315-4-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/emulate.c
arch/x86/kvm/x86.c

index d5ec3a2ed5a44f32e01a50684ae2dde6b658516d..aacb28c83e437d83712ed029c47f59ffc7c6cde7 100644 (file)
@@ -4132,6 +4132,9 @@ static int em_xsetbv(struct x86_emulate_ctxt *ctxt)
 {
        u32 eax, ecx, edx;
 
+       if (!(ctxt->ops->get_cr(ctxt, 4) & X86_CR4_OSXSAVE))
+               return emulate_ud(ctxt);
+
        eax = reg_read(ctxt, VCPU_REGS_RAX);
        edx = reg_read(ctxt, VCPU_REGS_RDX);
        ecx = reg_read(ctxt, VCPU_REGS_RCX);
index c95cf18a796c8f2a2ac8e59962edb624e9019d5e..b0c47b41c264982c993a098e738fa2ef8f9e6add 100644 (file)
@@ -1065,6 +1065,7 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
 
 int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu)
 {
+       /* Note, #UD due to CR4.OSXSAVE=0 has priority over the intercept. */
        if (static_call(kvm_x86_get_cpl)(vcpu) != 0 ||
            __kvm_set_xcr(vcpu, kvm_rcx_read(vcpu), kvm_read_edx_eax(vcpu))) {
                kvm_inject_gp(vcpu, 0);