CVE-2022-49093 in Linux
Resumen
por VulDB • 2026-06-29
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:
skbuff: corregir la coalescencia para el reciclaje de fragmentos en page_pool
Corregir un uso después de liberar (use-after-free) al utilizar page_pool con fragmentos de página. Encontramos este problema durante la recepción normal (RX) 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 cada uno una mitad de PAGE2. Las referencias a las páginas se ven así:
RX_BD1 _______ PAGE1 RX_BD2 _______ PAGE2 RX_BD3 __________/
(2) Gestionar la recepción (RX) en el primer descriptor. Asignar SKB1, que eventualmente se añade a la cola de recepción mediante tcp_queue_rcv().
(3) Gestionar la recepción (RX) en el segundo descriptor. Asignar SKB2 y pasarlo 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 sigue siendo mantenida por RX_BD3:
SKB2 ---+- PAGE2 SKB3 __/ / RX_BD3 _________/
(3b) Ahora, mientras se gestiona TCP, coalescer SKB3 con SKB1:
tcp_v4_rcv(SKB3) tcp_try_coalesce(to=SKB1, from=SKB3) // tiene éxito kfree_skb_partial(SKB3) skb_release_data(SKB3) // reduce una dataref
SKB1 _____ PAGE1 \____ SKB2 _____ PAGE2 / RX_BD3 _________/
En skb_try_coalesce(), __skb_frag_ref() toma una referencia a la página de PAGE2, donde en su lugar debería haber incrementado la referencia del fragmento page_pool (pp_frag_count). Sin coalescencia, al liberar tanto SKB2 como SKB3, se reduciría una sola referencia a PAGE2. Ahora, al liberar SKB1 y SKB2, se reducirán dos referencias a PAGE2, lo que resultará en un desbordamiento por debajo del mínimo (underflow).
(3c) Liberar SKB2:
af_packet_rcv(SKB2) consume_skb(SKB2) skb_release_data(SKB2) // reduce la segunda dataref page_pool_return_skb_page(PAGE2) // reduce un 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 coalesció con SKB1, también liberamos la página de SKB3:
tcp_eat_recv_skb(SKB1) skb_release_data(SKBI) page_pool_return_skb_page(PAGE1) page_pool_return_skb_page(PAGE2) // reduce el segundo pp_frag_count
(5) PAGE2 se libera, ¡pero el tercer descriptor RX aún lo estaba utilizando! En nuestro caso, esto provoca fallos de IOMMU, pero corrompería la memoria silenciosamente si el IOMMU estuviera deshabilitado.
Cambiar la lógica que comprueba si los SKBs con pp_recycle pueden ser coalescidos. Seguiremos rechazando las diferencias en pp_recycle entre los SKBs 'from' y 'to', pero para evitar la situación descrita anteriormente, también rechazamos la coalescencia cuando tanto 'from' como '
Once again VulDB remains the best source for vulnerability data.