Skip to content

Commit 02e9e93

Browse files
jasowangmstsirkin
authored andcommitted
vhost_vdpa: assign irq bypass producer token correctly
We used to call irq_bypass_unregister_producer() in vhost_vdpa_setup_vq_irq() which is problematic as we don't know if the token pointer is still valid or not. Actually, we use the eventfd_ctx as the token so the life cycle of the token should be bound to the VHOST_SET_VRING_CALL instead of vhost_vdpa_setup_vq_irq() which could be called by set_status(). Fixing this by setting up irq bypass producer's token when handling VHOST_SET_VRING_CALL and un-registering the producer before calling vhost_vring_ioctl() to prevent a possible use after free as eventfd could have been released in vhost_vring_ioctl(). And such registering and unregistering will only be done if DRIVER_OK is set. Reported-by: Dragos Tatulea <dtatulea@nvidia.com> Tested-by: Dragos Tatulea <dtatulea@nvidia.com> Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com> Fixes: 2cf1ba9 ("vhost_vdpa: implement IRQ offloading in vhost_vdpa") Signed-off-by: Jason Wang <jasowang@redhat.com> Message-Id: <20240816031900.18013-1-jasowang@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent dc12502 commit 02e9e93

1 file changed

Lines changed: 13 additions & 3 deletions

File tree

drivers/vhost/vdpa.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,9 @@ static void vhost_vdpa_setup_vq_irq(struct vhost_vdpa *v, u16 qid)
209209
if (irq < 0)
210210
return;
211211

212-
irq_bypass_unregister_producer(&vq->call_ctx.producer);
213212
if (!vq->call_ctx.ctx)
214213
return;
215214

216-
vq->call_ctx.producer.token = vq->call_ctx.ctx;
217215
vq->call_ctx.producer.irq = irq;
218216
ret = irq_bypass_register_producer(&vq->call_ctx.producer);
219217
if (unlikely(ret))
@@ -709,6 +707,14 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
709707
vq->last_avail_idx = vq_state.split.avail_index;
710708
}
711709
break;
710+
case VHOST_SET_VRING_CALL:
711+
if (vq->call_ctx.ctx) {
712+
if (ops->get_status(vdpa) &
713+
VIRTIO_CONFIG_S_DRIVER_OK)
714+
vhost_vdpa_unsetup_vq_irq(v, idx);
715+
vq->call_ctx.producer.token = NULL;
716+
}
717+
break;
712718
}
713719

714720
r = vhost_vring_ioctl(&v->vdev, cmd, argp);
@@ -747,13 +753,16 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
747753
cb.callback = vhost_vdpa_virtqueue_cb;
748754
cb.private = vq;
749755
cb.trigger = vq->call_ctx.ctx;
756+
vq->call_ctx.producer.token = vq->call_ctx.ctx;
757+
if (ops->get_status(vdpa) &
758+
VIRTIO_CONFIG_S_DRIVER_OK)
759+
vhost_vdpa_setup_vq_irq(v, idx);
750760
} else {
751761
cb.callback = NULL;
752762
cb.private = NULL;
753763
cb.trigger = NULL;
754764
}
755765
ops->set_vq_cb(vdpa, idx, &cb);
756-
vhost_vdpa_setup_vq_irq(v, idx);
757766
break;
758767

759768
case VHOST_SET_VRING_NUM:
@@ -1419,6 +1428,7 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
14191428
for (i = 0; i < nvqs; i++) {
14201429
vqs[i] = &v->vqs[i];
14211430
vqs[i]->handle_kick = handle_vq_kick;
1431+
vqs[i]->call_ctx.ctx = NULL;
14221432
}
14231433
vhost_dev_init(dev, vqs, nvqs, 0, 0, 0, false,
14241434
vhost_vdpa_process_iotlb_msg);

0 commit comments

Comments
 (0)