Live › vulnerability › CVE-2026-98939
Go to dashboardOn x86, the huge vmap code allocated memory with GFP_KERNEL while holding the init_mm mmap lock, which can deadlock when kswapd reclaims memory, as lockdep showed with a discrete GPU's TTM pool shrinker. The fix removes that allocation by freeing PTE tables straight from the detached PMD page.
Summary written from the sources below. Check the originals before acting.
First seen by InfraStack 2026-10-23 21:57 UTC. All times on this page are UTC.
Systems running an affected Linux kernel on x86, most likely hosts with a discrete GPU using the TTM page pool under memory pressure, where reclaim can trigger the lock cycle. The sources do not give a version range, so unknown.
No product ranges from the sources yet.
uname -r and compare against the fixed kernel builds listed in the NVD entry for CVE-2026-98939Each row is the first time that source carried this signal. The analyst’s rows are its own findings.
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:
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:
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 ]
fs_reclaim -> pool_shrink_rwsem
The same shrinker, called from reclaim.
(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. ]
This page as .md · .json · in your agent: get_signal("CVE-2026-98939")
NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.