Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ca70982 authored by Al Viro's avatar Al Viro Committed by Greg Kroah-Hartman
Browse files

Fix double fget() in vhost_net_set_backend()



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: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarJason Wang <jasowang@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6cdd53a4
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -1209,13 +1209,9 @@ static struct socket *get_raw_socket(int fd)
	return ERR_PTR(r);
}

static struct ptr_ring *get_tap_ptr_ring(int fd)
static struct ptr_ring *get_tap_ptr_ring(struct file *file)
{
	struct ptr_ring *ring;
	struct file *file = fget(fd);

	if (!file)
		return NULL;
	ring = tun_get_tx_ring(file);
	if (!IS_ERR(ring))
		goto out;
@@ -1224,7 +1220,6 @@ static struct ptr_ring *get_tap_ptr_ring(int fd)
		goto out;
	ring = NULL;
out:
	fput(file);
	return ring;
}

@@ -1311,8 +1306,12 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
		r = vhost_net_enable_vq(n, vq);
		if (r)
			goto err_used;
		if (index == VHOST_NET_VQ_RX)
			nvq->rx_ring = get_tap_ptr_ring(fd);
		if (index == VHOST_NET_VQ_RX) {
			if (sock)
				nvq->rx_ring = get_tap_ptr_ring(sock->file);
			else
				nvq->rx_ring = NULL;
		}

		oldubufs = nvq->ubufs;
		nvq->ubufs = ubufs;