+++ /dev/null
-From b0d49a30728d6df9f36ca076f38160317e784a1c Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 26 Jun 2026 13:22:50 +0200
-Subject: KVM: x86: Fix shadow paging use-after-free due to unexpected role
-
-From: Paolo Bonzini <pbonzini@redhat.com>
-
-commit 81ccda30b4e83d8f5cc4fd50503c44e3a33abfeb upstream.
-
-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 729240bc00a269..3e1218abbbb757 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -2453,13 +2453,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_shadow_page(vcpu, gfn, role);
- }
-
---
-2.53.0
-