KVM: x86: Protect exit_reason from being used in Spectre-v1/L1TF attacks
authorMarios Pomonis <pomonis@google.com>
Wed, 11 Dec 2019 20:47:51 +0000 (12:47 -0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 27 Jan 2020 18:59:42 +0000 (19:59 +0100)
This fixes a Spectre-v1/L1TF vulnerability in vmx_handle_exit().
While exit_reason is set by the hardware and therefore should not be
attacker-influenced, an unknown exit_reason could potentially be used to
perform such an attack.

Fixes: 55d2375e58a6 ("KVM: nVMX: Move nested code to dedicated files")

Signed-off-by: Marios Pomonis <pomonis@google.com>
Signed-off-by: Nick Finco <nifi@google.com>
Suggested-by: Sean Christopherson <sean.j.christopherson@intel.com>
Reviewed-by: Andrew Honig <ahonig@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/vmx.c

index 5415cd4..62fb639 100644 (file)
@@ -5913,34 +5913,41 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu,
        if (exit_fastpath == EXIT_FASTPATH_SKIP_EMUL_INS) {
                kvm_skip_emulated_instruction(vcpu);
                return 1;
-       } else if (exit_reason < kvm_vmx_max_exit_handlers
-           && kvm_vmx_exit_handlers[exit_reason]) {
+       }
+
+       if (exit_reason >= kvm_vmx_max_exit_handlers)
+               goto unexpected_vmexit;
 #ifdef CONFIG_RETPOLINE
-               if (exit_reason == EXIT_REASON_MSR_WRITE)
-                       return kvm_emulate_wrmsr(vcpu);
-               else if (exit_reason == EXIT_REASON_PREEMPTION_TIMER)
-                       return handle_preemption_timer(vcpu);
-               else if (exit_reason == EXIT_REASON_INTERRUPT_WINDOW)
-                       return handle_interrupt_window(vcpu);
-               else if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
-                       return handle_external_interrupt(vcpu);
-               else if (exit_reason == EXIT_REASON_HLT)
-                       return kvm_emulate_halt(vcpu);
-               else if (exit_reason == EXIT_REASON_EPT_MISCONFIG)
-                       return handle_ept_misconfig(vcpu);
+       if (exit_reason == EXIT_REASON_MSR_WRITE)
+               return kvm_emulate_wrmsr(vcpu);
+       else if (exit_reason == EXIT_REASON_PREEMPTION_TIMER)
+               return handle_preemption_timer(vcpu);
+       else if (exit_reason == EXIT_REASON_INTERRUPT_WINDOW)
+               return handle_interrupt_window(vcpu);
+       else if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
+               return handle_external_interrupt(vcpu);
+       else if (exit_reason == EXIT_REASON_HLT)
+               return kvm_emulate_halt(vcpu);
+       else if (exit_reason == EXIT_REASON_EPT_MISCONFIG)
+               return handle_ept_misconfig(vcpu);
 #endif
-               return kvm_vmx_exit_handlers[exit_reason](vcpu);
-       } else {
-               vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n",
-                               exit_reason);
-               dump_vmcs();
-               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-               vcpu->run->internal.suberror =
+
+       exit_reason = array_index_nospec(exit_reason,
+                                        kvm_vmx_max_exit_handlers);
+       if (!kvm_vmx_exit_handlers[exit_reason])
+               goto unexpected_vmexit;
+
+       return kvm_vmx_exit_handlers[exit_reason](vcpu);
+
+unexpected_vmexit:
+       vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n", exit_reason);
+       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;
-       }
+       vcpu->run->internal.ndata = 1;
+       vcpu->run->internal.data[0] = exit_reason;
+       return 0;
 }
 
 /*