From 4c050286bb202cffd5467c1cba982dff391d62e1 Mon Sep 17 00:00:00 2001 From: Gautam Dawar Date: Wed, 24 Feb 2021 17:18:45 +0530 Subject: vhost_vdpa: fix the missing irq_bypass_unregister_producer() invocation When qemu with vhost-vdpa netdevice is run for the first time, it works well. But after the VM is powered off, the next qemu run causes kernel panic due to a NULL pointer dereference in irq_bypass_register_producer(). When the VM is powered off, vhost_vdpa_clean_irq() misses on calling irq_bypass_unregister_producer() for irq 0 because of the existing check. This leaves stale producer nodes, which are reset in vhost_vring_call_reset() when vhost_dev_init() is invoked during the second qemu run. As the node member of struct irq_bypass_producer is also initialized to zero, traversal on the producers list causes crash due to NULL pointer dereference. Fixes: 2cf1ba9a4d15c ("vhost_vdpa: implement IRQ offloading in vhost_vdpa") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=211711 Signed-off-by: Gautam Dawar Acked-by: Jason Wang Link: https://lore.kernel.org/r/20210224114845.104173-1-gdawar.xilinx@gmail.com Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vdpa.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index ef688c8c0e0e..dfdd8e4a8b08 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -900,14 +900,10 @@ err: static void vhost_vdpa_clean_irq(struct vhost_vdpa *v) { - struct vhost_virtqueue *vq; int i; - for (i = 0; i < v->nvqs; i++) { - vq = &v->vqs[i]; - if (vq->call_ctx.producer.irq) - irq_bypass_unregister_producer(&vq->call_ctx.producer); - } + for (i = 0; i < v->nvqs; i++) + vhost_vdpa_unsetup_vq_irq(v, i); } static int vhost_vdpa_release(struct inode *inode, struct file *filep) -- cgit v1.2.3 From beb691e69f4dec7bfe8b81b509848acfd1f0dbf9 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 12 Mar 2021 15:09:13 +0100 Subject: vhost: Fix vhost_vq_reset() vhost_reset_is_le() is vhost_init_is_le(), and in the case of cross-endian legacy, vhost_init_is_le() depends on vq->user_be. vq->user_be is set by vhost_disable_cross_endian(). But in vhost_vq_reset(), we have: vhost_reset_is_le(vq); vhost_disable_cross_endian(vq); And so user_be is used before being set. To fix that, reverse the lines order as there is no other dependency between them. Signed-off-by: Laurent Vivier Link: https://lore.kernel.org/r/20210312140913.788592-1-lvivier@redhat.com Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a262e12c6dc2..5ccb0705beae 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -332,8 +332,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->error_ctx = NULL; vq->kick = NULL; vq->log_ctx = NULL; - vhost_reset_is_le(vq); vhost_disable_cross_endian(vq); + vhost_reset_is_le(vq); vq->busyloop_timeout = 0; vq->umem = NULL; vq->iotlb = NULL; -- cgit v1.2.3 From f6bbf0010ba004f5e90c7aefdebc0ee4bd3283b9 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Thu, 11 Mar 2021 14:52:56 +0100 Subject: vhost-vdpa: fix use-after-free of v->config_ctx When the 'v->config_ctx' eventfd_ctx reference is released we didn't set it to NULL. So if the same character device (e.g. /dev/vhost-vdpa-0) is re-opened, the 'v->config_ctx' is invalid and calling again vhost_vdpa_config_put() causes use-after-free issues like the following refcount_t underflow: refcount_t: underflow; use-after-free. WARNING: CPU: 2 PID: 872 at lib/refcount.c:28 refcount_warn_saturate+0xae/0xf0 RIP: 0010:refcount_warn_saturate+0xae/0xf0 Call Trace: eventfd_ctx_put+0x5b/0x70 vhost_vdpa_release+0xcd/0x150 [vhost_vdpa] __fput+0x8e/0x240 ____fput+0xe/0x10 task_work_run+0x66/0xa0 exit_to_user_mode_prepare+0x118/0x120 syscall_exit_to_user_mode+0x21/0x50 ? __x64_sys_close+0x12/0x40 do_syscall_64+0x45/0x50 entry_SYSCALL_64_after_hwframe+0x44/0xae Fixes: 776f395004d8 ("vhost_vdpa: Support config interrupt in vdpa") Cc: lingshan.zhu@intel.com Cc: stable@vger.kernel.org Signed-off-by: Stefano Garzarella Link: https://lore.kernel.org/r/20210311135257.109460-2-sgarzare@redhat.com Signed-off-by: Michael S. Tsirkin Reviewed-by: Zhu Lingshan Acked-by: Jason Wang --- drivers/vhost/vdpa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index dfdd8e4a8b08..4fc768813c4a 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -308,8 +308,10 @@ static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp) static void vhost_vdpa_config_put(struct vhost_vdpa *v) { - if (v->config_ctx) + if (v->config_ctx) { eventfd_ctx_put(v->config_ctx); + v->config_ctx = NULL; + } } static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp) -- cgit v1.2.3 From 0bde59c1723a29e294765c96dbe5c7fb639c2f96 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Thu, 11 Mar 2021 14:52:57 +0100 Subject: vhost-vdpa: set v->config_ctx to NULL if eventfd_ctx_fdget() fails In vhost_vdpa_set_config_call() if eventfd_ctx_fdget() fails the 'v->config_ctx' contains an error instead of a valid pointer. Since we consider 'v->config_ctx' valid if it is not NULL, we should set it to NULL in this case to avoid to use an invalid pointer in other functions such as vhost_vdpa_config_put(). Fixes: 776f395004d8 ("vhost_vdpa: Support config interrupt in vdpa") Cc: lingshan.zhu@intel.com Cc: stable@vger.kernel.org Signed-off-by: Stefano Garzarella Link: https://lore.kernel.org/r/20210311135257.109460-3-sgarzare@redhat.com Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vhost/vdpa.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 4fc768813c4a..e0a27e336293 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -331,8 +331,12 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp) if (!IS_ERR_OR_NULL(ctx)) eventfd_ctx_put(ctx); - if (IS_ERR(v->config_ctx)) - return PTR_ERR(v->config_ctx); + if (IS_ERR(v->config_ctx)) { + long ret = PTR_ERR(v->config_ctx); + + v->config_ctx = NULL; + return ret; + } v->vdpa->config->set_config_cb(v->vdpa, &cb); -- cgit v1.2.3