Linux virtualization list
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Michael S. Tsirkin" <mst@redhat.com>
Cc: virtualization@lists.linux.dev, "Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH net v5 7/7] virtio_net: cleanup protocol calculation
Date: Fri, 23 Oct 2026 12:59:08 +0000	[thread overview]
Message-ID: <sashiko-outbox-182808@kernel.org> (raw)
In-Reply-To: <f8621d16cf0c67335641d07c1555ec1e43f17628.1792668082.git.mst@redhat.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] net: use-after-free read of iph->ihl after pskb_may_pull() in ip4_parse()
- [High] virtio_net: failed drop of invalid non-GSO tunnel packets in virtio_net_hdr_tnl_to_skb()
--

commit 932b3459605ba3055ae9042b1894bc6eb02c03c4
Author: Michael S. Tsirkin <mst@redhat.com>

virtio_net: cleanup protocol calculation

This commit removes a duplicate assignment of inner_proto in
virtio_net_hdr_tnl_to_skb() by computing it once before calling
skb_set_inner_protocol().

> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index 063cc116e51a1..e984e446ba44a 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -613,8 +613,8 @@ virtio_net_hdr_tnl_to_skb(struct sk_buff *skb,
>  			return -EINVAL;
>  	}
>  
> -	skb_set_inner_protocol(skb, inner_isv6 ? htons(ETH_P_IPV6) :
> -			    htons(ETH_P_IP));
> +	inner_proto = inner_isv6 ? htons(ETH_P_IPV6) : htons(ETH_P_IP);
> +	skb_set_inner_protocol(skb, inner_proto);
>  	if (hdr->flags & VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM) {
>  		if (!tnl_csum_negotiated)
>  			return -EINVAL;
> @@ -638,7 +638,6 @@ virtio_net_hdr_tnl_to_skb(struct sk_buff *skb,
>  	 * We know VIRTIO_NET_HDR_F_NEEDS_CSUM was set so __virtio_net_hdr_to_skb
>  	 * set CHECKSUM_PARTIAL.
>  	 */
> -	inner_proto = inner_isv6 ? htons(ETH_P_IPV6) : htons(ETH_P_IP);
>  	if (virtio_net_csum_partial_ok_at_offset(skb, gso_inner_type, inner_nh,
>  						 inner_proto))
>  		return 0;

[Severity: High]
When virtio_net_csum_partial_ok_at_offset() validates an IPv4 header via
virtio_net_l4_start() -> ip4_parse() (introduced earlier in this series in
commit f0109d51e8b0 ("net: add ip4_parse()")), can ip4_parse() in
include/linux/ip.h perform a use-after-free read of iph->ihl?

In include/linux/ip.h:ip4_parse():

	if (!pskb_may_pull(skb, nhoff + sizeof(struct iphdr)))
		return NULL;

	iph = (struct iphdr *)(skb->data + nhoff);
	if (iph->version != 4 || iph->ihl < sizeof(struct iphdr) / sizeof(u32))
		return NULL;

	/* Pull the options as well: the transport header offset
	 * returned below must be within the linear data.
	 */
	if (!pskb_may_pull(skb, nhoff + iph->ihl * sizeof(u32)))
		return NULL;

	*thoff = nhoff + iph->ihl * sizeof(u32);
	return (struct iphdr *)(skb->data + nhoff);

When an IPv4 packet has options (iph->ihl > 5) that reside in nonlinear
paged data (so nhoff + iph->ihl * sizeof(u32) > skb_headlen(skb)), or when
the skb is cloned, the second pskb_may_pull() call invokes
__pskb_pull_tail() -> pskb_expand_head(), which allocates a new skb->head
buffer and frees the old buffer still pointed to by iph.

Dereferencing iph->ihl to compute *thoff after the second pskb_may_pull()
then reads from the freed buffer before iph is reloaded from
skb->data + nhoff. This affects all callers of ip4_parse(), including
ip_rcv_core(), virtio_net_l4_start(), br_validate_ipv4(), and
nf_reject_iphdr_validate().

Should ip4_parse() cache iph->ihl * sizeof(u32) in a local variable before
the second pskb_may_pull() call, or reload iph from skb->data + nhoff first?

[Severity: High]
Also in include/linux/virtio_net.h:virtio_net_hdr_tnl_to_skb(), what happens
when virtio_net_csum_partial_ok_at_offset() returns false for a non-gso
packet with a tunnel header?

Earlier in virtio_net_hdr_tnl_to_skb(), __virtio_net_hdr_to_skb() only sets
shinfo->gso_size and shinfo->gso_type when skb->len - nh_off > gso_size. If
a caller provides gso_size >= skb->len - nh_off, skb_is_gso(skb) remains
false, which virtio_net_hdr_tnl_to_skb() explicitly accounts for after
setting the inner header offsets and skb->encapsulation:

	skb->inner_transport_header = inner_th + skb_headroom(skb);
	skb->inner_network_header = inner_nh + skb_headroom(skb);
	skb->inner_mac_header = inner_nh + skb_headroom(skb);
	skb->transport_header = outer_th + skb_headroom(skb);
	skb->encapsulation = 1;

	if (!skb_is_gso(skb))
		skb_shinfo(skb)->gso_type &= ~(SKB_GSO_UDP_TUNNEL_CSUM |
					       SKB_GSO_UDP_TUNNEL);

	/*
	 * We know VIRTIO_NET_HDR_F_NEEDS_CSUM was set so __virtio_net_hdr_to_skb
	 * set CHECKSUM_PARTIAL.
	 */
	if (virtio_net_csum_partial_ok_at_offset(skb, gso_inner_type, inner_nh,
						 inner_proto))
		return 0;

	/* A tunnel header implies GSO, so drop. */
	return __virtio_net_resolve_csum_partial_mismatch(skb);

However, in include/linux/virtio_net.h:__virtio_net_resolve_csum_partial_mismatch():

static inline int __virtio_net_resolve_csum_partial_mismatch(struct sk_buff *skb)
{
	if (skb_is_gso(skb))
		return -EINVAL;

	return skb_checksum_help(skb) ?: 1;
}

When !skb_is_gso(skb) and virtio_net_csum_partial_ok_at_offset() fails
because the inner headers are malformed or do not match inner_th,
__virtio_net_resolve_csum_partial_mismatch(skb) does not drop the packet.
Instead, it completes the inner checksum via skb_checksum_help(skb) and
returns 1, which callers treat as success.

Does this allow a non-gso tunnel packet with invalid inner headers to enter
the networking stack with skb->encapsulation = 1, unvalidated inner header
offsets, and any requested outer tunnel checksum
(VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM) lost when skb_checksum_help() sets
ip_summed to CHECKSUM_NONE? Should virtio_net_hdr_tnl_to_skb() return
-EINVAL directly when virtio_net_csum_partial_ok_at_offset() returns false?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.v5.git.mst@redhat.com?part=7

  reply	other threads:[~2026-10-23 12:59 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22 12:57 [PATCH net v5 0/7] more virtio-net csum hardening Michael S. Tsirkin
2026-10-22 12:57 ` [PATCH net v5 1/7] net: account for ingress-resolved virtio net hdr state Michael S. Tsirkin
2026-10-22 14:37   ` Willem de Bruijn
2026-10-23 12:59   ` sashiko-bot
2026-10-25  5:30   ` netdev-bot+sashiko
2026-10-22 12:58 ` [PATCH net v5 2/7] um: vector: trim skbs before verifying the header Michael S. Tsirkin
2026-10-23 12:59   ` sashiko-bot
2026-10-25  5:31   ` netdev-bot+sashiko
2026-10-22 12:58 ` [PATCH net v5 3/7] virtio_net: parse tunnel csum_start little-endian Michael S. Tsirkin
2026-10-23 12:59   ` sashiko-bot
2026-10-22 12:58 ` [PATCH net v5 4/7] net: resolve uncommon partial checksums at ingress Michael S. Tsirkin
2026-10-22 14:52   ` Willem de Bruijn
2026-10-22 15:49     ` Michael S. Tsirkin
2026-10-22 17:52     ` Chris Arges
2026-10-22 23:38       ` Michael S. Tsirkin
2026-10-23  1:38         ` Chris Arges
2026-10-23 12:59   ` sashiko-bot
2026-10-25  5:31   ` netdev-bot+sashiko
2026-10-22 12:58 ` [PATCH net v5 5/7] net: add a sysctl to opt out of virtio net hdr checksum validation Michael S. Tsirkin
2026-10-23 12:59   ` sashiko-bot
2026-10-25  5:31   ` netdev-bot+sashiko
2026-10-22 12:58 ` [PATCH net v5 6/7] net: add ip4_parse() Michael S. Tsirkin
2026-10-23 12:59   ` sashiko-bot
2026-10-25  5:31   ` netdev-bot+sashiko
2026-10-22 12:58 ` [PATCH net v5 7/7] virtio_net: cleanup protocol calculation Michael S. Tsirkin
2026-10-23 12:59   ` sashiko-bot [this message]
2026-10-25  5:31   ` netdev-bot+sashiko
2026-10-22 17:54 ` [PATCH net v5 0/7] more virtio-net csum hardening Chris Arges

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-182808@kernel.org \
    --to=sashiko-bot@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox