[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250415000316.3122018-4-victor@mojatatu.com>
Date: Mon, 14 Apr 2025 21:03:15 -0300
From: Victor Nogueira <victor@...atatu.com>
To: netdev@...r.kernel.org
Cc: jhs@...atatu.com,
xiyou.wangcong@...il.com,
jiri@...nulli.us,
davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
toke@...hat.com,
gerrard.tai@...rlabs.sg,
pctammela@...atatu.com
Subject: [RFC PATCH net 3/4] net_sched: ets: 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 ets, there won't be a UAF, but the code will add the same
classifier to the list twice, which will cause memory corruption.
This patch checks, in parallel with the qlen being zero, whether the
class was already added to the active_list (cl_is_initialised) before
doing the addition.
Fixes: 37d9cf1a3ce3 ("sched: Fix detection of empty queues in child qdiscs")
[1] https://lore.kernel.org/netdev/CAHcdcOm+03OD2j6R0=YHKqmy=VgJ8xEOKuP6c7mSgnp-TEJJbw@mail.gmail.com/
Signed-off-by: Victor Nogueira <victor@...atatu.com>
---
net/sched/sch_ets.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
index c3bdeb14185b..b62aace5bc46 100644
--- a/net/sched/sch_ets.c
+++ b/net/sched/sch_ets.c
@@ -74,6 +74,11 @@ static const struct nla_policy ets_class_policy[TCA_ETS_MAX + 1] = {
[TCA_ETS_QUANTA_BAND] = { .type = NLA_U32 },
};
+static bool cl_is_initialised(struct ets_class *cl)
+{
+ return !list_empty(&cl->alist);
+}
+
static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
unsigned int *quantum,
struct netlink_ext_ack *extack)
@@ -415,8 +420,8 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
unsigned int len = qdisc_pkt_len(skb);
struct ets_sched *q = qdisc_priv(sch);
struct ets_class *cl;
+ bool is_empty;
int err = 0;
- bool first;
cl = ets_classify(skb, sch, &err);
if (!cl) {
@@ -426,7 +431,7 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return err;
}
- first = !cl->qdisc->q.qlen;
+ is_empty = !cl->qdisc->q.qlen;
err = qdisc_enqueue(skb, cl->qdisc, to_free);
if (unlikely(err != NET_XMIT_SUCCESS)) {
if (net_xmit_drop_count(err)) {
@@ -436,7 +441,7 @@ static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return err;
}
- if (first && !ets_class_is_strict(q, cl)) {
+ if (is_empty && cl_is_initialised(cl) && !ets_class_is_strict(q, cl)) {
list_add_tail(&cl->alist, &q->active);
cl->deficit = cl->quantum;
}
--
2.34.1
Powered by blists - more mailing lists