]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
7.1-stable patches master
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 25 Jul 2026 06:55:46 +0000 (08:55 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 25 Jul 2026 06:55:46 +0000 (08:55 +0200)
added patches:
kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch
kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch
kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch
kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch
risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch

queue-7.1/kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch [new file with mode: 0644]
queue-7.1/kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch [new file with mode: 0644]
queue-7.1/kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch [new file with mode: 0644]
queue-7.1/kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch [new file with mode: 0644]
queue-7.1/risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch [new file with mode: 0644]
queue-7.1/series

diff --git a/queue-7.1/kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch b/queue-7.1/kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch
new file mode 100644 (file)
index 0000000..605fb89
--- /dev/null
@@ -0,0 +1,54 @@
+From 622ebfac01ba4f9c0060cebd41257fe46fc4a0b3 Mon Sep 17 00:00:00 2001
+From: Hyunwoo Kim <imv4bel@gmail.com>
+Date: Fri, 17 Jul 2026 12:30:11 +0200
+Subject: KVM: nVMX: Hide shadow VMCS right after VMCLEAR
+
+From: Hyunwoo Kim <imv4bel@gmail.com>
+
+commit 622ebfac01ba4f9c0060cebd41257fe46fc4a0b3 upstream.
+
+free_nested() frees the shadow VMCS while vmcs01 still points to it. But
+because it is asynchronous with respect to loaded_vmcs_clear(), the vCPU
+might migrate before the pointer is cleared and __loaded_vmcs_clear()
+may then execute VMCLEAR.
+
+The VMCS needs to stay attached until its explicit VMCLEAR completes, but
+then it can be hidden and the page safely freed.
+
+Fixes: 355f4fb1405e ("kvm: nVMX: VMCLEAR an active shadow VMCS after last use")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/nested.c |   11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -336,6 +336,7 @@ static void nested_put_vmcs12_pages(stru
+ static void free_nested(struct kvm_vcpu *vcpu)
+ {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
++      struct vmcs *shadow_vmcs;
+       if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01))
+               vmx_switch_vmcs(vcpu, &vmx->vmcs01);
+@@ -353,9 +354,15 @@ static void free_nested(struct kvm_vcpu
+       vmx->nested.current_vmptr = INVALID_GPA;
+       if (enable_shadow_vmcs) {
+               vmx_disable_shadow_vmcs(vmx);
+-              vmcs_clear(vmx->vmcs01.shadow_vmcs);
+-              free_vmcs(vmx->vmcs01.shadow_vmcs);
++
++              /*
++               * Keep the pointer visible until after VMCLEAR, so migration
++               * can clear an active shadow VMCS on the old CPU.
++               */
++              shadow_vmcs = vmx->vmcs01.shadow_vmcs;
++              vmcs_clear(shadow_vmcs);
+               vmx->vmcs01.shadow_vmcs = NULL;
++              free_vmcs(shadow_vmcs);
+       }
+       kfree(vmx->nested.cached_vmcs12);
+       vmx->nested.cached_vmcs12 = NULL;
diff --git a/queue-7.1/kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch b/queue-7.1/kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch
new file mode 100644 (file)
index 0000000..637e4a9
--- /dev/null
@@ -0,0 +1,86 @@
+From 2abd5287f08319fa35764566b15c6e22cb1068db Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Mon, 13 Jul 2026 08:15:33 -0700
+Subject: KVM: x86: Check for invalid/obsolete root *after* making MMU pages available
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 2abd5287f08319fa35764566b15c6e22cb1068db upstream.
+
+Check for a "stale" page fault, i.e. for an invalid and/or obsolete root,
+after making MMU pages available for the shadow MMU.  If reclaiming shadow
+pages zaps an in-use root, i.e. marks it invalid, then KVM will attempt to
+map memory into an invalid root.  On its own, populating an invalid root is
+"fine", but because child shadow pages inherit their parent's role, any
+children created during the map/fetch will be created as invalid pages,
+thus violating KVM's invariant that invalid pages are never on the list of
+active MMU pages.
+
+Note, the underlying flaw has existed since KVM first started tracking
+invalid roots in 2008 (commit 2e53d63acba7, "KVM: MMU: ignore zapped root
+pagetables"), but the true badness only came along in 2020 (Linux 5.9)
+with the invariant that invalid shadow pages can't be on the list of
+active pages.
+
+Note #2, inheriting role.invalid when creating child shadow pages is also
+far from ideal; that flaw will be addressed separately.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Fixes: f95eec9bed76 ("KVM: x86/mmu: Don't put invalid SPs back on the list of active pages")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/mmu/mmu.c         |    9 +++++----
+ arch/x86/kvm/mmu/paging_tmpl.h |   10 ++++++----
+ 2 files changed, 11 insertions(+), 8 deletions(-)
+
+--- a/arch/x86/kvm/mmu/mmu.c
++++ b/arch/x86/kvm/mmu/mmu.c
+@@ -4837,16 +4837,17 @@ static int direct_page_fault(struct kvm_
+       if (r != RET_PF_CONTINUE)
+               return r;
+-      r = RET_PF_RETRY;
+       write_lock(&vcpu->kvm->mmu_lock);
+-      if (is_page_fault_stale(vcpu, fault))
+-              goto out_unlock;
+-
+       r = make_mmu_pages_available(vcpu);
+       if (r)
+               goto out_unlock;
++      if (is_page_fault_stale(vcpu, fault)) {
++              r = RET_PF_RETRY;
++              goto out_unlock;
++      }
++
+       r = direct_map(vcpu, fault);
+ out_unlock:
+--- a/arch/x86/kvm/mmu/paging_tmpl.h
++++ b/arch/x86/kvm/mmu/paging_tmpl.h
+@@ -827,15 +827,17 @@ static int FNAME(page_fault)(struct kvm_
+       }
+ #endif
+-      r = RET_PF_RETRY;
+       write_lock(&vcpu->kvm->mmu_lock);
+-      if (is_page_fault_stale(vcpu, fault))
+-              goto out_unlock;
+-
+       r = make_mmu_pages_available(vcpu);
+       if (r)
+               goto out_unlock;
++
++      if (is_page_fault_stale(vcpu, fault)) {
++              r = RET_PF_RETRY;
++              goto out_unlock;
++      }
++
+       r = FNAME(fetch)(vcpu, fault, &walker);
+ out_unlock:
diff --git a/queue-7.1/kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch b/queue-7.1/kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch
new file mode 100644 (file)
index 0000000..ea580d6
--- /dev/null
@@ -0,0 +1,76 @@
+From 52f2f7c30126037975389aa04d24c506a5177c35 Mon Sep 17 00:00:00 2001
+From: Phil Rosenthal <phil@phil.gs>
+Date: Sat, 18 Jul 2026 12:50:23 -0400
+Subject: KVM: x86/mmu: Fix use-after-free on vendor module reload
+
+From: Phil Rosenthal <phil@phil.gs>
+
+commit 52f2f7c30126037975389aa04d24c506a5177c35 upstream.
+
+mmu_destroy_caches() destroys pte_list_desc_cache and
+mmu_page_header_cache, but leaves both pointers unchanged.  The pointers
+live in kvm.ko, and therefore survive when a vendor module is unloaded
+while kvm.ko remains loaded.
+
+If creation of pte_list_desc_cache fails during a subsequent vendor
+module load, its assignment sets pte_list_desc_cache to NULL and the
+error path calls mmu_destroy_caches().  mmu_page_header_cache still
+points to the cache destroyed during the preceding vendor module
+unload.  Passing that stale pointer to kmem_cache_destroy() causes a
+slab use-after-free.
+
+Reproduce the issue on a v7.1.3 kernel with CONFIG_KASAN=y,
+CONFIG_KASAN_GENERIC=y, CONFIG_KVM=m, and CONFIG_KVM_INTEL=m.  A
+one-shot test hook forces pte_list_desc_cache to NULL on the second
+invocation of kvm_mmu_vendor_module_init():
+
+  1. Load kvm.ko and kvm-intel.ko, creating both caches.
+  2. Unload only kvm_intel, leaving kvm.ko loaded.
+  3. Reload kvm_intel and force initialization through the -ENOMEM path.
+
+KASAN reports:
+
+  BUG: KASAN: slab-use-after-free in
+  kvm_mmu_vendor_module_init+0x5b/0x170 [kvm]
+  ...
+  kmem_cache_destroy+0x21/0x1d0
+  kvm_mmu_vendor_module_init+0x5b/0x170 [kvm]
+  ...
+  Allocated by task 16817:
+  __kmem_cache_create_args+0x12c/0x3b0
+  __kmem_cache_create.constprop.0+0xb6/0xf0 [kvm]
+  kvm_mmu_vendor_module_init+0x13b/0x170 [kvm]
+  ...
+  Freed by task 16820:
+  kmem_cache_destroy+0x117/0x1d0
+  kvm_mmu_vendor_module_exit+0x21/0x30 [kvm]
+
+Clear both pointers immediately after destroying their caches so that
+the stored state reflects the caches' lifetime and repeated cleanup is
+safe.
+
+With the fix applied, the same injected vendor module reload fails with
+-ENOMEM as expected and produces no KASAN report.
+
+Fixes: cb498ea2ce1d ("KVM: Portability: Combine kvm_init and kvm_init_x86")
+Cc: stable@vger.kernel.org
+Signed-off-by: Phil Rosenthal <phil@phil.gs>
+Message-ID: <20260718-kvm-mmu-cache-uaf-v3-1-e103b93c74e1@phil.gs>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/mmu/mmu.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/x86/kvm/mmu/mmu.c
++++ b/arch/x86/kvm/mmu/mmu.c
+@@ -7502,7 +7502,9 @@ void kvm_mmu_invalidate_mmio_sptes(struc
+ static void mmu_destroy_caches(void)
+ {
+       kmem_cache_destroy(pte_list_desc_cache);
++      pte_list_desc_cache = NULL;
+       kmem_cache_destroy(mmu_page_header_cache);
++      mmu_page_header_cache = NULL;
+ }
+ static void kvm_wake_nx_recovery_thread(struct kvm *kvm)
diff --git a/queue-7.1/kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch b/queue-7.1/kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch
new file mode 100644 (file)
index 0000000..0e6345a
--- /dev/null
@@ -0,0 +1,64 @@
+From e800decd9c0ac4349bcd8f8f9b29fd21fe93165e Mon Sep 17 00:00:00 2001
+From: Venkatesh Srinivas <venkateshs@chromium.org>
+Date: Wed, 15 Jul 2026 23:42:35 +0000
+Subject: KVM: x86: Only reset TSC Deadline Timer in apic_timer_expired on KVM_RUN
+
+From: Venkatesh Srinivas <venkateshs@chromium.org>
+
+commit e800decd9c0ac4349bcd8f8f9b29fd21fe93165e upstream.
+
+On Intel platforms with a VMX preemption timer and APICv, if a VMM
+calls KVM_GET_LAPIC before KVM_GET_MSRS to save the vCPU state, it is
+possible to lose a pending timer interrupt.
+
+If the thread running these ioctls is migrated to another core after
+calling KVM_GET_LAPIC but before KVM_GET_MSRS and the guest is using
+their LAPIC timer in TSC-deadline mode, not only does the save LAPIC
+state not carry the pending interrupt, the TSCDEADLINE MSR will be
+zeroed.
+
+After migration across CPUs, KVM_GET_MSRS calls vcpu_load, posting the
+interrupt and clearing the MSR:
+vcpu_load() ->
+  kvm_arch_vcpu_load() ->
+    kvm_lapic_restart_hv_timer() ->
+      start_hv_timer() ->
+        apic_timer_expired() ->
+          kvm_apic_inject_pending_timer_irqs()
+            . post interrupt into the LAPIC state
+            . clear IA32_TSCDEADLINE
+
+The saved LAPIC state will be missing the pending interrupt and the saved
+MSR will be zero. Oops.
+
+Fix by only posting an interrupt when we're attempting to enter the guest
+(vcpu->wants_to_run == true), not for vcpu_load from other paths.
+
+Assisted-by: gemini:gemini-3.1-pro-preview
+Debugged-by: David Matlack <dmatlack@google.com>
+Debugged-by: Sean Christopherson <seanjc@google.com>
+Debugged-by: Jim Mattson <jmattson@google.com>
+Debugged-by: James Houghton <jthoughton@google.com>
+Signed-off-by: Venkatesh Srinivas <venkateshs@chromium.org>
+Message-ID: <20260715234234.15382-2-venkateshs@chromium.org>
+Reviewed-by: James Houghton <jthoughton@google.com>
+Reviewed-by: Chao Gao <chao.gao@intel.com>
+Cc: stable@vger.kernel.org
+Fixes: ae95f566b3d2 ("KVM: X86: TSCDEADLINE MSR emulation fastpath", 2020-05-15)
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/lapic.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -2052,7 +2052,7 @@ static void apic_timer_expired(struct kv
+       if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
+               ktimer->expired_tscdeadline = ktimer->tscdeadline;
+-      if (!from_timer_fn && apic->apicv_active) {
++      if (!from_timer_fn && apic->apicv_active && vcpu->wants_to_run) {
+               WARN_ON(kvm_get_running_vcpu() != vcpu);
+               kvm_apic_inject_pending_timer_irqs(apic);
+               return;
diff --git a/queue-7.1/risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch b/queue-7.1/risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch
new file mode 100644 (file)
index 0000000..55810d9
--- /dev/null
@@ -0,0 +1,382 @@
+From d024a0a7879e6f37c0152aacf6d8e37b214a1738 Mon Sep 17 00:00:00 2001
+From: Xie Bo <xb@ultrarisc.com>
+Date: Wed, 15 Jul 2026 10:03:59 +0800
+Subject: RISC-V: KVM: Serialize virtual interrupt pending state updates
+
+From: Xie Bo <xb@ultrarisc.com>
+
+commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream.
+
+KVM RISC-V tracks guest local interrupt state with two bitmaps:
+
+  - irqs_pending: interrupts that should be visible to the guest
+  - irqs_pending_mask: interrupts whose pending state changed
+
+The current code updates those bitmaps with independent atomic bitops
+and assumes a multiple-producer, single-consumer protocol. That model
+does not actually hold.
+
+kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest
+changes guest-visible HVIP state, sync_interrupts() writes both
+irqs_pending and irqs_pending_mask to reflect the new guest state back
+into KVM state. As a result, irqs_pending and irqs_pending_mask form a
+single logical state transition, but they are not updated atomically as
+a pair.
+
+This allows a race where a newly injected interrupt is lost. For
+example:
+
+  CPU0                              CPU1
+  ----                              ----
+  kvm_riscv_vcpu_set_interrupt(VS_SOFT)
+    set_bit(VS_SOFT, irqs_pending)
+                                    kvm_riscv_vcpu_sync_interrupts()
+                                      sees guest-cleared HVIP.VSSIP
+                                      sets irqs_pending_mask
+                                      clear_bit(IRQ_VS_SOFT, irqs_pending)
+    set_bit(VS_SOFT, irqs_pending_mask)
+    kvm_vcpu_kick()
+
+After that interleaving, a later flush can update HVIP without VSSIP
+even though a new virtual interrupt was injected. In practice, the
+guest can remain blocked in WFI with work pending.
+
+The same pending/mask protocol is shared by VS soft interrupts, PMU
+overflow delivery, and AIA high interrupt synchronization, so the race
+is not limited to one interrupt source.
+
+Fix this by serializing all updates to irqs_pending and irqs_pending_mask
+with a per-vCPU raw spinlock. This keeps the pending bit and the dirty
+mask as one state transition across:
+
+  - set/unset interrupt
+  - guest HVIP sync
+  - interrupt flush to guest CSR state
+  - vCPU reset
+  - AIA CSR writes that clear dirty state
+
+Use non-atomic bitmap operations while holding the lock. Hold the lock
+across the AIA sync, flush, and pending checks as well, so both bitmap
+words share the same serialization domain.
+
+This intentionally replaces the existing lockless protocol instead of
+trying to repair it with additional barriers. The problem is not memory
+ordering on a single field; it is that two separate bitmaps encode one
+shared state machine while both producers and sync paths can modify
+them. A per-vCPU raw spinlock keeps the fix small, local, and suitable
+for backporting.
+
+Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling")
+Cc: stable@vger.kernel.org
+Signed-off-by: Xie Bo <xb@ultrarisc.com>
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Link: https://lore.kernel.org/r/20260715020359.1521354-2-xb@ultrarisc.com
+Signed-off-by: Anup Patel <anup@brainfault.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/include/asm/kvm_host.h |   10 ++---
+ arch/riscv/kvm/aia.c              |   35 +++++++++++++++----
+ arch/riscv/kvm/vcpu.c             |   68 ++++++++++++++++++++++++++------------
+ arch/riscv/kvm/vcpu_onereg.c      |    8 +++-
+ 4 files changed, 87 insertions(+), 34 deletions(-)
+
+--- a/arch/riscv/include/asm/kvm_host.h
++++ b/arch/riscv/include/asm/kvm_host.h
+@@ -207,13 +207,13 @@ struct kvm_vcpu_arch {
+       /*
+        * VCPU interrupts
+        *
+-       * We have a lockless approach for tracking pending VCPU interrupts
+-       * implemented using atomic bitops. The irqs_pending bitmap represent
+-       * pending interrupts whereas irqs_pending_mask represent bits changed
+-       * in irqs_pending. Our approach is modeled around multiple producer
+-       * and single consumer problem where the consumer is the VCPU itself.
++       * The irqs_pending bitmap represents pending interrupts whereas
++       * irqs_pending_mask represents bits changed in irqs_pending. Updates
++       * to these bitmaps are serialized so vcpu interrupt sync/flush cannot
++       * drop a newly injected interrupt while syncing guest-visible HVIP.
+        */
+ #define KVM_RISCV_VCPU_NR_IRQS        64
++      raw_spinlock_t irqs_pending_lock;
+       DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
+       DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
+--- a/arch/riscv/kvm/aia.c
++++ b/arch/riscv/kvm/aia.c
+@@ -51,12 +51,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts
+       struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+       unsigned long mask, val;
++      lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
++
+       if (!kvm_riscv_aia_available())
+               return;
+-      if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
+-              mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
+-              val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
++      mask = vcpu->arch.irqs_pending_mask[1];
++      if (mask) {
++              vcpu->arch.irqs_pending_mask[1] = 0;
++              val = vcpu->arch.irqs_pending[1] & mask;
+               csr->hviph &= ~mask;
+               csr->hviph |= val;
+@@ -67,6 +70,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(
+ {
+       struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
++      lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
++
+       if (kvm_riscv_aia_available())
+               csr->vsieh = ncsr_read(CSR_VSIEH);
+ }
+@@ -75,13 +80,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts(
+ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
+ {
+       unsigned long seip;
++#ifdef CONFIG_32BIT
++      unsigned long flags;
++      bool pending;
++#endif
+       if (!kvm_riscv_aia_available())
+               return false;
+ #ifdef CONFIG_32BIT
+-      if (READ_ONCE(vcpu->arch.irqs_pending[1]) &
+-          (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask)))
++      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++      pending = vcpu->arch.irqs_pending[1] &
++                (vcpu->arch.aia_context.guest_csr.vsieh &
++                 upper_32_bits(mask));
++      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
++
++      if (pending)
+               return true;
+ #endif
+@@ -205,6 +219,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kv
+ {
+       struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+       unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
++#ifdef CONFIG_32BIT
++      unsigned long flags;
++#endif
+       if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
+               return -ENOENT;
+@@ -217,8 +234,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kv
+               ((unsigned long *)csr)[reg_num] = val;
+ #ifdef CONFIG_32BIT
+-              if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
+-                      WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
++              if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
++                      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++                      vcpu->arch.irqs_pending_mask[1] = 0;
++                      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
++                                                 flags);
++              }
+ #endif
+       }
+--- a/arch/riscv/kvm/vcpu.c
++++ b/arch/riscv/kvm/vcpu.c
+@@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset
+ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
+ {
++      unsigned long flags;
+       bool loaded;
+       /**
+@@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct
+       kvm_riscv_vcpu_aia_reset(vcpu);
++      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+       bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
+       bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
++      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+       kvm_riscv_vcpu_pmu_reset(vcpu);
+@@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu
+       /* Setup VCPU hfence queue */
+       spin_lock_init(&vcpu->arch.hfence_lock);
++      raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
+       spin_lock_init(&vcpu->arch.reset_state.lock);
+@@ -352,10 +356,14 @@ void kvm_riscv_vcpu_flush_interrupts(str
+ {
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       unsigned long mask, val;
++      unsigned long flags;
+-      if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
+-              mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
+-              val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
++      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++
++      mask = vcpu->arch.irqs_pending_mask[0];
++      if (mask) {
++              vcpu->arch.irqs_pending_mask[0] = 0;
++              val = vcpu->arch.irqs_pending[0] & mask;
+               csr->hvip &= ~mask;
+               csr->hvip |= val;
+@@ -363,11 +371,14 @@ void kvm_riscv_vcpu_flush_interrupts(str
+       /* Flush AIA high interrupts */
+       kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
++
++      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ }
+ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
+ {
+       unsigned long hvip;
++      unsigned long flags;
+       struct kvm_vcpu_arch *v = &vcpu->arch;
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+@@ -376,34 +387,41 @@ void kvm_riscv_vcpu_sync_interrupts(stru
+       /* Sync-up HVIP.VSSIP bit changes does by Guest */
+       hvip = ncsr_read(CSR_HVIP);
++
++      raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
++
+       if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
+               if (hvip & (1UL << IRQ_VS_SOFT)) {
+-                      if (!test_and_set_bit(IRQ_VS_SOFT,
+-                                            v->irqs_pending_mask))
+-                              set_bit(IRQ_VS_SOFT, v->irqs_pending);
++                      if (!__test_and_set_bit(IRQ_VS_SOFT,
++                                              v->irqs_pending_mask))
++                              __set_bit(IRQ_VS_SOFT, v->irqs_pending);
+               } else {
+-                      if (!test_and_set_bit(IRQ_VS_SOFT,
+-                                            v->irqs_pending_mask))
+-                              clear_bit(IRQ_VS_SOFT, v->irqs_pending);
++                      if (!__test_and_set_bit(IRQ_VS_SOFT,
++                                              v->irqs_pending_mask))
++                              __clear_bit(IRQ_VS_SOFT, v->irqs_pending);
+               }
+       }
+       /* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */
+       if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) {
+               if (!(hvip & (1UL << IRQ_PMU_OVF)) &&
+-                  !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
+-                      clear_bit(IRQ_PMU_OVF, v->irqs_pending);
++                  !__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
++                      __clear_bit(IRQ_PMU_OVF, v->irqs_pending);
+       }
+       /* Sync-up AIA high interrupts */
+       kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
++      raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
++
+       /* Sync-up timer CSRs */
+       kvm_riscv_vcpu_timer_sync(vcpu);
+ }
+ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ {
++      unsigned long flags;
++
+       /*
+        * We only allow VS-mode software, timer, and external
+        * interrupts when irq is one of the local interrupts
+@@ -416,9 +434,10 @@ int kvm_riscv_vcpu_set_interrupt(struct
+           irq != IRQ_PMU_OVF)
+               return -EINVAL;
+-      set_bit(irq, vcpu->arch.irqs_pending);
+-      smp_mb__before_atomic();
+-      set_bit(irq, vcpu->arch.irqs_pending_mask);
++      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++      __set_bit(irq, vcpu->arch.irqs_pending);
++      __set_bit(irq, vcpu->arch.irqs_pending_mask);
++      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+       kvm_vcpu_kick(vcpu);
+@@ -427,6 +446,8 @@ int kvm_riscv_vcpu_set_interrupt(struct
+ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ {
++      unsigned long flags;
++
+       /*
+        * We only allow VS-mode software, timer, counter overflow and external
+        * interrupts when irq is one of the local interrupts
+@@ -439,26 +460,33 @@ int kvm_riscv_vcpu_unset_interrupt(struc
+           irq != IRQ_PMU_OVF)
+               return -EINVAL;
+-      clear_bit(irq, vcpu->arch.irqs_pending);
+-      smp_mb__before_atomic();
+-      set_bit(irq, vcpu->arch.irqs_pending_mask);
++      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++      __clear_bit(irq, vcpu->arch.irqs_pending);
++      __set_bit(irq, vcpu->arch.irqs_pending_mask);
++      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+       return 0;
+ }
+ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
+ {
++      unsigned long flags;
+       unsigned long ie;
++      bool ret;
++      raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+       ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
+               << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
+       ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
+               (unsigned long)mask;
+-      if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie)
+-              return true;
++      ret = vcpu->arch.irqs_pending[0] & ie;
++      raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+       /* Check AIA high interrupts */
+-      return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
++      if (!ret)
++              ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
++
++      return ret;
+ }
+ void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
+--- a/arch/riscv/kvm/vcpu_onereg.c
++++ b/arch/riscv/kvm/vcpu_onereg.c
+@@ -276,6 +276,7 @@ static int kvm_riscv_vcpu_general_get_cs
+ {
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
++      unsigned long flags;
+       if (reg_num >= regs_max)
+               return -ENOENT;
+@@ -311,8 +312,11 @@ static int kvm_riscv_vcpu_general_set_cs
+       ((unsigned long *)csr)[reg_num] = reg_val;
+-      if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
+-              WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
++      if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
++              raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++              vcpu->arch.irqs_pending_mask[0] = 0;
++              raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
++      }
+       return 0;
+ }
index 24f64364a45833020c1305d708f8bdf7c3ca3785..00801c7732d8aa7b6edb1f0fa9d9d05cb4281eab 100644 (file)
@@ -2,3 +2,8 @@ platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch
 sched_ext-skip-ops.set_weight-for-disabled-tasks.patch
 drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch
 seqlock-allow-ubsan_alignment-to-fail-optimizing.patch
+risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch
+kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch
+kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch
+kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch
+kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch