--- /dev/null
+From fb4554c2232e44d595920f4d5c66cf8f7d13f9bc Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Mon, 16 May 2022 16:42:13 +0800
+Subject: Fix double fget() in vhost_net_set_backend()
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit fb4554c2232e44d595920f4d5c66cf8f7d13f9bc upstream.
+
+Descriptor table is a shared resource; two fget() on the same descriptor
+may return different struct file references. get_tap_ptr_ring() is
+called after we'd found (and pinned) the socket we'll be using and it
+tries to find the private tun/tap data structures associated with it.
+Redoing the lookup by the same file descriptor we'd used to get the
+socket is racy - we need to same struct file.
+
+Thanks to Jason for spotting a braino in the original variant of patch -
+I'd missed the use of fd == -1 for disabling backend, and in that case
+we can end up with sock == NULL and sock != oldsock.
+
+Cc: stable@kernel.org
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+[4.14: Account for get_tap_skb_array() instead of get_tap_ptr_ring()]
+Signed-off-by: Samuel Mendoza-Jonas <samjonas@amazon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/vhost/net.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- a/drivers/vhost/net.c
++++ b/drivers/vhost/net.c
+@@ -1047,13 +1047,9 @@ err:
+ return ERR_PTR(r);
+ }
+
+-static struct skb_array *get_tap_skb_array(int fd)
++static struct skb_array *get_tap_skb_array(struct file *file)
+ {
+ struct skb_array *array;
+- struct file *file = fget(fd);
+-
+- if (!file)
+- return NULL;
+ array = tun_get_skb_array(file);
+ if (!IS_ERR(array))
+ goto out;
+@@ -1062,7 +1058,6 @@ static struct skb_array *get_tap_skb_arr
+ goto out;
+ array = NULL;
+ out:
+- fput(file);
+ return array;
+ }
+
+@@ -1143,8 +1138,12 @@ static long vhost_net_set_backend(struct
+ vhost_net_disable_vq(n, vq);
+ vq->private_data = sock;
+ vhost_net_buf_unproduce(nvq);
+- if (index == VHOST_NET_VQ_RX)
+- nvq->rx_array = get_tap_skb_array(fd);
++ if (index == VHOST_NET_VQ_RX) {
++ if (sock)
++ nvq->rx_array = get_tap_skb_array(sock->file);
++ else
++ nvq->rx_array = NULL;
++ }
+ r = vhost_vq_init_access(vq);
+ if (r)
+ goto err_used;