Skip to content

Commit 97ee04f

Browse files
Feng Liumstsirkin
authored andcommitted
virtio_pci: Fix admin vq cleanup by using correct info pointer
vp_modern_avq_cleanup() and vp_del_vqs() clean up admin vq resources by virtio_pci_vq_info pointer. The info pointer of admin vq is stored in vp_dev->admin_vq.info instead of vp_dev->vqs[]. Using the info pointer from vp_dev->vqs[] for admin vq causes a kernel NULL pointer dereference bug. In vp_modern_avq_cleanup() and vp_del_vqs(), get the info pointer from vp_dev->admin_vq.info for admin vq to clean up the resources. Also make info ptr as argument of vp_del_vq() to be symmetric with vp_setup_vq(). vp_reset calls vp_modern_avq_cleanup, and causes the Call Trace: ================================================================== BUG: kernel NULL pointer dereference, address:0000000000000000 ... CPU: 49 UID: 0 PID: 4439 Comm: modprobe Not tainted 6.11.0-rc5 #1 RIP: 0010:vp_reset+0x57/0x90 [virtio_pci] Call Trace: <TASK> ... ? vp_reset+0x57/0x90 [virtio_pci] ? vp_reset+0x38/0x90 [virtio_pci] virtio_reset_device+0x1d/0x30 remove_vq_common+0x1c/0x1a0 [virtio_net] virtnet_remove+0xa1/0xc0 [virtio_net] virtio_dev_remove+0x46/0xa0 ... virtio_pci_driver_exit+0x14/0x810 [virtio_pci] ================================================================== Fixes: 4c3b54a ("virtio_pci_modern: use completion instead of busy loop to wait on admin cmd result") Signed-off-by: Feng Liu <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Reviewed-by: Parav Pandit <[email protected]> Message-Id: <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 7f8825b commit 97ee04f

File tree

3 files changed

+20
-17
lines changed

3 files changed

+20
-17
lines changed

drivers/virtio/virtio_pci_common.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ MODULE_PARM_DESC(force_legacy,
2424
"Force legacy mode for transitional virtio 1 devices");
2525
#endif
2626

27+
bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
28+
{
29+
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
30+
31+
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
32+
return false;
33+
34+
return index == vp_dev->admin_vq.vq_index;
35+
}
36+
2737
/* wait for pending irq handlers */
2838
void vp_synchronize_vectors(struct virtio_device *vdev)
2939
{
@@ -234,10 +244,9 @@ static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned int in
234244
return vq;
235245
}
236246

237-
static void vp_del_vq(struct virtqueue *vq)
247+
static void vp_del_vq(struct virtqueue *vq, struct virtio_pci_vq_info *info)
238248
{
239249
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
240-
struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
241250
unsigned long flags;
242251

243252
/*
@@ -258,13 +267,16 @@ static void vp_del_vq(struct virtqueue *vq)
258267
void vp_del_vqs(struct virtio_device *vdev)
259268
{
260269
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
270+
struct virtio_pci_vq_info *info;
261271
struct virtqueue *vq, *n;
262272
int i;
263273

264274
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
265-
if (vp_dev->per_vq_vectors) {
266-
int v = vp_dev->vqs[vq->index]->msix_vector;
275+
info = vp_is_avq(vdev, vq->index) ? vp_dev->admin_vq.info :
276+
vp_dev->vqs[vq->index];
267277

278+
if (vp_dev->per_vq_vectors) {
279+
int v = info->msix_vector;
268280
if (v != VIRTIO_MSI_NO_VECTOR &&
269281
!vp_is_slow_path_vector(v)) {
270282
int irq = pci_irq_vector(vp_dev->pci_dev, v);
@@ -273,7 +285,7 @@ void vp_del_vqs(struct virtio_device *vdev)
273285
free_irq(irq, vq);
274286
}
275287
}
276-
vp_del_vq(vq);
288+
vp_del_vq(vq, info);
277289
}
278290
vp_dev->per_vq_vectors = false;
279291

@@ -354,7 +366,7 @@ vp_find_one_vq_msix(struct virtio_device *vdev, int queue_idx,
354366
vring_interrupt, 0,
355367
vp_dev->msix_names[msix_vec], vq);
356368
if (err) {
357-
vp_del_vq(vq);
369+
vp_del_vq(vq, *p_info);
358370
return ERR_PTR(err);
359371
}
360372

drivers/virtio/virtio_pci_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev);
178178
#define VIRTIO_ADMIN_CMD_BITMAP 0
179179
#endif
180180

181+
bool vp_is_avq(struct virtio_device *vdev, unsigned int index);
181182
void vp_modern_avq_done(struct virtqueue *vq);
182183
int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
183184
struct virtio_admin_cmd *cmd);

drivers/virtio/virtio_pci_modern.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,6 @@ static int vp_avq_index(struct virtio_device *vdev, u16 *index, u16 *num)
4343
return 0;
4444
}
4545

46-
static bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
47-
{
48-
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
49-
50-
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
51-
return false;
52-
53-
return index == vp_dev->admin_vq.vq_index;
54-
}
55-
5646
void vp_modern_avq_done(struct virtqueue *vq)
5747
{
5848
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
@@ -245,7 +235,7 @@ static void vp_modern_avq_cleanup(struct virtio_device *vdev)
245235
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
246236
return;
247237

248-
vq = vp_dev->vqs[vp_dev->admin_vq.vq_index]->vq;
238+
vq = vp_dev->admin_vq.info->vq;
249239
if (!vq)
250240
return;
251241

0 commit comments

Comments
 (0)