Netdev List
 help / color / mirror / Atom feed
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, edumazet@google.com,
	pabeni@redhat.com, horms@kernel.org, andrew+netdev@lunn.ch,
	mst@redhat.com, jasowangio@gmail.com,
	Willem de Bruijn <willemb@google.com>,
	Paulos Yibelo <habte.yibelo@gmail.com>
Subject: [PATCH net] net: extend virtio_net_hdr csum_start checks to VLAN, IPv6 and IP options
Date: Wed,  7 Oct 2026 12:36:59 -0400	[thread overview]
Message-ID: <20261007163819.3041710-1-willemdebruijn.kernel@gmail.com> (raw)

From: Willem de Bruijn <willemb@google.com>

__virtio_net_hdr_to_skb() validates hdr->csum_start against nh_min_len:

    if (skb_transport_offset(skb) < nh_min_len)
        return -EINVAL;

Extend the check to account for the link layer header including VLAN
tags, IPv4 options, and IPv6 other than VIRTIO_NET_HDR_GSO_TCPV6.

Payload, gso_type and skb->protocol can come from userspace, so cannot
be trusted to be consistent, or correct.

Therefore:
- For Ethernet packets (ARPHRD_ETHER), parse from ETH_HLEN and
  eth_hdr(skb)->h_proto, advancing past any VLAN tags with
  __vlan_get_protocol().
- For non-Ethernet packets, use skb_network_offset(skb) as nhoff and
  infer the L3 protocol from iph->version at skb->data + nhoff.
- If skb->protocol is set and disagrees with the protocol parsed from
  the packet, enforce the minimum header length of both.
- For non-IP protocols, require only nhoff + nh_min_len. No in-tree
  non-IP protocol generates CHECKSUM_PARTIAL itself. They only carry it
  when encapsulating IP (e.g., MPLS), in which case csum_start lies
  beyond an inner IP header.

Reported-by: Paulos Yibelo <habte.yibelo@gmail.com>
Link: https://lore.kernel.org/netdev/20260922030310.8684-2-habte.yibelo@gmail.com/
Fixes: 49d14b54a527 ("net: test for not too small csum_start in virtio_net_hdr_to_skb()")
Co-developed-by: Paulos Yibelo <habte.yibelo@gmail.com>
Signed-off-by: Paulos Yibelo <habte.yibelo@gmail.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 include/linux/virtio_net.h | 48 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index d6466f96cdd0..6a30f58d9d65 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -48,6 +48,52 @@ static inline int virtio_net_hdr_set_proto(struct sk_buff *skb,
 	return 0;
 }
 
+static inline bool virtio_net_hdr_thoff_valid(const struct sk_buff *skb,
+					      unsigned int nh_min_len)
+{
+	int thoff = skb_transport_offset(skb);
+	const struct iphdr *iph;
+	__be16 proto = 0;
+	int nhoff;
+
+	DEBUG_NET_WARN_ON_ONCE(skb->mac_len);
+
+	if (skb->dev->type == ARPHRD_ETHER) {
+		if (unlikely(thoff < ETH_HLEN))
+			return false;
+		nhoff = ETH_HLEN;
+		proto = eth_hdr(skb)->h_proto;
+		if (eth_type_vlan(proto)) {
+			proto = __vlan_get_protocol(skb, proto, &nhoff);
+			if (!proto)
+				return false;
+		}
+	} else {
+		nhoff = skb_network_offset(skb);
+	}
+
+	if (unlikely(thoff < nhoff + nh_min_len))
+		return false;
+
+	iph = (const void *)(skb->data + nhoff);
+	if (!proto) {
+		if (iph->version == 4)
+			proto = htons(ETH_P_IP);
+		else if (iph->version == 6)
+			proto = htons(ETH_P_IPV6);
+	}
+
+	if (proto == htons(ETH_P_IP) || skb->protocol == htons(ETH_P_IP)) {
+		if (unlikely(iph->ihl < 5))
+			return false;
+		nh_min_len = max_t(u32, iph->ihl * 4, nh_min_len);
+	}
+	if (proto == htons(ETH_P_IPV6) || skb->protocol == htons(ETH_P_IPV6))
+		nh_min_len = max_t(u32, sizeof(struct ipv6hdr), nh_min_len);
+
+	return thoff >= nhoff + nh_min_len;
+}
+
 static inline int __virtio_net_hdr_to_skb(struct sk_buff *skb,
 					  const struct virtio_net_hdr *hdr,
 					  bool little_endian, u8 hdr_gso_type)
@@ -104,7 +150,7 @@ static inline int __virtio_net_hdr_to_skb(struct sk_buff *skb,
 
 		if (!skb_partial_csum_set(skb, start, off))
 			return -EINVAL;
-		if (skb_transport_offset(skb) < nh_min_len)
+		if (!virtio_net_hdr_thoff_valid(skb, nh_min_len))
 			return -EINVAL;
 
 		nh_min_len = skb_transport_offset(skb);
-- 
2.56.0.360.g66cac248cb-goog


             reply	other threads:[~2026-10-07 16:38 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-07 16:36 Willem de Bruijn [this message]
2026-10-07 16:40 ` [PATCH net] net: extend virtio_net_hdr csum_start checks to VLAN, IPv6 and IP options netdev-bot+sinfo
2026-10-07 17:02   ` Willem de Bruijn
2026-10-07 22:02 ` Michael S. Tsirkin
2026-10-07 22:38   ` Willem de Bruijn
2026-10-07 22:52     ` Michael S. Tsirkin
2026-10-07 23:42       ` Willem de Bruijn
2026-10-08 19:38 ` netdev-bot+sashiko
2026-10-08 20:04   ` Willem de Bruijn
2026-10-08 20:55     ` Michael S. Tsirkin
2026-10-08 21:06       ` Willem de Bruijn
2026-10-08 21:22         ` Michael S. Tsirkin

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=20261007163819.3041710-1-willemdebruijn.kernel@gmail.com \
    --to=willemdebruijn.kernel@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=habte.yibelo@gmail.com \
    --cc=horms@kernel.org \
    --cc=jasowangio@gmail.com \
    --cc=kuba@kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --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