virtio_ring: Initialize id field in packed indirect descriptors

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@cmss.chinamobile.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20261029072511.851-1-zhangjiao2@cmss.chinamobile.com>
This commit is contained in:
zhang jiao 2026-10-29 15:25:10 +08:00 committed by Michael S. Tsirkin
parent 058fc59326
commit 92368f4fb8

View File

@ -1575,6 +1575,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;