CVE-2025-38242: mm: userfaultfd: fix race of userfaultfd_move and swap cache

Published Jul 9, 2025
·
Updated

In the Linux kernel, the following vulnerability has been resolved:

mm: userfaultfd: fix race of userfaultfdmove and swap cache

This commit fixes two kinds of races, they may have different results:

Barry reported a BUGON in commit c50f8e6053b0, we may see the same BUGON if the filemap lookup returned NULL and folio is added to swap cache after that.

If another kind of race is triggered (folio changed after lookup) we may see RSS counter is corrupted:

[ 406.893936] BUG: Bad rss-counter state mm:ffff0000c5a9ddc0 type:MMANONPAGES val:-1 [ 406.894071] BUG: Bad rss-counter state mm:ffff0000c5a9ddc0 type:MMSHMEMPAGES val:1

Because the folio is being accounted to the wrong VMA.

I'm not sure if there will be any data corruption though, seems no. The issues above are critical already.

On seeing a swap entry PTE, userfaultfdmove does a lockless swap cache lookup, and tries to move the found folio to the faulting vma. Currently, it relies on checking the PTE value to ensure that the moved folio still belongs to the src swap entry and that no new folio has been added to the swap cache, which turns out to be unreliable.

While working and reviewing the swap table series with Barry, following existing races are observed and reproduced [1]:

In the example below, movepagespte is moving srcpte to dstpte, where srcpte is a swap entry PTE holding swap entry S1, and S1 is not in the swap cache:

CPU1 CPU2 userfaultfdmove movepagespte() entry = ptetoswpentry(origsrcpte); // Here it got entry = S1 ... < interrupted> ... <swapin srcpte, alloc and use folio A> // folio A is a new allocated folio // and get installed into srcpte <frees swap entry S1> // srcpte now points to folio A, S1 // has swap count == 0, it can be freed // by folioswapswap or swap // allocator's reclaim. <try to swap out another folio B> // folio B is a folio in another VMA. <put folio B to swap cache using S1 > // S1 is freed, folio B can use it // for swap out with no problem. ... folio = filemapgetfolio(S1) // Got folio B here !!! ... < interrupted again> ... <swapin folio B and free S1> // Now S1 is free to be used again. <swapout srcpte & folio A using S1> // Now srcpte is a swap entry PTE // holding S1 again. foliotrylock(folio) moveswappte doubleptlock isptepagesstable // Check passed because srcpte == S1 foliomoveanonrmap(...) // Moved invalid folio B here !!!

The race window is very short and requires multiple collisions of multiple rare events, so it's very unlikely to happen, but with a deliberately constructed reproducer and increased time window, it can be reproduced easily.

This can be fixed by checking if the folio returned by filemap is the valid swap cache folio after acquiring the folio lock.

Another similar race is possible: filemapgetfolio may return NULL, but folio (A) could be swapped in and then swapped out again using the same swap entry after the lookup. In such a case, folio (A) may remain in the swap cache, so it must be moved too:

CPU1 CPU2 userfaultfdmove movepagespte() entry = ptetoswpentry(origsrcpte); // Here it got entry = S1, and S1 is not in swap cache folio = filemapget ---truncated---

Affected Software

139 affected componentsFixes available
Linux Linux kernel
Linux Linux kernel>=6.8<6.12.37
Linux Linux kernel>=6.13<6.15.5
Linux Linux kernel=6.16-rc1
Linux Linux kernel=6.16-rc2
Linux Linux kernel=6.16-rc3
ubuntu/linux-hwe-edge*
ubuntu/linux-aws-5.0*
ubuntu/linux-aws-5.3*
ubuntu/linux-azure*
ubuntu/linux-azure-5.3*
ubuntu/linux-azure-edge*
ubuntu/linux-gcp*
ubuntu/linux-gcp-5.3*
ubuntu/linux-gke-4.15*
ubuntu/linux-gke-5.4*
ubuntu/linux-gkeop-5.4*
ubuntu/linux-hwe*
ubuntu/linux-hwe-edge*
ubuntu/linux-oem*
ubuntu/linux-oracle-5.0*
ubuntu/linux-oracle-5.3*
ubuntu/linux-aws-5.11*
ubuntu/linux-aws-5.13*
ubuntu/linux-aws-5.8*
ubuntu/linux-azure-5.11*
ubuntu/linux-azure-5.13*
ubuntu/linux-azure-5.8*
ubuntu/linux-azure-fde*
ubuntu/linux-gcp-5.11*
ubuntu/linux-gcp-5.13*
ubuntu/linux-gcp-5.8*
ubuntu/linux-gke*
ubuntu/linux-gke-5.15*
ubuntu/linux-gkeop*
ubuntu/linux-gkeop-5.15*
ubuntu/linux-hwe-5.11*
ubuntu/linux-hwe-5.13*
ubuntu/linux-hwe-5.8*
ubuntu/linux-intel-5.13*
ubuntu/linux-oem-5.10*
ubuntu/linux-oem-5.13*
ubuntu/linux-oem-5.6*
ubuntu/linux-oracle-5.11*
ubuntu/linux-oracle-5.13*
ubuntu/linux-oracle-5.8*
ubuntu/linux-raspi2*
ubuntu/linux-riscv*
ubuntu/linux-riscv-5.11*
ubuntu/linux-riscv-5.8*
ubuntu/linux-allwinner-5.19*
ubuntu/linux-aws-5.19*
ubuntu/linux-aws-6.2*
ubuntu/linux-aws-6.5*
ubuntu/linux-aws-6.8*
ubuntu/linux-azure-5.19*
ubuntu/linux-azure-6.2*
ubuntu/linux-azure-6.5*
ubuntu/linux-azure-6.8*
ubuntu/linux-azure-fde-5.19*
ubuntu/linux-azure-fde-6.2*
ubuntu/linux-azure-fde-6.8*
ubuntu/linux-gcp-5.19*
ubuntu/linux-gcp-6.2*
ubuntu/linux-gcp-6.5*
ubuntu/linux-gcp-6.8*
ubuntu/linux-hwe-5.19*
ubuntu/linux-hwe-6.2*
ubuntu/linux-hwe-6.5*
ubuntu/linux-ibm-6.8*
ubuntu/linux-intel-iot-realtime*
ubuntu/linux-lowlatency-hwe-5.19*
ubuntu/linux-lowlatency-hwe-6.2*
ubuntu/linux-lowlatency-hwe-6.5*
ubuntu/linux-lowlatency-hwe-6.8*
ubuntu/linux-nvidia-6.2*
ubuntu/linux-nvidia-6.5*
ubuntu/linux-nvidia-6.8*
ubuntu/linux-oem-5.17*
ubuntu/linux-oem-6.0*
ubuntu/linux-oem-6.1*
ubuntu/linux-oem-6.5*
ubuntu/linux-oracle-6.5*
ubuntu/linux-oracle-6.8*
ubuntu/linux-realtime*
ubuntu/linux-riscv*
ubuntu/linux-riscv-5.19*
ubuntu/linux-riscv-6.5*
ubuntu/linux-riscv-6.8*
ubuntu/linux-starfive-5.19*
ubuntu/linux-starfive-6.2*
ubuntu/linux-starfive-6.5*
ubuntu/linux-realtime-6.8*
ubuntu/linux*
ubuntu/linux-aws*
ubuntu/linux-aws-6.14<6.14.0-1015.15~24.04.1
6.14.0-1015.15~24.04.1
ubuntu/linux-azure*
ubuntu/linux-azure-6.11*
ubuntu/linux-azure-6.14<6.14.0-1014.14~24.04.1
6.14.0-1014.14~24.04.1
ubuntu/linux-azure-fde*
ubuntu/linux-azure-fde-6.17*
ubuntu/linux-azure-nvidia*
ubuntu/linux-azure-nvidia-6.14<6.14.0-1007.7
6.14.0-1007.7
ubuntu/linux-gcp*
ubuntu/linux-gcp-6.11*
ubuntu/linux-gcp-6.14<6.14.0-1018.19~24.04.1
6.14.0-1018.19~24.04.1
ubuntu/linux-gke*
ubuntu/linux-gkeop*
ubuntu/linux-hwe-6.11*
ubuntu/linux-ibm*
ubuntu/linux-intel*
ubuntu/linux-lowlatency*
ubuntu/linux-lowlatency-hwe-6.11*
ubuntu/linux-nvidia*
ubuntu/linux-nvidia-6.11*
ubuntu/linux-nvidia-lowlatency*
ubuntu/linux-nvidia-tegra<6.8.0-1035.38
6.8.0-1035.38
ubuntu/linux-oem-6.11*
ubuntu/linux-oem-6.14<6.14.0-1014.14
6.14.0-1014.14
ubuntu/linux-oem-6.8*
ubuntu/linux-oracle*
ubuntu/linux-oracle-6.14<6.14.0-1015.15~24.04.1
6.14.0-1015.15~24.04.1
ubuntu/linux-raspi*
ubuntu/linux-raspi-realtime*
ubuntu/linux-realtime*
ubuntu/linux-riscv*
ubuntu/linux-riscv-6.14<6.14.0-34.34.1~24.04.1
6.14.0-34.34.1~24.04.1
ubuntu/linux-vmware*
ubuntu/linux-xilinx*
ubuntu/linux-bluefield*
ubuntu/linux-raspi-realtime*
ubuntu/linux-realtime*
ubuntu/linux-realtime-6.14<6.14.0-1014.14~24.04.1
6.14.0-1014.14~24.04.1
ubuntu/linux-aws-fips*
ubuntu/linux-azure-fips*
ubuntu/linux-fips*
ubuntu/linux-gcp-fips*
ubuntu/linux-azure-fde*
ubuntu/linux-vmware*

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade ubuntu/linux-aws-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1015.15~24.04.1
  2. Upgrade

    Upgrade ubuntu/linux-azure-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1014.14~24.04.1
  3. Upgrade

    Upgrade ubuntu/linux-azure-nvidia-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1007.7
  4. Upgrade

    Upgrade ubuntu/linux-gcp-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1018.19~24.04.1
  5. Upgrade

    Upgrade ubuntu/linux-nvidia-tegra to a version that resolves this vulnerability.

    Fixed in 6.8.0-1035.38
  6. Upgrade

    Upgrade ubuntu/linux-oem-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1014.14
  7. Upgrade

    Upgrade ubuntu/linux-oracle-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1015.15~24.04.1
  8. Upgrade

    Upgrade ubuntu/linux-riscv-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-34.34.1~24.04.1
  9. Upgrade

    Upgrade ubuntu/linux-realtime-6.14 to a version that resolves this vulnerability.

    Fixed in 6.14.0-1014.14~24.04.1
  10. Compensating control

    In userfaultfd_move swap-cache handling, after acquiring the folio lock, verify that the folio returned by filemap_get_folio is still the valid folio for the source swap entry before moving or accounting it.

Event History

Jul 9, 2025
CVE Published
via MITRE·10:42 AM
Data Sourced
via MITRE·10:42 AM
DescriptionSeverity
Data Sourced
via OSV·11:15 AM
DescriptionSeverityAffected Software
Data Sourced
via NVD·11:15 AM
RemedyDescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

What is the severity of CVE-2025-38242?

CVE-2025-38242 has been classified with a medium severity level due to its potential impact on system stability.

2

How do I fix CVE-2025-38242?

To fix CVE-2025-38242, update the Linux kernel to the latest patched version that addresses this vulnerability.

3

What systems are affected by CVE-2025-38242?

CVE-2025-38242 affects various versions of the Linux kernel that utilize the userfaultfd feature.

4

What types of vulnerabilities does CVE-2025-38242 address?

CVE-2025-38242 addresses race conditions that can lead to unexpected behavior in memory management functions.

5

Can CVE-2025-38242 be exploited remotely?

Exploitation of CVE-2025-38242 typically requires local access, making remote exploitation unlikely.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203