From: Yuchao Zhang <ndaugoing@gmail.com>
To: netdev-bot+sashiko@kernel.org
Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, toke@redhat.com,
jhs@mojatatu.com, jiri@resnulli.us, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org,
Yuchao Zhang <ndaugoing@gmail.com>
Subject: [PATCH v2] net/sched: sch_cake: prevent shaper corruption and stall in cake_overhead()
Date: Tue, 22 Sep 2026 16:41:24 +0800 [thread overview]
Message-ID: <20260922084124.36858-1-ndaugoing@gmail.com> (raw)
In-Reply-To: <179000041222.2160803.11108326722307773525@kernel.org>
In cake_overhead(), the header length up to the transport layer is
computed using logic borrowed from qdisc_pkt_len_segs_init():
/* borrowed from qdisc_pkt_len_segs_init() */
if (!skb->encapsulation)
hdr_len = skb_transport_offset(skb);
else
hdr_len = skb_inner_transport_offset(skb);
However, cake_overhead() suffers from several issues:
1. When segs == 0 (e.g. from dodgy GSO packets where gso_segs is not
recomputed), the multi-segment arithmetic underflows: (segs - 1) wraps
to 4294967295, causing cake_calc_overhead() * (segs - 1) to produce
an enormous length. When charged in cake_advance_shaper(),
time_next_packet is pushed decades into the future, permanently
stalling the CAKE dequeue queue.
Fix this by returning cake_calc_overhead(q, len, off) for segs <= 1.
2. When the transport header was never set, skb->transport_header holds
the sentinel value ~0U. skb_transport_offset() returns ~65535, which
is not caught by a negative offset check. skb_header_pointer() fails,
and hdr_len stays ~65535, charging ~66 KB per segment to the shaper.
Fix this by mirroring qdisc_pkt_len_segs_init() and checking
unlikely(!skb_transport_header_was_set(skb)).
3. Both skb_transport_offset() and skb_inner_transport_offset() return
signed int, but hdr_len is declared as unsigned int. If post-enqueue
mangling (such as BPF packet trimming via bpf_skb_net_shrink())
produces a negative offset, hdr_len wraps to near UINT_MAX, causing
corrupted header length accounting.
Fix this by declaring hdr_len as int and falling back to
cake_calc_overhead(q, len, off) if hdr_len is negative.
Fixes: a41851bea7bf ("net: account for encap headers in qdisc pkt len")
Cc: stable@vger.kernel.org
Signed-off-by: Yuchao Zhang <ndaugoing@gmail.com>
---
v2:
- Accurately describe the impact as shaper accounting corruption / stall
rather than OOB read past the allocation per Sashiko review.
- Fix pre-existing high-severity integer underflow when segs == 0 by
checking segs <= 1.
- Import companion check !skb_transport_header_was_set(skb) from
qdisc_pkt_len_segs_init() to prevent unset transport header sentinel
(~0U) from inflating packet length to ~66 KB.
net/sched/sch_cake.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index dc93267029e7..45969c1b95fc 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -1413,21 +1413,28 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off)
static u32 cake_overhead(struct cake_sched_data *q, const struct sk_buff *skb)
{
const struct skb_shared_info *shinfo = skb_shinfo(skb);
- unsigned int hdr_len, last_len = 0;
+ unsigned int last_len = 0;
u32 off = skb_network_offset(skb);
u16 segs = qdisc_pkt_segs(skb);
u32 len = qdisc_pkt_len(skb);
+ int hdr_len;
WRITE_ONCE(q->avg_netoff, cake_ewma(q->avg_netoff, off << 16, 8));
- if (segs == 1)
+ if (segs <= 1)
return cake_calc_overhead(q, len, off);
/* borrowed from qdisc_pkt_len_segs_init() */
- if (!skb->encapsulation)
+ if (!skb->encapsulation) {
+ if (unlikely(!skb_transport_header_was_set(skb)))
+ return cake_calc_overhead(q, len, off);
hdr_len = skb_transport_offset(skb);
- else
+ } else {
hdr_len = skb_inner_transport_offset(skb);
+ }
+
+ if (unlikely(hdr_len < 0))
+ return cake_calc_overhead(q, len, off);
/* + transport layer */
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 |
--
2.53.0
next prev parent reply other threads:[~2026-09-22 8:41 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 ` [PATCH 1/2] net: fix OOB read in qdisc_pkt_len_segs_init() on negative transport offset zjamg
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 ` Yuchao Zhang [this message]
2026-09-25 11:42 ` [PATCH v2] net/sched: sch_cake: prevent shaper corruption and stall " 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=20260922084124.36858-1-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-bot+sashiko@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=toke@redhat.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.