Merge branch 'net-sched-fix-qdisc-graft-hierarchy-validation'

Zijie Huang says:

====================
net/sched: fix qdisc graft hierarchy validation

The qdisc create-and-graft path allows users to keep attaching new classful
qdiscs under an already deep parent hierarchy. Such a hierarchy can later
be walked recursively and exhaust the kernel stack.

This series stores the qdisc hierarchy depth in struct Qdisc and checks it
when a qdisc is grafted. New child qdiscs are rejected once the parent is
already at the maximum allowed depth. It also adds tdc coverage for the
maximum allowed depth and rejection above it.
====================

Link: https://patch.msgid.link/cover.1785434373.git.milkory@outlook.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-08-06 15:25:15 +02:00
commit cd0784790d
3 changed files with 84 additions and 0 deletions

View File

@ -99,6 +99,7 @@ struct Qdisc {
struct hlist_node hash;
u32 handle;
u32 parent;
int depth;
struct netdev_queue *dev_queue;

View 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 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
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;

View File

@ -0,0 +1,74 @@
[
{
"id": "ad43",
"name": "Create qdisc hierarchy at maximum depth",
"category": [
"qdisc",
"depth"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DUMMY root handle 1: htb default 1",
"$TC class add dev $DUMMY parent 1: classid 1:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 1:1 handle 2: htb default 1",
"$TC class add dev $DUMMY parent 2: classid 2:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 2:1 handle 3: htb default 1",
"$TC class add dev $DUMMY parent 3: classid 3:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 3:1 handle 4: htb default 1",
"$TC class add dev $DUMMY parent 4: classid 4:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 4:1 handle 5: htb default 1",
"$TC class add dev $DUMMY parent 5: classid 5:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 5:1 handle 6: htb default 1",
"$TC class add dev $DUMMY parent 6: classid 6:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 6:1 handle 7: htb default 1",
"$TC class add dev $DUMMY parent 7: classid 7:1 htb rate 10mbit"
],
"cmdUnderTest": "$TC qdisc add dev $DUMMY parent 7:1 handle 8: htb default 1",
"expExitCode": "0",
"verifyCmd": "$TC qdisc show dev $DUMMY",
"matchPattern": "qdisc htb 8: parent 7:1",
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DUMMY root"
]
},
{
"id": "c519",
"name": "Reject qdisc hierarchy above maximum depth",
"category": [
"qdisc",
"depth"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DUMMY root handle 1: htb default 1",
"$TC class add dev $DUMMY parent 1: classid 1:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 1:1 handle 2: htb default 1",
"$TC class add dev $DUMMY parent 2: classid 2:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 2:1 handle 3: htb default 1",
"$TC class add dev $DUMMY parent 3: classid 3:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 3:1 handle 4: htb default 1",
"$TC class add dev $DUMMY parent 4: classid 4:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 4:1 handle 5: htb default 1",
"$TC class add dev $DUMMY parent 5: classid 5:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 5:1 handle 6: htb default 1",
"$TC class add dev $DUMMY parent 6: classid 6:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 6:1 handle 7: htb default 1",
"$TC class add dev $DUMMY parent 7: classid 7:1 htb rate 10mbit",
"$TC qdisc add dev $DUMMY parent 7:1 handle 8: htb default 1",
"$TC class add dev $DUMMY parent 8: classid 8:1 htb rate 10mbit"
],
"cmdUnderTest": "$TC qdisc add dev $DUMMY parent 8:1 handle 9: htb default 1",
"expExitCode": "2",
"verifyCmd": "$TC qdisc show dev $DUMMY",
"matchPattern": "qdisc htb 9:",
"matchCount": "0",
"teardown": [
"$TC qdisc del dev $DUMMY root"
]
}
]