CVE-2026-98939
NoneCVSS
—
EPSS
0.2%
Published
Oct 23, 2026
CISA due date
—
Cloudanix analysis
A memory-handling mistake in the Linux kernel can make computers with separate graphics cards freeze when the system runs low on memory.
- Exploitation
- Local Privilege
- Attacker needs
- Local User
- Complexity
- Moderate
- Impact
- Denial Of Service
- Component
- OS kernel
- Class
- Race Condition
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
The flaw creates a circular locking dependency between init_mm.mmap_lock (taken during change_page_attr_set_clr and vmap huge PUD paths) and pool_shrink_rwsem (held by TTM shrinker during page freeing), because pud_free_pmd_page performs a GFP_KERNEL allocation while holding the mmap read lock.
Why it matters to the business
Linux systems using discrete GPUs can experience kernel deadlocks and system hangs or crashes when memory pressure activates the TTM page pool shrinker, disrupting workloads that rely on stable kernel operation.
How an attack unfolds
An attacker triggers memory reclaim combined with TTM pool shrinking and ioremap operations that exercise the vmap huge-PUD path; the resulting allocation in the page-table free path attempts to acquire the mmap lock already contended by the shrinker, producing deadlock.
How to fix it
Apply the upstream fix that removes the unnecessary PMD page copy, detaches the PMD at the PUD level, flushes mid-level caches, and frees PTE tables directly without allocation.
How to confirm the fix worked
Confirm the patched kernel no longer contains the GFP_KERNEL allocation inside pud_free_pmd_page and that lockdep reports no longer appear when TTM shrinking occurs under memory pressure.
Typical attack path
- Local process or workload induces memory pressure to activate kswapd and the TTM shrinker
- Shrinker holds pool_shrink_rwsem while calling set_pages_wb which takes init_mm.mmap_lock
- Concurrently an ioremap or vmap path holds init_mm.mmap_lock and enters pud_free_pmd_page
- pud_free_pmd_page performs GFP_KERNEL allocation that enters reclaim and attempts to acquire pool_shrink_rwsem, closing the cycle
How to detect it
Inspect kernel logs (dmesg, journalctl) for lockdep warnings that mention circular locking between (init_mm).mmap_lock and pool_shrink_rwsem during ttm_pool_shrink or change_page_attr_set_clr.
What your security team should do
- Prioritize kernel updates on systems with discrete GPUs once fixed packages are available
- Monitor kernel logs for lockdep splats referencing mmap_lock and pool_shrink_rwsem
- Reduce memory pressure or disable TTM shrinker where feasible as a temporary mitigation
The record
In the Linux kernel, the following vulnerability has been resolved: x86/mm: Drop unnecessary PMD page copy when freeing On a box with a discrete GPU, lockdep reports a possible deadlock as soon as kswapd shrinks the TTM page pool. The immediate cause is an x86 commit that added an mmap_read_lock() to kernel page protection munging code. The huge vmap code holds the same lock over a GFP_KERNEL allocation, which is a no-no now that reclaim can take it. That allocation is in a page table *free* path and ends up being for dubious purposes[1]. Basically, it tries to avoid hardware setting Accessed=1 in page table entries that are unreachable by the hardware, a non-issue. Remove the PMD copy. Detach the original PMD page at the PUD, flush the mid-level caches, and free the PTE tables straight from the detached PMD page. With no allocation left, the locking issue is gone. Lockdep splat/analysis: WARNING: possible circular locking dependency detected 7.3.0-rc3-f6e7b42bf05b+ #183 Tainted: G U ------------------------------------------------------ kswapd0/269 is trying to acquire lock: ((init_mm).mmap_lock){++++}-{4:4}, at: change_page_attr_set_clr+0x29a/0x4a0 but task is already holding lock: (pool_shrink_rwsem){.+.+}-{4:4}, at: ttm_pool_shrink+0xb2/0x330 [ttm] Chain exists of: (init_mm).mmap_lock --> fs_reclaim --> pool_shrink_rwsem The cycle is built from three edges: 1) pool_shrink_rwsem -> (init_mm).mmap_lock The TTM shrinker restores the caching attribute of every page it frees, while holding pool_shrink_rwsem: ttm_pool_shrink() -> ttm_pool_dispose_list() -> ttm_pool_free_page() -> set_pages_wb() -> change_page_attr_set_clr() [ init_mm mmap read lock ] 2) fs_reclaim -> pool_shrink_rwsem The same shrinker, called from reclaim. 3) (init_mm).mmap_lock -> fs_reclaim ioremap() installing a huge PUD mapping over an existing PMD table: ioremap_page_range() -> vmap_range_noflush() -> vmap_try_huge_pud() [ init_mm mmap read lock ] -> pud_free_pmd_page() -> __get_free_page(GFP_KERNEL) [ enters reclaim ] [ dhansen: Lots of changelog munging/trimming and merged comments from my version of the fix. ]
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|