diff mbox

[v3,5/7] KVM: x86: VMX: Intercept #GP to support access to VMware backdoor ports

Message ID 1520853173-7709-6-git-send-email-liran.alon@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Liran Alon March 12, 2018, 11:12 a.m. UTC
If KVM enable_vmware_backdoor module parameter is set,
the commit change VMX to now intercept #GP instead of being directly
deliviered from CPU to guest.

It is done to support access to VMware backdoor I/O ports
even if TSS I/O permission denies it.
In that case:
1. A #GP will be raised and intercepted.
2. #GP intercept handler will simulate I/O port access instruction.
3. I/O port access instruction simulation will allow access to VMware
backdoor ports specifically even if TSS I/O permission bitmap denies it.

Note that the above change introduce slight performance hit as now #GPs
are not deliviered directly from CPU to guest but instead
cause #VMExit and instruction emulation.
However, this behavior is introduced only when enable_vmware_backdoor
KVM module parameter is set.

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>
Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 arch/x86/kvm/vmx.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

Comments

Radim Krčmář March 16, 2018, 3:51 p.m. UTC | #1
2018-03-12 13:12+0200, Liran Alon:
> If KVM enable_vmware_backdoor module parameter is set,
> the commit change VMX to now intercept #GP instead of being directly
> deliviered from CPU to guest.
> 
> It is done to support access to VMware backdoor I/O ports
> even if TSS I/O permission denies it.
> In that case:
> 1. A #GP will be raised and intercepted.
> 2. #GP intercept handler will simulate I/O port access instruction.
> 3. I/O port access instruction simulation will allow access to VMware
> backdoor ports specifically even if TSS I/O permission bitmap denies it.
> 
> Note that the above change introduce slight performance hit as now #GPs
> are not deliviered directly from CPU to guest but instead
> cause #VMExit and instruction emulation.
> However, this behavior is introduced only when enable_vmware_backdoor
> KVM module parameter is set.
> 
> 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>
> Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> ---
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> @@ -6141,6 +6154,17 @@ static int handle_exception(struct kvm_vcpu *vcpu)
>  	if (intr_info & INTR_INFO_DELIVER_CODE_MASK)
>  		error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
>  
> +	if (!vmx->rmode.vm86_active && is_gp_fault(intr_info)) {

Do we have some guarantees that the backdoor ports are never going to be
used while vmx->rmode.vm86_active?

Thanks.

> +		WARN_ON_ONCE(!enable_vmware_backdoor);
> +		er = emulate_instruction(vcpu,
> +			EMULTYPE_VMWARE | EMULTYPE_NO_UD_ON_FAIL);
> +		if (er == EMULATE_USER_EXIT)
> +			return 0;
> +		else if (er != EMULATE_DONE)
> +			kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
> +		return 1;
> +	}
> +
>  	/*
>  	 * The #PF with PFEC.RSVD = 1 indicates the guest is accessing
>  	 * MMIO, it is better to report an internal error.
> -- 
> 1.9.1
>
Paolo Bonzini March 16, 2018, 4:28 p.m. UTC | #2
On 16/03/2018 16:51, Radim Krčmář wrote:
>> +	if (!vmx->rmode.vm86_active && is_gp_fault(intr_info)) {
> Do we have some guarantees that the backdoor ports are never going to be
> used while vmx->rmode.vm86_active?

While vmx->rmode.vm86_active, handle_rmode_exception simply runs the
emulator whenever it sees a #GP, so that works too (except for not
having EMULTYPE_NO_UD_ON_FAIL).

Paolo

> Thanks.
> 
>> +		WARN_ON_ONCE(!enable_vmware_backdoor);
>> +		er = emulate_instruction(vcpu,
>> +			EMULTYPE_VMWARE | EMULTYPE_NO_UD_ON_FAIL);
>> +		if (er == EMULATE_USER_EXIT)
>> +			return 0;
>> +		else if (er != EMULATE_DONE)
>> +			kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
>> +		return 1;
>> +	}
diff mbox

Patch

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 051dab74e4e9..d6ad1feda9f9 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1032,6 +1032,11 @@  static inline bool is_invalid_opcode(u32 intr_info)
 	return is_exception_n(intr_info, UD_VECTOR);
 }
 
+static inline bool is_gp_fault(u32 intr_info)
+{
+	return is_exception_n(intr_info, GP_VECTOR);
+}
+
 static inline bool is_external_interrupt(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
@@ -1858,6 +1863,14 @@  static void update_exception_bitmap(struct kvm_vcpu *vcpu)
 
 	eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) |
 	     (1u << DB_VECTOR) | (1u << AC_VECTOR);
+	/*
+	 * Guest access to VMware backdoor ports could legitimately
+	 * trigger #GP because of TSS I/O permission bitmap.
+	 * We intercept those #GP and allow access to them anyway
+	 * as VMware does.
+	 */
+	if (enable_vmware_backdoor)
+		eb |= (1u << GP_VECTOR);
 	if ((vcpu->guest_debug &
 	     (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) ==
 	    (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP))
@@ -6141,6 +6154,17 @@  static int handle_exception(struct kvm_vcpu *vcpu)
 	if (intr_info & INTR_INFO_DELIVER_CODE_MASK)
 		error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
 
+	if (!vmx->rmode.vm86_active && is_gp_fault(intr_info)) {
+		WARN_ON_ONCE(!enable_vmware_backdoor);
+		er = emulate_instruction(vcpu,
+			EMULTYPE_VMWARE | EMULTYPE_NO_UD_ON_FAIL);
+		if (er == EMULATE_USER_EXIT)
+			return 0;
+		else if (er != EMULATE_DONE)
+			kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
+		return 1;
+	}
+
 	/*
 	 * The #PF with PFEC.RSVD = 1 indicates the guest is accessing
 	 * MMIO, it is better to report an internal error.