diff mbox series

[v3] KVM: x86: accept userspace interrupt only if no event is injected

Message ID 20210727210916.1652841-1-pbonzini@redhat.com
State Accepted
Commit fa7a549d321a4189677b0cea86e58d9db7977f7b
Headers show
Series [v3] KVM: x86: accept userspace interrupt only if no event is injected | expand

Commit Message

Paolo Bonzini July 27, 2021, 9:09 p.m. UTC
Once an exception has been injected, any side effects related to
the exception (such as setting CR2 or DR6) have been taked place.
Therefore, once KVM sets the VM-entry interruption information
field or the AMD EVENTINJ field, the next VM-entry must deliver that
exception.

Pending interrupts are processed after injected exceptions, so
in theory it would not be a problem to use KVM_INTERRUPT when
an injected exception is present.  However, DOSEMU is using
run->ready_for_interrupt_injection to detect interrupt windows
and then using KVM_SET_SREGS/KVM_SET_REGS to inject the
interrupt manually.  For this to work, the interrupt window
must be delayed after the completion of the previous event
injection.

Cc: stable@vger.kernel.org
Reported-by: Stas Sergeev <stsp2@yandex.ru>
Tested-by: Stas Sergeev <stsp2@yandex.ru>
Fixes: 71cc849b7093 ("KVM: x86: Fix split-irqchip vs interrupt injection window request")
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/x86.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

Comments

Sean Christopherson July 28, 2021, 11:11 p.m. UTC | #1
On Tue, Jul 27, 2021, Paolo Bonzini wrote:
> Once an exception has been injected, any side effects related to

> the exception (such as setting CR2 or DR6) have been taked place.

> Therefore, once KVM sets the VM-entry interruption information

> field or the AMD EVENTINJ field, the next VM-entry must deliver that

> exception.

> 

> Pending interrupts are processed after injected exceptions, so

> in theory it would not be a problem to use KVM_INTERRUPT when

> an injected exception is present.  However, DOSEMU is using

> run->ready_for_interrupt_injection to detect interrupt windows

> and then using KVM_SET_SREGS/KVM_SET_REGS to inject the

> interrupt manually.  For this to work, the interrupt window

> must be delayed after the completion of the previous event

> injection.

> 

> Cc: stable@vger.kernel.org

> Reported-by: Stas Sergeev <stsp2@yandex.ru>

> Tested-by: Stas Sergeev <stsp2@yandex.ru>

> Fixes: 71cc849b7093 ("KVM: x86: Fix split-irqchip vs interrupt injection window request")

> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

> ---

>  arch/x86/kvm/x86.c | 13 +++++++++++--

>  1 file changed, 11 insertions(+), 2 deletions(-)

> 

> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c

> index 4116567f3d44..e5d5c5ed7dd4 100644

> --- a/arch/x86/kvm/x86.c

> +++ b/arch/x86/kvm/x86.c

> @@ -4358,8 +4358,17 @@ static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)

>  

>  static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)

>  {

> -	return kvm_arch_interrupt_allowed(vcpu) &&

> -		kvm_cpu_accept_dm_intr(vcpu);

> +	/*

> +	 * Do not cause an interrupt window exit if an exception

> +	 * is pending or an event needs reinjection; userspace

> +	 * might want to inject the interrupt manually using KVM_SET_REGS

> +	 * or KVM_SET_SREGS.  For that to work, we must be at an

> +	 * instruction boundary and with no events half-injected.

> +	 */

> +	return (kvm_arch_interrupt_allowed(vcpu) &&


Ha, adding a '(' is one way to fix the indentation.

Reviewed-by: Sean Christopherson <seanjc@google.com> 


> +		kvm_cpu_accept_dm_intr(vcpu) &&

> +		!kvm_event_needs_reinjection(vcpu) &&

> +		!vcpu->arch.exception.pending);

>  }

>  

>  static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,

> -- 

> 2.27.0

>
stsp Aug. 6, 2021, 5:59 p.m. UTC | #2
28.07.2021 00:09, Paolo Bonzini пишет:
> Once an exception has been injected, any side effects related to

> the exception (such as setting CR2 or DR6) have been taked place.

> Therefore, once KVM sets the VM-entry interruption information

> field or the AMD EVENTINJ field, the next VM-entry must deliver that

> exception.

>

> Pending interrupts are processed after injected exceptions, so

> in theory it would not be a problem to use KVM_INTERRUPT when

> an injected exception is present.  However, DOSEMU is using

> run->ready_for_interrupt_injection to detect interrupt windows

> and then using KVM_SET_SREGS/KVM_SET_REGS to inject the

> interrupt manually.  For this to work, the interrupt window

> must be delayed after the completion of the previous event

> injection.

>

> Cc: stable@vger.kernel.org

> Reported-by: Stas Sergeev <stsp2@yandex.ru>

> Tested-by: Stas Sergeev <stsp2@yandex.ru>

Acked-by: stsp2@yandex.ru
diff mbox series

Patch

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4116567f3d44..e5d5c5ed7dd4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4358,8 +4358,17 @@  static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)
 
 static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)
 {
-	return kvm_arch_interrupt_allowed(vcpu) &&
-		kvm_cpu_accept_dm_intr(vcpu);
+	/*
+	 * Do not cause an interrupt window exit if an exception
+	 * is pending or an event needs reinjection; userspace
+	 * might want to inject the interrupt manually using KVM_SET_REGS
+	 * or KVM_SET_SREGS.  For that to work, we must be at an
+	 * instruction boundary and with no events half-injected.
+	 */
+	return (kvm_arch_interrupt_allowed(vcpu) &&
+		kvm_cpu_accept_dm_intr(vcpu) &&
+		!kvm_event_needs_reinjection(vcpu) &&
+		!vcpu->arch.exception.pending);
 }
 
 static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,