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>
Wed, 26 Oct 2022 10:34:33 +0000 (12:34 +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 96e589edf9601cf78bf236a1da599dbe9e860751..91b182fafb43d2420ea10a0dc43a304fd8256ccf 100644 (file)
@@ -3826,7 +3826,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 e5584e974c7748a40a555c1c63947ea0d49668e6..ba457167ae8a24f67d15fa6a6f0e3de343577460 100644 (file)
@@ -1676,7 +1676,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;
        }