]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: x86: handle wrap around 32-bit address space
authorPaolo Bonzini <pbonzini@redhat.com>
Mon, 27 Apr 2020 15:55:59 +0000 (11:55 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 1 Oct 2020 11:18:00 +0000 (13:18 +0200)
[ Upstream commit fede8076aab4c2280c673492f8f7a2e87712e8b4 ]

KVM is not handling the case where EIP wraps around the 32-bit address
space (that is, outside long mode).  This is needed both in vmx.c
and in emulate.c.  SVM with NRIPS is okay, but it can still print
an error to dmesg due to integer overflow.

Reported-by: Nick Peterson <everdox@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/x86/kvm/emulate.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/vmx.c

index 128d3ad46e9651cbd723c2c6e95def9cd6e9122c..cc7823e7ef96c29043b9153990f47a0eef10b031 100644 (file)
@@ -5836,6 +5836,8 @@ writeback:
        }
 
        ctxt->eip = ctxt->_eip;
+       if (ctxt->mode != X86EMUL_MODE_PROT64)
+               ctxt->eip = (u32)ctxt->_eip;
 
 done:
        if (rc == X86EMUL_PROPAGATE_FAULT) {
index 3243a80ea32c07eedf7d97f97e43a8b39de9d987..802b5f9ab7446f776701b235590d2f71b222185c 100644 (file)
@@ -787,9 +787,6 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
                if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))
                        return 0;
        } else {
-               if (svm->next_rip - kvm_rip_read(vcpu) > MAX_INST_SIZE)
-                       pr_err("%s: ip 0x%lx next 0x%llx\n",
-                              __func__, kvm_rip_read(vcpu), svm->next_rip);
                kvm_rip_write(vcpu, svm->next_rip);
        }
        svm_set_interrupt_shadow(vcpu, 0);
index d4a364db27ee8c78713589322033b2474f4da63e..2a1ed3aae100e7a03a8cfd86ea7c35f30562d123 100644 (file)
@@ -1541,7 +1541,7 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data)
 
 static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
-       unsigned long rip;
+       unsigned long rip, orig_rip;
 
        /*
         * Using VMCS.VM_EXIT_INSTRUCTION_LEN on EPT misconfig depends on
@@ -1553,8 +1553,17 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
         */
        if (!static_cpu_has(X86_FEATURE_HYPERVISOR) ||
            to_vmx(vcpu)->exit_reason != EXIT_REASON_EPT_MISCONFIG) {
-               rip = kvm_rip_read(vcpu);
-               rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+               orig_rip = kvm_rip_read(vcpu);
+               rip = orig_rip + vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+#ifdef CONFIG_X86_64
+               /*
+                * We need to mask out the high 32 bits of RIP if not in 64-bit
+                * mode, but just finding out that we are in 64-bit mode is
+                * quite expensive.  Only do it if there was a carry.
+                */
+               if (unlikely(((rip ^ orig_rip) >> 31) == 3) && !is_64_bit_mode(vcpu))
+                       rip = (u32)rip;
+#endif
                kvm_rip_write(vcpu, rip);
        } else {
                if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))