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

Commit d8316f39 authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by David S. Miller
Browse files

vhost: fix total length when packets are too short



When mergeable buffers are disabled, and the
incoming packet is too large for the rx buffer,
get_rx_bufs returns success.

This was intentional in order for make recvmsg
truncate the packet and then handle_rx would
detect err != sock_len and drop it.

Unfortunately we pass the original sock_len to
recvmsg - which means we use parts of iov not fully
validated.

Fix this up by detecting this overrun and doing packet drop
immediately.

CVE-2014-0077

Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 05efa8c9
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -532,6 +532,12 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
	*iovcount = seg;
	*iovcount = seg;
	if (unlikely(log))
	if (unlikely(log))
		*log_num = nlogs;
		*log_num = nlogs;

	/* Detect overrun */
	if (unlikely(datalen > 0)) {
		r = UIO_MAXIOV + 1;
		goto err;
	}
	return headcount;
	return headcount;
err:
err:
	vhost_discard_vq_desc(vq, headcount);
	vhost_discard_vq_desc(vq, headcount);
@@ -587,6 +593,14 @@ static void handle_rx(struct vhost_net *net)
		/* On error, stop handling until the next kick. */
		/* On error, stop handling until the next kick. */
		if (unlikely(headcount < 0))
		if (unlikely(headcount < 0))
			break;
			break;
		/* On overrun, truncate and discard */
		if (unlikely(headcount > UIO_MAXIOV)) {
			msg.msg_iovlen = 1;
			err = sock->ops->recvmsg(NULL, sock, &msg,
						 1, MSG_DONTWAIT | MSG_TRUNC);
			pr_debug("Discarded rx packet: len %zd\n", sock_len);
			continue;
		}
		/* OK, now we need to know about added descriptors. */
		/* OK, now we need to know about added descriptors. */
		if (!headcount) {
		if (!headcount) {
			if (unlikely(vhost_enable_notify(&net->dev, vq))) {
			if (unlikely(vhost_enable_notify(&net->dev, vq))) {