From: zjamg <ndaugoing@gmail.com>
To: "David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: "Simon Horman" <horms@kernel.org>,
"Toke Høiland-Jørgensen" <toke@toke.dk>,
"Jamal Hadi Salim" <jhs@mojatatu.com>,
"Jiri Pirko" <jiri@resnulli.us>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
zjamg <ndaugoing@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH 1/2] net: fix OOB read in qdisc_pkt_len_segs_init() on negative transport offset
Date: Thu, 17 Sep 2026 20:21:52 +0800 [thread overview]
Message-ID: <20260917122153.62722-2-ndaugoing@gmail.com> (raw)
In-Reply-To: <20260917122153.62722-1-ndaugoing@gmail.com>
In qdisc_pkt_len_segs_init(), the header length up to the transport layer
is computed via skb_transport_offset() or skb_inner_transport_offset():
/* mac layer + network layer */
if (!skb->encapsulation) {
if (unlikely(!skb_transport_header_was_set(skb)))
return SKB_NOT_DROPPED_YET;
hdr_len = skb_transport_offset(skb);
} else {
hdr_len = skb_inner_transport_offset(skb);
}
Both offset accessors return a signed int, but hdr_len is declared as
unsigned int.
If a packet undergoes header operations (such as skb_vlan_untag() pulling
stacked VLAN tags without updating inner_transport_header, or other header
stripping that advances skb->data past the transport header), the offset
becomes negative.
When stored into unsigned int hdr_len, negative values are converted to
large positive numbers near UINT_MAX (e.g. (unsigned int)-16 is
0xFFFFFFF0). Subsequently:
1. pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)) evaluates
0xFFFFFFF0 + 20, which overflows 32-bit unsigned arithmetic to 4.
Since the packet length exceeds 4 bytes, pskb_may_pull() returns true,
bypassing the bounds check.
2. th = (const struct tcphdr *)(skb->data + hdr_len) zero-extends hdr_len
on 64-bit architectures, creating a wild pointer pointing ~4 GiB past
skb->data into unmapped memory.
3. __tcp_hdrlen(th) dereferences th->doff, triggering an immediate kernel
crash (page fault / KASAN wild-memory-access panic).
A similar unsigned overflow occurs for UDP (SKB_GSO_UDP_L4).
Fix this by declaring hdr_len as int to match the return types of
skb_transport_offset() and skb_inner_transport_offset(), and explicitly
rejecting negative offsets by returning SKB_DROP_REASON_SKB_BAD_GSO.
Fixes: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
Cc: stable@vger.kernel.org
Signed-off-by: zjamg <ndaugoing@gmail.com>
---
net/core/dev.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index ecfbd72d5d1a..f2dbf99181ec 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4159,8 +4159,9 @@ EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
- unsigned int hdr_len, tlen;
+ unsigned int tlen;
u16 gso_segs;
+ int hdr_len;
qdisc_skb_cb(skb)->pkt_len = skb->len;
if (!shinfo->gso_size) {
@@ -4182,6 +4183,8 @@ static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
} else {
hdr_len = skb_inner_transport_offset(skb);
}
+ if (unlikely(hdr_len < 0))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
/* + transport layer */
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
const struct tcphdr *th;
--
2.53.0
next prev parent reply other threads:[~2026-09-17 12:22 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-17 12:21 [PATCH 0/2] net: fix negative transport offset handling in GSO pkt len calculation zjamg
2026-09-17 12:21 ` zjamg [this message]
2026-09-17 12:21 ` [PATCH 2/2] net/sched: sch_cake: check negative transport offset in cake_overhead() zjamg
2026-09-21 14:20 ` netdev-bot+sashiko
2026-09-22 8:41 ` Yuchao Zhang
2026-09-22 8:41 ` [PATCH v2] net/sched: sch_cake: prevent shaper corruption and stall " Yuchao Zhang
2026-09-25 11:42 ` netdev-bot+sashiko
2026-09-27 11:29 ` Simon Horman
2026-09-27 11:31 ` Simon Horman
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=20260917122153.62722-2-ndaugoing@gmail.com \
--to=ndaugoing@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=jhs@mojatatu.com \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=toke@toke.dk \
/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.