Vulnerabilidad en kernel de Linux (CVE-2022-49093)
Gravedad CVSS v3.1:
ALTA
Tipo:
CWE-416
Utilización después de liberación
Fecha de publicación:
26/02/2025
Última modificación:
25/03/2025
Descripción
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: skbuff: corrección de coalescencia para reciclaje de fragmentos de page_pool Corrige un use-after-free al usar page_pool con fragmentos de página. Encontramos este problema durante RX normal en el controlador hns3: (1) Inicialmente tenemos tres descriptores en la cola RX. El primero asigna PAGE1 a través de page_pool, y los otros dos asignan la mitad de PAGE2 cada uno. Las referencias de página se ven así: RX_BD1 _______ PAGE1 RX_BD2 _______ PAGE2 RX_BD3 _________/ (2) Manejar RX en el primer descriptor. Asignar SKB1, eventualmente agregado a la cola de recepción por tcp_queue_rcv(). (3) Manejar RX en el segundo descriptor. Asigne SKB2 y páselo a netif_receive_skb(): netif_receive_skb(SKB2) ip_rcv(SKB2) SKB3 = skb_clone(SKB2) SKB2 y SKB3 comparten una referencia a PAGE2 a través de skb_shinfo()->dataref. La otra referencia a PAGE2 todavía la mantiene RX_BD3: SKB2 ---+- PAGE2 SKB3 __/ / RX_BD3 _________/ (3b) Ahora, mientras maneja TCP, fusione SKB3 con SKB1: tcp_v4_rcv(SKB3) tcp_try_coalesce(to=SKB1, from=SKB3) // tiene éxito kfree_skb_partial(SKB3) skb_release_data(SKB3) // elimina una referencia de datos SKB1 _____ PAGE1 \____ SKB2 _____ PAGE2 / RX_BD3 _________/ En skb_try_coalesce(), __skb_frag_ref() toma una referencia de página a PAGE2, donde en cambio debería haber aumentado la referencia de fragmento de page_pool, pp_frag_count. Sin la fusión, al liberar SKB2 y SKB3, se eliminaría una única referencia a PAGE2. Ahora, al liberar SKB1 y SKB2, se descartarán dos referencias a PAGE2, lo que provocará un desbordamiento. (3c) Descartar SKB2: af_packet_rcv(SKB2) consume_skb(SKB2) skb_release_data(SKB2) // descarta la segunda referencia de datos page_pool_return_skb_page(PAGE2) // descarta una pp_frag_count SKB1 _____ PAGE1 \____ PAGE2 / RX_BD3 _________/ (4) El espacio de usuario llama a recvmsg() Copia SKB1 y lo libera. Dado que SKB3 se fusionó con SKB1, también liberamos la página SKB3: tcp_eat_recv_skb(SKB1) skb_release_data(SKB1) page_pool_return_skb_page(PAGE1) page_pool_return_skb_page(PAGE2) // elimina el segundo pp_frag_count (5) PAGE2 se libera, ¡pero el tercer descriptor RX todavía lo estaba usando! En nuestro caso, esto causa fallas de IOMMU, pero corrompería silenciosamente la memoria si IOMMU estuviera deshabilitado. Cambie la lógica que verifica si los SKB pp_recycle se pueden fusionar. Aún rechazamos diferentes pp_recycle entre SKB 'from' y 'to', pero para evitar la situación descrita anteriormente, también rechazamos la fusión cuando tanto 'from' como 'to' son pp_recycled y 'from' es clonado. La nueva lógica permite fusionar un SKB pp_recycle clonado en uno con referencia de página, porque en este caso la versión (4) eliminará la referencia correcta, la tomada por skb_try_coalesce().
Impacto
Puntuación base 3.x
7.80
Gravedad 3.x
ALTA
Productos y versiones vulnerables
CPE | Desde | Hasta |
---|---|---|
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 5.15 (incluyendo) | 5.15.34 (excluyendo) |
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 5.16 (incluyendo) | 5.16.20 (excluyendo) |
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 5.17 (incluyendo) | 5.17.3 (excluyendo) |
cpe:2.3:o:linux:linux_kernel:5.18:rc1:*:*:*:*:*:* |
Para consultar la lista completa de nombres de CPE con productos y versiones, ver esta página