]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 29 Aug 2025 14:23:29 +0000 (16:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 29 Aug 2025 14:23:29 +0000 (16:23 +0200)
added patches:
vhost-net-protect-ubufs-with-rcu-read-lock-in-vhost_net_ubuf_put.patch

queue-6.12/series
queue-6.12/vhost-net-protect-ubufs-with-rcu-read-lock-in-vhost_net_ubuf_put.patch [new file with mode: 0644]

index 62e35ec1723bd7cd570ad8f64183132d921fdd2e..e260a49596b1229e86cfa624d1d552b3cab0ee98 100644 (file)
@@ -15,3 +15,4 @@ smb-client-fix-race-with-concurrent-opens-in-rename-.patch
 asoc-codecs-tx-macro-correct-tx_macro_component_drv-.patch
 erofs-fix-atomic-context-detection-when-config_debug.patch
 acpi-ec-add-device-to-acpi_ec_no_wakeup-qurik-list.patch
+vhost-net-protect-ubufs-with-rcu-read-lock-in-vhost_net_ubuf_put.patch
diff --git a/queue-6.12/vhost-net-protect-ubufs-with-rcu-read-lock-in-vhost_net_ubuf_put.patch b/queue-6.12/vhost-net-protect-ubufs-with-rcu-read-lock-in-vhost_net_ubuf_put.patch
new file mode 100644 (file)
index 0000000..9d745a3
--- /dev/null
@@ -0,0 +1,79 @@
+From dd54bcf86c91a4455b1f95cbc8e9ac91205f3193 Mon Sep 17 00:00:00 2001
+From: Nikolay Kuratov <kniv@yandex-team.ru>
+Date: Tue, 5 Aug 2025 16:09:17 +0300
+Subject: vhost/net: Protect ubufs with rcu read lock in vhost_net_ubuf_put()
+
+From: Nikolay Kuratov <kniv@yandex-team.ru>
+
+commit dd54bcf86c91a4455b1f95cbc8e9ac91205f3193 upstream.
+
+When operating on struct vhost_net_ubuf_ref, the following execution
+sequence is theoretically possible:
+CPU0 is finalizing DMA operation                   CPU1 is doing VHOST_NET_SET_BACKEND
+                             // ubufs->refcount == 2
+vhost_net_ubuf_put()                               vhost_net_ubuf_put_wait_and_free(oldubufs)
+                                                     vhost_net_ubuf_put_and_wait()
+                                                       vhost_net_ubuf_put()
+                                                         int r = atomic_sub_return(1, &ubufs->refcount);
+                                                         // r = 1
+int r = atomic_sub_return(1, &ubufs->refcount);
+// r = 0
+                                                      wait_event(ubufs->wait, !atomic_read(&ubufs->refcount));
+                                                      // no wait occurs here because condition is already true
+                                                    kfree(ubufs);
+if (unlikely(!r))
+  wake_up(&ubufs->wait);  // use-after-free
+
+This leads to use-after-free on ubufs access. This happens because CPU1
+skips waiting for wake_up() when refcount is already zero.
+
+To prevent that use a read-side RCU critical section in vhost_net_ubuf_put(),
+as suggested by Hillf Danton. For this lock to take effect, free ubufs with
+kfree_rcu().
+
+Cc: stable@vger.kernel.org
+Fixes: 0ad8b480d6ee9 ("vhost: fix ref cnt checking deadlock")
+Reported-by: Andrey Ryabinin <arbn@yandex-team.com>
+Suggested-by: Hillf Danton <hdanton@sina.com>
+Signed-off-by: Nikolay Kuratov <kniv@yandex-team.ru>
+Message-Id: <20250805130917.727332-1-kniv@yandex-team.ru>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/vhost/net.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/vhost/net.c
++++ b/drivers/vhost/net.c
+@@ -96,6 +96,7 @@ struct vhost_net_ubuf_ref {
+       atomic_t refcount;
+       wait_queue_head_t wait;
+       struct vhost_virtqueue *vq;
++      struct rcu_head rcu;
+ };
+ #define VHOST_NET_BATCH 64
+@@ -247,9 +248,13 @@ vhost_net_ubuf_alloc(struct vhost_virtqu
+ static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs)
+ {
+-      int r = atomic_sub_return(1, &ubufs->refcount);
++      int r;
++
++      rcu_read_lock();
++      r = atomic_sub_return(1, &ubufs->refcount);
+       if (unlikely(!r))
+               wake_up(&ubufs->wait);
++      rcu_read_unlock();
+       return r;
+ }
+@@ -262,7 +267,7 @@ static void vhost_net_ubuf_put_and_wait(
+ static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
+ {
+       vhost_net_ubuf_put_and_wait(ubufs);
+-      kfree(ubufs);
++      kfree_rcu(ubufs, rcu);
+ }
+ static void vhost_net_clear_ubuf_info(struct vhost_net *n)