Skip to content

Commit db06c29

Browse files
CIQ Kernel Automationroxanan1996
authored andcommitted
net/sched: sch_cake: Fix incorrect qlen reduction in cake_drop
jira VULN-186699 cve CVE-2025-68325 commit-author Xiang Mei <xmei5@asu.edu> commit 9fefc78 upstream-diff | In this kernel, cake_drop() has the qdisc_tree_reduce_backlog() call before __qdisc_drop()/sch->q.qlen-- rather than after. The upstream patch context for that hunk did not match, so the removal of qdisc_tree_reduce_backlog() from cake_drop() was manually applied. Functionally identical to upstream. Matches the 5.15 stable backport (commit 38abf6e931b1). In cake_drop(), qdisc_tree_reduce_backlog() is used to update the qlen and backlog of the qdisc hierarchy. Its caller, cake_enqueue(), assumes that the parent qdisc will enqueue the current packet. However, this assumption breaks when cake_enqueue() returns NET_XMIT_CN: the parent qdisc stops enqueuing current packet, leaving the tree qlen/backlog accounting inconsistent. This mismatch can lead to a NULL dereference (e.g., when the parent Qdisc is qfq_qdisc). This patch computes the qlen/backlog delta in a more robust way by observing the difference before and after the series of cake_drop() calls, and then compensates the qdisc tree accounting if cake_enqueue() returns NET_XMIT_CN. To ensure correct compensation when ACK thinning is enabled, a new variable is introduced to keep qlen unchanged. Fixes: 15de71d ("net/sched: Make cake_enqueue return NET_XMIT_CN when past buffer_limit") Signed-off-by: Xiang Mei <xmei5@asu.edu> Reviewed-by: Toke Høiland-Jørgensen <toke@toke.dk> Link: https://patch.msgid.link/20251128001415.377823-1-xmei5@asu.edu Signed-off-by: Paolo Abeni <pabeni@redhat.com> (cherry picked from commit 9fefc78) Signed-off-by: CIQ Kernel Automation <ciq_kernel_automation@ciq.com>
1 parent 7efae41 commit db06c29

1 file changed

Lines changed: 32 additions & 26 deletions

File tree

net/sched/sch_cake.c

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,7 +1539,6 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
15391539
b->backlogs[idx] -= len;
15401540
b->tin_backlog -= len;
15411541
sch->qstats.backlog -= len;
1542-
qdisc_tree_reduce_backlog(sch, 1, len);
15431542

15441543
flow->dropped++;
15451544
b->tin_dropped++;
@@ -1695,14 +1694,14 @@ static void cake_reconfigure(struct Qdisc *sch);
16951694
static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
16961695
struct sk_buff **to_free)
16971696
{
1697+
u32 idx, tin, prev_qlen, prev_backlog, drop_id;
16981698
struct cake_sched_data *q = qdisc_priv(sch);
1699-
int len = qdisc_pkt_len(skb);
1700-
int ret;
1699+
int len = qdisc_pkt_len(skb), ret;
17011700
struct sk_buff *ack = NULL;
17021701
ktime_t now = ktime_get();
17031702
struct cake_tin_data *b;
17041703
struct cake_flow *flow;
1705-
u32 idx, tin;
1704+
bool same_flow = false;
17061705

17071706
/* choose flow to insert into */
17081707
idx = cake_classify(sch, &b, skb, q->flow_mode, &ret);
@@ -1775,6 +1774,8 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
17751774
consume_skb(skb);
17761775
} else {
17771776
/* not splitting */
1777+
int ack_pkt_len = 0;
1778+
17781779
cobalt_set_enqueue_time(skb, now);
17791780
get_cobalt_cb(skb)->adjusted_len = cake_overhead(q, skb);
17801781
flow_queue_add(flow, skb);
@@ -1785,13 +1786,13 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
17851786
if (ack) {
17861787
b->ack_drops++;
17871788
sch->qstats.drops++;
1788-
b->bytes += qdisc_pkt_len(ack);
1789-
len -= qdisc_pkt_len(ack);
1789+
ack_pkt_len = qdisc_pkt_len(ack);
1790+
b->bytes += ack_pkt_len;
17901791
q->buffer_used += skb->truesize - ack->truesize;
17911792
if (q->rate_flags & CAKE_FLAG_INGRESS)
17921793
cake_advance_shaper(q, b, ack, now, true);
17931794

1794-
qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(ack));
1795+
qdisc_tree_reduce_backlog(sch, 1, ack_pkt_len);
17951796
consume_skb(ack);
17961797
} else {
17971798
sch->q.qlen++;
@@ -1800,11 +1801,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
18001801

18011802
/* stats */
18021803
b->packets++;
1803-
b->bytes += len;
1804-
b->backlogs[idx] += len;
1805-
b->tin_backlog += len;
1806-
sch->qstats.backlog += len;
1807-
q->avg_window_bytes += len;
1804+
b->bytes += len - ack_pkt_len;
1805+
b->backlogs[idx] += len - ack_pkt_len;
1806+
b->tin_backlog += len - ack_pkt_len;
1807+
sch->qstats.backlog += len - ack_pkt_len;
1808+
q->avg_window_bytes += len - ack_pkt_len;
18081809
}
18091810

18101811
if (q->overflow_timeout)
@@ -1897,24 +1898,29 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
18971898
if (q->buffer_used > q->buffer_max_used)
18981899
q->buffer_max_used = q->buffer_used;
18991900

1900-
if (q->buffer_used > q->buffer_limit) {
1901-
bool same_flow = false;
1902-
u32 dropped = 0;
1903-
u32 drop_id;
1901+
if (q->buffer_used <= q->buffer_limit)
1902+
return NET_XMIT_SUCCESS;
19041903

1905-
while (q->buffer_used > q->buffer_limit) {
1906-
dropped++;
1907-
drop_id = cake_drop(sch, to_free);
1904+
prev_qlen = sch->q.qlen;
1905+
prev_backlog = sch->qstats.backlog;
19081906

1909-
if ((drop_id >> 16) == tin &&
1910-
(drop_id & 0xFFFF) == idx)
1911-
same_flow = true;
1912-
}
1913-
b->drop_overlimit += dropped;
1907+
while (q->buffer_used > q->buffer_limit) {
1908+
drop_id = cake_drop(sch, to_free);
1909+
if ((drop_id >> 16) == tin &&
1910+
(drop_id & 0xFFFF) == idx)
1911+
same_flow = true;
1912+
}
1913+
1914+
prev_qlen -= sch->q.qlen;
1915+
prev_backlog -= sch->qstats.backlog;
1916+
b->drop_overlimit += prev_qlen;
19141917

1915-
if (same_flow)
1916-
return NET_XMIT_CN;
1918+
if (same_flow) {
1919+
qdisc_tree_reduce_backlog(sch, prev_qlen - 1,
1920+
prev_backlog - len);
1921+
return NET_XMIT_CN;
19171922
}
1923+
qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog);
19181924
return NET_XMIT_SUCCESS;
19191925
}
19201926

0 commit comments

Comments
 (0)