diff options
author | Pedro Tammela <[email protected]> | 2024-10-24 12:55:47 -0400 |
---|---|---|
committer | Jakub Kicinski <[email protected]> | 2024-10-29 11:32:26 -0700 |
commit | 2e95c4384438adeaa772caa560244b1a2efef816 (patch) | |
tree | f6a197ed9e1774a29bd1d35ba11283c9b1aa47c2 | |
parent | c59d72d0a4fbaa5fd7a04b2d13cfc101d01310db (diff) |
net/sched: stop qdisc_tree_reduce_backlog on TC_H_ROOT
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 <[email protected]>
Suggested-by: Jamal Hadi Salim <[email protected]>
Tested-by: Victor Nogueira <[email protected]>
Signed-off-by: Pedro Tammela <[email protected]>
Signed-off-by: Jamal Hadi Salim <[email protected]>
net/sched/sch_api.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Horman <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>
-rw-r--r-- | net/sched/sch_api.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 2eefa4783879..a1d27bc039a3 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -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) |