[RHEL7,COMMIT] ms/KVM: x86: always stop emulation on page fault

Submitted by Konstantin Khorenko on Oct. 3, 2019, 12:03 p.m.

Details

Message ID 201910031203.x93C3lTM010700@finist-ce7.sw.ru
State New
Series "ms/KVM: x86: always stop emulation on page fault"
Headers show

Commit Message

Konstantin Khorenko Oct. 3, 2019, 12:03 p.m.
The commit is pushed to "branch-rh7-3.10.0-957.27.2.vz7.107.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.27.2.vz7.107.13
------>
commit 3c5c13d81c09d4309897418722bef03423e6436a
Author: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
Date:   Thu Oct 3 15:03:47 2019 +0300

    ms/KVM: x86: always stop emulation on page fault
    
    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>
    
    https://jira.sw.ru/browse/PSBM-68018
    (cherry-picked from 8530a79c5a9f4e29e6ffb35ec1a79d81f4968ec8)
    
    =====================
    Patchset description:
    
    fix emulation error on Windows bootup
    
    This series intended to fix (again) a bug that was a subject of the
    following change:
    
      6ea6e84 ("KVM: x86: inject exceptions produced by x86_decode_insn")
    
    Suddenly, that fix had a couple mistakes. First, ctxt->have_exception was
    not set if fault happened during instruction decoding. Second, returning
    value of inject_emulated_instruction was used to make the decision to
    reenter guest, but this could happen iff on nested page fault, that is not
    the scope where this bug could occur.
    
    https://lkml.org/lkml/2019/8/29/152
    
    Jan Dakinevich (2):
      KVM: x86: always stop emulation on page fault
      KVM: x86: set ctxt->have_exception in x86_decode_insn()
    
    Paolo Bonzini (1):
      KVM: x86: inject exceptions produced by x86_decode_insn
---
 arch/x86/kvm/x86.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 94cfe99bc4c9..8ed5b23ff055 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5759,8 +5759,10 @@  int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 			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, emulation_type);