]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
net/sched: stop qdisc_tree_reduce_backlog on TC_H_ROOT
authorPedro Tammela <pctammela@mojatatu.com>
Thu, 24 Oct 2024 16:55:47 +0000 (12:55 -0400)
committerJakub Kicinski <kuba@kernel.org>
Tue, 29 Oct 2024 18:32:26 +0000 (11:32 -0700)
In qdisc_tree_reduce_backlog, Qdiscs with major handle ffff: are assumed
to be either root or ingress. This assumption is bogus since it's valid
to create egress qdiscs with major handle ffff:
Budimir Markovic found that for qdiscs like DRR that maintain an active
class list, it will cause a UAF with a dangling class pointer.

In 066a3b5b2346, the concern was to avoid iterating over the ingress
qdisc since its parent is itself. The proper fix is to stop when parent
TC_H_ROOT is reached because the only way to retrieve ingress is when a
hierarchy which does not contain a ffff: major handle call into
qdisc_lookup with TC_H_MAJ(TC_H_ROOT).

In the scenario where major ffff: is an egress qdisc in any of the tree
levels, the updates will also propagate to TC_H_ROOT, which then the
iteration must stop.

Fixes: 066a3b5b2346 ("[NET_SCHED] sch_api: fix qdisc_tree_decrease_qlen() loop")
Reported-by: Budimir Markovic <markovicbudimir@gmail.com>
Suggested-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
 net/sched/sch_api.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20241024165547.418570-1-jhs@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/sched/sch_api.c

index 2eefa4783879971c557ca3d98b74ac1218ea2bd1..a1d27bc039a364d5088d0e1a9083bc61b0e267e9 100644 (file)
@@ -791,7 +791,7 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
        drops = max_t(int, n, 0);
        rcu_read_lock();
        while ((parentid = sch->parent)) {
-               if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
+               if (parentid == TC_H_ROOT)
                        break;
 
                if (sch->flags & TCQ_F_NOPARENT)