CVE-2025-38242

In the Linux kernel, the following vulnerability has been resolved: mm: userfaultfd: fix race of userfaultfd_move and swap cache This commit fixes two kinds of races, they may have different results: Barry reported a BUG_ON in commit c50f8e6053b0, we may see the same BUG_ON 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:MM_ANONPAGES val:-1 [ 406.894071] BUG: Bad rss-counter state mm:ffff0000c5a9ddc0 type:MM_SHMEMPAGES 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, userfaultfd_move 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, move_pages_pte is moving src_pte to dst_pte, where src_pte is a swap entry PTE holding swap entry S1, and S1 is not in the swap cache: CPU1 CPU2 userfaultfd_move move_pages_pte() entry = pte_to_swp_entry(orig_src_pte); // Here it got entry = S1 ... < interrupted> ... <swapin src_pte, alloc and use folio A> // folio A is a new allocated folio // and get installed into src_pte <frees swap entry S1> // src_pte now points to folio A, S1 // has swap count == 0, it can be freed // by folio_swap_swap 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 = filemap_get_folio(S1) // Got folio B here !!! ... < interrupted again> ... <swapin folio B and free S1> // Now S1 is free to be used again. <swapout src_pte & folio A using S1> // Now src_pte is a swap entry PTE // holding S1 again. folio_trylock(folio) move_swap_pte double_pt_lock is_pte_pages_stable // Check passed because src_pte == S1 folio_move_anon_rmap(...) // 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: filemap_get_folio 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 userfaultfd_move move_pages_pte() entry = pte_to_swp_entry(orig_src_pte); // Here it got entry = S1, and S1 is not in swap cache folio = filemap_get ---truncated---
Configurations

Configuration 1 (hide)

OR cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.16:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.16:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.16:rc3:*:*:*:*:*:*

History

19 Nov 2025, 15:44

Type Values Removed Values Added
CVSS v2 : unknown
v3 : unknown
v2 : unknown
v3 : 4.7
CPE cpe:2.3:o:linux:linux_kernel:6.16:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.16:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.16:rc2:*:*:*:*:*:*
CWE CWE-362
First Time Linux
Linux linux Kernel
References () https://git.kernel.org/stable/c/0ea148a799198518d8ebab63ddd0bb6114a103bc - () https://git.kernel.org/stable/c/0ea148a799198518d8ebab63ddd0bb6114a103bc - Patch
References () https://git.kernel.org/stable/c/4c443046d8c9ed8724a4f4c3c2457d3ac8814b2f - () https://git.kernel.org/stable/c/4c443046d8c9ed8724a4f4c3c2457d3ac8814b2f - Patch
References () https://git.kernel.org/stable/c/db2ca8074955ca64187a4fb596dd290b9c446cd3 - () https://git.kernel.org/stable/c/db2ca8074955ca64187a4fb596dd290b9c446cd3 - Patch

10 Jul 2025, 15:15

Type Values Removed Values Added
References
  • () https://git.kernel.org/stable/c/4c443046d8c9ed8724a4f4c3c2457d3ac8814b2f -

10 Jul 2025, 13:17

Type Values Removed Values Added
Summary
  • (es) En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: mm: userfaultfd: corrige la ejecución de userfaultfd_move y la caché de intercambio. Esta confirmación corrige dos tipos de ejecuciones, pueden tener resultados diferentes: Barry informó un BUG_ON en el commit c50f8e6053b0, podemos ver el mismo BUG_ON si la búsqueda del mapa de archivos devolvió NULL y folio se agrega a la caché de intercambio después de eso. Si se activa otro tipo de ejecución (folio modificado tras la búsqueda), es posible que el contador RSS esté dañado: [406.893936] ERROR: Estado incorrecto del contador RSS mm:ffff0000c5a9ddc0 tipo:MM_ANONPAGES val:-1 [406.894071] ERROR: Estado incorrecto del contador RSS mm:ffff0000c5a9ddc0 tipo:MM_SHMEMPAGES val:1 Porque el folio se está contabilizando en la VMA incorrecta. No estoy seguro de si habrá alguna corrupción de datos, aunque parece que no. Los problemas anteriores ya son críticos. Al ver un PTE de entrada de intercambio, userfaultfd_move realiza una búsqueda de caché de intercambio sin bloqueo e intenta mover el folio encontrado a la VMA que falla. Actualmente, se basa en la comprobación del valor de PTE para garantizar que el folio movido siga perteneciendo a la entrada de intercambio src y que no se haya añadido ningún folio nuevo a la caché de intercambio, lo cual resulta poco fiable. Al trabajar y revisar la serie de tablas de intercambio con Barry, se observan y reproducen las siguientes ejecuciones existentes [1]: En el siguiente ejemplo, move_pages_pte mueve src_pte a dst_pte, donde src_pte es una PTE de entrada de intercambio que contiene la entrada de intercambio S1, y S1 no está en la caché de intercambio: CPU1 CPU2 userfaultfd_move move_pages_pte() entry = pte_to_swp_entry(orig_src_pte); // Aquí tiene entrada = S1 ... ... // folio A es un nuevo folio asignado // y se instala en src_pte // src_pte ahora apunta al folio A, S1 // tiene conteo de intercambio == 0, puede liberarse // mediante folio_swap_swap o la recuperación del asignador de intercambio. // folio B es un folio en otro VMA. // S1 se libera, el folio B puede usarlo // para intercambiar sin problemas. ... folio = filemap_get_folio(S1) // ¡¡¡Tengo el folio B aquí!!! ... ... // Ahora S1 está libre para volver a usarse. // Ahora src_pte es una entrada de intercambio PTE // que mantiene S1 de nuevo. folio_trylock(folio) move_swap_pte double_pt_lock is_pte_pages_stable // Comprobación aprobada porque src_pte == S1 folio_move_anon_rmap(...) // ¡¡¡Se movió el folio B inválido aquí!!! La ventana de ejecución es muy corta y requiere múltiples colisiones de múltiples eventos raros, por lo que es muy improbable que suceda, pero con un reproductor construido deliberadamente y una ventana de tiempo mayor, se puede reproducir fácilmente. Esto se puede arreglar comprobando si el folio devuelto por filemap es el folio de caché de intercambio válido después de adquirir el bloqueo de folio. Otra ejecución similar es posible: filemap_get_folio puede devolver NULL, pero el folio (A) podría intercambiarse dentro y fuera de nuevo usando la misma entrada de intercambio después de la búsqueda. En tal caso, el folio (A) puede permanecer en el caché de intercambio, por lo que también debe moverse: CPU1 CPU2 userfaultfd_move move_pages_pte() entry = pte_to_swp_entry(orig_src_pte); // Aquí obtuvo entry = S1, y S1 no está en el caché de intercambio folio = filemap_get ---truncated---

09 Jul 2025, 11:15

Type Values Removed Values Added
New CVE

Information

Published : 2025-07-09 11:15

Updated : 2025-11-19 15:44


NVD link : CVE-2025-38242

Mitre link : CVE-2025-38242

CVE.ORG link : CVE-2025-38242


JSON object : View

Products Affected

linux

  • linux_kernel
CWE
CWE-362

Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')