diff mbox series

[Bionic,4/4] KVM: nVMX: Check IO instruction VM-exit conditions

Message ID 20200227185125.650784-9-cascardo@canonical.com
State New
Headers show
Series None | expand

Commit Message

Thadeu Lima de Souza Cascardo Feb. 27, 2020, 6:51 p.m. UTC
From: Oliver Upton <oupton@google.com>

CVE-2020-2732

commit 35a571346a94fb93b5b3b6a599675ef3384bc75c upstream.

Consult the 'unconditional IO exiting' and 'use IO bitmaps' VM-execution
controls when checking instruction interception. If the 'use IO bitmaps'
VM-execution control is 1, check the instruction access against the IO
bitmaps to determine if the instruction causes a VM-exit.

Signed-off-by: Oliver Upton <oupton@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
---
 arch/x86/kvm/vmx.c | 59 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 52 insertions(+), 7 deletions(-)

Comments

Khalid Elmously Feb. 28, 2020, 4 a.m. UTC | #1
This patch doesn't apply to Bionic

On 2020-02-27 15:51:22 , Thadeu Lima de Souza Cascardo wrote:
> From: Oliver Upton <oupton@google.com>
> 
> CVE-2020-2732
> 
> commit 35a571346a94fb93b5b3b6a599675ef3384bc75c upstream.
> 
> Consult the 'unconditional IO exiting' and 'use IO bitmaps' VM-execution
> controls when checking instruction interception. If the 'use IO bitmaps'
> VM-execution control is 1, check the instruction access against the IO
> bitmaps to determine if the instruction causes a VM-exit.
> 
> Signed-off-by: Oliver Upton <oupton@google.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
> ---
>  arch/x86/kvm/vmx.c | 59 ++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 52 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 6a2da0068ae2..3728ecea95e4 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -5004,7 +5004,7 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
>  				       struct vmcs12 *vmcs12)
>  {
>  	unsigned long exit_qualification;
> -	unsigned int port;
> +	unsigned short port;
>  	int size;
>  
>  	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
> @@ -12342,6 +12342,39 @@ static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu,
>  		to_vmx(vcpu)->nested.sync_shadow_vmcs = true;
>  }
>  
> +static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
> +				  struct x86_instruction_info *info)
> +{
> +	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
> +	unsigned short port;
> +	bool intercept;
> +	int size;
> +
> +	if (info->intercept == x86_intercept_in ||
> +	    info->intercept == x86_intercept_ins) {
> +		port = info->src_val;
> +		size = info->dst_bytes;
> +	} else {
> +		port = info->dst_val;
> +		size = info->src_bytes;
> +	}
> +
> +	/*
> +	 * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
> +	 * VM-exits depend on the 'unconditional IO exiting' VM-execution
> +	 * control.
> +	 *
> +	 * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
> +	 */
> +	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
> +		intercept = nested_cpu_has(vmcs12,
> +					   CPU_BASED_UNCOND_IO_EXITING);
> +	else
> +		intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
> +
> +	return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
> +}
> +
>  static int vmx_check_intercept(struct kvm_vcpu *vcpu,
>  			       struct x86_instruction_info *info,
>  			       enum x86_intercept_stage stage)
> @@ -12349,18 +12382,30 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
>  	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
>  	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
>  
> +	switch (info->intercept) {
>  	/*
>  	 * RDPID causes #UD if disabled through secondary execution controls.
>  	 * Because it is marked as EmulateOnUD, we need to intercept it here.
>  	 */
> -	if (info->intercept == x86_intercept_rdtscp &&
> -	    !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
> -		ctxt->exception.vector = UD_VECTOR;
> -		ctxt->exception.error_code_valid = false;
> -		return X86EMUL_PROPAGATE_FAULT;
> -	}
> +	case x86_intercept_rdtscp:
> +		if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
> +			ctxt->exception.vector = UD_VECTOR;
> +			ctxt->exception.error_code_valid = false;
> +			return X86EMUL_PROPAGATE_FAULT;
> +		}
> +		break;
> +
> +	case x86_intercept_in:
> +	case x86_intercept_ins:
> +	case x86_intercept_out:
> +	case x86_intercept_outs:
> +		return vmx_check_intercept_io(vcpu, info);
>  
>  	/* TODO: check more intercepts... */
> +	default:
> +		break;
> +	}
> +
>  	return X86EMUL_UNHANDLEABLE;
>  }
>  
> -- 
> 2.25.1
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Thadeu Lima de Souza Cascardo Feb. 28, 2020, 10:37 a.m. UTC | #2
On Thu, Feb 27, 2020 at 11:00:56PM -0500, Khaled Elmously wrote:
> This patch doesn't apply to Bionic
> 

~/bionic$ git reset --hard 22000e3c4bde
HEAD is now at 22000e3c4bde UBUNTU: Ubuntu-4.15.0-90.91
~/bionic$ git am ~/tmp/2732.mbox
Applying: KVM: x86: emulate RDPID
Applying: KVM: nVMX: Don't emulate instructions in guest mode
Applying: KVM: nVMX: Refactor IO bitmap checks into helper function
Applying: KVM: nVMX: Check IO instruction VM-exit conditions
~/bionic$

> On 2020-02-27 15:51:22 , Thadeu Lima de Souza Cascardo wrote:
> > From: Oliver Upton <oupton@google.com>
> > 
> > CVE-2020-2732
> > 
> > commit 35a571346a94fb93b5b3b6a599675ef3384bc75c upstream.
> > 
> > Consult the 'unconditional IO exiting' and 'use IO bitmaps' VM-execution
> > controls when checking instruction interception. If the 'use IO bitmaps'
> > VM-execution control is 1, check the instruction access against the IO
> > bitmaps to determine if the instruction causes a VM-exit.
> > 
> > Signed-off-by: Oliver Upton <oupton@google.com>
> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
> > ---
> >  arch/x86/kvm/vmx.c | 59 ++++++++++++++++++++++++++++++++++++++++------
> >  1 file changed, 52 insertions(+), 7 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> > index 6a2da0068ae2..3728ecea95e4 100644
> > --- a/arch/x86/kvm/vmx.c
> > +++ b/arch/x86/kvm/vmx.c
> > @@ -5004,7 +5004,7 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
> >  				       struct vmcs12 *vmcs12)
> >  {
> >  	unsigned long exit_qualification;
> > -	unsigned int port;
> > +	unsigned short port;
> >  	int size;
> >  
> >  	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
> > @@ -12342,6 +12342,39 @@ static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu,
> >  		to_vmx(vcpu)->nested.sync_shadow_vmcs = true;
> >  }
> >  
> > +static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
> > +				  struct x86_instruction_info *info)
> > +{
> > +	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
> > +	unsigned short port;
> > +	bool intercept;
> > +	int size;
> > +
> > +	if (info->intercept == x86_intercept_in ||
> > +	    info->intercept == x86_intercept_ins) {
> > +		port = info->src_val;
> > +		size = info->dst_bytes;
> > +	} else {
> > +		port = info->dst_val;
> > +		size = info->src_bytes;
> > +	}
> > +
> > +	/*
> > +	 * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
> > +	 * VM-exits depend on the 'unconditional IO exiting' VM-execution
> > +	 * control.
> > +	 *
> > +	 * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
> > +	 */
> > +	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
> > +		intercept = nested_cpu_has(vmcs12,
> > +					   CPU_BASED_UNCOND_IO_EXITING);
> > +	else
> > +		intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
> > +
> > +	return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
> > +}
> > +
> >  static int vmx_check_intercept(struct kvm_vcpu *vcpu,
> >  			       struct x86_instruction_info *info,
> >  			       enum x86_intercept_stage stage)
> > @@ -12349,18 +12382,30 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
> >  	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
> >  	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
> >  
> > +	switch (info->intercept) {
> >  	/*
> >  	 * RDPID causes #UD if disabled through secondary execution controls.
> >  	 * Because it is marked as EmulateOnUD, we need to intercept it here.
> >  	 */
> > -	if (info->intercept == x86_intercept_rdtscp &&
> > -	    !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
> > -		ctxt->exception.vector = UD_VECTOR;
> > -		ctxt->exception.error_code_valid = false;
> > -		return X86EMUL_PROPAGATE_FAULT;
> > -	}
> > +	case x86_intercept_rdtscp:
> > +		if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
> > +			ctxt->exception.vector = UD_VECTOR;
> > +			ctxt->exception.error_code_valid = false;
> > +			return X86EMUL_PROPAGATE_FAULT;
> > +		}
> > +		break;
> > +
> > +	case x86_intercept_in:
> > +	case x86_intercept_ins:
> > +	case x86_intercept_out:
> > +	case x86_intercept_outs:
> > +		return vmx_check_intercept_io(vcpu, info);
> >  
> >  	/* TODO: check more intercepts... */
> > +	default:
> > +		break;
> > +	}
> > +
> >  	return X86EMUL_UNHANDLEABLE;
> >  }
> >  
> > -- 
> > 2.25.1
> > 
> > 
> > -- 
> > kernel-team mailing list
> > kernel-team@lists.ubuntu.com
> > https://lists.ubuntu.com/mailman/listinfo/kernel-team
diff mbox series

Patch

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 6a2da0068ae2..3728ecea95e4 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5004,7 +5004,7 @@  static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
 				       struct vmcs12 *vmcs12)
 {
 	unsigned long exit_qualification;
-	unsigned int port;
+	unsigned short port;
 	int size;
 
 	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
@@ -12342,6 +12342,39 @@  static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu,
 		to_vmx(vcpu)->nested.sync_shadow_vmcs = true;
 }
 
+static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
+				  struct x86_instruction_info *info)
+{
+	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+	unsigned short port;
+	bool intercept;
+	int size;
+
+	if (info->intercept == x86_intercept_in ||
+	    info->intercept == x86_intercept_ins) {
+		port = info->src_val;
+		size = info->dst_bytes;
+	} else {
+		port = info->dst_val;
+		size = info->src_bytes;
+	}
+
+	/*
+	 * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
+	 * VM-exits depend on the 'unconditional IO exiting' VM-execution
+	 * control.
+	 *
+	 * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
+	 */
+	if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+		intercept = nested_cpu_has(vmcs12,
+					   CPU_BASED_UNCOND_IO_EXITING);
+	else
+		intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
+
+	return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
+}
+
 static int vmx_check_intercept(struct kvm_vcpu *vcpu,
 			       struct x86_instruction_info *info,
 			       enum x86_intercept_stage stage)
@@ -12349,18 +12382,30 @@  static int vmx_check_intercept(struct kvm_vcpu *vcpu,
 	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
 
+	switch (info->intercept) {
 	/*
 	 * RDPID causes #UD if disabled through secondary execution controls.
 	 * Because it is marked as EmulateOnUD, we need to intercept it here.
 	 */
-	if (info->intercept == x86_intercept_rdtscp &&
-	    !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
-		ctxt->exception.vector = UD_VECTOR;
-		ctxt->exception.error_code_valid = false;
-		return X86EMUL_PROPAGATE_FAULT;
-	}
+	case x86_intercept_rdtscp:
+		if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
+			ctxt->exception.vector = UD_VECTOR;
+			ctxt->exception.error_code_valid = false;
+			return X86EMUL_PROPAGATE_FAULT;
+		}
+		break;
+
+	case x86_intercept_in:
+	case x86_intercept_ins:
+	case x86_intercept_out:
+	case x86_intercept_outs:
+		return vmx_check_intercept_io(vcpu, info);
 
 	/* TODO: check more intercepts... */
+	default:
+		break;
+	}
+
 	return X86EMUL_UNHANDLEABLE;
 }