| From 8530a79c5a9f4e29e6ffb35ec1a79d81f4968ec8 Mon Sep 17 00:00:00 2001 |
| From: Jan Dakinevich <jan.dakinevich@virtuozzo.com> |
| Date: Tue, 27 Aug 2019 13:07:09 +0000 |
| Subject: KVM: x86: always stop emulation on page fault |
| |
| From: Jan Dakinevich <jan.dakinevich@virtuozzo.com> |
| |
| commit 8530a79c5a9f4e29e6ffb35ec1a79d81f4968ec8 upstream. |
| |
| inject_emulated_exception() returns true if and only if nested page |
| fault happens. However, page fault can come from guest page tables |
| walk, either nested or not nested. In both cases we should stop an |
| attempt to read under RIP and give guest to step over its own page |
| fault handler. |
| |
| This is also visible when an emulated instruction causes a #GP fault |
| and the VMware backdoor is enabled. To handle the VMware backdoor, |
| KVM intercepts #GP faults; with only the next patch applied, |
| x86_emulate_instruction() injects a #GP but returns EMULATE_FAIL |
| instead of EMULATE_DONE. EMULATE_FAIL causes handle_exception_nmi() |
| (or gp_interception() for SVM) to re-inject the original #GP because it |
| thinks emulation failed due to a non-VMware opcode. This patch prevents |
| the issue as x86_emulate_instruction() will return EMULATE_DONE after |
| injecting the #GP. |
| |
| Fixes: 6ea6e84309ca ("KVM: x86: inject exceptions produced by x86_decode_insn") |
| Cc: stable@vger.kernel.org |
| Cc: Denis Lunev <den@virtuozzo.com> |
| Cc: Roman Kagan <rkagan@virtuozzo.com> |
| Cc: Denis Plotnikov <dplotnikov@virtuozzo.com> |
| Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/x86.c | 4 +++- |
| 1 file changed, 3 insertions(+), 1 deletion(-) |
| |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -5764,8 +5764,10 @@ int x86_emulate_instruction(struct kvm_v |
| if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, |
| emulation_type)) |
| return EMULATE_DONE; |
| - if (ctxt->have_exception && inject_emulated_exception(vcpu)) |
| + if (ctxt->have_exception) { |
| + inject_emulated_exception(vcpu); |
| return EMULATE_DONE; |
| + } |
| if (emulation_type & EMULTYPE_SKIP) |
| return EMULATE_FAIL; |
| return handle_emulation_failure(vcpu); |