[RHEL7,COMMIT] ms/KVM: x86: Emulate only IN/OUT instructions when accessing VMware backdoor

Submitted by Konstantin Khorenko on May 8, 2018, 9:26 a.m.

Details

Message ID 201805080926.w489QOAM001453@finist_ce7.work
State New
Series "ms/KVM: x86: Emulate only IN/OUT instructions when accessing VMware backdoor"
Headers show

Commit Message

Konstantin Khorenko May 8, 2018, 9:26 a.m.
The commit is pushed to "branch-rh7-3.10.0-693.21.1.vz7.47.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.21.1.vz7.47.5
------>
commit 0dbd0baa2b9c5c8499d0a659930fa03d3e14a7bd
Author: Liran Alon <liran.alon@oracle.com>
Date:   Tue May 8 12:26:24 2018 +0300

    ms/KVM: x86: Emulate only IN/OUT instructions when accessing VMware backdoor
    
    Access to VMware backdoor ports is done by one of the IN/OUT/INS/OUTS
    instructions. These ports must be allowed access even if TSS I/O
    permission bitmap don't allow it.
    
    To handle this, VMX/SVM will be changed in future commits
    to intercept #GP which was raised by such access and
    handle it by calling x86 emulator to emulate instruction.
    If it was one of these instructions, the x86 emulator already handles
    it correctly (Since commit "KVM: x86: Always allow access to VMware
    backdoor I/O ports") by not checking these ports against TSS I/O
    permission bitmap.
    
    One may wonder why checking for specific instructions is necessary
    as we can just forward all #GPs to the x86 emulator.
    There are multiple reasons for doing so:
    
    1. We don't want the x86 emulator to be reached easily
    by guest by just executing an instruction that raises #GP as that
    exposes the x86 emulator as a bigger attack surface.
    
    2. The x86 emulator is incomplete and therefore certain instructions
    that can cause #GP cannot be emulated. Such an example is "INT x"
    (opcode 0xcd) which reaches emulate_int() which can only emulate
    the instruction if vCPU is in real-mode.
    
    Signed-off-by: Liran Alon <liran.alon@oracle.com>
    Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
    Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
    Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
    
    (cherry picked from commit 04789b6664a60474aeb8b07a9a94d923a217690e)
    Signed-off-by: Jan Dakinevich <jan.dakinevich@virtuozzo.com>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/x86.c              | 28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

Patch hide | download patch | download mbox

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 4aadb8916e9a..d8966018ae60 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1075,6 +1075,7 @@  enum emulation_result {
 #define EMULTYPE_RETRY		    (1 << 3)
 #define EMULTYPE_NO_REEXECUTE	    (1 << 4)
 #define EMULTYPE_NO_UD_ON_FAIL	    (1 << 5)
+#define EMULTYPE_VMWARE		    (1 << 6)
 int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
 			    int emulation_type, void *insn, int insn_len);
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bcaf39f0e918..eb1bb7e89f34 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5486,6 +5486,30 @@  static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
 	return false;
 }
 
+static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt)
+{
+	if (ctxt->opcode_len != 1)
+		return false;
+
+	switch (ctxt->b) {
+	case 0xe4:	/* IN */
+	case 0xe5:
+	case 0xec:
+	case 0xed:
+	case 0xe6:	/* OUT */
+	case 0xe7:
+	case 0xee:
+	case 0xef:
+	case 0x6c:	/* INS */
+	case 0x6d:
+	case 0x6e:	/* OUTS */
+	case 0x6f:
+		return true;
+	}
+
+	return false;
+}
+
 int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 			    unsigned long cr2,
 			    int emulation_type,
@@ -5540,6 +5564,10 @@  int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 		}
 	}
 
+	if ((emulation_type & EMULTYPE_VMWARE) &&
+	    !is_vmware_backdoor_opcode(ctxt))
+		return EMULATE_FAIL;
+
 	if (emulation_type & EMULTYPE_SKIP) {
 		kvm_rip_write(vcpu, ctxt->_eip);
 		if (ctxt->eflags & X86_EFLAGS_RF)