summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2021-09-08 14:42:09 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-09-22 13:26:41 +0300
commite7332a1ac14e8b21ff6f1dd335ca6cedbd33a977 (patch)
tree0f9dee7437635cae6f6b4b093fbe5fce021665d9
parent172749c879f5302ae4c580f2faec5b948e71cc47 (diff)
downloadlinux-e7332a1ac14e8b21ff6f1dd335ca6cedbd33a977.tar.xz
vhost_net: fix OoB on sendmsg() failure.
commit 3c4cea8fa7f71f00c5279547043a84bc2a4d8b8c upstream. If the sendmsg() call in vhost_tx_batch() fails, both the 'batched_xdp' and 'done_idx' indexes are left unchanged. If such failure happens when batched_xdp == VHOST_NET_BATCH, the next call to vhost_net_build_xdp() will access and write memory outside the xdp buffers area. Since sendmsg() can only error with EBADFD, this change addresses the issue explicitly freeing the XDP buffers batch on error. Fixes: 0a0be13b8fe2 ("vhost_net: batch submitting XDP buffers to underlayer sockets") Suggested-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/vhost/net.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 48e574ae6033..cec9173aac6f 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -466,7 +466,7 @@ static void vhost_tx_batch(struct vhost_net *net,
.num = nvq->batched_xdp,
.ptr = nvq->xdp,
};
- int err;
+ int i, err;
if (nvq->batched_xdp == 0)
goto signal_used;
@@ -475,6 +475,15 @@ static void vhost_tx_batch(struct vhost_net *net,
err = sock->ops->sendmsg(sock, msghdr, 0);
if (unlikely(err < 0)) {
vq_err(&nvq->vq, "Fail to batch sending packets\n");
+
+ /* free pages owned by XDP; since this is an unlikely error path,
+ * keep it simple and avoid more complex bulk update for the
+ * used pages
+ */
+ for (i = 0; i < nvq->batched_xdp; ++i)
+ put_page(virt_to_head_page(nvq->xdp[i].data));
+ nvq->batched_xdp = 0;
+ nvq->done_idx = 0;
return;
}