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)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 13 May 2020 16:14:59 +0000 (12:14 -0400)
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>
arch/x86/kvm/emulate.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c

index bddaba9c68dd2c945209d5d4774f4bed3d3a441c..de5476f8683e919f9d0c909c2e8ce048da06fe85 100644 (file)
@@ -5798,6 +5798,8 @@ writeback:
        }
 
        ctxt->eip = ctxt->_eip;
+       if (ctxt->mode != X86EMUL_MODE_PROT64)
+               ctxt->eip = (u32)ctxt->_eip;
 
 done:
        if (rc == X86EMUL_PROPAGATE_FAULT) {
index 45c6e4b87eee615e48f684228309bc971aea6c42..83175933c0a1c464c387bfcbeebcce7b18e36eab 100644 (file)
@@ -319,9 +319,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 e1f5fc919fd92803678c4a19351285312c1aa51f..f519fc7a22a36d60527b8c6449c1539ac4a5d7c0 100644 (file)
@@ -1555,7 +1555,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
@@ -1567,8 +1567,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))