virtio_ring: Check used descriptors are chain heads

When the device returns used buffers, it should refer to the descriptor
that is the head of the descriptor chain for that buffer. Confirm this
to be the case by tracking the head of descriptor chains that have been
made available to the device.

Signed-off-by: Andrew Scull <ascull@google.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Andrew Scull 2022-05-16 10:41:32 +00:00 committed by Tom Rini
parent 10a1453636
commit fbef3f53d4
2 changed files with 14 additions and 0 deletions

View File

@ -82,6 +82,9 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
/* Update free pointer */ /* Update free pointer */
vq->free_head = i; vq->free_head = i;
/* Mark the descriptor as the head of a chain. */
vq->vring_desc_shadow[head].chain_head = true;
/* /*
* Put entry in available array (but don't update avail->idx * Put entry in available array (but don't update avail->idx
* until they do sync). * until they do sync).
@ -144,6 +147,9 @@ static void detach_buf(struct virtqueue *vq, unsigned int head)
{ {
unsigned int i; unsigned int i;
/* Unmark the descriptor as the head of a chain. */
vq->vring_desc_shadow[head].chain_head = false;
/* Put back on free list: unmap first-level descriptors and find end */ /* Put back on free list: unmap first-level descriptors and find end */
i = head; i = head;
@ -194,6 +200,12 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
return NULL; return NULL;
} }
if (unlikely(!vq->vring_desc_shadow[i].chain_head)) {
printf("(%s.%d): id %u is not a head\n",
vq->vdev->name, vq->index, i);
return NULL;
}
detach_buf(vq, i); detach_buf(vq, i);
vq->last_used_idx++; vq->last_used_idx++;
/* /*

View File

@ -61,6 +61,8 @@ struct vring_desc_shadow {
u32 len; u32 len;
u16 flags; u16 flags;
u16 next; u16 next;
/* Metadata about the descriptor. */
bool chain_head;
}; };
struct vring_avail { struct vring_avail {