All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Eric Dumazet" <edumazet@kernel.org>
Cc: virtualization@lists.linux.dev,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH net 1/3] net: virtio: validate outer protocol of UDP tunnel GSO packets
Date: Wed, 04 Nov 2026 20:31:31 +0000	[thread overview]
Message-ID: <sashiko-outbox-198016@kernel.org> (raw)
In-Reply-To: <20261103203113.550604-2-edumazet@kernel.org>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] net: virtio: unreliable L3 check in virtio_net_tnl_outer_proto_ok()
--

commit 02f420dee7a050b3832ecf552c44f9c2eeaaddc1
Author: Eric Dumazet <edumazet@kernel.org>

net: virtio: validate outer protocol of UDP tunnel GSO packets

This commit validates that the outer L3 protocol of a UDP tunnel GSO packet
matches the tunnel type declared in the virtio header in
virtio_net_hdr_tnl_to_skb().

> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index d6466f96cdd00..d3f97d71d81cc 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -282,6 +282,31 @@ static inline unsigned int virtio_l3min(bool is_ipv6)
>  	return is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr);
>  }
>  
> +/* The outer network header of a UDP tunnel GSO packet must match the
> + * tunnel type declared in the virtio header, otherwise the GSO stack
> + * would parse the packet as something else (e.g. NSH).
> + */
> +static inline bool virtio_net_tnl_outer_proto_ok(const struct sk_buff *skb,
> +						 bool outer_isv6,
> +						 unsigned int outer_th)
> +{
> +	__be16 expected = outer_isv6 ? htons(ETH_P_IPV6) : htons(ETH_P_IP);
> +	__be16 proto = skb->protocol;
> +	int nh_off = ETH_HLEN;
> +
> +	/* L3 device (IFF_TUN): the caller already set the protocol. */
> +	if (proto)
> +		return proto == expected;

[Severity: High]
Can testing if (proto) here be bypassed in tun_get_user() in two ways?

First, on an IFF_TAP device with IFF_NAPI_FRAGS enabled, tun_get_user()
allocates the skb via tun_napi_alloc_frags() -> napi_get_frags(). When a
prior packet was merged by GRO (GRO_MERGED_FREE in napi_frags_finish()),
napi_reuse_skb() caches napi->skb for reuse without clearing skb->protocol
(which napi_frags_skb() set to the previous frame's eth->h_proto, such as
htons(ETH_P_IP)).

In drivers/net/tun.c:tun_get_user(), tun_vnet_hdr_tnl_to_skb() runs before
eth_type_trans() updates skb->protocol for the new frame:

	if (tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, &hdr)) {
		atomic_long_inc(&tun->rx_frame_errors);
		err = -EINVAL;
		goto free_skb;
	}

	if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP)
		skb->protocol = eth_type_trans(skb, tun->dev);

With a reused napi->skb still carrying skb->protocol == htons(ETH_P_IP),
virtio_net_tnl_outer_proto_ok() takes the if (proto) branch and returns true
without inspecting eth_hdr(skb)->h_proto or checking nh_off +
virtio_l3min(outer_isv6) <= outer_th, and eth_type_trans() then sets
skb->protocol to the new frame's actual EtherType (such as ETH_P_NSH).

Second, on an IFF_TUN device without IFF_NO_PI, tun_get_user() copies struct
tun_pi from userspace and sets skb->protocol = pi.proto:

		skb_reset_network_header(skb);
		skb->protocol = pi.proto;
		break;

If userspace passes pi.proto == 0, proto is 0, so
virtio_net_tnl_outer_proto_ok() falls through to the Ethernet path and checks
eth_hdr(skb)->h_proto inside the L3 payload, leaving skb->protocol == 0 with
SKB_GSO_UDP_TUNNEL set if those bytes match expected.

Since all callers set skb->network_header before calling
virtio_net_hdr_tnl_to_skb() (to 0 via skb_reset_network_header() for IFF_TUN,
and to ETH_HLEN via skb_set_network_header() for IFF_TAP and virtio_net),
would checking !skb_network_offset(skb) instead of if (proto) avoid both
issues?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261103203113.550604-1-edumazet@kernel.org?part=1

  parent reply	other threads:[~2026-11-04 20:31 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03 20:31 [PATCH net 0/3] net: virtio: validate outer protocol of UDP tunnel GSO packets Eric Dumazet
2026-11-03 20:31 ` [PATCH net 1/3] " Eric Dumazet
2026-11-04  2:01   ` Willem de Bruijn
2026-11-04  4:49     ` Eric Dumazet
2026-11-04 20:31   ` sashiko-bot [this message]
2026-11-05  8:32   ` netdev-bot+sashiko
2026-11-03 20:31 ` [PATCH net 2/3] selftests: net: tuntap: fix UDP checksum length in build_udp_packet_csum() Eric Dumazet
2026-11-04  2:10   ` Willem de Bruijn
2026-11-04 20:31   ` sashiko-bot
2026-11-03 20:31 ` [PATCH net 3/3] selftests: net: tun: test outer protocol of UDP tunnel GSO packets Eric Dumazet
2026-11-04  2:19   ` Willem de Bruijn
2026-11-04 20:31   ` sashiko-bot
2026-11-05  8:32   ` netdev-bot+sashiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-198016@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=edumazet@kernel.org \
    --cc=eperezma@redhat.com \
    --cc=mst@redhat.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=virtualization@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.