CVE-2026-97945: x86/mm: Fix user-space data loss with MADV_FREE and THP
In the Linux kernel, the following vulnerability has been resolved:
x86/mm: Fix user-space data loss with MADVFREE and THP
Some of users of Polars (a data analytics library) have lost production data from this bug. They seem to have just the right combination of huge pages, MADVFREE and heavy reclaim pressure.
pmdmodify() masks the old value with (HPAGECHGMASK & ~PAGEDIRTY), silently discarding the hardware dirty bit. The subsequent pmdmksaveddirty() call is supposed to transfer PAGEDIRTY into PAGESAVEDDIRTY when write-protecting, but the dirty bit was already stripped from the value, so there is nothing left to transfer.
Contrast with ptemodify(), which keeps PAGEDIRTYBITS in its mask, and pudmodify(), which keeps HPAGECHGMASK untouched: pmdmodify() is the odd one out. Any pmdmodify() on a writable, dirty PMD loses the dirty state.
One visible consequence is data loss with MADVFREE on PMD-mapped THP:
memset(buf, 0x5A, size); // PMD-mapped THP, PMD dirty madvise(buf, size, MADVFREE); // PMD cleaned but left writable, // folio marked lazyfree memset(buf, 0x5A, size); // hardware sets PAGEDIRTY again mprotect(buf, size, PROTREAD); // pmdmodify() drops the dirty bit mprotect(buf, size, PROTREAD|PROTWRITE); // ... memory pressure ...
Reclaim (e.g. under memcg pressure) then finds the lazyfree folio with no dirty bit set anywhere and frees it in discardanonfoliopmdlocked(), even though the data was rewritten after MADVFREE; subsequent reads fault in fresh zero pages. NUMA hinting alone can trigger the same loss, as dohugepmdnumapage() restores the PMD through pmdmodify() as well.
PMD-mapped file THPs are affected too: mprotect()/NUMA hinting dropping the dirty bit means rewritten data is never written back.
Fix it by keeping PAGEDIRTY in the preserved mask, exactly like ptemodify() and pudmodify() do. The existing pmdmksaveddirty()/pmdclearsaveddirty() pair then performs the hardware-dirty <-> saved-dirty transition based on the write bit, preserving the shadow-stack encoding rules.
Affected Software
Event History
Frequently Asked Questions
Which workloads are most exposed to data loss?
Applications using PMD-mapped transparent huge pages together with MADV_FREE are exposed when modified pages are later write-protected and the system experiences heavy reclaim pressure. Polars users were reported to have lost production data under this combination.
What sequence causes the dirty state to be lost?
A writable, dirty PMD can lose its dirty state whenever pmd_modify() is used. In the described case, data is written to a PMD-mapped THP, marked with MADV_FREE, written again, and then made read-only with mprotect(), after which reclaim can discard data that should have been retained.
Is the issue specific to Polars?
No. Polars is an observed affected workload, but the underlying condition is any pmd_modify() operation on a writable, dirty PMD; the MADV_FREE and PMD-mapped THP combination is a documented data-loss consequence.