diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.9.21/0024-KVM-nVMX-Fix-races-when-sending-nested-PI-while-dest.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.9.21/0024-KVM-nVMX-Fix-races-when-sending-nested-PI-while-dest.patch | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.9.21/0024-KVM-nVMX-Fix-races-when-sending-nested-PI-while-dest.patch b/common/recipes-kernel/linux/linux-yocto-4.9.21/0024-KVM-nVMX-Fix-races-when-sending-nested-PI-while-dest.patch new file mode 100644 index 00000000..8feed73a --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.9.21/0024-KVM-nVMX-Fix-races-when-sending-nested-PI-while-dest.patch @@ -0,0 +1,100 @@ +From 36417bad8e288e64df1067207030c67304c26ee5 Mon Sep 17 00:00:00 2001 +From: Liran Alon <liran.alon@oracle.com> +Date: Thu, 9 Nov 2017 20:27:20 +0200 +Subject: [PATCH 24/33] KVM: nVMX: Fix races when sending nested PI while dest + enters/leaves L2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 6b6977117f50d60455ace86b2d256f6fb4f3de05 upstream. + +Consider the following scenario: +1. CPU A calls vmx_deliver_nested_posted_interrupt() to send an IPI +to CPU B via virtual posted-interrupt mechanism. +2. CPU B is currently executing L2 guest. +3. vmx_deliver_nested_posted_interrupt() calls +kvm_vcpu_trigger_posted_interrupt() which will note that +vcpu->mode == IN_GUEST_MODE. +4. Assume that before CPU A sends the physical POSTED_INTR_NESTED_VECTOR +IPI, CPU B exits from L2 to L0 during event-delivery +(valid IDT-vectoring-info). +5. CPU A now sends the physical IPI. The IPI is received in host and +it's handler (smp_kvm_posted_intr_nested_ipi()) does nothing. +6. Assume that before CPU A sets pi_pending=true and KVM_REQ_EVENT, +CPU B continues to run in L0 and reach vcpu_enter_guest(). As +KVM_REQ_EVENT is not set yet, vcpu_enter_guest() will continue and resume +L2 guest. +7. At this point, CPU A sets pi_pending=true and KVM_REQ_EVENT but +it's too late! CPU B already entered L2 and KVM_REQ_EVENT will only be +consumed at next L2 entry! + +Another scenario to consider: +1. CPU A calls vmx_deliver_nested_posted_interrupt() to send an IPI +to CPU B via virtual posted-interrupt mechanism. +2. Assume that before CPU A calls kvm_vcpu_trigger_posted_interrupt(), +CPU B is at L0 and is about to resume into L2. Further assume that it is +in vcpu_enter_guest() after check for KVM_REQ_EVENT. +3. At this point, CPU A calls kvm_vcpu_trigger_posted_interrupt() which +will note that vcpu->mode != IN_GUEST_MODE. Therefore, do nothing and +return false. Then, will set pi_pending=true and KVM_REQ_EVENT. +4. Now CPU B continue and resumes into L2 guest without processing +the posted-interrupt until next L2 entry! + +To fix both issues, we just need to change +vmx_deliver_nested_posted_interrupt() to set pi_pending=true and +KVM_REQ_EVENT before calling kvm_vcpu_trigger_posted_interrupt(). + +It will fix the first scenario by chaging step (6) to note that +KVM_REQ_EVENT and pi_pending=true and therefore process +nested posted-interrupt. + +It will fix the second scenario by two possible ways: +1. If kvm_vcpu_trigger_posted_interrupt() is called while CPU B has changed +vcpu->mode to IN_GUEST_MODE, physical IPI will be sent and will be received +when CPU resumes into L2. +2. If kvm_vcpu_trigger_posted_interrupt() is called while CPU B hasn't yet +changed vcpu->mode to IN_GUEST_MODE, then after CPU B will change +vcpu->mode it will call kvm_request_pending() which will return true and +therefore force another round of vcpu_enter_guest() which will note that +KVM_REQ_EVENT and pi_pending=true and therefore process nested +posted-interrupt. + +Fixes: 705699a13994 ("KVM: nVMX: Enable nested posted interrupt processing") +Signed-off-by: Liran Alon <liran.alon@oracle.com> +Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com> +Reviewed-by: Krish Sadhukhan <krish.sadhukhan@oracle.com> +[Add kvm_vcpu_kick to also handle the case where L1 doesn't intercept L2 HLT + and L2 executes HLT instruction. - Paolo] +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + arch/x86/kvm/vmx.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index c564d03..85078c7 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -4944,14 +4944,15 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu, + + if (is_guest_mode(vcpu) && + vector == vmx->nested.posted_intr_nv) { +- /* the PIR and ON have been set by L1. */ +- kvm_vcpu_trigger_posted_interrupt(vcpu); + /* + * If a posted intr is not recognized by hardware, + * we will accomplish it in the next vmentry. + */ + vmx->nested.pi_pending = true; + kvm_make_request(KVM_REQ_EVENT, vcpu); ++ /* the PIR and ON have been set by L1. */ ++ if (!kvm_vcpu_trigger_posted_interrupt(vcpu)) ++ kvm_vcpu_kick(vcpu); + return 0; + } + return -1; +-- +2.7.4 + |