{"id":24674,"date":"2026-09-16T20:32:37","date_gmt":"2026-09-16T12:32:37","guid":{"rendered":"https:\/\/www.54iter.cn\/?vuln=cve-2026-89987"},"modified":"2026-09-16T20:32:37","modified_gmt":"2026-09-16T12:32:37","slug":"cve-2026-89987","status":"publish","type":"vuln","link":"https:\/\/www.54iter.cn\/?vuln=cve-2026-89987","title":{"rendered":"CVE-2026-89987 &#8211; In the Linux kernel, the following vulnerability has been resolved:\n\nmm\/huge_memory: trans"},"content":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>mm\/huge_memory: transfer the pmd dirty bit to the folio on zap<\/p>\n<p>zap_huge_pmd_folio() propagates the pmd young bit to the folio for the<br \/>\nfile case, but not the dirty bit.  The pte path does propagate it, in<br \/>\nzap_present_folio_ptes() and so does the pmd split path, in<br \/>\n__split_huge_pmd_locked().<\/p>\n<p>For most file mappings the omission is harmless, because writing to a<br \/>\nshared file mapping goes through page_mkwrite(), which dirties the folio.<br \/>\ntmpfs is different: it has no page_mkwrite(), and vma_wants_writenotify()<br \/>\nis false for it, so a *read* fault on a MAP_SHARED tmpfs mapping installs<br \/>\na writable pmd via do_read_fault().  do_read_fault() does not call<br \/>\nfault_dirty_shared_page(), so subsequent stores through that mapping set<br \/>\nonly the hardware dirty bit in the pmd and never call folio_mark_dirty().<br \/>\nA shmem folio allocated by a fault is marked uptodate but not dirty (see<br \/>\nthe clear: block in shmem_get_folio_gfp()), so PG_dirty is never set at<br \/>\nall.<\/p>\n<p>Unmapping such a folio &#8211; munmap(), or exit_mmap() when the process dies &#8211;<br \/>\nthen loses the only record that it was written, because zap_huge_pmd()<br \/>\ndrops the pmd without transferring the dirty bit.  Reclaim afterwards sees<br \/>\na clean shmem folio: the whole swap-out block in shrink_folio_list() is<br \/>\ninside &#8220;if (folio_test_dirty(folio))&#8221;, so pageout() is skipped and the<br \/>\nfolio falls into __remove_mapping().  There, folio_is_file_lru() is false<br \/>\nfor a swapbacked folio, so no shadow entry is created and<br \/>\n__filemap_remove_folio(folio, NULL) simply empties the i_pages slot.  The<br \/>\ndata is freed without ever being written to swap, and the next fault on<br \/>\nthat index returns a freshly zeroed folio.<\/p>\n<p>This is silent data loss for any process that keeps state in a MAP_SHARED<br \/>\ntmpfs segment across an unmap &#8211; for example a cache handed from one<br \/>\nprocess generation to the next through \/dev\/shm.  It requires the folio to<br \/>\nbe PMD-mapped, so it only shows up once shmem THP is enabled (which is<br \/>\nwhat we did in Meta fleet and started noticing crashes); with THP off the<br \/>\npte path transfers the dirty bit correctly.  It also only becomes visible<br \/>\nwhen swap is enabled, because with no swap device shmem folios (which are<br \/>\non the anon LRU) are not scanned by reclaim at all, so the clean folio is<br \/>\nnever dropped.<\/p>\n<p>Reproduced on x86_64 with a tmpfs mounted huge=within_size: read-fault a<br \/>\n2MB-backed region, write a known pattern through the resulting mapping,<br \/>\nmunmap, force reclaim of the cgroup, then re-map and read back.  Without<br \/>\nthis patch the region reads back as zeros and vmstat shows zswpout 0 &#8211; the<br \/>\ndata was discarded rather than swapped.  With this patch the region reads<br \/>\nback correctly and the pages are swapped out as expected.  With<br \/>\nhuge=never, or when the first touch is a write, the test passes either<br \/>\nway.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>mm\/huge_memory: transfer the pmd dirty bit to the folio on zap<\/p>\n<p>zap_huge_pmd_folio() propagates the pmd young bit to the folio for <\/p>\n","protected":false},"template":"","meta":[],"categories":[],"tags":[],"class_list":["post-24674","vuln","type-vuln","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln\/24674","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln"}],"about":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/types\/vuln"}],"wp:attachment":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=24674"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=24674"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=24674"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}