Joerg Roedel 4072fc
From: Oliver Upton <oupton@google.com>
Joerg Roedel 4072fc
Date: Tue, 4 Feb 2020 15:26:31 -0800
Joerg Roedel 4072fc
Subject: KVM: nVMX: Check IO instruction VM-exit conditions
Joerg Roedel 4072fc
Git-commit: 35a571346a94fb93b5b3b6a599675ef3384bc75c
Joerg Roedel 4072fc
References: CVE-2020-2732 bsc#1163971
Joerg Roedel 4072fc
Patch-mainline: v5.6-rc4
Joerg Roedel 4072fc
Joerg Roedel 4072fc
Consult the 'unconditional IO exiting' and 'use IO bitmaps' VM-execution
Joerg Roedel 4072fc
controls when checking instruction interception. If the 'use IO bitmaps'
Joerg Roedel 4072fc
VM-execution control is 1, check the instruction access against the IO
Joerg Roedel 4072fc
bitmaps to determine if the instruction causes a VM-exit.
Joerg Roedel 4072fc
Joerg Roedel 4072fc
Signed-off-by: Oliver Upton <oupton@google.com>
Joerg Roedel 4072fc
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Joerg Roedel 4072fc
Acked-by: Joerg Roedel <jroedel@suse.de>
Joerg Roedel 4072fc
---
Joerg Roedel 4072fc
 arch/x86/kvm/vmx/nested.c |  2 +-
Joerg Roedel 4072fc
 arch/x86/kvm/vmx/vmx.c    | 57 ++++++++++++++++++++++++++++++++++++++++++-----
Joerg Roedel 4072fc
 2 files changed, 52 insertions(+), 7 deletions(-)
Joerg Roedel 4072fc
Joerg Roedel 4072fc
--- a/arch/x86/kvm/vmx.c
Joerg Roedel 4072fc
+++ b/arch/x86/kvm/vmx.c
Joerg Roedel 4072fc
@@ -8570,7 +8570,7 @@ static bool nested_vmx_exit_handled_io(s
Joerg Roedel 4072fc
 				       struct vmcs12 *vmcs12)
Joerg Roedel 4072fc
 {
Joerg Roedel 4072fc
 	unsigned long exit_qualification;
Joerg Roedel 4072fc
-	unsigned int port;
Joerg Roedel 4072fc
+	unsigned short port;
Joerg Roedel 4072fc
 	int size;
Joerg Roedel 4072fc
 
Joerg Roedel 4072fc
 	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
Joerg Roedel 4072fc
@@ -12386,10 +12386,55 @@ static void nested_vmx_entry_failure(str
Joerg Roedel 4072fc
 		to_vmx(vcpu)->nested.sync_shadow_vmcs = true;
Joerg Roedel 4072fc
 }
Joerg Roedel 4072fc
 
Joerg Roedel 4072fc
+static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
Joerg Roedel 4072fc
+				  struct x86_instruction_info *info)
Joerg Roedel 4072fc
+{
Joerg Roedel 4072fc
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
Joerg Roedel 4072fc
+	unsigned short port;
Joerg Roedel 4072fc
+	bool intercept;
Joerg Roedel 4072fc
+	int size;
Joerg Roedel 4072fc
+
Joerg Roedel 4072fc
+	if (info->intercept == x86_intercept_in ||
Joerg Roedel 4072fc
+	    info->intercept == x86_intercept_ins) {
Joerg Roedel 4072fc
+		port = info->src_val;
Joerg Roedel 4072fc
+		size = info->dst_bytes;
Joerg Roedel 4072fc
+	} else {
Joerg Roedel 4072fc
+		port = info->dst_val;
Joerg Roedel 4072fc
+		size = info->src_bytes;
Joerg Roedel 4072fc
+	}
Joerg Roedel 4072fc
+
Joerg Roedel 4072fc
+	/*
Joerg Roedel 4072fc
+	 * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
Joerg Roedel 4072fc
+	 * VM-exits depend on the 'unconditional IO exiting' VM-execution
Joerg Roedel 4072fc
+	 * control.
Joerg Roedel 4072fc
+	 *
Joerg Roedel 4072fc
+	 * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
Joerg Roedel 4072fc
+	 */
Joerg Roedel 4072fc
+	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
Joerg Roedel 4072fc
+		intercept = nested_cpu_has(vmcs12,
Joerg Roedel 4072fc
+					   CPU_BASED_UNCOND_IO_EXITING);
Joerg Roedel 4072fc
+	else
Joerg Roedel 4072fc
+		intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
Joerg Roedel 4072fc
+
Joerg Roedel 4072fc
+	return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
Joerg Roedel 4072fc
+}
Joerg Roedel 4072fc
+
Joerg Roedel 4072fc
 static int vmx_check_intercept(struct kvm_vcpu *vcpu,
Joerg Roedel 4072fc
 			       struct x86_instruction_info *info,
Joerg Roedel 4072fc
 			       enum x86_intercept_stage stage)
Joerg Roedel 4072fc
 {
Joerg Roedel 4072fc
+	switch (info->intercept) {
Joerg Roedel 4072fc
+	case x86_intercept_in:
Joerg Roedel 4072fc
+	case x86_intercept_ins:
Joerg Roedel 4072fc
+	case x86_intercept_out:
Joerg Roedel 4072fc
+	case x86_intercept_outs:
Joerg Roedel 4072fc
+		return vmx_check_intercept_io(vcpu, info);
Joerg Roedel 4072fc
+
Joerg Roedel 4072fc
+	/* TODO: check more intercepts... */
Joerg Roedel 4072fc
+	default:
Joerg Roedel 4072fc
+		break;
Joerg Roedel 4072fc
+	}
Joerg Roedel 4072fc
+
Joerg Roedel 4072fc
 	return X86EMUL_UNHANDLEABLE;
Joerg Roedel 4072fc
 }
Joerg Roedel 4072fc