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
next 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