From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: Eric Dumazet <edumazet@kernel.org>,
netdev@vger.kernel.org, "David S. Miller" <davem@davemloft.net>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
mst@redhat.com
Cc: "Eric Dumazet" <edumazet@kernel.org>,
"Simon Horman" <horms@kernel.org>,
"Willem de Bruijn" <willemb@google.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Hassan Sultan" <hassansultan@google.com>,
virtualization@lists.linux.dev
Subject: Re: [PATCH net 1/3] net: virtio: validate outer protocol of UDP tunnel GSO packets
Date: Tue, 03 Nov 2026 21:01:50 -0500 [thread overview]
Message-ID: <willemdebruijn.kernel.2e11b18d6e190@gmail.com> (raw)
In-Reply-To: <20261103203113.550604-2-edumazet@kernel.org>
Eric Dumazet wrote:
> virtio_net_hdr_tnl_to_skb() trusts the virtio header to describe a
> UDP tunnel over IPv4 or IPv6, but never checks that the frame actually
> carries such an outer header. Because VIRTIO_NET_HDR_F_NEEDS_CSUM is
> mandatory for tunnel GSO, __virtio_net_hdr_to_skb() skips the flow
> dissector, so virtio_net_hdr_match_proto() is never applied either.
>
> A guest (or a tap writer) can then inject a frame with an arbitrary
> outer ethertype, for example ETH_P_NSH, with SKB_GSO_UDP_TUNNEL set.
> The GSO stack then runs nsh_gso_segment() on top of the UDP tunnel
> segmentation, which assumes a different header layout. The result is
> segments with skb->data before skb->head, and a host crash in
> skb_under_panic() as soon as a later layer pushes a header:
>
> skbuff: skb_under_panic: ... put:4 ... dev:gretap1
> kernel BUG at net/core/skbuff.c:215!
> skb_push
> __gre_xmit
> gre_tap_xmit
> ...
> tun_get_user
>
> Require the outer L3 protocol to match the declared tunnel type:
> for Ethernet frames, look at the ethertype after optional VLAN tags,
> and check that the outer network header fits before outer_th_offset.
> For IFF_TUN, skb->protocol is already set by the caller.
>
> Fixes: a2fb4bc4e2a6 ("net: implement virtio helpers to handle UDP GSO tunneling.")
> Reported-by: Hassan Sultan <hassansultan@google.com>
> Signed-off-by: Eric Dumazet <edumazet@kernel.org>
> Cc: Willem de Bruijn <willemb@google.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
Thanks for the fix. It overlaps with
commit "net: resolve uncommon partial checksums at ingress"
https://lore.kernel.org/netdev/93d0e37c99711bebdf60c120af03010455c2f2e2.1793276116.git.mst@redhat.com/
There are a bunch of subtle issues here. That series is up to v7.
Two specific issues are that
- skb->protocol in general cannot be trusted, and
- non-L3 sources cannot be assumed Ethernet
Would it make sense to take the relevant parts from the quoted commit,
which has hopefully resolved those edge cases, and send that on its own?
The rest of the series can come later.
> ---
> include/linux/virtio_net.h | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index d6466f96cdd0..d3f97d71d81c 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;
> +
> + /* Ethernet frame, possibly VLAN tagged. */
> + proto = eth_hdr(skb)->h_proto;
> + if (eth_type_vlan(proto))
> + proto = __vlan_get_protocol(skb, proto, &nh_off);
> +
> + return proto == expected &&
> + nh_off + virtio_l3min(outer_isv6) <= outer_th;
> +}
> +
> static inline int
> virtio_net_hdr_tnl_to_skb(struct sk_buff *skb,
> const struct virtio_net_hdr_v1_hash_tunnel *vhdr,
> @@ -338,6 +363,9 @@ virtio_net_hdr_tnl_to_skb(struct sk_buff *skb,
> if (ret)
> return ret;
>
> + if (!virtio_net_tnl_outer_proto_ok(skb, outer_isv6, outer_th))
> + return -EINVAL;
> +
> /* In case of USO, the inner protocol is still unknown and
> * `inner_isv6` is just a guess, additional parsing is needed.
> * The previous validation ensures that accessing an ipv4 inner
> --
> 2.53.0
>
next prev parent reply other threads:[~2026-11-04 2:01 UTC|newest]
Thread overview: 8+ 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 [this message]
2026-11-04 4:49 ` Eric Dumazet
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-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
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=willemdebruijn.kernel.2e11b18d6e190@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=eperezma@redhat.com \
--cc=hassansultan@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=virtualization@lists.linux.dev \
--cc=willemb@google.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox