CVE-2026-89928 Overview
CVE-2026-89928 is a use-after-free vulnerability in the Linux kernel's Kernel-based Virtual Machine (KVM) x86 Memory Management Unit (MMU) subsystem. The flaw resides in the lockless reverse map (rmap) walk performed by kvm_rmap_age_gfn_range(). When __kvm_rmap_lock() elides the rmap lock on an empty rmap, the aging path ignores the returned value and re-reads rmap_head->val through rmap_get_first(). A concurrent writer holding mmu_lock can populate and then free the pte_list_desc chain via kmem_cache_free() while the walker traverses it, producing a slab use-after-free on hosts built with CONFIG_KVM_MMU_LOCKLESS_AGING=y.
Critical Impact
A local attacker with the ability to trigger KVM MMU aging on a system hosting virtual machines can induce a slab use-after-free, potentially leading to kernel memory corruption and privilege escalation.
Affected Products
- Linux kernel builds enabling KVM x86 with CONFIG_KVM_MMU_LOCKLESS_AGING=y
- Hypervisor hosts running KVM on x86 architectures
- Distributions shipping affected upstream kernel revisions prior to the referenced fix commits
Discovery Timeline
- 2026-09-16 - CVE-2026-89928 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-89928
Vulnerability Analysis
The vulnerability lives in KVM's x86 shadow paging code path used for tracking guest page accesses. __kvm_rmap_lock() deliberately skips taking the rmap lock when it observes an empty rmap. In that case kvm_rmap_lock_readonly() also re-enables preemption and returns zero, so the caller holds neither the rmap lock nor a preemption reference.
The elision documents an invariant: lockless readers cannot walk empty rmaps, and only writers holding mmu_lock for write manipulate them. However, kvm_rmap_age_gfn_range() discards the value returned by the lock helper and unconditionally invokes for_each_rmap_spte_lockless(). The iterator internally calls rmap_get_first(), which re-reads rmap_head->val a second time.
Between those two reads a writer can install a KVM_RMAP_MANY rmap containing a pte_list_desc chain. Because preemption was re-enabled, the window between the two reads can span an arbitrary scheduling delay, making the race practical to hit under load.
Root Cause
The root cause is a lock-elision invariant violation: the lockless walker re-reads shared state instead of consuming the value that the lock helper already sampled. This breaks the guarantee that empty-rmap fast paths remain mutually exclusive with writers holding mmu_lock.
Attack Vector
Exploitation requires local access and the ability to trigger KVM MMU aging on a host running guests. A malicious or compromised process capable of driving memory pressure and inducing page-aging callbacks can race a KVM writer that zaps rmaps through kvm_zap_all_rmap_sptes() or the recycle path. When the writer frees the pte_list_desc chain via kmem_cache_free() while the lockless walker follows it, the walker dereferences freed slab memory. See the upstream fix commit for the code path details.
Detection Methods for CVE-2026-89928
Indicators of Compromise
- Kernel oops or panic messages referencing kvm_rmap_age_gfn_range, for_each_rmap_spte_lockless, or pte_list_desc in the call stack
- KASAN slab-use-after-free reports naming the pte_list_desc slab cache on KVM hosts
- Unexplained guest VM instability or host reboots on kernels with CONFIG_KVM_MMU_LOCKLESS_AGING=y
Detection Strategies
- Enable Kernel Address Sanitizer (KASAN) in test kernels to surface the use-after-free before it reaches production
- Audit running kernel versions and configuration options across the hypervisor fleet to identify hosts exposing the vulnerable code path
- Correlate host crash dumps with KVM subsystem symbols to distinguish this issue from unrelated MMU faults
Monitoring Recommendations
- Ship kernel ring buffer output and kdump crash artifacts from KVM hosts to a centralized logging pipeline for review
- Alert on repeated KVM-related kernel warnings, especially on hosts running untrusted guest workloads
- Track patch state for the upstream commits 41debfc9, 8edb3c09, and e428f977 across managed kernels
How to Mitigate CVE-2026-89928
Immediate Actions Required
- Inventory hypervisor hosts running KVM on x86 and confirm whether kernels were built with CONFIG_KVM_MMU_LOCKLESS_AGING=y
- Apply the stable kernel updates that include the fix once available from the Linux distribution vendor
- Restrict local access to KVM hosts and limit which workloads can trigger aggressive memory aging on shared hypervisors
Patch Information
The fix splits rmap_get_first() into __rmap_get_first(), which starts iteration from an already-read rmap value. for_each_rmap_spte_lockless() now takes that value directly, and kvm_rmap_age_gfn_range() passes the value returned by kvm_rmap_lock_readonly(). When the lock was elided, the value is zero, __rmap_get_first() returns NULL, and the walk is skipped. Reference the following upstream commits: 41debfc9, 8edb3c09, and e428f977.
Workarounds
- Rebuild affected kernels with CONFIG_KVM_MMU_LOCKLESS_AGING disabled where feasible to remove the racing code path until patches are deployed
- Reduce host overcommit and memory pressure to lower the frequency of rmap zap operations that create the race window
- Isolate untrusted tenants onto patched hosts and defer live migration of guests to unpatched hypervisors
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

