From 09861858a68342f851f71c669ac0f69865c32151 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 2 Mar 2026 03:51:49 -0500 Subject: vhost: fix vhost_get_avail_idx for a non empty ring vhost_get_avail_idx is supposed to report whether it has updated vq->avail_idx. Instead, it returns whether all entries have been consumed, which is usually the same. But not always - in drivers/vhost/net.c and when mergeable buffers have been enabled, the driver checks whether the combined entries are big enough to store an incoming packet. If not, the driver re-enables notifications with available entries still in the ring. The incorrect return value from vhost_get_avail_idx propagates through vhost_enable_notify and causes the host to livelock if the guest is not making progress, as vhost will immediately disable notifications and retry using the available entries. This goes back to commit d3bb267bbdcb ("vhost: cache avail index in vhost_enable_notify()") which changed vhost_enable_notify() to compare the freshly read avail index against vq->last_avail_idx instead of the previously cached vq->avail_idx. Commit 7ad472397667 ("vhost: move smp_rmb() into vhost_get_avail_idx()") then carried over the same comparison when refactoring vhost_enable_notify() to call the unified vhost_get_avail_idx(). The obvious fix is to make vhost_get_avail_idx do what the comment says it does and report whether new entries have been added. Reported-by: ShuangYu Fixes: d3bb267bbdcb ("vhost: cache avail index in vhost_enable_notify()") Cc: Stefan Hajnoczi Acked-by: Jason Wang Reviewed-by: Stefano Garzarella Signed-off-by: Michael S. Tsirkin Message-Id: <559b04ae6ce52973c535dc47e461638b7f4c3d63.1772441455.git.mst@redhat.com> --- drivers/vhost/vhost.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2f2c45d20883..db329a6f6145 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1522,6 +1522,7 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d) static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) { __virtio16 idx; + u16 avail_idx; int r; r = vhost_get_avail(vq, idx, &vq->avail->idx); @@ -1532,17 +1533,19 @@ static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) } /* Check it isn't doing very strange thing with available indexes */ - vq->avail_idx = vhost16_to_cpu(vq, idx); - if (unlikely((u16)(vq->avail_idx - vq->last_avail_idx) > vq->num)) { + avail_idx = vhost16_to_cpu(vq, idx); + if (unlikely((u16)(avail_idx - vq->last_avail_idx) > vq->num)) { vq_err(vq, "Invalid available index change from %u to %u", - vq->last_avail_idx, vq->avail_idx); + vq->last_avail_idx, avail_idx); return -EINVAL; } /* We're done if there is nothing new */ - if (vq->avail_idx == vq->last_avail_idx) + if (avail_idx == vq->avail_idx) return 0; + vq->avail_idx = avail_idx; + /* * We updated vq->avail_idx so we need a memory barrier between * the index read above and the caller reading avail ring entries. -- cgit From bb26ed5f3a8b233e8389b6f946cb1ec269cf45e9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 13 May 2026 16:50:04 +0200 Subject: vhost/vsock: Refuse the connection immediately when guest isn't ready When the host initiates an AF_VSOCK connect() to a guest that has not yet loaded the virtio-vsock transport (i.e. still booting), the caller blocks for VSOCK_DEFAULT_CONNECT_TIMEOUT. A caller that wants to know if the guest is up yet instead of waiting could theoretically tune SO_VM_SOCKETS_CONNECT_TIMEOUT, but it's tricky to find the right timeout, if not impossible: there's no way to distinguish "guest won't reply because it's not up yet" vs "guest is up and tried to reply, but was too slow". Furthermore, this delay is pointless: - If the guest doesn't initialize within this timeout, connect() returns ETIMEDOUT. - If the guest **does** initialize, it'll reply with RST immediately, because there won't be a listener on the port yet; connect() returns ECONNRESET. That's also inconsistent with the behavior at other initialization stages: if a connection is attempted when the guest driver is already loaded, but nothing is listening yet, we return ECONNRESET immediately without waiting. Fix this by checking the RX virtqueue backend in vhost_transport_send_pkt() before queuing. If it's NULL, return -EHOSTUNREACH immediately. Callers that used to get ETIMEDOUT will now usually get EHOSTUNREACH. Signed-off-by: Denis V. Lunev Co-developed-by: Polina Vishneva Signed-off-by: Polina Vishneva Reviewed-by: Stefano Garzarella Signed-off-by: Michael S. Tsirkin Message-ID: <20260513145842.809404-1-polina.vishneva@virtuozzo.com> --- drivers/vhost/vsock.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 1d8ec6bed53e..9aaab6bb8061 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -302,6 +302,22 @@ vhost_transport_send_pkt(struct sk_buff *skb, struct net *net) return -ENODEV; } + /* Fast-fail if the guest hasn't enabled the RX vq yet. Queuing the packet + * and making the caller wait is pointless: even if the guest manages to init + * within the timeout, it'll immediately reply with RST, because there's no + * listener on the port yet. + * + * vhost_vq_get_backend() without vq->mutex is acceptable here: locking + * the mutex would be too expensive in this hot path, and we already have + * all the outcomes covered: if the backend becomes NULL right after the check, + * vhost_transport_do_send_pkt() will check it under the mutex anyway. + */ + if (unlikely(!data_race(vhost_vq_get_backend(&vsock->vqs[VSOCK_VQ_RX])))) { + rcu_read_unlock(); + kfree_skb(skb); + return -EHOSTUNREACH; + } + if (virtio_vsock_skb_reply(skb)) atomic_inc(&vsock->queued_replies); -- cgit From 929e4f044621c8cc30b612fb74e1410bef09e41b Mon Sep 17 00:00:00 2001 From: Qihang Tang Date: Fri, 8 May 2026 15:58:21 +0800 Subject: vhost/vdpa: validate virtqueue index in mmap and fault paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost_vdpa_mmap() and vhost_vdpa_fault() use vma->vm_pgoff as a virtqueue index for get_vq_notification(), but they do not validate that the index is smaller than v->nvqs. The ioctl path already performs both a bounds check and array_index_nospec(), but the mmap/fault path only checks that the index fits in u16. This allows an out-of-range queue index to reach driver-specific get_vq_notification() callbacks. Fix this by extracting a unified vhost_vdpa_get_vq_notification() helper that validates the queue index against v->nvqs and applies array_index_nospec() before calling the driver callback. Both the mmap and fault paths use this helper, and the bounds checking is consolidated into a single location. From source inspection, the most defensible impact is out-of-bounds access in the callback path, potentially leading to invalid PFN remaps and crash/DoS. Fixes: ddd89d0a059d ("vhost_vdpa: support doorbell mapping via mmap") Acked-by: Eugenio PĂ©rez Acked-by: Michael S. Tsirkin Signed-off-by: Qihang Tang Signed-off-by: Michael S. Tsirkin Message-ID: <20260508075821.92656-1-q.h.hack.winter@gmail.com> --- drivers/vhost/vdpa.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 692564b1bcbb..ac55275fa0d0 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -1482,16 +1482,32 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) } #ifdef CONFIG_MMU -static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) +static int +vhost_vdpa_get_vq_notification(struct vhost_vdpa *v, unsigned long index, + struct vdpa_notification_area *notify) { - struct vhost_vdpa *v = vmf->vma->vm_file->private_data; struct vdpa_device *vdpa = v->vdpa; const struct vdpa_config_ops *ops = vdpa->config; + + if (index > 65535 || index >= v->nvqs) + return -EINVAL; + + index = array_index_nospec(index, v->nvqs); + + *notify = ops->get_vq_notification(vdpa, index); + + return 0; +} + +static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) +{ + struct vhost_vdpa *v = vmf->vma->vm_file->private_data; struct vdpa_notification_area notify; struct vm_area_struct *vma = vmf->vma; - u16 index = vma->vm_pgoff; + unsigned long index = vma->vm_pgoff; - notify = ops->get_vq_notification(vdpa, index); + if (vhost_vdpa_get_vq_notification(v, index, ¬ify)) + return VM_FAULT_SIGBUS; return vmf_insert_pfn(vma, vmf->address & PAGE_MASK, PFN_DOWN(notify.addr)); } @@ -1514,8 +1530,6 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; if (vma->vm_flags & VM_READ) return -EINVAL; - if (index > 65535) - return -EINVAL; if (!ops->get_vq_notification) return -ENOTSUPP; @@ -1523,7 +1537,8 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) * support the doorbell which sits on the page boundary and * does not share the page with other registers. */ - notify = ops->get_vq_notification(vdpa, index); + if (vhost_vdpa_get_vq_notification(v, index, ¬ify)) + return -EINVAL; if (notify.addr & (PAGE_SIZE - 1)) return -EINVAL; if (vma->vm_end - vma->vm_start != notify.size) -- cgit From 8f6898fe80794f2d7c3d38c1158c806e4074a1c4 Mon Sep 17 00:00:00 2001 From: Qing Ming Date: Mon, 1 Jun 2026 18:43:00 +0800 Subject: vhost/net: complete zerocopy ubufs only once vhost-net initializes one ubuf_info per outstanding zerocopy TX descriptor and hands it to the backend socket. The networking stack may then clone a zerocopy skb before all skb references are released. For example, batman-adv fragmentation reaches skb_split(), which calls skb_zerocopy_clone() and increments the same ubuf_info refcount. vhost_zerocopy_complete() currently treats every ubuf callback as a completed vhost descriptor. It dereferences ubuf->ctx, writes the descriptor completion state, and drops the vhost_net_ubuf_ref even when the callback only releases a cloned skb reference. A backend reset can therefore wait for and free the vhost_net_ubuf_ref while another cloned skb still carries the same ubuf_info. A later completion then dereferences the freed ubufs pointer. KASAN reports the stale completion as: BUG: KASAN: slab-use-after-free in vhost_zerocopy_complete+0x1d7/0x1f0 BUG: KASAN: slab-use-after-free in vhost_zerocopy_complete+0x101/0x1f0 vhost_zerocopy_complete skb_copy_ubufs __dev_forward_skb2 veth_xmit The freed object was allocated from vhost_net_ioctl() while setting the backend and freed through kfree_rcu()/kvfree_rcu_bulk after backend removal, while delayed skb completion still reached vhost_zerocopy_complete(). Honor the generic ubuf_info refcount before touching vhost state, and run the vhost descriptor completion only for the final ubuf reference. This matches the msg_zerocopy_complete() ownership rule for cloned zerocopy skbs. Fixes: bab632d69ee4 ("vhost: vhost TX zero-copy support") Signed-off-by: Qing Ming Signed-off-by: Michael S. Tsirkin Message-ID: <20260601104300.197210-1-a0yami@mailbox.org> --- drivers/vhost/net.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index c6536cad9c4f..b9af63fb6306 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -390,13 +390,20 @@ static void vhost_zerocopy_signal_used(struct vhost_net *net, static void vhost_zerocopy_complete(struct sk_buff *skb, struct ubuf_info *ubuf_base, bool success) { - struct ubuf_info_msgzc *ubuf = uarg_to_msgzc(ubuf_base); - struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; - struct vhost_virtqueue *vq = ubufs->vq; + struct ubuf_info_msgzc *ubuf; + struct vhost_net_ubuf_ref *ubufs; + struct vhost_virtqueue *vq; int cnt; - rcu_read_lock_bh(); + /* Only the final cloned skb reference completes the vhost descriptor. */ + if (!refcount_dec_and_test(&ubuf_base->refcnt)) + return; + + ubuf = uarg_to_msgzc(ubuf_base); + ubufs = ubuf->ctx; + vq = ubufs->vq; + rcu_read_lock_bh(); /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; -- cgit From b20b0867f2b36f382d6e77b8f2a489cc37a94366 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Fri, 30 Jan 2026 18:00:09 -0800 Subject: vhost: remove unnecessary module_init/exit functions The vhost driver has unnecessary empty module_init and module_exit functions. Remove them. Note that if a module_init function exists, a module_exit function must also exist; otherwise, the module cannot be unloaded. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Michael S. Tsirkin Message-ID: <20260131020010.45647-1-enelsonmoore@gmail.com> --- drivers/vhost/vhost.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/vhost') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index db329a6f6145..4c525b3e16ea 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -3324,18 +3324,6 @@ void vhost_set_backend_features(struct vhost_dev *dev, u64 features) } EXPORT_SYMBOL_GPL(vhost_set_backend_features); -static int __init vhost_init(void) -{ - return 0; -} - -static void __exit vhost_exit(void) -{ -} - -module_init(vhost_init); -module_exit(vhost_exit); - MODULE_VERSION("0.0.1"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Michael S. Tsirkin"); -- cgit