KVM: eventfd: Fix false positive RCU usage warning
Subsystems (2)
Sasha Levin
maintainerPATCH 1/6 KVM: eventfd: Fix false positive RCU usage warning
From: Hou Wenlong <[email protected]>
[ Upstream commit 6a0c61703e3a5d67845a4b275e1d9d7bc1b5aad7 ]
Fix the following false positive warning:
=============================
WARNING: suspicious RCU usage
5.16.0-rc4+ #57 Not tainted
-----------------------------
arch/x86/kvm/../../../virt/kvm/eventfd.c:484 RCU-list traversed in non-reader section!!
other info that might help us debug this:
rcu_scheduler_active = 2, debug_locks = 1
3 locks held by fc_vcpu 0/330:
#0: ffff8884835fc0b0 (&vcpu->mutex){+.+.}-{3:3}, at: kvm_vcpu_ioctl+0x88/0x6f0 [kvm] #1: ffffc90004c0bb68 (&kvm->srcu){....}-{0:0}, at: vcpu_enter_guest+0x600/0x1860 [kvm] #2: ffffc90004c0c1d0 (&kvm->irq_srcu){....}-{0:0}, at: kvm_notify_acked_irq+0x36/0x180 [kvm]
stack backtrace: CPU: 26 PID: 330 Comm: fc_vcpu 0 Not tainted 5.16.0-rc4+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x44/0x57 kvm_notify_acked_gsi+0x6b/0x70 [kvm] kvm_notify_acked_irq+0x8d/0x180 [kvm] kvm_ioapic_update_eoi+0x92/0x240 [kvm] kvm_apic_set_eoi_accelerated+0x2a/0xe0 [kvm] handle_apic_eoi_induced+0x3d/0x60 [kvm_intel] vmx_handle_exit+0x19c/0x6a0 [kvm_intel] vcpu_enter_guest+0x66e/0x1860 [kvm] kvm_arch_vcpu_ioctl_run+0x438/0x7f0 [kvm] kvm_vcpu_ioctl+0x38a/0x6f0 [kvm] __x64_sys_ioctl+0x89/0xc0 do_syscall_64+0x3a/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae
Since kvm_unregister_irq_ack_notifier() does synchronize_srcu(&kvm->irq_srcu), kvm->irq_ack_notifier_list is protected by kvm->irq_srcu. In fact, kvm->irq_srcu SRCU read lock is held in kvm_notify_acked_irq(), making it a false positive warning. So use hlist_for_each_entry_srcu() instead of hlist_for_each_entry_rcu().
Message-Id: <f98bac4f5052bad2c26df9ad50f7019e40434512.1643265976.git.houwenlong.hwl@antgroup.com>
--- virt/kvm/eventfd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
virt/kvm/eventfd.c +4 -4
@@ -451,8 +451,8 @@ bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) idx =srcu_read_lock (&kvm->irq_srcu); gsi =kvm_irq_map_chip_pin (kvm, irqchip, pin);if (gsi !=-1 ) -hlist_for_each_entry_rcu (kian, &kvm->irq_ack_notifier_list, - link) +hlist_for_each_entry_srcu (kian, &kvm->irq_ack_notifier_list, + link,srcu_read_lock_held (&kvm->irq_srcu))if (kian->gsi == gsi) {srcu_read_unlock (&kvm->irq_srcu, idx);return true;
@@ -468,8 +468,8 @@ void kvm_notify_acked_gsi(struct kvm *kvm, int gsi) {struct kvm_irq_ack_notifier *kian; -hlist_for_each_entry_rcu (kian, &kvm->irq_ack_notifier_list, - link) +hlist_for_each_entry_srcu (kian, &kvm->irq_ack_notifier_list, + link,srcu_read_lock_held (&kvm->irq_srcu))if (kian->gsi == gsi) kian->irq_acked (kian); }
Signature · 1 line
2.34.1
Sasha Levin
maintainerPATCH 2/6 KVM: nVMX: eVMCS: Filter out VM_EXIT_SAVE_VMX_PREEMPTION_TIMER
From: Vitaly Kuznetsov <[email protected]>
[ Upstream commit 7a601e2cf61558dfd534a9ecaad09f5853ad8204 ]
Enlightened VMCS v1 doesn't have VMX_PREEMPTION_TIMER_VALUE field, PIN_BASED_VMX_PREEMPTION_TIMER is also filtered out already so it makes sense to filter out VM_EXIT_SAVE_VMX_PREEMPTION_TIMER too.
Note, none of the currently existing Windows/Hyper-V versions are known to enable 'save VMX-preemption timer value' when eVMCS is in use, the change is aimed at making the filtering future proof.
Message-Id: <[email protected]>
--- arch/x86/kvm/vmx/evmcs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/evmcs.h +3 -1
@@ -59,7 +59,9 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs); SECONDARY_EXEC_SHADOW_VMCS | \ SECONDARY_EXEC_TSC_SCALING | \ SECONDARY_EXEC_PAUSE_LOOP_EXITING) -#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) +#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL \ + (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)#define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
Signature · 1 line
2.34.1
Re: [PATCH MANUALSEL 5.10 2/6] KVM: nVMX: eVMCS: Filter out VM_EXIT_SAVE_VMX_PREEMPTION_TIMER
Quoted 3 lines · Sasha Levin
From: Vitaly Kuznetsov <[email protected]>
[ Upstream commit
7a601e2cf61558dfd534a9ecaad09f5853ad8204]
Paolo
Quoted 31 lines
Enlightened VMCS v1 doesn't have
VMX_PREEMPTION_TIMER_VALUEfield,PIN_BASED_VMX_PREEMPTION_TIMERis also filtered out already so it makes sense to filter outVM_EXIT_SAVE_VMX_PREEMPTION_TIMERtoo.Note, none of the currently existing Windows/Hyper-V versions are known to enable 'save VMX-preemption timer value' when eVMCS is in use, the change is aimed at making the filtering future proof.
Signed-off-by Vitaly Kuznetsov <[email protected]>Message-Id: <[email protected]>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/x86/kvm/vmx/evmcs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)arch/x86/kvm/vmx/evmcs.h +3
-1@@ -59,7 +59,9 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs); SECONDARY_EXEC_SHADOW_VMCS | \ SECONDARY_EXEC_TSC_SCALING | \ SECONDARY_EXEC_PAUSE_LOOP_EXITING) -#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) +#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL \ + (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)#define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
Sasha Levin
maintainerPATCH 3/6 KVM: nVMX: Also filter MSR_IA32_VMX_TRUE_PINBASED_CTLS when eVMCS
In reply to Sasha LevinFrom: Vitaly Kuznetsov <[email protected]>
[ Upstream commit f80ae0ef089a09e8c18da43a382c3caac9a424a7 ]
Similar to MSR_IA32_VMX_EXIT_CTLS/MSR_IA32_VMX_TRUE_EXIT_CTLS, MSR_IA32_VMX_ENTRY_CTLS/MSR_IA32_VMX_TRUE_ENTRY_CTLS pair, MSR_IA32_VMX_TRUE_PINBASED_CTLS needs to be filtered the same way MSR_IA32_VMX_PINBASED_CTLS is currently filtered as guests may solely rely on 'true' MSR data.
Note, none of the currently existing Windows/Hyper-V versions are known to stumble upon the unfiltered MSR_IA32_VMX_TRUE_PINBASED_CTLS, the change is aimed at making the filtering future proof.
Message-Id: <[email protected]>
--- arch/x86/kvm/vmx/evmcs.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/kvm/vmx/evmcs.c +1 -0
@@ -361,6 +361,7 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)case MSR_IA32_VMX_PROCBASED_CTLS2 : ctl_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC ;break ; +case MSR_IA32_VMX_TRUE_PINBASED_CTLS :case MSR_IA32_VMX_PINBASED_CTLS : ctl_high &= ~EVMCS1_UNSUPPORTED_PINCTRL ;break ;
Signature · 1 line
2.34.1
Re: [PATCH MANUALSEL 5.10 3/6] KVM: nVMX: Also filter MSR_IA32_VMX_TRUE_PINBASED_CTLS when eVMCS
Quoted 3 lines · Sasha Levin
From: Vitaly Kuznetsov <[email protected]>
[ Upstream commit
f80ae0ef089a09e8c18da43a382c3caac9a424a7]
Paolo
Quoted 30 lines
Similar to MSR_IA32_VMX_EXIT_CTLS/MSR_IA32_VMX_TRUE_EXIT_CTLS, MSR_IA32_VMX_ENTRY_CTLS/MSR_IA32_VMX_TRUE_ENTRY_CTLS pair,
MSR_IA32_VMX_TRUE_PINBASED_CTLSneeds to be filtered the same wayMSR_IA32_VMX_PINBASED_CTLSis currently filtered as guests may solely rely on 'true' MSR data.Note, none of the currently existing Windows/Hyper-V versions are known to stumble upon the unfiltered
MSR_IA32_VMX_TRUE_PINBASED_CTLS, the change is aimed at making the filtering future proof.Signed-off-by Vitaly Kuznetsov <[email protected]>Message-Id: <[email protected]>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/x86/kvm/vmx/evmcs.c | 1 + 1 file changed, 1 insertion(+)arch/x86/kvm/vmx/evmcs.c +1
-0@@ -361,6 +361,7 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)case MSR_IA32_VMX_PROCBASED_CTLS2 : ctl_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC ;break ; +case MSR_IA32_VMX_TRUE_PINBASED_CTLS :case MSR_IA32_VMX_PINBASED_CTLS : ctl_high &= ~EVMCS1_UNSUPPORTED_PINCTRL ;break ;
Sasha Levin
maintainerPATCH 4/6 KVM: nVMX: WARN on any attempt to allocate shadow VMCS for vmcs02
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit d6e656cd266cdcc95abd372c7faef05bee271d1a ]
WARN if KVM attempts to allocate a shadow VMCS for vmcs02. KVM emulates VMCS shadowing but doesn't virtualize it, i.e. KVM should never allocate a "real" shadow VMCS for L2.
The previous code WARNed but continued anyway with the allocation, presumably in an attempt to avoid NULL pointer dereference. However, alloc_vmcs (and hence alloc_shadow_vmcs) can fail, and indeed the sole caller does:
if (enable_shadow_vmcs && !alloc_shadow_vmcs(vcpu)) goto out_shadow_vmcs;
which makes it not a useful attempt.
Message-Id: <[email protected]>
--- arch/x86/kvm/vmx/nested.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
arch/x86/kvm/vmx/nested.c +12 -10
@@ -4786,18 +4786,20 @@ static struct vmcs *alloc_shadow_vmcs(struct kvm_vcpu *vcpu)struct loaded_vmcs *loaded_vmcs = vmx->loaded_vmcs;/* -* We should allocate a shadow vmcs for vmcs01 only when L1 -* executes VMXON and free it when L1 executes VMXOFF. -* As it is invalid to execute VMXON twice, we shouldn't reach -* here when vmcs01 already have an allocated shadow vmcs. +* KVM allocates a shadow VMCS only when L1 executes VMXON and frees it +* when L1 executes VMXOFF or the vCPU is forced out of nested +* operation. VMXON faults if the CPU is already post-VMXON, so it +* should be impossible to already have an allocated shadow VMCS. KVM +* doesn't support virtualization of VMCS shadowing, so vmcs01 should +* always be the loaded VMCS. */ -WARN_ON (loaded_vmcs == &vmx->vmcs01 && loaded_vmcs->shadow_vmcs); +if (WARN_ON (loaded_vmcs != &vmx->vmcs01 || loaded_vmcs->shadow_vmcs)) +return loaded_vmcs->shadow_vmcs; + + loaded_vmcs->shadow_vmcs =alloc_vmcs (true); +if (loaded_vmcs->shadow_vmcs) +vmcs_clear (loaded_vmcs->shadow_vmcs); -if (!loaded_vmcs->shadow_vmcs) { - loaded_vmcs->shadow_vmcs =alloc_vmcs (true); -if (loaded_vmcs->shadow_vmcs) -vmcs_clear (loaded_vmcs->shadow_vmcs); - }return loaded_vmcs->shadow_vmcs; }
Signature · 1 line
2.34.1
Re: [PATCH MANUALSEL 5.10 4/6] KVM: nVMX: WARN on any attempt to allocate shadow VMCS for vmcs02
Quoted 51 lines · Sasha Levin
From: Sean Christopherson <[email protected]>
[ Upstream commit
d6e656cd266cdcc95abd372c7faef05bee271d1a]WARN if KVM attempts to allocate a shadow VMCS for vmcs02. KVM emulates VMCS shadowing but doesn't virtualize it, i.e. KVM should never allocate a "real" shadow VMCS for L2.
The previous code WARNed but continued anyway with the allocation, presumably in an attempt to avoid NULL pointer dereference. However,
alloc_vmcs(and hencealloc_shadow_vmcs) can fail, and indeed the sole caller does:if (enable_shadow_vmcs && !alloc_shadow_vmcs(vcpu)) goto out_shadow_vmcs;which makes it not a useful attempt.
Signed-off-by Sean Christopherson <[email protected]>Message-Id: <[email protected]>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/x86/kvm/vmx/nested.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)arch/x86/kvm/vmx/nested.c +11
-5@@ -4786,18 +4786,20 @@ static struct vmcs *alloc_shadow_vmcs(struct kvm_vcpu *vcpu)struct loaded_vmcs *loaded_vmcs = vmx->loaded_vmcs;/* -* We should allocate a shadow vmcs for vmcs01 only when L1 -* executes VMXON and free it when L1 executes VMXOFF. -* As it is invalid to execute VMXON twice, we shouldn't reach -* here when vmcs01 already have an allocated shadow vmcs. +* KVM allocates a shadow VMCS only when L1 executes VMXON and frees it +* when L1 executes VMXOFF or the vCPU is forced out of nested +* operation. VMXON faults if the CPU is already post-VMXON, so it +* should be impossible to already have an allocated shadow VMCS. KVM +* doesn't support virtualization of VMCS shadowing, so vmcs01 should +* always be the loaded VMCS. */ -WARN_ON (loaded_vmcs == &vmx->vmcs01 && loaded_vmcs->shadow_vmcs); +if (WARN_ON (loaded_vmcs != &vmx->vmcs01 || loaded_vmcs->shadow_vmcs)) +return loaded_vmcs->shadow_vmcs; + + loaded_vmcs->shadow_vmcs =alloc_vmcs (true); +if (loaded_vmcs->shadow_vmcs)
arch/x86/kvm/vmx/nested.c static struct vmcs *alloc_shadow_vmcs(struct kvm_vcpu *vcpu) · line 4805
Quoted 10 lines
arch/x86/kvm/vmx/nested.c +1
-5+vmcs_clear (loaded_vmcs->shadow_vmcs); -if (!loaded_vmcs->shadow_vmcs) { - loaded_vmcs->shadow_vmcs =alloc_vmcs (true); -if (loaded_vmcs->shadow_vmcs) -vmcs_clear (loaded_vmcs->shadow_vmcs); - }return loaded_vmcs->shadow_vmcs; }
NACK
Sasha Levin
maintainerPATCH 5/6 KVM: SVM: Don't kill SEV guest if SMAP erratum triggers in usermode
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit cdf85e0c5dc766fc7fc779466280e454a6d04f87 ]
Inject a #GP instead of synthesizing triple fault to try to avoid killing the guest if emulation of an SEV guest fails due to encountering the SMAP erratum. The injected #GP may still be fatal to the guest, e.g. if the userspace process is providing critical functionality, but KVM should make every attempt to keep the guest alive.
Message-Id: <[email protected]>
--- arch/x86/kvm/svm/svm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
arch/x86/kvm/svm/svm.c +15 -1
@@ -4155,7 +4155,21 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int ireturn true;pr_err_ratelimited ("KVM: SEV Guest triggered AMD Erratum 1096\n" ); -kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu); + +/* +* If the fault occurred in userspace, arbitrarily inject #GP +* to avoid killing the guest and to hopefully avoid confusing +* the guest kernel too much, e.g. injecting #PF would not be +* coherent with respect to the guest's page tables. Request +* triple fault if the fault occurred in the kernel as there's +* no fault that KVM can inject without confusing the guest. +* In practice, the triple fault is moot as no sane SEV kernel +* will execute from user memory while also running with SMAP=1. +*/ +if (is_user) +kvm_inject_gp (vcpu,0 ); +else +kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu); }return false;
Signature · 1 line
2.34.1
Re: [PATCH MANUALSEL 5.10 5/6] KVM: SVM: Don't kill SEV guest if SMAP erratum triggers in usermode
Quoted 3 lines · Sasha Levin
From: Sean Christopherson <[email protected]>
[ Upstream commit
cdf85e0c5dc766fc7fc779466280e454a6d04f87]
Paolo
Quoted 43 lines
Inject a #GP instead of synthesizing triple fault to try to avoid killing the guest if emulation of an SEV guest fails due to encountering the SMAP erratum. The injected #GP may still be fatal to the guest, e.g. if the userspace process is providing critical functionality, but KVM should make every attempt to keep the guest alive.
Signed-off-by Sean Christopherson <[email protected]>Reviewed-by Liam Merwick <[email protected]>Message-Id: <[email protected]>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/x86/kvm/svm/svm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)arch/x86/kvm/svm/svm.c +15
-1@@ -4155,7 +4155,21 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int ireturn true;pr_err_ratelimited ("KVM: SEV Guest triggered AMD Erratum 1096\n" ); -kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu); + +/* +* If the fault occurred in userspace, arbitrarily inject #GP +* to avoid killing the guest and to hopefully avoid confusing +* the guest kernel too much, e.g. injecting #PF would not be +* coherent with respect to the guest's page tables. Request +* triple fault if the fault occurred in the kernel as there's +* no fault that KVM can inject without confusing the guest. +* In practice, the triple fault is moot as no sane SEV kernel +* will execute from user memory while also running with SMAP=1. +*/ +if (is_user) +kvm_inject_gp (vcpu,0 ); +else +kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu); }return false;
Re: [PATCH MANUALSEL 5.10 5/6] KVM: SVM: Don't kill SEV guest if SMAP erratum triggers in usermode
In reply to Sasha LevinQuoted 3 lines · Sasha Levin
From: Sean Christopherson <[email protected]>
[ Upstream commit
cdf85e0c5dc766fc7fc779466280e454a6d04f87]
Paolo
Quoted 42 lines
Inject a #GP instead of synthesizing triple fault to try to avoid killing the guest if emulation of an SEV guest fails due to encountering the SMAP erratum. The injected #GP may still be fatal to the guest, e.g. if the userspace process is providing critical functionality, but KVM should make every attempt to keep the guest alive.
Signed-off-by Sean Christopherson <[email protected]>Reviewed-by Liam Merwick <[email protected]>Message-Id: <[email protected]>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/x86/kvm/svm/svm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)arch/x86/kvm/svm/svm.c +15
-1@@ -4155,7 +4155,21 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int ireturn true;pr_err_ratelimited ("KVM: SEV Guest triggered AMD Erratum 1096\n" ); -kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu); + +/* +* If the fault occurred in userspace, arbitrarily inject #GP +* to avoid killing the guest and to hopefully avoid confusing +* the guest kernel too much, e.g. injecting #PF would not be +* coherent with respect to the guest's page tables. Request +* triple fault if the fault occurred in the kernel as there's +* no fault that KVM can inject without confusing the guest. +* In practice, the triple fault is moot as no sane SEV kernel +* will execute from user memory while also running with SMAP=1. +*/ +if (is_user) +kvm_inject_gp (vcpu,0 ); +else +kvm_make_request (KVM_REQ_TRIPLE_FAULT , vcpu); }return false;
Sasha Levin
maintainerPATCH 6/6 KVM: VMX: Set vmcs.PENDING_DBG.BS on #DB in STI/MOVSS blocking shadow
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit b9bed78e2fa9571b7c983b20666efa0009030c71 ]
Set vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS, a.k.a. the pending single-step breakpoint flag, when re-injecting a #DB with RFLAGS.TF=1, and STI or MOVSS blocking is active. Setting the flag is necessary to make VM-Entry consistency checks happy, as VMX has an invariant that if RFLAGS.TF is set and STI/MOVSS blocking is true, then the previous instruction must have been STI or MOV/POP, and therefore a single-step #DB must be pending since the RFLAGS.TF cannot have been set by the previous instruction, i.e. the one instruction delay after setting RFLAGS.TF must have already expired.
Normally, the CPU sets vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS appropriately when recording guest state as part of a VM-Exit, but #DB VM-Exits intentionally do not treat the #DB as "guest state" as interception of the #DB effectively makes the #DB host-owned, thus KVM needs to manually set PENDING_DBG.BS when forwarding/re-injecting the #DB to the guest.
Note, although this bug can be triggered by guest userspace, doing so requires IOPL=3, and guest userspace running with IOPL=3 has full access to all I/O ports (from the guest's perspective) and can crash/reboot the guest any number of ways. IOPL=3 is required because STI blocking kicks in if and only if RFLAGS.IF is toggled 0=>1, and if CPL>IOPL, STI either takes a #GP or modifies RFLAGS.VIF, not RFLAGS.IF.
MOVSS blocking can be initiated by userspace, but can be coincident with a #DB if and only if DR7.GD=1 (General Detect enabled) and a MOV DR is executed in the MOVSS shadow. MOV DR #GPs at CPL>0, thus MOVSS blocking is problematic only for CPL0 (and only if the guest is crazy enough to access a DR in a MOVSS shadow). All other sources of #DBs are either suppressed by MOVSS blocking (single-step, code fetch, data, and I/O), are mutually exclusive with MOVSS blocking (T-bit task switch), or are already handled by KVM (ICEBP, a.k.a. INT1).
This bug was originally found by running tests[1] created for XSA-308[2]. Note that Xen's userspace test emits ICEBP in the MOVSS shadow, which is presumably why the Xen bug was deemed to be an exploitable DOS from guest userspace. KVM already handles ICEBP by skipping the ICEBP instruction and thus clears MOVSS blocking as a side effect of its "emulation".
[1] http://xenbits.xenproject.org/docs/xtf/xsa-308_2main_8c_source.html
[2] https://xenbits.xen.org/xsa/advisory-308.html
Message-Id: <[email protected]>
--- arch/x86/kvm/vmx/vmx.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
arch/x86/kvm/vmx/vmx.c +25 -0
@@ -4846,8 +4846,33 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu) dr6 =vmx_get_exit_qual (vcpu);if (!(vcpu->guest_debug & (KVM_GUESTDBG_SINGLESTEP |KVM_GUESTDBG_USE_HW_BP ))) { +/* +* If the #DB was due to ICEBP, a.k.a. INT1, skip the +* instruction. ICEBP generates a trap-like #DB, but +* despite its interception control being tied to #DB, +* is an instruction intercept, i.e. the VM-Exit occurs +* on the ICEBP itself. Note, skipping ICEBP also +* clears STI and MOVSS blocking. +* +* For all other #DBs, set vmcs.PENDING_DBG_EXCEPTIONS.BS +* if single-step is enabled in RFLAGS and STI or MOVSS +* blocking is active, as the CPU doesn't set the bit +* on VM-Exit due to #DB interception. VM-Entry has a +* consistency check that a single-step #DB is pending +* in this scenario as the previous instruction cannot +* have toggled RFLAGS.TF 0=>1 (because STI and POP/MOV +* don't modify RFLAGS), therefore the one instruction +* delay when activating single-step breakpoints must +* have already expired. Note, the CPU sets/clears BS +* as appropriate for all other VM-Exits types. +*/ if (is_icebp (intr_info))WARN_ON (!skip_emulated_instruction (vcpu)); +else if ((vmx_get_rflags (vcpu) &X86_EFLAGS_TF ) && + (vmcs_read32 (GUEST_INTERRUPTIBILITY_INFO ) & + (GUEST_INTR_STATE_STI |GUEST_INTR_STATE_MOV_SS ))) +vmcs_writel (GUEST_PENDING_DBG_EXCEPTIONS , +vmcs_readl (GUEST_PENDING_DBG_EXCEPTIONS ) |DR6_BS );kvm_queue_exception_p (vcpu,DB_VECTOR , dr6);return 1 ;
Signature · 1 line
2.34.1
Re: [PATCH MANUALSEL 5.10 6/6] KVM: VMX: Set vmcs.PENDING_DBG.BS on #DB in STI/MOVSS blocking shadow
Quoted 3 lines · Sasha Levin
From: Sean Christopherson <[email protected]>
[ Upstream commit
b9bed78e2fa9571b7c983b20666efa0009030c71]
Paolo
Quoted 89 lines
Set vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS, a.k.a. the pending single-step breakpoint flag, when re-injecting a #DB with RFLAGS.TF=1, and STI or MOVSS blocking is active. Setting the flag is necessary to make VM-Entry consistency checks happy, as VMX has an invariant that if RFLAGS.TF is set and STI/MOVSS blocking is true, then the previous instruction must have been STI or MOV/POP, and therefore a single-step #DB must be pending since the RFLAGS.TF cannot have been set by the previous instruction, i.e. the one instruction delay after setting RFLAGS.TF must have already expired.
Normally, the CPU sets vmcs.GUEST_PENDING_DBG_EXCEPTIONS.BS appropriately when recording guest state as part of a VM-Exit, but #DB VM-Exits intentionally do not treat the #DB as "guest state" as interception of the #DB effectively makes the #DB host-owned, thus KVM needs to manually set PENDING_DBG.BS when forwarding/re-injecting the #DB to the guest.
Note, although this bug can be triggered by guest userspace, doing so requires IOPL=3, and guest userspace running with IOPL=3 has full access to all I/O ports (from the guest's perspective) and can crash/reboot the guest any number of ways. IOPL=3 is required because STI blocking kicks in if and only if RFLAGS.IF is toggled 0=>1, and if CPL>IOPL, STI either takes a #GP or modifies RFLAGS.VIF, not RFLAGS.IF.
MOVSS blocking can be initiated by userspace, but can be coincident with a #DB if and only if DR7.GD=1 (General Detect enabled) and a MOV DR is executed in the MOVSS shadow. MOV DR #GPs at CPL>0, thus MOVSS blocking is problematic only for CPL0 (and only if the guest is crazy enough to access a DR in a MOVSS shadow). All other sources of #DBs are either suppressed by MOVSS blocking (single-step, code fetch, data, and I/O), are mutually exclusive with MOVSS blocking (T-bit task switch), or are already handled by KVM (ICEBP, a.k.a. INT1).
This bug was originally found by running tests[1] created for XSA-308[2]. Note that Xen's userspace test emits ICEBP in the MOVSS shadow, which is presumably why the Xen bug was deemed to be an exploitable DOS from guest userspace. KVM already handles ICEBP by skipping the ICEBP instruction and thus clears MOVSS blocking as a side effect of its "emulation".
[1] http://xenbits.xenproject.org/docs/xtf/xsa-308_2main_8c_source.html
[2] https://xenbits.xen.org/xsa/advisory-308.htmlReported-by David Woodhouse <[email protected]>Reported-by Alexander Graf <[email protected]>Signed-off-by Sean Christopherson <[email protected]>Message-Id: <[email protected]>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/x86/kvm/vmx/vmx.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)arch/x86/kvm/vmx/vmx.c +25
-0@@ -4846,8 +4846,33 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu) dr6 =vmx_get_exit_qual (vcpu);if (!(vcpu->guest_debug & (KVM_GUESTDBG_SINGLESTEP |KVM_GUESTDBG_USE_HW_BP ))) { +/* +* If the #DB was due to ICEBP, a.k.a. INT1, skip the +* instruction. ICEBP generates a trap-like #DB, but +* despite its interception control being tied to #DB, +* is an instruction intercept, i.e. the VM-Exit occurs +* on the ICEBP itself. Note, skipping ICEBP also +* clears STI and MOVSS blocking. +* +* For all other #DBs, set vmcs.PENDING_DBG_EXCEPTIONS.BS +* if single-step is enabled in RFLAGS and STI or MOVSS +* blocking is active, as the CPU doesn't set the bit +* on VM-Exit due to #DB interception. VM-Entry has a +* consistency check that a single-step #DB is pending +* in this scenario as the previous instruction cannot +* have toggled RFLAGS.TF 0=>1 (because STI and POP/MOV +* don't modify RFLAGS), therefore the one instruction +* delay when activating single-step breakpoints must +* have already expired. Note, the CPU sets/clears BS +* as appropriate for all other VM-Exits types. +*/ if (is_icebp (intr_info))WARN_ON (!skip_emulated_instruction (vcpu)); +else if ((vmx_get_rflags (vcpu) &X86_EFLAGS_TF ) && + (vmcs_read32 (GUEST_INTERRUPTIBILITY_INFO ) & + (GUEST_INTR_STATE_STI |GUEST_INTR_STATE_MOV_SS ))) +vmcs_writel (GUEST_PENDING_DBG_EXCEPTIONS , +vmcs_readl (GUEST_PENDING_DBG_EXCEPTIONS ) |DR6_BS );kvm_queue_exception_p (vcpu,DB_VECTOR , dr6);return 1 ;
Quoted 3 lines · Sasha Levin
From: Hou Wenlong <[email protected]>
[ Upstream commit
6a0c61703e3a5d67845a4b275e1d9d7bc1b5aad7]
Paolo
Quoted 75 lines
Fix the following false positive warning:
=============================
WARNING: suspicious RCU usage
5.16.0-rc4+ #57 Not tainted
-----------------------------
arch/x86/kvm/../../../virt/kvm/eventfd.c:484RCU-list traversed in non-reader section!!other info that might help us debug this:
rcu_scheduler_active= 2,debug_locks= 1
3 locks held byfc_vcpu0/330:#0: ffff8884835fc0b0 (&vcpu->mutex){+.+.}-{3:3}, at: kvm_vcpu_ioctl+0x88/0x6f0 [kvm] #1: ffffc90004c0bb68 (&kvm->srcu){....}-{0:0}, at: vcpu_enter_guest+0x600/0x1860 [kvm] #2: ffffc90004c0c1d0 (&kvm->irq_srcu){....}-{0:0}, at: kvm_notify_acked_irq+0x36/0x180 [kvm]stack backtrace: CPU: 26 PID: 330 Comm: fc_vcpu 0 Not tainted 5.16.0-rc4+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x44/0x57 kvm_notify_acked_gsi+0x6b/0x70 [kvm] kvm_notify_acked_irq+0x8d/0x180 [kvm] kvm_ioapic_update_eoi+0x92/0x240 [kvm] kvm_apic_set_eoi_accelerated+0x2a/0xe0 [kvm] handle_apic_eoi_induced+0x3d/0x60 [kvm_intel] vmx_handle_exit+0x19c/0x6a0 [kvm_intel] vcpu_enter_guest+0x66e/0x1860 [kvm] kvm_arch_vcpu_ioctl_run+0x438/0x7f0 [kvm] kvm_vcpu_ioctl+0x38a/0x6f0 [kvm] __x64_sys_ioctl+0x89/0xc0 do_syscall_64+0x3a/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xaeSince
kvm_unregister_irq_ack_notifier()doessynchronize_srcu(&kvm->irq_srcu),kvm->irq_ack_notifier_listis protected bykvm->irq_srcu. In fact,kvm->irq_srcuSRCU read lock is held inkvm_notify_acked_irq(), making it a false positive warning. So usehlist_for_each_entry_srcu()instead ofhlist_for_each_entry_rcu().Reviewed-by Sean Christopherson <[email protected]>Signed-off-by Hou Wenlong <[email protected]>Message-Id: <f98bac4f5052bad2c26df9ad50f7019e40434512.1643265976.git.houwenlong.hwl@antgroup.com>
Signed-off-by Paolo Bonzini <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- virt/kvm/eventfd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)virt/kvm/eventfd.c +4
-4@@ -451,8 +451,8 @@ bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) idx =srcu_read_lock (&kvm->irq_srcu); gsi =kvm_irq_map_chip_pin (kvm, irqchip, pin);if (gsi !=-1 ) -hlist_for_each_entry_rcu (kian, &kvm->irq_ack_notifier_list, - link) +hlist_for_each_entry_srcu (kian, &kvm->irq_ack_notifier_list, + link,srcu_read_lock_held (&kvm->irq_srcu))if (kian->gsi == gsi) {srcu_read_unlock (&kvm->irq_srcu, idx);return true;@@ -468,8 +468,8 @@ void kvm_notify_acked_gsi(struct kvm *kvm, int gsi) {struct kvm_irq_ack_notifier *kian; -hlist_for_each_entry_rcu (kian, &kvm->irq_ack_notifier_list, - link) +hlist_for_each_entry_srcu (kian, &kvm->irq_ack_notifier_list, + link,srcu_read_lock_held (&kvm->irq_srcu))if (kian->gsi == gsi) kian->irq_acked (kian); }