Vulnerabilidad en kernel de Linux (CVE-2024-38306)
Gravedad CVSS v3.1:
MEDIA
Tipo:
CWE-362
Ejecución concurrente utilizando recursos compartidos con una incorrecta sincronización (Condición de carrera)
Fecha de publicación:
25/06/2024
Última modificación:
17/09/2025
Descripción
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: btrfs: proteger folio::privado al adjuntar folios de búfer de extensión [ERROR] Desde la versión 6.8, varias personas reportan fallas raras del kernel, el factor común son mensajes de error de estado incorrecto de la página así: ERROR: Estado incorrecto de la página en el proceso kswapd0 pfn:d6e840 página: refcount:0 mapcount:0 mapeo:000000007512f4f2 index:0x2796c2c7c pfn:0xd6e840 aops:btree_aops ino:1 flags: 0x17ffffe0000008(uptodate|node=0|zone= 2 |lastcpupid=0x3fffff) tipo de página: 0xffffffff() raw: 0017ffffe0000008 dead000000000100 dead000000000122 ffff88826d0be4c0 raw: 00000002796c2c7c 0000000000000000 0000 0000ffffffff 0000000000000000 página volcada porque: mapeo no NULL [CAUSA] Commit 09e6cef19c9f ("btrfs: refactor alloc_extent_buffer() para asignar el método luego adjuntar ") cambia la secuencia al asignar un nuevo búfer de extensión. Anteriormente siempre llamábamos a grab_extent_buffer() en mapeo->i_private_lock, para garantizar la seguridad en la modificación en folio::private (que es un puntero al búfer de extensión para el tamaño de sector normal). Esto puede llevar a la siguiente ejecución: el subproceso A está intentando asignar un búfer de extensión en el bytenr X, con 4 páginas de 4K, mientras que el subproceso B está intentando liberar la página en X + 4K (la segunda página del búfer de extensión en X) . Hilo A | Hilo B -----------------------------------+------------ ------------------------- | btree_release_folio() | | Esto es para la página en X + 4K, | | No la página X. | | alloc_extent_buffer() | |- release_extent_buffer() |- filemap_add_folio() para el | | |- atomic_dec_and_test(eb->refs) | página en bytenr X (la primera | | | | página). | | | | Que devolvió -EEXIST. | | | | | | | |- filemap_lock_folio() | | | | Devolvió la primera página bloqueada. | | | | | | | |- grab_extent_buffer() | | | | |- atomic_inc_not_zero() | | | | | Devuelto falso | | | | |- folio_detach_private() | | |- folio_detach_private() para X | |- folio_test_private() | | |- folio_test_private() | Devuelto verdadero | | | Devuelto verdadero |- folio_put() | |- folio_put() Ahora hay dos opciones de venta en el mismo folio en el folio X, lo que provoca un recuento insuficiente del folio X y, finalmente, provoca el error BUG_ON() en la página->mapeo. La condición no es tan fácil de cumplir: - La publicación debe activarse para la página intermedia de un eb. Si la publicación está en la misma primera página de un eb, el bloqueo de página se activaría e impediría la ejecución. - folio_detach_private() tiene una ventana de ejecución muy pequeña. Es solo entre folio_test_private() y folio_clear_private(). Eso es exactamente cuando se usa mapeo->i_private_lock para evitar dicha ejecución, y la confirmación 09e6cef19c9f ("btrfs: refactor alloc_extent_buffer() para asignar-luego-adjuntar método") arruinó eso. En ese momento, pensé que el bloqueo de página se activaría ya que filemap_release_folio() también requiere que la página esté bloqueada, pero olvidé que filemap_release_folio() solo bloquea una página, no todas las páginas de un búfer de extensión. [FIX] Mueva todo el código que requiere i_private_lock a adjunto_eb_folio_to_filemap(), para que todo se haga con la protección de bloqueo adecuada. Además, para evitar problemas futuros, agregue un lockdep_assert_locked() adicional para garantizar que mantenemos el bloqueo adecuado. Para el reproductor que puede iniciar la ejecución (tarda unos minutos con el código instrumentado insertando retrasos en alloc_extent_buffer()): #!/bin/sh drop_caches () { while(true); hacer echo 3 > /proc/sys/vm/drop_caches echo 1 > /proc/sys/vm/compact_memory hecho } run_tar () { while(true); hacer para x en `seq 1 80`; hacer tar cf /dev/zero /mnt > /dev/null & hecho esperar hecho } mkfs.btrfs -f -d single -m single ---truncado---
Impacto
Puntuación base 3.x
4.70
Gravedad 3.x
MEDIA
Productos y versiones vulnerables
CPE | Desde | Hasta |
---|---|---|
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 6.8 (incluyendo) | 6.9.5 (excluyendo) |
cpe:2.3:o:linux:linux_kernel:6.10:rc1:*:*:*:*:*:* | ||
cpe:2.3:o:linux:linux_kernel:6.10:rc2:*:*:*:*:*:* |
Para consultar la lista completa de nombres de CPE con productos y versiones, ver esta página