]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: VMX: Drop bits 31:16 when shoving exception error code into VMCS
authorSean Christopherson <seanjc@google.com>
Tue, 30 Aug 2022 23:15:49 +0000 (23:15 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Oct 2022 07:56:59 +0000 (09:56 +0200)
commit eba9799b5a6efe2993cf92529608e4aa8163d73b upstream.

Deliberately truncate the exception error code when shoving it into the
VMCS (VM-Entry field for vmcs01 and vmcs02, VM-Exit field for vmcs12).
Intel CPUs are incapable of handling 32-bit error codes and will never
generate an error code with bits 31:16, but userspace can provide an
arbitrary error code via KVM_SET_VCPU_EVENTS.  Failure to drop the bits
on exception injection results in failed VM-Entry, as VMX disallows
setting bits 31:16.  Setting the bits on VM-Exit would at best confuse
L1, and at worse induce a nested VM-Entry failure, e.g. if L1 decided to
reinject the exception back into L2.

Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Reviewed-by: Jim Mattson <jmattson@google.com>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Link: https://lore.kernel.org/r/20220830231614.3580124-3-seanjc@google.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmx.c

index 4fbbd97e3bf9f5ec0ea13af946aaa37e7a0a846e..b98b8cede264265a4201a18463ddfbdd264aeb49 100644 (file)
@@ -3839,7 +3839,16 @@ static void nested_vmx_inject_exception_vmexit(struct kvm_vcpu *vcpu,
        u32 intr_info = nr | INTR_INFO_VALID_MASK;
 
        if (vcpu->arch.exception.has_error_code) {
-               vmcs12->vm_exit_intr_error_code = vcpu->arch.exception.error_code;
+               /*
+                * Intel CPUs do not generate error codes with bits 31:16 set,
+                * and more importantly VMX disallows setting bits 31:16 in the
+                * injected error code for VM-Entry.  Drop the bits to mimic
+                * hardware and avoid inducing failure on nested VM-Entry if L1
+                * chooses to inject the exception back to L2.  AMD CPUs _do_
+                * generate "full" 32-bit error codes, so KVM allows userspace
+                * to inject exception error codes with bits 31:16 set.
+                */
+               vmcs12->vm_exit_intr_error_code = (u16)vcpu->arch.exception.error_code;
                intr_info |= INTR_INFO_DELIVER_CODE_MASK;
        }
 
index b09a50e0af29dfd8b410c3024431ad49acb76b07..98526e708f32781df682cbad1f391751d8399d27 100644 (file)
@@ -1687,7 +1687,17 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu)
        kvm_deliver_exception_payload(vcpu);
 
        if (has_error_code) {
-               vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+               /*
+                * Despite the error code being architecturally defined as 32
+                * bits, and the VMCS field being 32 bits, Intel CPUs and thus
+                * VMX don't actually supporting setting bits 31:16.  Hardware
+                * will (should) never provide a bogus error code, but AMD CPUs
+                * do generate error codes with bits 31:16 set, and so KVM's
+                * ABI lets userspace shove in arbitrary 32-bit values.  Drop
+                * the upper bits to avoid VM-Fail, losing information that
+                * does't really exist is preferable to killing the VM.
+                */
+               vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, (u16)error_code);
                intr_info |= INTR_INFO_DELIVER_CODE_MASK;
        }