Commit 1cb36e25 authored by Stefano Garzarella's avatar Stefano Garzarella Committed by Paolo Abeni
Browse files

vsock/virtio: fix MSG_ZEROCOPY pinned-pages accounting



virtio_transport_init_zcopy_skb() uses iter->count as the size argument
for msg_zerocopy_realloc(), which in turn passes it to
mm_account_pinned_pages() for RLIMIT_MEMLOCK accounting. However, this
function is called after virtio_transport_fill_skb() has already consumed
the iterator via __zerocopy_sg_from_iter(), so on the last skb, iter->count
will be 0, skipping the RLIMIT_MEMLOCK enforcement.

Pass pkt_len (the total bytes being sent) as an explicit parameter to
virtio_transport_init_zcopy_skb() instead of reading the already-consumed
iter->count.

This matches TCP and UDP, which both call msg_zerocopy_realloc() with
the original message size.

Fixes: 581512a6 ("vsock/virtio: MSG_ZEROCOPY flag support")
Reported-by: default avatarYiming Qian <yimingqian591@gmail.com>
Signed-off-by: default avatarStefano Garzarella <sgarzare@redhat.com>
Reviewed-by: default avatarBobby Eshleman <bobbyeshleman@meta.com>
Link: https://patch.msgid.link/20260420132051.217589-1-sgarzare@redhat.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 42ea37b0
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops,
static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk,
					   struct sk_buff *skb,
					   struct msghdr *msg,
					   size_t pkt_len,
					   bool zerocopy)
{
	struct ubuf_info *uarg;
@@ -81,12 +82,10 @@ static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk,
		uarg = msg->msg_ubuf;
		net_zcopy_get(uarg);
	} else {
		struct iov_iter *iter = &msg->msg_iter;
		struct ubuf_info_msgzc *uarg_zc;

		uarg = msg_zerocopy_realloc(sk_vsock(vsk),
					    iter->count,
					    NULL, false);
					    pkt_len, NULL, false);
		if (!uarg)
			return -1;

@@ -398,11 +397,17 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
		 * each iteration. If this is last skb for this buffer
		 * and MSG_ZEROCOPY mode is in use - we must allocate
		 * completion for the current syscall.
		 *
		 * Pass pkt_len because msg iter is already consumed
		 * by virtio_transport_fill_skb(), so iter->count
		 * can not be used for RLIMIT_MEMLOCK pinned-pages
		 * accounting done by msg_zerocopy_realloc().
		 */
		if (info->msg && info->msg->msg_flags & MSG_ZEROCOPY &&
		    skb_len == rest_len && info->op == VIRTIO_VSOCK_OP_RW) {
			if (virtio_transport_init_zcopy_skb(vsk, skb,
							    info->msg,
							    pkt_len,
							    can_zcopy)) {
				kfree_skb(skb);
				ret = -ENOMEM;