// For flags

CVE-2024-26960

mm: swap: fix race between free_swap_and_cache() and swapoff()

Severity Score

5.5
*CVSS v3.1

Exploit Likelihood

*EPSS

Affected Versions

*CPE

Public Exploits

0
*Multiple Sources

Exploited in Wild

-
*KEV

Decision

Track
*SSVC
Descriptions

In the Linux kernel, the following vulnerability has been resolved: mm: swap: fix race between free_swap_and_cache() and swapoff() There was previously a theoretical window where swapoff() could run and
teardown a swap_info_struct while a call to free_swap_and_cache() was
running in another thread. This could cause, amongst other bad
possibilities, swap_page_trans_huge_swapped() (called by
free_swap_and_cache()) to access the freed memory for swap_map. This is a theoretical problem and I haven't been able to provoke it from a
test case. But there has been agreement based on code review that this is
possible (see link below). Fix it by using get_swap_device()/put_swap_device(), which will stall
swapoff(). There was an extra check in _swap_info_get() to confirm that
the swap entry was not free. This isn't present in get_swap_device()
because it doesn't make sense in general due to the race between getting
the reference and swapoff. So I've added an equivalent check directly in
free_swap_and_cache(). Details of how to provoke one possible issue (thanks to David Hildenbrand
for deriving this): --8<----- __swap_entry_free() might be the last user and result in
"count == SWAP_HAS_CACHE". swapoff->try_to_unuse() will stop as soon as soon as si->inuse_pages==0. So the question is: could someone reclaim the folio and turn
si->inuse_pages==0, before we completed swap_page_trans_huge_swapped(). Imagine the following: 2 MiB folio in the swapcache. Only 2 subpages are
still references by swap entries. Process 1 still references subpage 0 via swap entry.
Process 2 still references subpage 1 via swap entry. Process 1 quits. Calls free_swap_and_cache().
-> count == SWAP_HAS_CACHE
[then, preempted in the hypervisor etc.] Process 2 quits. Calls free_swap_and_cache().
-> count == SWAP_HAS_CACHE Process 2 goes ahead, passes swap_page_trans_huge_swapped(), and calls
__try_to_reclaim_swap(). __try_to_reclaim_swap()->folio_free_swap()->delete_from_swap_cache()->
put_swap_folio()->free_swap_slot()->swapcache_free_entries()->
swap_entry_free()->swap_range_free()->
...
WRITE_ONCE(si->inuse_pages, si->inuse_pages - nr_entries); What stops swapoff to succeed after process 2 reclaimed the swap cache
but before process1 finished its call to swap_page_trans_huge_swapped()? --8<-----

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: mm: swap: corrige la ejecución entre free_swap_and_cache() y swapoff() Anteriormente existía una ventana teórica donde swapoff() podía ejecutar y desmantelar un swap_info_struct mientras se realizaba una llamada a free_swap_and_cache(). corriendo en otro hilo. Esto podría causar, entre otras malas posibilidades, que swap_page_trans_huge_swapped() (llamado por free_swap_and_cache()) acceda a la memoria liberada para swap_map. Este es un problema teórico y no he podido provocarlo a partir de un caso de prueba. Pero ha habido un acuerdo basado en la revisión del código de que esto es posible (ver enlace a continuación). Solucionarlo usando get_swap_device()/put_swap_device(), lo que detendrá swapoff(). Hubo una verificación adicional en _swap_info_get() para confirmar que la entrada de intercambio no era gratuita. Esto no está presente en get_swap_device() porque en general no tiene sentido debido a la ejecución entre obtener la referencia y el intercambio. Así que agregué una verificación equivalente directamente en free_swap_and_cache(). Detalles de cómo provocar un posible problema (gracias a David Hildenbrand por derivar esto): --8&lt;----- __swap_entry_free() podría ser el último usuario y dar como resultado "count == SWAP_HAS_CACHE". swapoff-&gt;try_to_unuse() se detendrá tan pronto como si-&gt;inuse_pages==0. Entonces la pregunta es: ¿alguien podría reclamar la publicación y activar si-&gt;inuse_pages==0, antes de que completemos swap_page_trans_huge_swapped()? Imagine lo siguiente: folio de 2 MiB en el swapcache. Sólo 2 subpáginas siguen siendo referencias mediante entradas de intercambio. El proceso 1 todavía hace referencia a la subpágina 0 mediante la entrada de intercambio. El proceso 2 todavía hace referencia a la subpágina 1 mediante la entrada de intercambio. El proceso 1 se cierra. Llama a free_swap_and_cache(). -&gt; count == SWAP_HAS_CACHE [luego, adelantado en el hipervisor, etc.] El proceso 2 se cierra. Llama a free_swap_and_cache(). -&gt; count == SWAP_HAS_CACHE El proceso 2 continúa, pasa swap_page_trans_huge_swapped() y llama a __try_to_reclaim_swap(). __try_to_reclaim_swap()-&gt;folio_free_swap()-&gt;delete_from_swap_cache()-&gt; put_swap_folio()-&gt;free_swap_slot()-&gt;swapcache_free_entries()-&gt; swap_entry_free()-&gt;swap_range_free()-&gt; ... WRITE_ONCE(si-&gt;inuse_pages, si-&gt;inuse_pages - nr_entries); ¿Qué impide que el intercambio tenga éxito después de que el proceso 2 recuperó el caché de intercambio pero antes de que el proceso 1 terminara su llamada a swap_page_trans_huge_swapped()? --8&lt;-----

In the Linux kernel, the following vulnerability has been resolved: mm: swap: fix race between free_swap_and_cache() and swapoff() There was previously a theoretical window where swapoff() could run and teardown a swap_info_struct while a call to free_swap_and_cache() was running in another thread. This could cause, amongst other bad possibilities, swap_page_trans_huge_swapped() (called by free_swap_and_cache()) to access the freed memory for swap_map. This is a theoretical problem and I haven't been able to provoke it from a test case. But there has been agreement based on code review that this is possible (see link below). Fix it by using get_swap_device()/put_swap_device(), which will stall swapoff(). There was an extra check in _swap_info_get() to confirm that the swap entry was not free. This isn't present in get_swap_device() because it doesn't make sense in general due to the race between getting the reference and swapoff. So I've added an equivalent check directly in free_swap_and_cache(). Details of how to provoke one possible issue (thanks to David Hildenbrand for deriving this): --8<----- __swap_entry_free() might be the last user and result in "count == SWAP_HAS_CACHE". swapoff->try_to_unuse() will stop as soon as soon as si->inuse_pages==0. So the question is: could someone reclaim the folio and turn si->inuse_pages==0, before we completed swap_page_trans_huge_swapped(). Imagine the following: 2 MiB folio in the swapcache. Only 2 subpages are still references by swap entries. Process 1 still references subpage 0 via swap entry. Process 2 still references subpage 1 via swap entry. Process 1 quits. Calls free_swap_and_cache(). -> count == SWAP_HAS_CACHE [then, preempted in the hypervisor etc.] Process 2 quits. Calls free_swap_and_cache(). -> count == SWAP_HAS_CACHE Process 2 goes ahead, passes swap_page_trans_huge_swapped(), and calls __try_to_reclaim_swap(). __try_to_reclaim_swap()->folio_free_swap()->delete_from_swap_cache()-> put_swap_folio()->free_swap_slot()->swapcache_free_entries()-> swap_entry_free()->swap_range_free()-> ... WRITE_ONCE(si->inuse_pages, si->inuse_pages - nr_entries); What stops swapoff to succeed after process 2 reclaimed the swap cache but before process1 finished its call to swap_page_trans_huge_swapped()? --8<-----

Ziming Zhang discovered that the DRM driver for VMware Virtual GPU did not properly handle certain error conditions, leading to a NULL pointer dereference. A local attacker could possibly trigger this vulnerability to cause a denial of service. Zheng Wang discovered that the Broadcom FullMAC WLAN driver in the Linux kernel contained a race condition during device removal, leading to a use- after-free vulnerability. A physically proximate attacker could possibly use this to cause a denial of service.

*Credits: N/A
CVSS Scores
Attack Vector
Local
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High
Attack Vector
Local
Attack Complexity
Low
Authentication
Single
Confidentiality
None
Integrity
None
Availability
Complete
Attack Vector
Network
Attack Complexity
Low
Authentication
Single
Confidentiality
Complete
Integrity
Complete
Availability
Complete
* Common Vulnerability Scoring System
SSVC
  • Decision:Track
Exploitation
None
Automatable
No
Tech. Impact
Partial
* Organization's Worst-case Scenario
Timeline
  • 2024-02-19 CVE Reserved
  • 2024-05-01 CVE Published
  • 2025-02-05 CVE Updated
  • 2025-03-29 EPSS Updated
  • ---------- Exploited in Wild
  • ---------- KEV Due Date
  • ---------- First Exploit
CWE
  • CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
CAPEC
Affected Vendors, Products, and Versions
Vendor Product Version Other Status
Vendor Product Version Other Status <-- --> Vendor Product Version Other Status
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 5.10.215
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 5.10.215"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 5.15.154
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 5.15.154"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 6.1.84
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 6.1.84"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 6.6.24
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 6.6.24"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 6.7.12
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 6.7.12"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 6.8.3
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 6.8.3"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 4.11 < 6.9
Search vendor "Linux" for product "Linux Kernel" and version " >= 4.11 < 6.9"
en
Affected