All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH net] net: reject a negative TCP header offset in qdisc_pkt_len_segs_init()
Date: Mon, 02 Nov 2026 19:44:49 +0000	[thread overview]
Message-ID: <sashiko-outbox-194018@kernel.org> (raw)
In-Reply-To: <20261101194433.2637113-1-alexei.starovoitov@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] net: negative hdr_len in qdisc_pkt_len_segs_init() only checked for TCP
--

commit dddca5a283a51c0b9bd1d1aef355eda12933179b
Author: Alexei Starovoitov <ast@kernel.org>

net: reject a negative TCP header offset in qdisc_pkt_len_segs_init()

This commit adds a negative offset check on hdr_len inside the TCP GSO
branch of qdisc_pkt_len_segs_init() to prevent an out-of-bounds read when
a stale transport header points in front of skb->data.

> diff --git a/net/core/dev.c b/net/core/dev.c
> index f32353b0467cd..af948e4424035 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -4320,7 +4320,9 @@ static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
>  	if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
>  		const struct tcphdr *th;
>  
> -		if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)))
> +		/* A header in front of skb->data gives a negative offset. */
> +		if ((int)hdr_len < 0 ||
> +		    !pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)))
>  			return SKB_DROP_REASON_SKB_BAD_GSO;

[Severity: High]
Should the (int)hdr_len < 0 check be placed immediately after hdr_len is
computed rather than only inside the SKB_GSO_TCPV4 | SKB_GSO_TCPV6 branch?

In net/core/dev.c:qdisc_pkt_len_segs_init(), leaving non-TCP GSO types
unguarded when skb_transport_offset(skb) or skb_inner_transport_offset(skb)
is negative appears to leave three issues:

First, for SKB_GSO_UDP_L4 packets:

	} else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
		if (!pskb_may_pull(skb, hdr_len + sizeof(struct udphdr)))
			return SKB_DROP_REASON_SKB_BAD_GSO;
		hdr_len += sizeof(struct udphdr);
	}

When (int)hdr_len < -8, hdr_len + sizeof(struct udphdr) wraps to an
unsigned int in [0x80000008, 0xffffffff] (> INT_MAX), which triggers
DEBUG_NET_WARN_ON_ONCE(len > INT_MAX) in
include/linux/skbuff.h:pskb_may_pull_reason() before returning
SKB_DROP_REASON_SKB_BAD_GSO.

Second, when -8 <= (int)hdr_len < 0 on an SKB_GSO_UDP_L4 packet,
hdr_len + sizeof(struct udphdr) wraps to 0..7. pskb_may_pull() succeeds
without pulling the UDP header into skb->head, hdr_len wraps to 0..7, and
qdisc_pkt_len_segs_init() returns SKB_NOT_DROPPED_YET. If the packet is
then transmitted on a NETIF_F_GSO_UDP_L4 device whose driver uses the TSO
helpers in net/core/tso.c (such as bnxt_sw_udp_gso_xmit(),
enetc_map_tx_tso_buffs(), or otx2_sq_append_tso()), tso_build_hdr()
advances hdr by the negative transport offset:

	hdr += skb_transport_offset(skb);
	if (tso->tlen != sizeof(struct udphdr)) {
		...
	} else {
		struct udphdr *uh = (struct udphdr *)hdr;

		/* size is after segmentation. */
		udp_set_len_short(uh, sizeof(*uh) + size);
	}

Can this write uh->len (and uh->check in bnxt_sw_udp_gso_xmit() and
enetc_tso_hdr_csum()) before the start of the header buffer when
skb_transport_offset(skb) < -4?

Third, for other GSO types (such as SKB_GSO_FRAGLIST, SKB_GSO_UDP,
SKB_GSO_SCTP, or SKB_GSO_ESP), hdr_len remains 2^32 - |offset| at the end
of qdisc_pkt_len_segs_init():

	qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;

When (gso_segs - 1) * |offset| > skb->len, can qdisc_skb_cb(skb)->pkt_len
underflow in 32-bit unsigned arithmetic to ~4.29 GiB (exceeding
QDISC_PKT_LEN_MAX), causing deficit-based schedulers such as drr_dequeue()
and ets_dequeue() to spin in their deficit-refill loops?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261101194433.2637113-1-alexei.starovoitov@gmail.com?part=1

  parent reply	other threads:[~2026-11-02 19:44 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-01 19:44 [PATCH net] net: reject a negative TCP header offset in qdisc_pkt_len_segs_init() Alexei Starovoitov
2026-11-01 19:49 ` netdev-bot+sinfo
2026-11-02 19:44 ` sashiko-bot [this message]
2026-11-02 22:46   ` Alexei Starovoitov
2026-11-04  8:41     ` Paolo Abeni
2026-11-04 16:52       ` Alexei Starovoitov
2026-11-03 19:37 ` Eric Dumazet
2026-11-04 12:04 ` Michael S. Tsirkin
2026-11-04 12:30 ` patchwork-bot+netdevbpf

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-194018@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=alexei.starovoitov@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=sashiko-reviews@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 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.