Skip to content

Commit 24ea458

Browse files
committed
sched: Avoid dereferencing skb pointer after child enqueue
jira VULN-68349 cve-pre CVE-2025-38000 commit-author Toke Høiland-Jørgensen <toke@redhat.com> commit f6bab19 upstream-diff No changes were made to sch_cbs.c because it doesn't support child qdiscs in this kernel because it lacks "990e35ecba1c cbs: Add support for graft function" Parent qdiscs may dereference the pointer to the enqueued skb after enqueue. However, both CAKE and TBF call consume_skb() on the original skb when splitting GSO packets, leading to a potential use-after-free in the parent. Fix this by avoiding dereferencing the skb pointer after enqueueing to the child. Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> (cherry picked from commit f6bab19) Signed-off-by: Brett Mastbergen <bmastbergen@ciq.com>
1 parent 50fda57 commit 24ea458

File tree

7 files changed

+21
-15
lines changed

7 files changed

+21
-15
lines changed

net/sched/sch_drr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
336336
static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
337337
struct sk_buff **to_free)
338338
{
339+
unsigned int len = qdisc_pkt_len(skb);
339340
struct drr_sched *q = qdisc_priv(sch);
340341
struct drr_class *cl;
341342
int err = 0;
@@ -362,7 +363,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
362363
cl->deficit = cl->quantum;
363364
}
364365

365-
qdisc_qstats_backlog_inc(sch, skb);
366+
sch->qstats.backlog += len;
366367
sch->q.qlen++;
367368
return err;
368369
}

net/sched/sch_dsmark.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl)
196196
static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch,
197197
struct sk_buff **to_free)
198198
{
199+
unsigned int len = qdisc_pkt_len(skb);
199200
struct dsmark_qdisc_data *p = qdisc_priv(sch);
200201
int err;
201202

@@ -268,7 +269,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch,
268269
return err;
269270
}
270271

271-
qdisc_qstats_backlog_inc(sch, skb);
272+
sch->qstats.backlog += len;
272273
sch->q.qlen++;
273274

274275
return NET_XMIT_SUCCESS;

net/sched/sch_hfsc.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,7 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
15521552
static int
15531553
hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
15541554
{
1555+
unsigned int len = qdisc_pkt_len(skb);
15551556
struct hfsc_class *cl;
15561557
int uninitialized_var(err);
15571558

@@ -1573,8 +1574,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
15731574
}
15741575

15751576
if (cl->qdisc->q.qlen == 1) {
1576-
unsigned int len = qdisc_pkt_len(skb);
1577-
15781577
if (cl->cl_flags & HFSC_RSC)
15791578
init_ed(cl, len);
15801579
if (cl->cl_flags & HFSC_FSC)
@@ -1589,7 +1588,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
15891588

15901589
}
15911590

1592-
qdisc_qstats_backlog_inc(sch, skb);
1591+
sch->qstats.backlog += len;
15931592
sch->q.qlen++;
15941593

15951594
return NET_XMIT_SUCCESS;

net/sched/sch_htb.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
597597
struct sk_buff **to_free)
598598
{
599599
int uninitialized_var(ret);
600+
unsigned int len = qdisc_pkt_len(skb);
600601
struct htb_sched *q = qdisc_priv(sch);
601602
struct htb_class *cl = htb_classify(skb, sch, &ret);
602603

@@ -626,7 +627,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
626627
htb_activate(q, cl);
627628
}
628629

629-
qdisc_qstats_backlog_inc(sch, skb);
630+
sch->qstats.backlog += len;
630631
sch->q.qlen++;
631632
return NET_XMIT_SUCCESS;
632633
}

net/sched/sch_prio.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
7171
static int
7272
prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
7373
{
74+
unsigned int len = qdisc_pkt_len(skb);
7475
struct Qdisc *qdisc;
7576
int ret;
7677

@@ -87,7 +88,7 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
8788

8889
ret = qdisc_enqueue(skb, qdisc, to_free);
8990
if (ret == NET_XMIT_SUCCESS) {
90-
qdisc_qstats_backlog_inc(sch, skb);
91+
sch->qstats.backlog += len;
9192
sch->q.qlen++;
9293
return NET_XMIT_SUCCESS;
9394
}

net/sched/sch_qfq.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *q)
12331233
static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
12341234
struct sk_buff **to_free)
12351235
{
1236+
unsigned int len = qdisc_pkt_len(skb), gso_segs;
12361237
struct qfq_sched *q = qdisc_priv(sch);
12371238
struct qfq_class *cl;
12381239
struct qfq_aggregate *agg;
@@ -1247,17 +1248,17 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
12471248
}
12481249
pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid);
12491250

1250-
if (unlikely(cl->agg->lmax < qdisc_pkt_len(skb))) {
1251+
if (unlikely(cl->agg->lmax < len)) {
12511252
pr_debug("qfq: increasing maxpkt from %u to %u for class %u",
1252-
cl->agg->lmax, qdisc_pkt_len(skb), cl->common.classid);
1253-
err = qfq_change_agg(sch, cl, cl->agg->class_weight,
1254-
qdisc_pkt_len(skb));
1253+
cl->agg->lmax, len, cl->common.classid);
1254+
err = qfq_change_agg(sch, cl, cl->agg->class_weight, len);
12551255
if (err) {
12561256
cl->qstats.drops++;
12571257
return qdisc_drop(skb, sch, to_free);
12581258
}
12591259
}
12601260

1261+
gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
12611262
err = qdisc_enqueue(skb, cl->qdisc, to_free);
12621263
if (unlikely(err != NET_XMIT_SUCCESS)) {
12631264
pr_debug("qfq_enqueue: enqueue failed %d\n", err);
@@ -1268,16 +1269,17 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
12681269
return err;
12691270
}
12701271

1271-
bstats_update(&cl->bstats, skb);
1272-
qdisc_qstats_backlog_inc(sch, skb);
1272+
cl->bstats.bytes += len;
1273+
cl->bstats.packets += gso_segs;
1274+
sch->qstats.backlog += len;
12731275
++sch->q.qlen;
12741276

12751277
agg = cl->agg;
12761278
/* if the queue was not empty, then done here */
12771279
if (cl->qdisc->q.qlen != 1) {
12781280
if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) &&
12791281
list_first_entry(&agg->active, struct qfq_class, alist)
1280-
== cl && cl->deficit < qdisc_pkt_len(skb))
1282+
== cl && cl->deficit < len)
12811283
list_move_tail(&cl->alist, &agg->active);
12821284

12831285
return err;

net/sched/sch_tbf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
185185
struct sk_buff **to_free)
186186
{
187187
struct tbf_sched_data *q = qdisc_priv(sch);
188+
unsigned int len = qdisc_pkt_len(skb);
188189
int ret;
189190

190191
if (qdisc_pkt_len(skb) > q->max_size) {
@@ -199,7 +200,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
199200
return ret;
200201
}
201202

202-
qdisc_qstats_backlog_inc(sch, skb);
203+
sch->qstats.backlog += len;
203204
sch->q.qlen++;
204205
return NET_XMIT_SUCCESS;
205206
}

0 commit comments

Comments
 (0)