From: Akihiko Odaki Date: Fri, 7 Feb 2025 06:10:52 +0000 (+0900) Subject: tun: Keep hdr_len in tun_get_user() X-Git-Tag: v6.15-rc1~160^2~362^2~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=07e8b3bae2f8f49e3cd6ea51f899a3d062100822;p=thirdparty%2Fkernel%2Flinux.git tun: Keep hdr_len in tun_get_user() hdr_len is repeatedly used so keep it in a local variable. Signed-off-by: Akihiko Odaki Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20250207-tun-v6-2-fb49cf8b103e@daynix.com Signed-off-by: Jakub Kicinski --- diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8a9a29031bd88..ecc32421dbb51 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1747,6 +1747,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, struct virtio_net_hdr gso = { 0 }; int good_linear; int copylen; + int hdr_len = 0; bool zerocopy = false; int err; u32 rxhash = 0; @@ -1773,19 +1774,21 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, if (!copy_from_iter_full(&gso, sizeof(gso), from)) return -EFAULT; - if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && - tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len)) - gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2); + hdr_len = tun16_to_cpu(tun, gso.hdr_len); - if (tun16_to_cpu(tun, gso.hdr_len) > len) + if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { + hdr_len = max(tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2, hdr_len); + gso.hdr_len = cpu_to_tun16(tun, hdr_len); + } + + if (hdr_len > len) return -EINVAL; iov_iter_advance(from, vnet_hdr_sz - sizeof(gso)); } if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) { align += NET_IP_ALIGN; - if (unlikely(len < ETH_HLEN || - (gso.hdr_len && tun16_to_cpu(tun, gso.hdr_len) < ETH_HLEN))) + if (unlikely(len < ETH_HLEN || (hdr_len && hdr_len < ETH_HLEN))) return -EINVAL; } @@ -1798,9 +1801,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, * enough room for skb expand head in case it is used. * The rest of the buffer is mapped from userspace. */ - copylen = gso.hdr_len ? tun16_to_cpu(tun, gso.hdr_len) : GOODCOPY_LEN; - if (copylen > good_linear) - copylen = good_linear; + copylen = min(hdr_len ? hdr_len : GOODCOPY_LEN, good_linear); linear = copylen; iov_iter_advance(&i, copylen); if (iov_iter_npages(&i, INT_MAX) <= MAX_SKB_FRAGS) @@ -1821,10 +1822,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } else { if (!zerocopy) { copylen = len; - if (tun16_to_cpu(tun, gso.hdr_len) > good_linear) - linear = good_linear; - else - linear = tun16_to_cpu(tun, gso.hdr_len); + linear = min(hdr_len, good_linear); } if (frags) {