]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/sched: reject overly deep qdisc hierarchies
authorZijie Huang <milkory@outlook.com>
Sat, 1 Aug 2026 13:42:33 +0000 (21:42 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 6 Aug 2026 13:24:44 +0000 (15:24 +0200)
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>
include/net/sch_generic.h
net/sched/sch_api.c

index 45a1e8c78222bd7f6e0e44977c118ecee6420c54..cbc24877651187137cd5bdeb8cfdecfae47ed155 100644 (file)
@@ -99,6 +99,7 @@ struct Qdisc {
        struct hlist_node       hash;
        u32                     handle;
        u32                     parent;
+       int                     depth;
 
        struct netdev_queue     *dev_queue;
 
index 668bcd60d183e0c6826e78309c5a83b3cf8057fe..65b35528d125f48d9d016be2aee66dfbc8444178 100644 (file)
@@ -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;