Vulnerabilidad en kernel de Linux (CVE-2024-49993)
Gravedad CVSS v3.1:
MEDIA
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
21/10/2024
Última modificación:
10/11/2024
Descripción
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: iommu/vt-d: Se corrige el bloqueo potencial si se llama a qi_submit_sync con un recuento de 0 Si se invoca qi_submit_sync() con 0 descriptores de invalidación (por ejemplo, para fines de vaciado de DMA), podemos encontrarnos con un error en el que un hilo de envío no detecta la finalización de invalidation_wait. Posteriormente, esto condujo a un bloqueo suave. Actualmente, este error no tiene impacto en los usuarios existentes porque ningún llamante está enviando invalidaciones con 0 descriptores. Esta corrección permitirá a los futuros usuarios (como DMA drain) llamar a qi_submit_sync() con un recuento de 0. Supongamos que el hilo T1 invoca qi_submit_sync() con descriptores distintos de cero, mientras que, al mismo tiempo, el hilo T2 llama a qi_submit_sync() con cero descriptores. Ambos hilos entran entonces en un bucle while, esperando a que se completen sus respectivos descriptores. T1 detecta su finalización (es decir, el estado invalidation_wait de T1 cambia a QI_DONE por HW) y procede a llamar a reclaim_free_desc() para recuperar todos los descriptores, incluyendo potencialmente los adyacentes de otros subprocesos que también están marcados como QI_DONE. Durante este tiempo, mientras T2 espera adquirir el qi->q_lock, el hardware IOMMU puede completar la invalidación para T2, estableciendo su estado en QI_DONE. Sin embargo, si la ejecución de reclaim_free_desc() por parte de T1 libera el descriptor invalidation_wait de T2 y cambia su estado a QI_FREE, T2 no observará el estado QI_DONE para su invalidation_wait y permanecerá bloqueado indefinidamente. Este bloqueo suave no ocurre cuando solo se envían descriptores distintos de cero. En tales casos, los descriptores de invalidación se intercalan entre los descriptores de espera con el estado QI_IN_USE, actuando como barreras. Estas barreras evitan que el código de recuperación libere por error descriptores que pertenecen a otros remitentes. Considere la siguiente línea de tiempo de ejemplo: T1 T2 ========================================= ID1 WD1 while(WD1!=QI_DONE) unlock lock WD1=QI_DONE* WD2 while(WD2!=QI_DONE) unlock lock WD1==QI_DONE? ID1=QI_DONE WD2=DONE* reclaim() ID1=FREE WD1=FREE WD2=FREE unlock soft lockup! T2 nunca ve QI_DONE en WD2 Donde: ID = descriptor de invalidación WD = descriptor de espera * Escrito por hardware La raíz del problema es que el indicador de estado del descriptor QI_DONE se usa para dos propósitos conflictivos: 1. señalar que un descriptor está listo para ser recuperado (para ser liberado) 2. señalar por el hardware que un descriptor de espera está completo La solución (en este parche) es la separación de estados mediante el uso del indicador QI_FREE para #1. Una vez que los descriptores de invalidación de un hilo están completos, su estado se establecería en QI_FREE. La función reclaim_free_desc() solo liberaría los descriptores marcados como QI_FREE en lugar de los marcados como QI_DONE. Este cambio asegura que T2 (del ejemplo anterior) observará correctamente la finalización de su invalidation_wait (marcada como QI_DONE).
Impacto
Puntuación base 3.x
5.50
Gravedad 3.x
MEDIA
Referencias a soluciones, herramientas e información
- https://git.kernel.org/stable/c/07e4e92f84b7d3018b7064ef8d8438aeb54a2ca5
- https://git.kernel.org/stable/c/3cf74230c139f208b7fb313ae0054386eee31a81
- https://git.kernel.org/stable/c/8840dc73ac9e1028291458ef1429ec3c2524ffec
- https://git.kernel.org/stable/c/92ba5b014d5435dd7a1ee02a2c7f2a0e8fe06c36
- https://git.kernel.org/stable/c/de9e7f68762585f7532de8a06de9485bf39dbd38
- https://git.kernel.org/stable/c/dfdbc5ba10fb792c9d6d12ba8cb6e465f97365ed
- https://git.kernel.org/stable/c/e03f00aa4a6c0c49c17857a4048f586636abdc32