From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: Guoyu Su <yss2813483011xxl@gmail.com>,
Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Cc: edumazet@google.com, davem@davemloft.net, kuba@kernel.org,
pabeni@redhat.com, netdev@vger.kernel.org, horms@kernel.org,
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com,
syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
Subject: Re: [PATCH net v5] net: use skb_header_pointer() only for DODGY TCPv4 GSO skbs
Date: Sun, 22 Mar 2026 23:36:58 -0400 [thread overview]
Message-ID: <willemdebruijn.kernel.35a7766bac9d6@gmail.com> (raw)
In-Reply-To: <CAMa1Pe5XGeyk4rf7rX+4FjwPzUhxdKEw5Qsi2GwkeOMr6fw6Jg@mail.gmail.com>
Guoyu Su wrote:
> Thanks Willem, this is a good point.
>
> I reran with instrumentation at two exact points:
> 1) packet_snd(), immediately after virtio_net_hdr_to_skb() returns
> (net/packet/af_packet.c)
> 2) gso_features_check(), in the SKB_GSO_DODGY branch before frag_off access
> (net/core/dev.c)
>
> For the same skb, I consistently see (first 20 dumps):
> - pkt_after_vnet:
> skb=... len=56584 headlen=172 data_len=56412 netoff=172 transoff=88
> gso_type=0x3
> skb_dump: headroom=4, mac=(4,172), trans=92
> - gso_dodgy:
> skb=... nhoff=172 headlen=172 netoff=172 transoff=88
>
> So in this run, coverage up to p_off on the transport-side does not imply
> safe direct access at nhoff on the network-side (nhoff/headlen are
> both 172 here).
Perhaps you're running a different repro from the one I used. Which is
the C repro from the run at commit ca4ee40bf13d.
I see that the virtio_net_hdr has hdr_len 106 and csum_start 88. Those
are fine. Same for your repro?
The question is how skb->network_header can be greater than
skb->transport_header right after virtio_net_hdr_to_skb. And whether
this can be a sanity test to drop clearly malformed packets.
E.g.,
@@ -105,8 +108,12 @@ static inline int __virtio_net_hdr_to_skb(struct sk_buff *skb,
return -EINVAL;
if (skb_transport_offset(skb) < nh_min_len)
return -EINVAL;
+ if (skb_transport_offset(skb) < skb_network_offset(skb) + nh_min_len)
+ return -EINVAL;
As far as I can see network_header is set entirely in packet_snd, not
updated in virtio_net_hdr_to_skb in this path.
It seems that hard_header_len for this device is 76. That is part of
the answer. It is an ip6gretap device, so this is the encap hlen.
> I agree that validating/dropping malformed packets as early as possible in
> virtio_net_hdr_to_skb() would be preferable if we can make that check precise.
> This patch addresses the observed safety gap at gso_features_check() for DODGY
> packets in the current path.
>
> If helpful, I can share more skb_dump snippets / full serial log.
Friendly reminder to not top post
https://docs.kernel.org/process/submitting-patches.html#use-trimmed-interleaved-replies-in-email-discussions
> Willem de Bruijn <willemdebruijn.kernel@gmail.com> 于2026年3月22日周日 04:58写道:
> >
> > Scars wrote:
> > > I instrumented packet_snd(), __virtio_net_hdr_to_skb(), and
> > > gso_features_check() while running the C repro.
> > >
> > > In repeated runs, for the same skb, I consistently observed:
> > > - __virtio_net_hdr_to_skb() (NEEDS_CSUM path):
> > > skb_transport_offset=88, thlen=20, so p_off=108;
> > > pskb_may_pull(..., 108)
> >
> > All the above matches the skb_dump from my previous post.
> >
> > > succeeds (headlen=172).
> >
> > My output shows headlen 108. Here we start to diverge.
> >
> > > - gso_features_check() on the resulting DODGY TCPv4 skb uses
> > > nhoff=skb_network_offset(skb)=172.
> >
> > And I see headroom of 4, so mac at 4, skb->network_header at 80 and
> > skb->transport_header at 92. No 172.
> >
> > That part is key. My measurement is in packet_snd right after
> > virtio_net_hdr_to_skb. Where do you see this, and can you perhaps get
> > an skb_dump (NOT full_skb, as these are large, just the header
> > metadata).
> >
> > I don't mean to delay the fix. Just, in general, a preferable fix for
> > these weird user injected packets is to detect and drop as close to
> > kerne entry as possible, meaning in virtio_net_hdr_to_skb, rather than
> > have to make the main datapath robust against crazy packets -- which
> > comes with branches and other overhead on the legitimate hot path.
> >
> >
> > >
> > > So the pull checks in __virtio_net_hdr_to_skb() guarantee access up to
> > > p_off, but do not guarantee that the
> > > header at nhoff is safely linear for direct iph->frag_off dereference.
> > >
> > > In this run, nhoff==headlen on the observed packets (IPv4 header
> > > starts at the linear tail boundary). Using
> > > skb_header_pointer() in the DODGY branch avoids this gap.
> > >
> > > I did not hit a KMSAN report in this rerun (instrumented/patched
> > > kernel), but the offset mismatch above was
> > > reproducible.
> > >
> > > Willem de Bruijn <willemdebruijn.kernel@gmail.com> 于2026年3月21日周六 09:36写道:
> > > >
> > > > Willem de Bruijn wrote:
> > > > > Guoyu Su wrote:
> > > > > > Syzbot reported a KMSAN uninit-value warning in gso_features_check()
> > > > > > called from netif_skb_features() [1].
> > > > > >
> > > > > > The current direct skb->len check is not sufficient for SKB_GSO_DODGY
> > > > > > packets. In the AF_PACKET/PACKET_VNET_HDR path, packet_snd() can build
> > > > > > a DODGY GSO skb whose total length is large enough, while the IPv4
> > > > > > header is not fully available as initialized linear data for a direct
> > > > > > iph->frag_off access.
> > > > >
> > > > > The fix looks fine, but the AI review of an earlier revision brings up
> > > > > a good point: __virtio_net_hdr_to_skb calls pskb_may_pull in all paths
> > > > > to ensure the network header is fully in skb linear. What kind of packet
> > > > > is this that managed to escape those checks?
> > > >
> > > > The packets I got out of the C repro just after virtio_net_hdr_to_skb
> > > > look as below.
> > > >
> > > > [ 76.539562] vnet_hdr: flags=0x75 gso_type=0x1 hlen=0x6a gso_sz=0x416d cstart=0x58
> > > > [ 76.539755] skb len=56584 data_len=56476 headroom=4 headlen=108 tailroom=0
> > > > [ 76.539755] end-tail=208 mac=(4,76) mac_len=0 net=(80,12) trans=92
> > > > [ 76.539755] shinfo(txflags=0 nr_frags=3 gso(size=16749 type=3 segs=0))
> > > > [ 76.539755] csum(0x10005c start=92 offset=16 ip_summed=3 complete_sw=0 valid=0 level=0)
> > > > [ 76.539755] hash(0x0 sw=0 l4=0) proto=0x0800 pkttype=0 iif=0
> > > > [ 76.539755] priority=0x0 mark=0x0 alloc_cpu=0 vlan_all=0x0
> > > > [ 76.539755] encapsulation=0 inner(proto=0x0000, mac=0, net=0, trans=0)
> > > > [ 76.540713] dev name=ip6gretap0 feat=0x0000000e401d4869
> > > > [ 76.540843] sk family=17 type=3 proto=0
> > > >
> > > > Clearly fishy. They do have VIRTIO_NET_HDR_F_NEEDS_CSUM set, so we
> > > > know which branch they take.
> > > >
> > > > skb_reset_mac_header(skb);
> > > >
> > > > if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
> > > > u32 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
> > > > u32 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
> > > > u32 needed = start + max_t(u32, thlen, off + sizeof(__sum16));
> > > >
> > > > // start == 88
> > > > // needed == 88 + 18 == 106
> > > >
> > > > if (!pskb_may_pull(skb, needed))
> > > > return -EINVAL;
> > > >
> > > > if (!skb_partial_csum_set(skb, start, off))
> > > > return -EINVAL;
> > > > if (skb_transport_offset(skb) < nh_min_len)
> > > > return -EINVAL;
> > > >
> > > > nh_min_len = skb_transport_offset(skb);
> > > >
> > > > // nh_min_len == 88
> > > >
> > > > p_off = nh_min_len + thlen;
> > > >
> > > > // p_off == 108
> > > >
> > > > if (!pskb_may_pull(skb, p_off))
> > > > return -EINVAL;
> > > >
> > > > // headlen == 108
> > > >
> > > > At the end of this headlen == 108, so all of iphdr should be in
> > > > linear.
> > > >
> > > > Since the syz repro requires repeat it is possible that I simply did
> > > > not capture the right packet, but I don't see the C program vary the
> > > > packet contents.
> >
> >
next prev parent reply other threads:[~2026-03-23 3:37 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-07 16:29 [PATCH net] net: clear mangleid_features for SKB_GSO_DODGY TCPv4 Guoyu Su
2026-03-07 16:43 ` Eric Dumazet
2026-03-08 8:33 ` [PATCH net v2] net: use skb_header_pointer() in gso_features_check() for TCPv4 GSO Guoyu Su
2026-03-11 0:48 ` Jakub Kicinski
2026-03-12 10:43 ` [PATCH net v3] net: use skb_header_pointer() only for DODGY TCPv4 GSO skbs Guoyu Su
2026-03-17 10:22 ` Paolo Abeni
2026-03-19 0:54 ` [PATCH net v4] " Guoyu Su
2026-03-19 13:17 ` Willem de Bruijn
2026-03-20 14:14 ` [PATCH net v5] " Guoyu Su
2026-03-20 19:24 ` Willem de Bruijn
2026-03-21 1:36 ` Willem de Bruijn
2026-03-21 15:31 ` Scars
2026-03-21 20:58 ` Willem de Bruijn
2026-03-22 4:26 ` Guoyu Su
2026-03-23 3:36 ` Willem de Bruijn [this message]
2026-03-24 10:40 ` Guoyu Su
2026-03-26 3:12 ` Willem de Bruijn
2026-03-26 12:18 ` [PATCH net v6] net: use skb_header_pointer() for TCPv4 GSO frag_off Guoyu Su
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.35a7766bac9d6@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com \
--cc=syzkaller-bugs@googlegroups.com \
--cc=yss2813483011xxl@gmail.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