KVM: x86: Return to userspace with internal error on unexpected exit reason
authorLiran Alon <liran.alon@oracle.com>
Mon, 26 Aug 2019 10:16:43 +0000 (13:16 +0300)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 11 Sep 2019 13:42:45 +0000 (15:42 +0200)
Receiving an unexpected exit reason from hardware should be considered
as a severe bug in KVM. Therefore, instead of just injecting #UD to
guest and ignore it, exit to userspace on internal error so that
it could handle it properly (probably by terminating guest).

In addition, prefer to use vcpu_unimpl() instead of WARN_ONCE()
as handling unexpected exit reason should be a rare unexpected
event (that was expected to never happen) and we prefer to print
a message on it every time it occurs to guest.

Furthermore, dump VMCS/VMCB to dmesg to assist diagnosing such cases.

Reviewed-by: Mihai Carabas <mihai.carabas@oracle.com>
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/vmx.c
include/uapi/linux/kvm.h

index 890b1bffcf7ce68446237044e6f70fd92cf7f366..fdeaf8f44949cb866b13dc2a41673f072e4f3f8d 100644 (file)
@@ -4981,9 +4981,14 @@ static int handle_exit(struct kvm_vcpu *vcpu)
 
        if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
            || !svm_exit_handlers[exit_code]) {
-               WARN_ONCE(1, "svm: unexpected exit reason 0x%x\n", exit_code);
-               kvm_queue_exception(vcpu, UD_VECTOR);
-               return 1;
+               vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%x\n", exit_code);
+               dump_vmcb(vcpu);
+               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               vcpu->run->internal.suberror =
+                       KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON;
+               vcpu->run->internal.ndata = 1;
+               vcpu->run->internal.data[0] = exit_code;
+               return 0;
        }
 
        return svm_exit_handlers[exit_code](svm);
index 024cb9bf5ad34bcc0e62c76de9b922ae46f2d1a1..d95c2f3c027ce77b8d6ec30783b1ac9bee8103fb 100644 (file)
@@ -5870,8 +5870,13 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
        else {
                vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n",
                                exit_reason);
-               kvm_queue_exception(vcpu, UD_VECTOR);
-               return 1;
+               dump_vmcs();
+               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               vcpu->run->internal.suberror =
+                       KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON;
+               vcpu->run->internal.ndata = 1;
+               vcpu->run->internal.data[0] = exit_reason;
+               return 0;
        }
 }
 
index 5414b6588fbb64571ce502560235e229d658dea9..233efbb1c81ca153c64693814d8518756284e1d0 100644 (file)
@@ -243,6 +243,8 @@ struct kvm_hyperv_exit {
 #define KVM_INTERNAL_ERROR_SIMUL_EX    2
 /* Encounter unexpected vm-exit due to delivery event. */
 #define KVM_INTERNAL_ERROR_DELIVERY_EV 3
+/* Encounter unexpected vm-exit reason */
+#define KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON      4
 
 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
 struct kvm_run {