summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZijie Huang <milkory@outlook.com>2026-08-01 21:42:33 +0800
committerPaolo Abeni <pabeni@redhat.com>2026-08-06 15:24:44 +0200
commitdedd34b0f2310e28c5f6d4875cfbf4b7ed821c01 (patch)
tree0ccba782af4a99ebde5b0742667f644666834607
parent7e2d693af0d4c05bddccb3541a0aabd69f4cb244 (diff)
net/sched: reject overly deep qdisc hierarchies
Deep qdisc hierarchies can lead to excessive recursion in qdisc tree walkers and exhaust the kernel stack. The existing loop check does not cover the create-and-graft path, so a hierarchy can still be extended by creating a new child qdisc below an already deep parent. Store the hierarchy depth in struct Qdisc and update it when qdiscs are grafted. Reject new child qdiscs once the parent is already at the maximum allowed depth. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Suggested-by: Jamal Hadi Salim <jhs@mojatatu.com> Reported-by: Vega <vega@nebusec.ai> Assisted-by: Codex:gpt-5.4 Signed-off-by: Zijie Huang <milkory@outlook.com> Signed-off-by: Ren Wei <enjou1224z@gmail.com> Reviewed-by: Victor Nogueira <victor@mojatatu.com> Link: https://patch.msgid.link/1e9ab39597423fd5d13cfaaf52279b8ee3d9fc3c.1785434373.git.milkory@outlook.com Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--include/net/sch_generic.h1
-rw-r--r--net/sched/sch_api.c9
2 files changed, 10 insertions, 0 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 45a1e8c78222..cbc248776511 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -99,6 +99,7 @@ struct Qdisc {
struct hlist_node hash;
u32 handle;
u32 parent;
+ int depth;
struct netdev_queue *dev_queue;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 668bcd60d183..65b35528d125 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1114,6 +1114,9 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
unsigned int i, num_q, ingress;
struct netdev_queue *dev_queue;
+ if (new)
+ new->depth = 0;
+
ingress = 0;
num_q = dev->num_tx_queues;
if ((q && q->flags & TCQ_F_INGRESS) ||
@@ -1211,9 +1214,15 @@ skip:
NL_SET_ERR_MSG(extack, "STAB not supported on a non root");
return -EINVAL;
}
+ if (new && parent->depth >= 7) {
+ NL_SET_ERR_MSG(extack, "Qdisc hierarchy is too deep");
+ return -E2BIG;
+ }
err = cops->graft(parent, cl, new, &old, extack);
if (err)
return err;
+ if (new)
+ new->depth = parent->depth + 1;
notify_and_destroy(net, skb, n, classid, old, new, extack);
}
return 0;