Re: [PATCH] virtio_ring: Initialize id field in packed indirect descriptors

From: Michael S. Tsirkin

Date: Mon Nov 02 2026 - 14:17:01 EST


On Thu, Oct 29, 2026 at 03:25:10PM +0800, zhangjiao2 wrote:
> From: zhang jiao <zhangjiao2@xxxxxxxxxxxxxxxxxxxx>
>
> The virtqueue_add_indirect_packed() function fills an indirect
> descriptor table with addr, len, and flags for each entry, but does
> not initialize the id field of struct vring_packed_desc. The table is
> allocated via kmalloc() (not kzalloc) and then DMA-mapped with
> DMA_TO_DEVICE, making the uninitialized 2-byte id field of each
> descriptor readable by the device.
>
> This leaks kernel heap memory to the device for every packed indirect
> descriptor entry. A malicious or compromised device could extract heap
> contents by reading the id fields from the DMA-mapped indirect
> descriptor tables. This affects all virtio devices that use packed
> virtqueues with indirect descriptors, which is the common configuration
> for modern virtio devices.
>
> Fix this by explicitly initializing desc[i].id to zero in the
> descriptor filling loop. The id field is unused in indirect descriptor
> table entries per the virtio specification (only the head descriptor in
> the main ring uses id for buffer identification), so setting it to zero
> is semantically correct.
>
> This matches the split ring path where all four fields of struct
> vring_desc (addr, len, flags, next) are explicitly written in
> virtqueue_add_desc_split().
>
> Signed-off-by: zhang jiao <zhangjiao2@xxxxxxxxxxxxxxxxxxxx>

This is defnitely not trivial material.
Pls report to the proper list in the future.

> ---
> drivers/virtio/virtio_ring.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 5c169fbb418a..42883b01fab0 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -1571,6 +1571,11 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
> 0 : VRING_DESC_F_WRITE);
> desc[i].addr = cpu_to_le64(addr);
> desc[i].len = cpu_to_le32(len);
> + /* The id field is unused in indirect descriptors but
> + * must be initialized to prevent leaking kernel heap
> + * memory to the device through the DMA-mapped table.
> + */



> + desc[i].id = 0;
>
> if (unlikely(vq->use_map_api)) {
> extra[i].addr = premapped ? DMA_MAPPING_ERROR : addr;
> --
> 2.33.0
>
>