Skip to content

Commit 02aa6f4

Browse files
committed
net/sched: sch_cake: Fix incorrect qlen reduction in cake_drop
jira VULN-187517 cve CVE-2025-68325 commit-author Xiang Mei <xmei5@asu.edu> commit 9fefc78 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: Roxana Nicolescu <rnicolescu@ciq.com>
1 parent 195e5dc commit 02aa6f4

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
@@ -1548,7 +1548,6 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
15481548

15491549
__qdisc_drop(skb, to_free);
15501550
sch->q.qlen--;
1551-
qdisc_tree_reduce_backlog(sch, 1, len);
15521551

15531552
cake_heapify(q, 0);
15541553

@@ -1694,14 +1693,14 @@ static void cake_reconfigure(struct Qdisc *sch);
16941693
static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
16951694
struct sk_buff **to_free)
16961695
{
1696+
u32 idx, tin, prev_qlen, prev_backlog, drop_id;
16971697
struct cake_sched_data *q = qdisc_priv(sch);
1698-
int len = qdisc_pkt_len(skb);
1699-
int ret;
1698+
int len = qdisc_pkt_len(skb), ret;
17001699
struct sk_buff *ack = NULL;
17011700
ktime_t now = ktime_get();
17021701
struct cake_tin_data *b;
17031702
struct cake_flow *flow;
1704-
u32 idx, tin;
1703+
bool same_flow = false;
17051704

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

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

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

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

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

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

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

1914-
if (same_flow)
1915-
return NET_XMIT_CN;
1917+
if (same_flow) {
1918+
qdisc_tree_reduce_backlog(sch, prev_qlen - 1,
1919+
prev_backlog - len);
1920+
return NET_XMIT_CN;
19161921
}
1922+
qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog);
19171923
return NET_XMIT_SUCCESS;
19181924
}
19191925

0 commit comments

Comments
 (0)