Blob Blame History Raw
Patch-mainline: v5.14-rc7
Git-commit: 0e566c8f0f2e8325e35f6f97e13cde5356b41814
References: git-fixes
From: Parav Pandit <parav@nvidia.com>
Date: Wed, 21 Jul 2021 17:26:47 +0300
Subject: [PATCH] virtio: Protect vqs list access

VQs may be accessed to mark the device broken while they are
created/destroyed. Hence protect the access to the vqs list.

[ jgross: preserve kABI by using config_lock instead ]

Fixes: e2dcdfe95c0b ("virtio: virtio_break_device() to mark all virtqueues broken.")
Signed-off-by: Parav Pandit <parav@nvidia.com>
Link: https://lore.kernel.org/r/20210721142648.1525924-4-parav@nvidia.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
---
 drivers/virtio/virtio.c      | 1 +
 drivers/virtio/virtio_ring.c | 8 ++++++++
 include/linux/virtio.h       | 1 +
 3 files changed, 10 insertions(+)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index d5934c2e5a89..c2aaa0eff6df 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -971,6 +971,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
 {
 	unsigned int i;
 	struct vring_virtqueue *vq;
+	unsigned long flags;
 
 	vq = kmalloc(sizeof(*vq) + vring.num * sizeof(struct vring_desc_state),
 		     GFP_KERNEL);
@@ -993,7 +994,9 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
 	vq->avail_flags_shadow = 0;
 	vq->avail_idx_shadow = 0;
 	vq->num_added = 0;
+	spin_lock_irqsave(&vdev->config_lock, flags);
 	list_add_tail(&vq->vq.list, &vdev->vqs);
+	spin_unlock_irqrestore(&vdev->config_lock, flags);
 #ifdef DEBUG
 	vq->in_use = false;
 	vq->last_add_time_valid = false;
@@ -1159,12 +1162,15 @@ void vring_del_virtqueue(struct virtqueue *_vq)
 void vring_del_virtqueue(struct virtqueue *_vq)
 {
 	struct vring_virtqueue *vq = to_vvq(_vq);
+	unsigned long flags;
 
 	if (vq->we_own_ring) {
 		vring_free_queue(vq->vq.vdev, vq->queue_size_in_bytes,
 				 vq->vring.desc, vq->queue_dma_addr);
 	}
+	spin_lock_irqsave(&vq->vq.vdev->config_lock, flags);
 	list_del(&_vq->list);
+	spin_unlock_irqrestore(&vq->vq.vdev->config_lock, flags);
 	kfree(vq);
 }
 EXPORT_SYMBOL_GPL(vring_del_virtqueue);
@@ -1223,13 +1229,16 @@ void virtio_break_device(struct virtio_device *dev)
 void virtio_break_device(struct virtio_device *dev)
 {
 	struct virtqueue *_vq;
+	unsigned long flags;
 
+	spin_lock_irqsave(&dev->config_lock, flags);
 	list_for_each_entry(_vq, &dev->vqs, list) {
 		struct vring_virtqueue *vq = to_vvq(_vq);
 
 		/* Pairs with READ_ONCE() in virtqueue_is_broken(). */
 		WRITE_ONCE(vq->broken, true);
 	}
+	spin_unlock_irqrestore(&dev->config_lock, flags);
 }
 EXPORT_SYMBOL_GPL(virtio_break_device);
 
-- 
2.35.3