The Zephyr virtio driver does not validate the descriptor-chain head id that the virtio device writes into the used ring. In virtio_isr()…
zephyr·CWE-129·Published 2026-08-24
The Zephyr virtio driver does not validate the descriptor-chain head id that the virtio device writes into the used ring. In virtio_isr() (drivers/virtio/virtio_common.c), the device-written vq->used->ring[idx].id is used directly as an index into vq->recv_cbs[] and vq->desc[], which are both allocated with exactly vq->num entries. recv_cbs[] holds {cb, opaque} callback entries, and the indexed callback pointer is then invoked as cbe.cb(cbe.opaque, used_len). Because the id is consumed as a 16-bit value with no bound check, a malicious or compromised virtio backend (an untrusted hypervisor, or an untrusted hardware/peer-processor virtio device on a PCI or MMIO transport) can supply an id far beyond vq->num. This causes an out-of-bounds read of a {function pointer, argument} pair from heap memory beyond recv_cbs[], after which the driver calls that attacker-shaped pointer in the guest's interrupt context. No guest privileges or user interaction are required; the backend triggers it by writing the shared used ring and raising the queue interrupt. The result is an arbitrary / attacker-influenced function-pointer call in the Zephyr guest, i.e. a control-flow-hijack primitive that can lead to code execution or, at minimum, a reliable crash. The fix rejects any used-ring id >= vq->num before indexing recv_cbs[]/desc[] or invoking the callback. This affects builds using CONFIG_VIRTIO with the PCI or MMIO transport.
The Zephyr virtio driver does not validate the descriptor-chain head id that the virtio device writes into the used ring. In virtio_isr() (drivers/virtio/virtio_common.c), the device-written vq->used->ring[idx].id is used directly as an index into vq->recv_cbs[] and vq->desc[], which are both allocated with exactly vq->num entries. recv_cbs[] holds {cb, opaque} callback entries, and the indexed callback pointer is then invoked as cbe.cb(cbe.opaque, used_len). Because the id is consumed as a 16-bit value with no bound check, a malicious or compromised virtio backend (an untrusted hypervisor, or an untrusted hardware/peer-processor virtio device on a PCI or MMIO transport) can supply an id far beyond vq->num. This causes an out-of-bounds read of a {function pointer, argument} pair from heap memory beyond recv_cbs[], after which the driver calls that attacker-shaped pointer in the guest's interrupt context. No guest privileges or user interaction are required; the backend triggers it by writing the shared used ring and raising the queue interrupt. The result is an arbitrary / attacker-influenced function-pointer call in the Zephyr guest, i.e. a control-flow-hijack primitive that can lead to code execution or, at minimum, a reliable crash. The fix rejects any used-ring id >= vq->num before indexing recv_cbs[]/desc[] or invoking the callback. This affects builds using CONFIG_VIRTIO with the PCI or MMIO transport.
El controlador virtio de Zephyr no valida el ID de cabecera de la cadena de descriptores que el dispositivo virtio escribe en el anillo de usados. En virtio_isr() (drivers/virtio/virtio_common.c), el ID vq -> used -> ring[idx].id escrito por el dispositivo se utiliza directamente como un índice en vq -> recv_cbs[] y vq -> desc[], los cuales están ambos asignados con exactamente vq -> num entradas. recv_cbs[] contiene entradas de callback {cb, opaque}, y el puntero de callback indexado se invoca entonces como cbe.cb(cbe.opaque, used_len). Debido a que el ID se consume como un valor de 16 bits sin verificación de límites, un backend virtio malicioso o comprometido (un hipervisor no confiable, o un dispositivo virtio de hardware/procesador par no confiable en un transporte PCI o MMIO) puede suministrar un ID mucho más allá de vq -> num. Esto causa una lectura fuera de límites de un par {puntero de función, argumento} de la memoria del heap más allá de recv_cbs[], después de lo cual el controlador llama a ese puntero con forma de atacante en el contexto de interrupción del invitado. No se requieren privilegios de invitado ni interacción del usuario; el backend lo activa escribiendo en el anillo de usados compartido y elevando la interrupción de la cola. El resultado es una llamada a puntero de función arbitraria / influenciada por el atacante en el invitado Zephyr, es decir, una primitiva de secuestro de flujo de control que puede conducir a la ejecución de código o, como mínimo, a un fallo fiable. La solución rechaza cualquier ID de anillo de usados >= vq -> num antes de indexar recv_cbs[]/desc[] o invocar el callback. Esto afecta a las compilaciones que utilizan CONFIG_VIRTIO con el transporte PCI o MMIO.
| Version | Type | Source | Base | Exp | Impact | Vector |
|---|---|---|---|---|---|---|
| 3.1 | Primary | cve.org | 8.8 | — | — | CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| 3.1 | Primary | cve.org | 8.8 | — | — | CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| 3.1 | Primary | cve.org | 8.8 | — | — | CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| 3.1 | Secondary | NVD | 8.8 | 2.8 | 5.9 | CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| 3.1 | Secondary | ENISA EUVD | 8.8 | — | — | CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |