From: "Michael S. Tsirkin" <mst@redhat.com>
To: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Cc: linux-kernel@vger.kernel.org,
"Chris Arges" <carges@cloudflare.com>,
"Björn Töpel" <bjorn@kernel.org>, "Phil Sutter" <phil@nwl.cc>,
"Jason Wang" <jasowangio@gmail.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
netdev@vger.kernel.org, virtualization@lists.linux.dev,
"Max Krasnyansky" <maxk@qualcomm.com>,
"Rusty Russell" <rusty@rustcorp.com.au>,
"Paulos Yibelo" <habte.yibelo@gmail.com>
Subject: Re: [PATCH net v6 4/5] net: resolve uncommon partial checksums at ingress
Date: Fri, 23 Oct 2026 19:46:00 -0400 [thread overview]
Message-ID: <20261023192005-mutt-send-email-mst@kernel.org> (raw)
In-Reply-To: <willemdebruijn.kernel.3ae6f662e1ed8@gmail.com>
On Fri, Oct 23, 2026 at 03:37:48PM -0400, Willem de Bruijn wrote:
> Michael S. Tsirkin wrote:
> > As reported first by Paulos Yibelo <habte.yibelo@gmail.com> (after which
> > others, credited below, found more ways the bug can affect users) a
> > virtio net header can place CHECKSUM_PARTIAL at any in-packet offset.
> > If that state is retained, later checksum completion can modify the
> > packet after protocol processing has made decisions from it.
> >
> > Let's fix that: let's validate csum_start and csum_offset and only keep
> > CHECKSUM_PARTIAL when csum_start and csum_offset match a parsed TCP or
> > UDP header, while handling VLAN headers, IPv4 options and IPv6 extension
> > headers. Complete other non-GSO checksums immediately, before any
> > protocol processing runs.
> >
> > We can't easily "complete the checksum" for GSO we don't recognize - GSO
> > assumes knowledge of the protocol. We could segment ignoring the
> > checksum then do whatever csum_start and csum_offset say, but that
> > seems like an overkill for something that shouldn't happen.
> >
> > There's some risk here:
> > - non-gso packets which can't be parsed get checksum calculated in
> > software, adding performance overhead
> > - gso packets which can't be parsed get dropped
> >
> > Note that for zero copy, userspace can change the data after the
> > checksum has been calculated. This is fundamental to zero copy by
> > design, and the only outcome is a bad checksum and a packet drop.
> >
> > To mitigate the risks, the following patch will add a sysctl knob to
> > bypass the resolution. This is reasonable if the setup is such that
> > there is no protocol processing at all.
> >
> > UDP tunnel headers get the same handling on the inner header.
> >
> > Packets without VIRTIO_NET_HDR_F_NEEDS_CSUM are unaffected.
> >
> > Reported-by: Paulos Yibelo <habte.yibelo@gmail.com>
> > Reported-by: Chris Arges <carges@cloudflare.com>
> > Tested-by: Chris Arges <carges@cloudflare.com>
> > Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr")
> > Suggested-by: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> A few comments inline. All but one cosmetic. Feel free to ignore
> those. Please do review the comment from an LLM about the tunnel.
> Aside from that LGTM.
>
...
> > @@ -368,7 +637,20 @@ virtio_net_hdr_tnl_to_skb(struct sk_buff *skb,
> > skb->inner_mac_header = inner_nh + skb_headroom(skb);
> > skb->transport_header = outer_th + skb_headroom(skb);
> > skb->encapsulation = 1;
> > - return 0;
> > +
> > + 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;
> > +
> > + return __virtio_net_resolve_csum_partial_mismatch(skb);
>
> Allowing `!skb_is_gso(skb)` packets through `virtio_net_hdr_tnl_to_skb()`
> has a few issues:
>
> 1. When `!skb_is_gso(skb)` and `virtio_net_csum_partial_ok_at_offset()`
> returns false, `__virtio_net_resolve_csum_partial_mismatch()` completes
> the checksum in software and lets the packet pass, but `skb->encapsulation`,
> `skb->inner_protocol`, `skb->inner_transport_header`,
> `skb->inner_network_header`, and `skb->inner_mac_header` have already
> been populated with the unvalidated `inner_th` (`csum_start`) and
> `inner_nh` offsets (unlike `virtio_net_hdr_to_skb()`, which restores
> `skb->transport_header`).
Oh right. Hmm. I can just run the check first.
> 2. If `!skb_is_gso(skb)` and `VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM` is set,
> clearing `SKB_GSO_UDP_TUNNEL_CSUM` drops the outer UDP checksum request,
> since a non-GSO skb can only carry a single `CHECKSUM_PARTIAL` offset
> (at `inner_th`).
Right. But it works! Because the checksum is 0 then. I'll ponder what is
best.
> 3. On RX, a non-GSO UDP packet with `CHECKSUM_PARTIAL` at `inner_th` causes
> `skb_csum_unnecessary()` (`skb_checksum_start_offset(skb) >= 0`) to treat
> the outer UDP checksum as already validated.
>
> Unlike plain GSO (commit 7c6d2ecbda83), UDP tunnel offload is modern-only and
> explicitly requires GSO (`/* The UDP tunnel must carry a GSO packet, but no UFO. */`).
> Why not reject `!skb_is_gso(skb)` right after `__virtio_net_hdr_to_skb()`, and
> return `-EINVAL` directly if `!virtio_net_csum_partial_ok_at_offset()`?
This will break apps, I think. See 7c6d2ecbda83
--
MST
next prev parent reply other threads:[~2026-10-23 23:46 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 15:09 [PATCH net v6 0/5] more virtio-net csum hardening Michael S. Tsirkin
2026-10-23 15:09 ` [PATCH net v6 1/5] net: account for ingress-resolved virtio net hdr state Michael S. Tsirkin
2026-10-24 15:09 ` sashiko-bot
2026-10-23 15:09 ` [PATCH net v6 2/5] um: vector: trim skbs before verifying the header Michael S. Tsirkin
2026-10-24 15:09 ` sashiko-bot
2026-10-23 15:09 ` [PATCH net v6 3/5] virtio_net: parse tunnel csum_start little-endian Michael S. Tsirkin
2026-10-24 15:09 ` sashiko-bot
2026-10-23 15:09 ` [PATCH net v6 4/5] net: resolve uncommon partial checksums at ingress Michael S. Tsirkin
2026-10-23 19:37 ` Willem de Bruijn
2026-10-23 23:46 ` Michael S. Tsirkin [this message]
2026-10-24 15:09 ` sashiko-bot
2026-10-23 15:09 ` [PATCH net v6 5/5] net: add a sysctl to opt out of virtio net hdr checksum validation Michael S. Tsirkin
2026-10-24 15:09 ` sashiko-bot
2026-10-23 18:07 ` [PATCH net v6 0/5] more virtio-net csum hardening Chris Arges
2026-10-24 15:42 ` Michael S. Tsirkin
2026-10-24 16:08 ` Willem de Bruijn
2026-10-24 16:20 ` Michael S. Tsirkin
2026-10-25 13:50 ` Michael S. Tsirkin
2026-10-28 22:43 ` Jakub Kicinski
2026-10-29 7: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=20261023192005-mutt-send-email-mst@kernel.org \
--to=mst@redhat.com \
--cc=andrew+netdev@lunn.ch \
--cc=bjorn@kernel.org \
--cc=carges@cloudflare.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=eperezma@redhat.com \
--cc=habte.yibelo@gmail.com \
--cc=jasowangio@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maxk@qualcomm.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=phil@nwl.cc \
--cc=rusty@rustcorp.com.au \
--cc=virtualization@lists.linux.dev \
--cc=willemdebruijn.kernel@gmail.com \
--cc=xuanzhuo@linux.alibaba.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 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.