]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Drop some KVM patches from 5.15
authorSasha Levin <sashal@kernel.org>
Tue, 30 Jun 2026 15:47:12 +0000 (11:47 -0400)
committerSasha Levin <sashal@kernel.org>
Tue, 30 Jun 2026 15:48:49 +0000 (11:48 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch [deleted file]
queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529 [deleted file]
queue-5.15/kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch [deleted file]
queue-5.15/kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch [deleted file]
queue-5.15/kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch [deleted file]
queue-5.15/kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch [deleted file]
queue-5.15/kvm-x86-mmu-use-a-bool-for-direct.patch [deleted file]
queue-5.15/series

diff --git a/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch b/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch
deleted file mode 100644 (file)
index 589f885..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-From c5187da0baea9ce4ae374f34426c36ca619aa217 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:17 +0200
-Subject: KVM: x86: Fix shadow paging use-after-free due to unexpected GFN
-
-From: Sean Christopherson <seanjc@google.com>
-
-commit 0cb2af2ea66ad8ff195c156ea690f11216285bdf upstream.
-
-The shadow MMU computes GFNs for direct shadow pages using sp->gfn plus
-the SPTE index. This assumption breaks for shadow paging if the guest
-page tables are modified between VM entries (similar to commit
-aad885e77496, "KVM: x86/mmu: Drop/zap existing present SPTE even
-when creating an MMIO SPTE", 2026-03-27).  The flow is as follows:
-
-- a PDE is installed for a 2MB mapping, and a page in that area is
-  accessed.  KVM creates a kvm_mmu_page consisting of 512 4KB pages;
-  the kvm_mmu_page is marked by FNAME(fetch) as direct-mapped because
-  the guest's mapping is a huge page (and thus contiguous).
-
-- the PDE mapping is changed from outside the guest.
-
-- the guest accesses another page in the same 2MB area.  KVM installs
-  a new leaf SPTE and rmap entry; the SPTE uses the "correct" GFN
-  (i.e. based on the new mapping, as changed in the previous step) but
-  that GFN is outside of the [sp->gfn, sp->gfn + 511] range; therefore
-  the rmap entry cannot be found and removed when the kvm_mmu_page
-  is zapped.
-
-- the memslot that covers the first 2MB mapping is deleted, and the
-  kvm_mmu_page for the now-invalid GPA is zapped.  However, rmap_remove()
-  only looks at the [sp->gfn, sp->gfn + 511] range established in step 1,
-  and fails to find the rmap entry that was recorded by step 3.
-
-- any operation that causes an rmap walk for the same page accessed
-  by step 3 then walks a stale rmap and dereferences a freed kvm_mmu_page.
-  This includes dirty logging or MMU notifier invalidations (e.g., from
-  MADV_DONTNEED).
-
-The underlying issue is that KVM's walking of shadow PTEs assumes that
-if a SPTE is present when KVM wants to install a non-leaf SPTE, then the
-existing kvm_mmu_page must be for the correct gfn.  Because the only way
-for the gfn to be wrong is if KVM messed up and failed to zap a SPTE...
-which shouldn't happen, but *actually* only happens in response to a
-guest write.
-
-That bug dates back literally forever, as even the first version of KVM
-assumes that the GFN matches and walks into the "wrong" shadow page.
-However, that was only an imprecision until 2032a93d66fa ("KVM: MMU:
-Don't allocate gfns page for direct mmu pages") came along.
-
-Fix it by checking for a target gfn mismatch and zapping the existing
-SPTE.  That way the old SP and rmap entries are gone, KVM installs
-the rmap in the right location, and everyone is happy.
-
-Fixes: 2032a93d66fa ("KVM: MMU: Don't allocate gfns page for direct mmu pages")
-Fixes: 6aa8b732ca01 ("kvm: userspace interface")
-Reported-by: Alexander Bulekov <bkov@amazon.com>
-Reported-by: Fred Griffoul <fgriffo@amazon.co.uk>
-Cc: stable@vger.kernel.org
-Signed-off-by: Sean Christopherson <seanjc@google.com>
-Link: https://patch.msgid.link/20260503201029.106481-1-pbonzini@redhat.com/
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c  | 33 ++++++++++++++-------------------
- arch/x86/kvm/mmu/spte.h |  5 +++++
- 2 files changed, 19 insertions(+), 19 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index d58be2e698f795..6c9656b8062e4e 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -188,6 +188,8 @@ static struct percpu_counter kvm_total_used_mmu_pages;
- static void mmu_spte_set(u64 *sptep, u64 spte);
- static union kvm_mmu_page_role
- kvm_mmu_calc_root_page_role(struct kvm_vcpu *vcpu);
-+static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,
-+                          u64 *spte, struct list_head *invalid_list);
- struct kvm_mmu_role_regs {
-       const unsigned long cr0;
-@@ -1179,18 +1181,6 @@ static void drop_spte(struct kvm *kvm, u64 *sptep)
-               rmap_remove(kvm, sptep);
- }
--static void drop_large_spte(struct kvm *kvm, u64 *sptep)
--{
--      struct kvm_mmu_page *sp;
--
--      sp = sptep_to_sp(sptep);
--      WARN_ON(sp->role.level == PG_LEVEL_4K);
--
--      drop_spte(kvm, sptep);
--      kvm_flush_remote_tlbs_with_address(kvm, sp->gfn,
--                      KVM_PAGES_PER_HPAGE(sp->role.level));
--}
--
- /*
-  * Write-protect on the specified @sptep, @pt_protect indicates whether
-  * spte write-protection is caused by protecting shadow page table.
-@@ -2187,7 +2177,8 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
- {
-       union kvm_mmu_page_role role;
--      if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
-+      if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
-+          spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
-               return ERR_PTR(-EEXIST);
-       role = kvm_mmu_child_role(sptep, direct, access);
-@@ -2265,12 +2256,16 @@ static void __link_shadow_page(struct kvm_vcpu *vcpu,
-       BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
--      /*
--       * If an SPTE is present already, it must be a leaf and therefore
--       * a large one.  Drop it and flush the TLB before installing sp.
--       */
--      if (is_shadow_present_pte(*sptep))
--              drop_large_spte(vcpu->kvm, sptep);
-+      if (is_shadow_present_pte(*sptep)) {
-+              struct kvm_mmu_page *parent_sp;
-+              LIST_HEAD(invalid_list);
-+
-+              parent_sp = sptep_to_sp(sptep);
-+              WARN_ON_ONCE(parent_sp->role.level == PG_LEVEL_4K);
-+
-+              mmu_page_zap_pte(vcpu->kvm, parent_sp, sptep, &invalid_list);
-+              kvm_mmu_remote_flush_or_zap(vcpu->kvm, &invalid_list, true);
-+      }
-       spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp));
-diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h
-index 31d6456d8ac333..31d03d15415c01 100644
---- a/arch/x86/kvm/mmu/spte.h
-+++ b/arch/x86/kvm/mmu/spte.h
-@@ -267,6 +267,11 @@ static inline bool is_executable_pte(u64 spte)
-       return (spte & (shadow_x_mask | shadow_nx_mask)) == shadow_x_mask;
- }
-+static inline struct kvm_mmu_page *spte_to_child_sp(u64 spte)
-+{
-+      return to_shadow_page(spte & PT64_BASE_ADDR_MASK);
-+}
-+
- static inline kvm_pfn_t spte_to_pfn(u64 pte)
- {
-       return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
--- 
-2.53.0
-
diff --git a/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529 b/queue-5.15/kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529
deleted file mode 100644 (file)
index 772f811..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-From 6d15eee7dcdbc7794d7e83bb36847eeeea7d4938 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:18 +0200
-Subject: KVM: x86: Fix shadow paging use-after-free due to unexpected role
-
-From: Paolo Bonzini <pbonzini@redhat.com>
-
-[ Upstream commit 81ccda30b4e83d8f5cc4fd50503c44e3a33abfeb ]
-
-Commit 0cb2af2ea66ad ("KVM: x86: Fix shadow paging use-after-free due
-to unexpected GFN") fixed a shadow paging mismatch between stored and
-computed GFNs; the bug could be triggered by changing a PDE mapping from
-outside the guest, and then deleting a memslot.  The rmap_remove()
-call would miss entries created after the PDE change because the GFN
-of the leaf SPTE does not match the GFN of the struct kvm_mmu_page.
-
-A similar hole however remains if the modified PDE points to a non-leaf
-page.  In this case the gfn can be made to match, but the role does not
-match: the original large 2MB page creates a kvm_mmu_page with direct=1,
-while the new 4KB needs a kvm_mmu_page with direct=0.  However,
-kvm_mmu_get_child_sp() does not compare the role, and therefore reuses
-the page.
-
-The next step is installing a leaf (4KB) SPTE on the new path which
-records an rmap entry under the gfn resolved by the walk.  But when
-that child is zapped its parent kvm_mmu_page has direct=1 and
-kvm_mmu_page_get_gfn() computes the gfn for the 4KB page as
-sp->gfn + index instead of using sp->shadowed_translation[] (or sp->gfns[]
-in older kernels).  It therefore fails to remove the recorded entry.
-
-When the memslot is dropped the shadow page is freed but the rmap
-entry survives, as in the scenario that was already fixed.  Code that
-later walks that gfn (dirty logging, MMU notifier invalidation, and
-so on) dereferences an sptep that lies in the freed page, causing the
-use-after-free.
-
-Fixes: 2032a93d66fa ("KVM: MMU: Don't allocate gfns page for direct mmu pages")
-Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index 6c9656b8062e4e..e9dbe3e7ec622f 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -2175,13 +2175,15 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
-                                                u64 *sptep, gfn_t gfn,
-                                                bool direct, unsigned int access)
- {
--      union kvm_mmu_page_role role;
-+      union kvm_mmu_page_role role = kvm_mmu_child_role(sptep, direct, access);
--      if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
--          spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
-+      if (is_shadow_present_pte(*sptep) &&
-+          !is_large_pte(*sptep) &&
-+          spte_to_child_sp(*sptep) &&
-+          spte_to_child_sp(*sptep)->gfn == gfn &&
-+          spte_to_child_sp(*sptep)->role.word == role.word)
-               return ERR_PTR(-EEXIST);
--      role = kvm_mmu_child_role(sptep, direct, access);
-       return kvm_mmu_get_page(vcpu, gfn, role);
- }
--- 
-2.53.0
-
diff --git a/queue-5.15/kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch b/queue-5.15/kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch
deleted file mode 100644 (file)
index b3502dc..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-From cd2b29b10c0f8055c823c5df970fb98e897f65b9 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:15 +0200
-Subject: KVM: x86/mmu: Always pass 0 for @quadrant when gptes are 8 bytes
-
-From: Paolo Bonzini <pbonzini@redhat.com>
-
-commit 7f49777550e55a7d6832cbb0873f48f91c175b9c upstream.
-
-The quadrant is only used when gptes are 4 bytes, but
-mmu_alloc_{direct,shadow}_roots() pass in a non-zero quadrant for PAE
-page directories regardless. Make this less confusing by only passing in
-a non-zero quadrant when it is actually necessary.
-
-Signed-off-by: David Matlack <dmatlack@google.com>
-Message-Id: <20220516232138.1783324-6-dmatlack@google.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c | 20 ++++++++++++++------
- 1 file changed, 14 insertions(+), 6 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index 3a5ed967037765..dbc18d4cc572c1 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -3444,9 +3444,10 @@ static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant,
-       struct kvm_mmu_page *sp;
-       role.level = level;
-+      role.quadrant = quadrant;
--      if (!role.gpte_is_8_bytes)
--              role.quadrant = quadrant;
-+      WARN_ON_ONCE(quadrant && role.gpte_is_8_bytes);
-+      WARN_ON_ONCE(role.direct && !role.gpte_is_8_bytes);
-       sp = kvm_mmu_get_page(vcpu, gfn, role);
-       ++sp->root_count;
-@@ -3482,7 +3483,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
-               for (i = 0; i < 4; ++i) {
-                       WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i]));
--                      root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), i,
-+                      root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), 0,
-                                             PT32_ROOT_LEVEL);
-                       mmu->pae_root[i] = root | PT_PRESENT_MASK |
-                                          shadow_me_mask;
-@@ -3506,9 +3507,8 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
-       struct kvm_mmu *mmu = vcpu->arch.mmu;
-       u64 pdptrs[4], pm_mask;
-       gfn_t root_gfn, root_pgd;
-+      int quadrant, i, r;
-       hpa_t root;
--      unsigned i;
--      int r;
-       root_pgd = mmu->get_guest_pgd(vcpu);
-       root_gfn = root_pgd >> PAGE_SHIFT;
-@@ -3591,7 +3591,15 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
-                       root_gfn = pdptrs[i] >> PAGE_SHIFT;
-               }
--              root = mmu_alloc_root(vcpu, root_gfn, i, PT32_ROOT_LEVEL);
-+              /*
-+               * If shadowing 32-bit non-PAE page tables, each PAE page
-+               * directory maps one quarter of the guest's non-PAE page
-+               * directory. Othwerise each PAE page direct shadows one guest
-+               * PAE page directory so that quadrant should be 0.
-+               */
-+              quadrant = !mmu->mmu_role.base.gpte_is_8_bytes ? i : 0;
-+
-+              root = mmu_alloc_root(vcpu, root_gfn, quadrant, PT32_ROOT_LEVEL);
-               mmu->pae_root[i] = root | pm_mask;
-       }
--- 
-2.53.0
-
diff --git a/queue-5.15/kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch b/queue-5.15/kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch
deleted file mode 100644 (file)
index 77edb26..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-From 3776b66e4f8c1d6c8b888792cf8a31987b316bd6 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:14 +0200
-Subject: KVM: x86/mmu: Derive shadow MMU page role from parent
-
-From: Paolo Bonzini <pbonzini@redhat.com>
-
-commit 2e65e842c57d72e9a573ba42bc2055b7f626ea1f upstream.
-
-Instead of computing the shadow page role from scratch for every new
-page, derive most of the information from the parent shadow page.  This
-eliminates the dependency on the vCPU root role to allocate shadow page
-tables, and reduces the number of parameters to kvm_mmu_get_page().
-
-Preemptively split out the role calculation to a separate function for
-use in a following commit.
-
-Note that when calculating the MMU root role, we can take
-@role.passthrough, @role.direct, and @role.access directly from
-@vcpu->arch.mmu->root_role. Only @role.level and @role.quadrant still
-must be overridden for PAE page directories, when shadowing 32-bit
-guest page tables with PAE page tables.
-
-No functional change intended.
-
-Reviewed-by: Peter Xu <peterx@redhat.com>
-Signed-off-by: David Matlack <dmatlack@google.com>
-Message-Id: <20220516232138.1783324-5-dmatlack@google.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c         | 99 ++++++++++++++++++++++------------
- arch/x86/kvm/mmu/paging_tmpl.h |  9 ++--
- 2 files changed, 71 insertions(+), 37 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index bd7650380ad9e7..3a5ed967037765 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -2070,33 +2070,15 @@ static void clear_sp_write_flooding_count(u64 *spte)
-       __clear_sp_write_flooding_count(sptep_to_sp(spte));
- }
--static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
--                                           gfn_t gfn,
--                                           gva_t gaddr,
--                                           unsigned level,
--                                           bool direct,
--                                           unsigned int access)
-+static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn,
-+                                           union kvm_mmu_page_role role)
- {
-       bool direct_mmu = vcpu->arch.mmu->direct_map;
--      union kvm_mmu_page_role role;
-       struct hlist_head *sp_list;
--      unsigned quadrant;
-       struct kvm_mmu_page *sp;
-       int collisions = 0;
-       LIST_HEAD(invalid_list);
--      role = vcpu->arch.mmu->mmu_role.base;
--      role.level = level;
--      role.direct = direct;
--      if (role.direct)
--              role.gpte_is_8_bytes = true;
--      role.access = access;
--      if (!direct_mmu && vcpu->arch.mmu->root_level <= PT32_ROOT_LEVEL) {
--              quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
--              quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
--              role.quadrant = quadrant;
--      }
--
-       sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)];
-       for_each_valid_sp(vcpu->kvm, sp, sp_list) {
-               if (sp->gfn != gfn) {
-@@ -2114,7 +2096,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
-                        * Unsync pages must not be left as is, because the new
-                        * upper-level page will be write-protected.
-                        */
--                      if (level > PG_LEVEL_4K && sp->unsync)
-+                      if (role.level > PG_LEVEL_4K && sp->unsync)
-                               kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
-                                                        &invalid_list);
-                       continue;
-@@ -2152,14 +2134,14 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
-       ++vcpu->kvm->stat.mmu_cache_miss;
--      sp = kvm_mmu_alloc_page(vcpu, direct);
-+      sp = kvm_mmu_alloc_page(vcpu, role.direct);
-       sp->gfn = gfn;
-       sp->role = role;
-       hlist_add_head(&sp->hash_link, sp_list);
--      if (!direct) {
-+      if (!role.direct) {
-               account_shadowed(vcpu->kvm, sp);
--              if (level == PG_LEVEL_4K && rmap_write_protect(vcpu, gfn))
-+              if (role.level == PG_LEVEL_4K && rmap_write_protect(vcpu, gfn))
-                       kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn, 1);
-       }
-       trace_kvm_mmu_get_page(sp, true);
-@@ -2171,6 +2153,54 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
-       return sp;
- }
-+static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsigned int access)
-+{
-+      struct kvm_mmu_page *parent_sp = sptep_to_sp(sptep);
-+      union kvm_mmu_page_role role;
-+
-+      role = parent_sp->role;
-+      role.level--;
-+      role.access = access;
-+      role.direct = direct;
-+
-+      /*
-+       * If the guest has 4-byte PTEs then that means it's using 32-bit,
-+       * 2-level, non-PAE paging. KVM shadows such guests with PAE paging
-+       * (i.e. 8-byte PTEs). The difference in PTE size means that KVM must
-+       * shadow each guest page table with multiple shadow page tables, which
-+       * requires extra bookkeeping in the role.
-+       *
-+       * Specifically, to shadow the guest's page directory (which covers a
-+       * 4GiB address space), KVM uses 4 PAE page directories, each mapping
-+       * 1GiB of the address space. @role.quadrant encodes which quarter of
-+       * the address space each maps.
-+       *
-+       * To shadow the guest's page tables (which each map a 4MiB region), KVM
-+       * uses 2 PAE page tables, each mapping a 2MiB region. For these,
-+       * @role.quadrant encodes which half of the region they map.
-+       *
-+       * Note, the 4 PAE page directories are pre-allocated and the quadrant
-+       * assigned in mmu_alloc_root(). So only page tables need to be handled
-+       * here.
-+       */
-+      if (!role.gpte_is_8_bytes) {
-+              WARN_ON_ONCE(role.level != PG_LEVEL_4K);
-+              role.quadrant = (sptep - parent_sp->spt) % 2;
-+      }
-+
-+      return role;
-+}
-+
-+static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
-+                                               u64 *sptep, gfn_t gfn,
-+                                               bool direct, unsigned int access)
-+{
-+      union kvm_mmu_page_role role;
-+
-+      role = kvm_mmu_child_role(sptep, direct, access);
-+      return kvm_mmu_get_page(vcpu, gfn, role);
-+}
-+
- static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterator,
-                                       struct kvm_vcpu *vcpu, hpa_t root,
-                                       u64 addr)
-@@ -3013,8 +3043,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
-               if (is_shadow_present_pte(*it.sptep))
-                       continue;
--              sp = kvm_mmu_get_page(vcpu, base_gfn, it.addr,
--                                    it.level - 1, true, ACC_ALL);
-+              sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, true, ACC_ALL);
-               link_shadow_page(vcpu, it.sptep, sp);
-               if (is_tdp && huge_page_disallowed &&
-@@ -3408,13 +3437,18 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
-       return ret;
- }
--static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva,
-+static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant,
-                           u8 level)
- {
--      bool direct = vcpu->arch.mmu->mmu_role.base.direct;
-+      union kvm_mmu_page_role role = vcpu->arch.mmu->mmu_role.base;
-       struct kvm_mmu_page *sp;
--      sp = kvm_mmu_get_page(vcpu, gfn, gva, level, direct, ACC_ALL);
-+      role.level = level;
-+
-+      if (!role.gpte_is_8_bytes)
-+              role.quadrant = quadrant;
-+
-+      sp = kvm_mmu_get_page(vcpu, gfn, role);
-       ++sp->root_count;
-       return __pa(sp->spt);
-@@ -3448,8 +3482,8 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
-               for (i = 0; i < 4; ++i) {
-                       WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i]));
--                      root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT),
--                                            i << 30, PT32_ROOT_LEVEL);
-+                      root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), i,
-+                                            PT32_ROOT_LEVEL);
-                       mmu->pae_root[i] = root | PT_PRESENT_MASK |
-                                          shadow_me_mask;
-               }
-@@ -3557,8 +3591,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
-                       root_gfn = pdptrs[i] >> PAGE_SHIFT;
-               }
--              root = mmu_alloc_root(vcpu, root_gfn, i << 30,
--                                    PT32_ROOT_LEVEL);
-+              root = mmu_alloc_root(vcpu, root_gfn, i, PT32_ROOT_LEVEL);
-               mmu->pae_root[i] = root | pm_mask;
-       }
-diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
-index a1811f51eda925..cc70cbb3f261ba 100644
---- a/arch/x86/kvm/mmu/paging_tmpl.h
-+++ b/arch/x86/kvm/mmu/paging_tmpl.h
-@@ -704,8 +704,9 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
-               if (!is_shadow_present_pte(*it.sptep)) {
-                       table_gfn = gw->table_gfn[it.level - 2];
-                       access = gw->pt_access[it.level - 2];
--                      sp = kvm_mmu_get_page(vcpu, table_gfn, addr,
--                                            it.level-1, false, access);
-+                      sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn,
-+                                                false, access);
-+
-                       /*
-                        * We must synchronize the pagetable before linking it
-                        * because the guest doesn't need to flush tlb when
-@@ -763,8 +764,8 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
-               drop_large_spte(vcpu, it.sptep);
-               if (!is_shadow_present_pte(*it.sptep)) {
--                      sp = kvm_mmu_get_page(vcpu, base_gfn, addr,
--                                            it.level - 1, true, direct_access);
-+                      sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn,
-+                                                true, direct_access);
-                       link_shadow_page(vcpu, it.sptep, sp);
-                       if (huge_page_disallowed && req_level >= it.level)
-                               account_huge_nx_page(vcpu->kvm, sp);
--- 
-2.53.0
-
diff --git a/queue-5.15/kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch b/queue-5.15/kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch
deleted file mode 100644 (file)
index 920b801..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-From bcc6397d244844807014d82fa65afa416d431f0b Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:16 +0200
-Subject: KVM: x86/mmu: pull call to drop_large_spte() into
- __link_shadow_page()
-
-From: Paolo Bonzini <pbonzini@redhat.com>
-
-commit 0cd8dc739833080aa0813cbd94d907a93e3a14c3 upstream.
-
-Before allocating a child shadow page table, all callers check
-whether the parent already points to a huge page and, if so, they
-drop that SPTE.  This is done by drop_large_spte().
-
-However, dropping the large SPTE is really only necessary before the
-sp is installed.  While the sp is returned by kvm_mmu_get_child_sp(),
-installing it happens later in __link_shadow_page().  Move the call
-there instead of having it in each and every caller.
-
-To ensure that the shadow page is not linked twice if it was present,
-do _not_ opportunistically make kvm_mmu_get_child_sp() idempotent:
-instead, return an error value if the shadow page already existed.
-This is a bit more verbose, but clearer than NULL.
-
-Finally, now that the drop_large_spte() name is not taken anymore,
-remove the two underscores in front of __drop_large_spte().
-
-Reviewed-by: Sean Christopherson <seanjc@google.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c         | 49 +++++++++++++++++++---------------
- arch/x86/kvm/mmu/paging_tmpl.h | 29 +++++++++-----------
- 2 files changed, 40 insertions(+), 38 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index dbc18d4cc572c1..d58be2e698f795 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -1179,26 +1179,16 @@ static void drop_spte(struct kvm *kvm, u64 *sptep)
-               rmap_remove(kvm, sptep);
- }
--
--static bool __drop_large_spte(struct kvm *kvm, u64 *sptep)
-+static void drop_large_spte(struct kvm *kvm, u64 *sptep)
- {
--      if (is_large_pte(*sptep)) {
--              WARN_ON(sptep_to_sp(sptep)->role.level == PG_LEVEL_4K);
--              drop_spte(kvm, sptep);
--              return true;
--      }
--
--      return false;
--}
-+      struct kvm_mmu_page *sp;
--static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep)
--{
--      if (__drop_large_spte(vcpu->kvm, sptep)) {
--              struct kvm_mmu_page *sp = sptep_to_sp(sptep);
-+      sp = sptep_to_sp(sptep);
-+      WARN_ON(sp->role.level == PG_LEVEL_4K);
--              kvm_flush_remote_tlbs_with_address(vcpu->kvm, sp->gfn,
-+      drop_spte(kvm, sptep);
-+      kvm_flush_remote_tlbs_with_address(kvm, sp->gfn,
-                       KVM_PAGES_PER_HPAGE(sp->role.level));
--      }
- }
- /*
-@@ -2197,6 +2187,9 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
- {
-       union kvm_mmu_page_role role;
-+      if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
-+              return ERR_PTR(-EEXIST);
-+
-       role = kvm_mmu_child_role(sptep, direct, access);
-       return kvm_mmu_get_page(vcpu, gfn, role);
- }
-@@ -2264,13 +2257,21 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator)
-       __shadow_walk_next(iterator, *iterator->sptep);
- }
--static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
--                           struct kvm_mmu_page *sp)
-+static void __link_shadow_page(struct kvm_vcpu *vcpu,
-+                             struct kvm_mmu_memory_cache *cache, u64 *sptep,
-+                             struct kvm_mmu_page *sp)
- {
-       u64 spte;
-       BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
-+      /*
-+       * If an SPTE is present already, it must be a leaf and therefore
-+       * a large one.  Drop it and flush the TLB before installing sp.
-+       */
-+      if (is_shadow_present_pte(*sptep))
-+              drop_large_spte(vcpu->kvm, sptep);
-+
-       spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp));
-       mmu_spte_set(sptep, spte);
-@@ -2281,6 +2282,12 @@ static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
-               mark_unsync(sptep);
- }
-+static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
-+                           struct kvm_mmu_page *sp)
-+{
-+      __link_shadow_page(vcpu, &vcpu->arch.mmu_pte_list_desc_cache, sptep, sp);
-+}
-+
- static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
-                                  unsigned direct_access)
- {
-@@ -3039,11 +3046,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
-               if (it.level == level)
-                       break;
--              drop_large_spte(vcpu, it.sptep);
--              if (is_shadow_present_pte(*it.sptep))
--                      continue;
--
-               sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, true, ACC_ALL);
-+              if (sp == ERR_PTR(-EEXIST))
-+                      continue;
-               link_shadow_page(vcpu, it.sptep, sp);
-               if (is_tdp && huge_page_disallowed &&
-diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
-index cc70cbb3f261ba..0f68f5afa642c8 100644
---- a/arch/x86/kvm/mmu/paging_tmpl.h
-+++ b/arch/x86/kvm/mmu/paging_tmpl.h
-@@ -698,15 +698,13 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
-               gfn_t table_gfn;
-               clear_sp_write_flooding_count(it.sptep);
--              drop_large_spte(vcpu, it.sptep);
--              sp = NULL;
--              if (!is_shadow_present_pte(*it.sptep)) {
--                      table_gfn = gw->table_gfn[it.level - 2];
--                      access = gw->pt_access[it.level - 2];
--                      sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn,
--                                                false, access);
-+              table_gfn = gw->table_gfn[it.level - 2];
-+              access = gw->pt_access[it.level - 2];
-+              sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn,
-+                                        false, access);
-+              if (sp != ERR_PTR(-EEXIST)) {
-                       /*
-                        * We must synchronize the pagetable before linking it
-                        * because the guest doesn't need to flush tlb when
-@@ -735,7 +733,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
-               if (FNAME(gpte_changed)(vcpu, gw, it.level - 1))
-                       goto out_gpte_changed;
--              if (sp)
-+              if (sp != ERR_PTR(-EEXIST))
-                       link_shadow_page(vcpu, it.sptep, sp);
-       }
-@@ -761,15 +759,14 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr,
-               validate_direct_spte(vcpu, it.sptep, direct_access);
--              drop_large_spte(vcpu, it.sptep);
-+              sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn,
-+                                        true, direct_access);
-+              if (sp == ERR_PTR(-EEXIST))
-+                      continue;
--              if (!is_shadow_present_pte(*it.sptep)) {
--                      sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn,
--                                                true, direct_access);
--                      link_shadow_page(vcpu, it.sptep, sp);
--                      if (huge_page_disallowed && req_level >= it.level)
--                              account_huge_nx_page(vcpu->kvm, sp);
--              }
-+              link_shadow_page(vcpu, it.sptep, sp);
-+              if (huge_page_disallowed && req_level >= it.level)
-+                      account_huge_nx_page(vcpu->kvm, sp);
-       }
-       ret = mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault,
--- 
-2.53.0
-
diff --git a/queue-5.15/kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch b/queue-5.15/kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch
deleted file mode 100644 (file)
index ef4721e..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-From 18d012c4f2b01a72e0682e509dad85caf3248d11 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:13 +0200
-Subject: KVM: x86/mmu: Stop passing "direct" to mmu_alloc_root()
-
-From: David Matlack <dmatlack@google.com>
-
-commit 86938ab6925b8fe174ca6abf397e6ea9d3c054a4 upstream.
-
-The "direct" argument is vcpu->arch.mmu->root_role.direct,
-because unlike non-root page tables, it's impossible to have
-a direct root in an indirect MMU.  So just use that.
-
-Suggested-by: Lai Jiangshan <jiangshanlai@gmail.com>
-Signed-off-by: David Matlack <dmatlack@google.com>
-Message-Id: <20220516232138.1783324-4-dmatlack@google.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index c03c4341a87fd7..bd7650380ad9e7 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -3409,8 +3409,9 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
- }
- static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva,
--                          u8 level, bool direct)
-+                          u8 level)
- {
-+      bool direct = vcpu->arch.mmu->mmu_role.base.direct;
-       struct kvm_mmu_page *sp;
-       sp = kvm_mmu_get_page(vcpu, gfn, gva, level, direct, ACC_ALL);
-@@ -3436,7 +3437,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
-               root = kvm_tdp_mmu_get_vcpu_root_hpa(vcpu);
-               mmu->root_hpa = root;
-       } else if (shadow_root_level >= PT64_ROOT_4LEVEL) {
--              root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level, true);
-+              root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level);
-               mmu->root_hpa = root;
-       } else if (shadow_root_level == PT32E_ROOT_LEVEL) {
-               if (WARN_ON_ONCE(!mmu->pae_root)) {
-@@ -3448,7 +3449,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
-                       WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i]));
-                       root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT),
--                                            i << 30, PT32_ROOT_LEVEL, true);
-+                                            i << 30, PT32_ROOT_LEVEL);
-                       mmu->pae_root[i] = root | PT_PRESENT_MASK |
-                                          shadow_me_mask;
-               }
-@@ -3511,7 +3512,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
-        */
-       if (mmu->root_level >= PT64_ROOT_4LEVEL) {
-               root = mmu_alloc_root(vcpu, root_gfn, 0,
--                                    mmu->shadow_root_level, false);
-+                                    mmu->shadow_root_level);
-               mmu->root_hpa = root;
-               goto set_root_pgd;
-       }
-@@ -3557,7 +3558,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
-               }
-               root = mmu_alloc_root(vcpu, root_gfn, i << 30,
--                                    PT32_ROOT_LEVEL, false);
-+                                    PT32_ROOT_LEVEL);
-               mmu->pae_root[i] = root | pm_mask;
-       }
--- 
-2.53.0
-
diff --git a/queue-5.15/kvm-x86-mmu-use-a-bool-for-direct.patch b/queue-5.15/kvm-x86-mmu-use-a-bool-for-direct.patch
deleted file mode 100644 (file)
index 3798122..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-From 88a03cd0c1f9927e56dc6fd8cb5dc4c44b2666d8 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 19:46:12 +0200
-Subject: KVM: x86/mmu: Use a bool for direct
-
-From: David Matlack <dmatlack@google.com>
-
-commit 27a59d57f073f21f029df1517c2c0a1abea5b0ce upstream.
-
-The parameter "direct" can either be true or false, and all of the
-callers pass in a bool variable or true/false literal, so just use the
-type bool.
-
-No functional change intended.
-
-Reviewed-by: Lai Jiangshan <jiangshanlai@gmail.com>
-Reviewed-by: Sean Christopherson <seanjc@google.com>
-Signed-off-by: David Matlack <dmatlack@google.com>
-Message-Id: <20220516232138.1783324-3-dmatlack@google.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- arch/x86/kvm/mmu/mmu.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index e4813964bfa07a..c03c4341a87fd7 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -1737,7 +1737,7 @@ static void drop_parent_pte(struct kvm_mmu_page *sp,
-       mmu_spte_clear_no_track(parent_pte);
- }
--static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct)
-+static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, bool direct)
- {
-       struct kvm_mmu_page *sp;
-@@ -2074,7 +2074,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
-                                            gfn_t gfn,
-                                            gva_t gaddr,
-                                            unsigned level,
--                                           int direct,
-+                                           bool direct,
-                                            unsigned int access)
- {
-       bool direct_mmu = vcpu->arch.mmu->direct_map;
--- 
-2.53.0
-
index 0a9cc78a3f876bc1d728e9b606935c3b84fd4ad2..0aa956bebf49570eedd878cdf87865cd5a8d3532 100644 (file)
@@ -23,13 +23,6 @@ media-vidtv-fix-null-pointer-dereference-in-vidtv_mux_push_si.patch
 virtiofs-fix-uaf-on-submount-umount.patch
 revert-selftest-ptp-update-ptp-selftest-to-exercise-.patch
 revert-ptp-add-testptp-mask-test.patch
-kvm-x86-mmu-use-a-bool-for-direct.patch
-kvm-x86-mmu-stop-passing-direct-to-mmu_alloc_root.patch
-kvm-x86-mmu-derive-shadow-mmu-page-role-from-parent.patch
-kvm-x86-mmu-always-pass-0-for-quadrant-when-gptes-ar.patch
-kvm-x86-mmu-pull-call-to-drop_large_spte-into-__link.patch
-kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch
-kvm-x86-fix-shadow-paging-use-after-free-due-to-unex.patch-23529
 kvm-x86-mmu-ensure-hugepage-is-in-by-slot-before-che.patch
 kselftest-arm64-signal-skip-sve-signal-test-if-not-e.patch
 batman-adv-tp_meter-keep-unacked-list-in-ascending-o.patch