Skip to content

Commit f99a3fb

Browse files
vbnogueirakuba-moo
authored andcommitted
net_sched: drr: Fix double list add in class with netem as child qdisc
As described in Gerrard's report [1], there are use cases where a netem child qdisc will make the parent qdisc's enqueue callback reentrant. In the case of drr, there won't be a UAF, but the code will add the same classifier to the list twice, which will cause memory corruption. In addition to checking for qlen being zero, this patch checks whether the class was already added to the active_list (cl_is_active) before adding to the list to cover for the reentrant case. [1] https://lore.kernel.org/netdev/CAHcdcOm+03OD2j6R0=YHKqmy=VgJ8xEOKuP6c7mSgnp-TEJJbw@mail.gmail.com/ Fixes: 37d9cf1 ("sched: Fix detection of empty queues in child qdiscs") Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/20250425220710.3964791-2-victor@mojatatu.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent dfd7601 commit f99a3fb

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

net/sched/sch_drr.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ struct drr_sched {
3535
struct Qdisc_class_hash clhash;
3636
};
3737

38+
static bool cl_is_active(struct drr_class *cl)
39+
{
40+
return !list_empty(&cl->alist);
41+
}
42+
3843
static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
3944
{
4045
struct drr_sched *q = qdisc_priv(sch);
@@ -337,7 +342,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
337342
struct drr_sched *q = qdisc_priv(sch);
338343
struct drr_class *cl;
339344
int err = 0;
340-
bool first;
341345

342346
cl = drr_classify(skb, sch, &err);
343347
if (cl == NULL) {
@@ -347,7 +351,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
347351
return err;
348352
}
349353

350-
first = !cl->qdisc->q.qlen;
351354
err = qdisc_enqueue(skb, cl->qdisc, to_free);
352355
if (unlikely(err != NET_XMIT_SUCCESS)) {
353356
if (net_xmit_drop_count(err)) {
@@ -357,7 +360,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch,
357360
return err;
358361
}
359362

360-
if (first) {
363+
if (!cl_is_active(cl)) {
361364
list_add_tail(&cl->alist, &q->active);
362365
cl->deficit = cl->quantum;
363366
}

0 commit comments

Comments
 (0)