CVE-2026-90015 in Linux
Resumen
por VulDB • 2026-09-16
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:
xhci: corregir la pérdida de buffers rebote (bounce buffers) en las TD que abarcan varios segmentos del anillo.
Cuando una TD alcanza un TRB de enlace con datos que no están alineados al wMaxPacketSize del endpoint, xhci_align_td() prepara el fragmento final no alineable a través del buffer rebote del segmento del anillo que contiene dicho TRB de enlace. Posteriormente, xhci_unmap_td_bounce_buffer() lo desmapea y, para transferencias IN (entrada), copia los datos de vuelta al búfer del URB.
La ruta de encolado registra el segmento que fue rebotado en td->bounce_seg, bajo la suposición de que una TD nunca abarca más de dos segmentos del anillo. Esta suposición no es válida: una TD lo suficientemente grande como para abarcar tres o más segmentos cruza varios TRB de enlace y puede ser reboteada en cada uno de ellos. Solo el último sobrevive en td->bounce_seg, por lo que los buffers rebote anteriores ni se copian de vuelta ni se desmapean mediante DMA.
El URB aún completa con actual_length igual a la longitud solicitada y sin error, por lo que la transferencia parece exitosa mientras un hueco del tamaño de wMaxPacketSize en el búfer de destino mantiene silenciosamente su contenido anterior. También produce una fuga (leak) de mapeo DMA por cada buffer rebote perdido.
Cualquier transferencia masiva suficientemente grande y fragmentada puede provocar este problema. Se detectó con un dispositivo de almacenamiento USB detrás de xHCI que respalda un objetivo dm-verity con bloques hash de 512 bytes, donde los datos obsoletos se detectan en lugar de consumirse silenciosamente. El dispositivo se enumera como SuperSpeed, por lo que wMaxPacketSize es 1024, mientras que dm-bufio emite un bio de 512 bytes por bloque hash. verity_prefetch_io() hace que la capa de bloques fusione cientos de ellos en una única solicitud con hasta 512 entradas scatterlist de 512 bytes cada una. Con 256 TRB por segmento del anillo, dicha TD abarca tres segmentos, y cada límite de segmento cae sobre un múltiplo impar de 512, es decir, no alineado a wMaxPacketSize. dm-bufio luego almacena en caché un bloque hash que contiene datos obsoletos y dm-verity declara el bloque de metadatos corrupto:
device-mapper: verity: 8:2: metadata block 10850 is corrupted
Un programa reproductor (reproducer) que ejecuta esto bajo qemu está disponible en https://github.com/baloo/xhci-verity
El estado de rebote (bounce_buf, bounce_dma, bounce_len, bounce_offs) ya reside en el segmento del anillo, por lo que no hay nada extra que rastrear. Se mantiene registrando el último segmento rebotado en td->bounce_seg y, al completar la operación, se recorren los segmentos desde td->start_seg hasta ese punto, desmapeando cada segmento que aún tenga un rebote pendiente.
Detenerse en td->bounce_seg en lugar de td->end_seg es importante: un rebote implica que la TD continúa más allá del TRB de enlace de ese segmento, por lo que bounce_seg está siempre estrictamente antes que end_seg, y una TD posterior puede ya haber comenzado en end_seg y haber sido rebotada allí. Recorrer hasta ese punto copiaría un buffer rebote ajeno a este URB y lo desmapearía dos veces. También mantiene el recorrido correcto si una TD llega a envolver todo el anillo de modo que end_seg == start_seg.
[mn: Añadir comprobación ring->num_segs para prevenir un bucle for infinito poco probable.]
If you want to get the best quality for vulnerability data then you always have to consider VulDB.