* [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths
[not found] <all>
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 1/8] net/sched: fq: clamp quantum and initial_quantum in change path Jamal Hadi Salim
` (7 more replies)
0 siblings, 8 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
This is a followup to commit 709f34f7c28d ("net/sched: fq: add overflow
bounds to quantum and initial quantum").
The quantum_backlog_overflow series and the five siblings that followed
clamped the init-path quantum in fq, fq_codel, fq_pie, hhf, sfq. The
change() paths were not clamped but it is the same pattern, same writer
of q->quantum, same privilege level (CAP_NET_ADMIN in a user namespace).
A user can override the init clamp via tc qdisc change, restoring the
small-quantum deficit spin that the init clamp was meant to prevent.
This series also covers two siblings that were missed entirely by the
original series: sch_dualpi2 and sch_pie call psched_mtu() without any
clamp at all. With a crafted size table qdisc_pkt_len reaches ~2 GiB,
so quantum=1 (or a zero psched_mtu on a headerless device) makes the
deficit-refill loop spin ~2^31 times under the qdisc lock (a soft
lockup / denial of service).
Each patch fixes one qdisc with its own Fixes: tag so they can be
backported independently — the commits they fix shift differently in
the git tree.
Patch 1: fq — clamp TCA_FQ_QUANTUM and TCA_FQ_INITIAL_QUANTUM in change
Patch 2: fq_pie — clamp quantum in change path
Patch 3: sfq — clamp quantum and reject > 1<<20 in change path
Patch 4: hhf — clamp quantum in change and init paths
Patch 5: dualpi2 — clamp psched_mtu at all 3 call sites
Patch 6: pie — clamp psched_mtu in pie_drop_early
Patch 7: drr — clamp quantum in change class
Patch 8: ets — clamp quantum in parse and fallback paths
Conditions to recreate (applies to all): create the qdisc, then
tc qdisc change ... quantum 1 with a STAB size table inflating
qdisc_pkt_len. Requires CAP_NET_ADMIN in a user namespace (unshare -Urn).
Sashiko links:
- gemini: https://sashiko.dev/#/patchset/20260826074056.7873-1-jhs@mojatatu.com
- nipa: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260826074056.7873-1-jhs@mojatatu.com
v1 -> v2:
- Split the single monolithic patch into 8 per-qdisc patches, each with
its own Fixes: tag, so stable backports can cherry-pick individually.
- Add cover letter.
- ETS: move 256 floor into ets_quantum_parse() so explicit quanta are
clamped, not just the fallback path (Sashiko gemini + nipa gpt-5-6-sol-1-7).
- DRR: add upper bound clamp_t(u32, quantum, 256, 1<<20) matching sfq
(Sashiko nipa gpt-5-6-sol-3-19).
- ETS: add upper bound clamp in ets_quantum_parse() and fallback path.
- sch_fq: add 256 floor in fq_change() for TCA_FQ_QUANTUM and clamp
fq_init() quantum to [256, 1<<20] for tiny-MTU devices
(Sashiko gemini + nipa main-1-1).
- hhf: clamp hhf_init() to [256, 1<<20] matching siblings
(Sashiko gemini + nipa gpt-5-6-sol-6-24).
- Add Fixes: dcc68b4d8084 for ETS (Sashiko nipa gpt-5-6-sol-1-8).
- Re-add Toke's Reviewed-by from v1 (kept since v2 only splits the patch,
the code Toke reviewed is unchanged in approach).
Jamal Hadi Salim (8):
net/sched: fq: clamp quantum and initial_quantum in change path
net/sched: fq_pie: clamp quantum in change path
net/sched: sfq: clamp quantum in change path
net/sched: hhf: clamp quantum in change and init paths
net/sched: dualpi2: clamp psched_mtu at all call sites
net/sched: pie: clamp psched_mtu in pie_drop_early
net/sched: drr: clamp quantum in change class
net/sched: ets: clamp quantum in parse and fallback paths
net/sched/sch_drr.c | 3 ++-
net/sched/sch_dualpi2.c | 10 +++++++---
net/sched/sch_ets.c | 12 +++++-------
net/sched/sch_fq.c | 14 +++++---------
net/sched/sch_fq_pie.c | 3 ++-
net/sched/sch_hhf.c | 8 ++------
net/sched/sch_pie.c | 2 +-
net/sched/sch_sfq.c | 7 ++++++-
8 files changed, 30 insertions(+), 29 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH net v2 1/8] net/sched: fq: clamp quantum and initial_quantum in change path
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 2/8] net/sched: fq_pie: clamp quantum " Jamal Hadi Salim
` (6 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
The fq change path accepts TCA_FQ_QUANTUM in [1, INT_MAX] and
TCA_FQ_INITIAL_QUANTUM up to INT_MAX, while fq_init() already clamps to
[1, 1<<20]. A user can override the init clamp via tc qdisc change,
restoring the small-quantum deficit spin that the init clamp prevents.
Narrow iq_range.max to 1<<20 so TCA_FQ_INITIAL_QUANTUM is rejected at
parse time. Clamp TCA_FQ_QUANTUM to [256, 1<<20] in fq_change() and
fq_init() quantum to [256, 1<<20] for tiny-MTU devices.
Conditions to recreate the bug:
CONFIG_NET_SCH_FQ=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root fq
tc qdisc change dev dummy0 root fq quantum 1 stab data 32768 size_log 15 cell_log 0
Fixes: 709f34f7c28d ("net/sched: fq: add overflow bounds to quantum and initial quantum")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_fq.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 6144b5686f13..35f940b2205d 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -980,7 +980,7 @@ static int fq_resize(struct Qdisc *sch, u32 log)
}
static const struct netlink_range_validation iq_range = {
- .max = INT_MAX,
+ .max = 1 << 20,
};
static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = {
@@ -1106,14 +1106,10 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt,
nla_get_u32(tb[TCA_FQ_FLOW_PLIMIT]));
if (tb[TCA_FQ_QUANTUM]) {
- u32 quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]);
+ u32 quantum = clamp_t(u32, nla_get_u32(tb[TCA_FQ_QUANTUM]),
+ 256, 1 << 20);
- if (quantum > 0 && quantum <= (1 << 20)) {
- WRITE_ONCE(q->quantum, quantum);
- } else {
- NL_SET_ERR_MSG_MOD(extack, "invalid quantum");
- err = -EINVAL;
- }
+ WRITE_ONCE(q->quantum, quantum);
}
if (tb[TCA_FQ_INITIAL_QUANTUM])
@@ -1232,7 +1228,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt,
sch->limit = 10000;
q->flow_plimit = 100;
mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 1, 1 << 20);
- q->quantum = min_t(u32, 2 * mtu, 1 << 20);
+ q->quantum = clamp_t(u32, 2 * mtu, 256, 1 << 20);
q->initial_quantum = min_t(u32, 10 * mtu, 1 << 20);
q->flow_refill_delay = msecs_to_jiffies(40);
q->flow_max_rate = ~0UL;
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 2/8] net/sched: fq_pie: clamp quantum in change path
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 1/8] net/sched: fq: clamp quantum and initial_quantum in change path Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 3/8] net/sched: sfq: " Jamal Hadi Salim
` (5 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
fq_pie_change() accepts any quantum value from userspace, including 1.
With a crafted size table qdisc_pkt_len reaches ~2 GiB, so quantum=1
makes the deficit-refill loop spin ~2^31 times under the qdisc lock
(a soft lockup / denial of service).
Add max(256U, ...) matching fq_codel_change().
Conditions to recreate the bug:
CONFIG_NET_SCH_FQ_PIE=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root fq_pie
tc qdisc change dev dummy0 root fq_pie quantum 1 stab data 32768 size_log 15 cell_log 0
Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_fq_pie.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
index b27d95418707..5982847df8f8 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -341,7 +341,8 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
nla_get_u32(tb[TCA_FQ_PIE_BETA]));
if (tb[TCA_FQ_PIE_QUANTUM])
- WRITE_ONCE(q->quantum, nla_get_u32(tb[TCA_FQ_PIE_QUANTUM]));
+ WRITE_ONCE(q->quantum,
+ max(256U, nla_get_u32(tb[TCA_FQ_PIE_QUANTUM])));
if (tb[TCA_FQ_PIE_MEMORY_LIMIT])
WRITE_ONCE(q->memory_limit,
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 3/8] net/sched: sfq: clamp quantum in change path
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 1/8] net/sched: fq: clamp quantum and initial_quantum in change path Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 2/8] net/sched: fq_pie: clamp quantum " Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 4/8] net/sched: hhf: clamp quantum in change and init paths Jamal Hadi Salim
` (4 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
sfq_change() accepts any non-negative quantum (only rejects
(int)ctl->quantum < 0). With a crafted size table qdisc_pkt_len reaches
~2 GiB, so quantum=1 makes the deficit-refill loop spin ~2^31 times
under the qdisc lock (a soft lockup / denial of service).
Add max(256U, ...) matching fq_codel_change(). Reject quantum > 1<<20
with -EINVAL, matching fq_codel_change() and the init clamp.
Conditions to recreate the bug:
CONFIG_NET_SCH_SFQ=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root sfq
tc qdisc change dev dummy0 root sfq quantum 1 stab data 32768 size_log 15 cell_log 0
Fixes: e4650d7ae425 ("net_sched: sch_sfq: handle bigger packets")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_sfq.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 187d3ed578f2..8bbcfc9e85d9 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -660,6 +660,11 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
return -EINVAL;
}
+ if (ctl->quantum > 1 << 20) {
+ NL_SET_ERR_MSG_MOD(extack, "quantum too large");
+ return -EINVAL;
+ }
+
if (ctl->perturb_period < 0 ||
ctl->perturb_period > INT_MAX / HZ) {
NL_SET_ERR_MSG_MOD(extack, "invalid perturb period");
@@ -688,7 +693,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
/* update and validate configuration */
if (ctl->quantum)
- quantum = ctl->quantum;
+ quantum = max(256U, ctl->quantum);
if (ctl->flows)
maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
if (ctl->divisor) {
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 4/8] net/sched: hhf: clamp quantum in change and init paths
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
` (2 preceding siblings ...)
2026-08-29 8:12 ` [PATCH net v2 3/8] net/sched: sfq: " Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 5/8] net/sched: dualpi2: clamp psched_mtu at all call sites Jamal Hadi Salim
` (3 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
hhf_change() accepts any quantum from userspace, including 1. With a
crafted size table qdisc_pkt_len reaches ~2 GiB, so quantum=1 makes
the deficit-refill loop spin ~2^31 times under the qdisc lock
(a soft lockup / denial of service).
Add max(256U, ...) in hhf_change() matching fq_codel_change(). Clamp
hhf_init() to [256, 1<<20] matching the siblings, and remove the old
fallback that only set quantum=256 on overflow.
Conditions to recreate the bug:
CONFIG_NET_SCH_HHF=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root hhf
tc qdisc change dev dummy0 root hhf quantum 1 stab data 32768 size_log 15 cell_log 0
Fixes: 10239edf86f1 ("net-qdisc-hhf: Heavy-Hitter Filter (HHF) qdisc")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_hhf.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index 96acab6a8da0..fc72f825fbd9 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -551,7 +551,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt,
return err;
if (tb[TCA_HHF_QUANTUM])
- new_quantum = nla_get_u32(tb[TCA_HHF_QUANTUM]);
+ new_quantum = max(256U, nla_get_u32(tb[TCA_HHF_QUANTUM]));
if (tb[TCA_HHF_NON_HH_WEIGHT])
new_hhf_non_hh_weight = nla_get_u32(tb[TCA_HHF_NON_HH_WEIGHT]);
@@ -613,7 +613,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt,
int i;
sch->limit = 1000;
- q->quantum = psched_mtu(qdisc_dev(sch));
+ q->quantum = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 256, 1 << 20);
get_random_bytes(&q->perturbation, sizeof(q->perturbation));
INIT_LIST_HEAD(&q->new_buckets);
INIT_LIST_HEAD(&q->old_buckets);
@@ -624,10 +624,6 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt,
q->hhf_evict_timeout = HZ; /* 1 sec */
q->hhf_non_hh_weight = 2;
- if ((int)q->quantum <= 0 ||
- (u64)q->quantum * q->hhf_non_hh_weight > INT_MAX)
- q->quantum = 256;
-
if (opt) {
int err = hhf_change(sch, opt, extack);
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 5/8] net/sched: dualpi2: clamp psched_mtu at all call sites
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
` (3 preceding siblings ...)
2026-08-29 8:12 ` [PATCH net v2 4/8] net/sched: hhf: clamp quantum in change and init paths Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 6/8] net/sched: pie: clamp psched_mtu in pie_drop_early Jamal Hadi Salim
` (2 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
dualpi2_calculate_c_protection(), must_drop(), and get_memory_limit()
call psched_mtu() with no clamp. A huge MTU makes (s32)psched_mtu()
overflow in the signed multiply for c_protection_init, and 2 *
psched_mtu() wraps in get_memory_limit(). With a crafted size table
qdisc_pkt_len reaches ~2 GiB, causing a soft lockup / denial of service.
Clamp psched_mtu() to [1, 1<<20] at all three call sites.
Conditions to recreate the bug:
CONFIG_NET_SCH_DUALPI2=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root dualpi2
tc qdisc change dev dummy0 root dualpi2 stab data 32768 size_log 15 cell_log 0
Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_dualpi2.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
index 4f678d4ff10e..4947def7c49e 100644
--- a/net/sched/sch_dualpi2.c
+++ b/net/sched/sch_dualpi2.c
@@ -208,9 +208,11 @@ static void dualpi2_reset_c_protection(struct dualpi2_sched_data *q)
static void dualpi2_calculate_c_protection(struct Qdisc *sch,
struct dualpi2_sched_data *q, u32 wc)
{
+ u32 mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 1, 1 << 20);
+
q->c_protection_wc = wc;
q->c_protection_wl = MAX_WC - wc;
- q->c_protection_init = (s32)psched_mtu(qdisc_dev(sch)) *
+ q->c_protection_init = (s32)mtu *
((int)q->c_protection_wc - (int)q->c_protection_wl);
dualpi2_reset_c_protection(q);
}
@@ -285,8 +287,9 @@ static bool must_drop(struct Qdisc *sch, struct dualpi2_sched_data *q,
u64 local_l_prob;
bool overload;
u32 prob;
+ u32 mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 1, 1 << 20);
- if (sch->qstats.backlog < 2 * psched_mtu(qdisc_dev(sch)))
+ if (sch->qstats.backlog < 2 * mtu)
return false;
prob = READ_ONCE(q->pi2_prob);
@@ -712,7 +715,8 @@ static u32 get_memory_limit(struct Qdisc *sch, u32 limit)
/* Apply rule of thumb, i.e., doubling the packet length,
* to further include per packet overhead in memory_limit.
*/
- u64 memlim = mul_u32_u32(limit, 2 * psched_mtu(qdisc_dev(sch)));
+ u64 memlim = mul_u32_u32(limit, 2 * clamp_t(u32, psched_mtu(qdisc_dev(sch)),
+ 1, 1 << 20));
if (upper_32_bits(memlim))
return U32_MAX;
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 6/8] net/sched: pie: clamp psched_mtu in pie_drop_early
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
` (4 preceding siblings ...)
2026-08-29 8:12 ` [PATCH net v2 5/8] net/sched: dualpi2: clamp psched_mtu at all call sites Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 7/8] net/sched: drr: clamp quantum in change class Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths Jamal Hadi Salim
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
pie_drop_early() calls psched_mtu() with no clamp. With mtu=0x80000000
the bytemode divide silently zeroes the drop probability, disabling AQM.
Clamp to [1, 1<<20].
Conditions to recreate the bug:
CONFIG_NET_SCH_PIE=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root pie
tc qdisc change dev dummy0 root pie stab data 32768 size_log 15 cell_log 0
Fixes: d4b36210c2e6 ("net: pkt_sched: PIE AQM scheme")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_pie.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c
index b41f2def2e2c..3b7863ffd284 100644
--- a/net/sched/sch_pie.c
+++ b/net/sched/sch_pie.c
@@ -35,7 +35,7 @@ bool pie_drop_early(struct Qdisc *sch, struct pie_params *params,
{
u64 rnd;
u64 local_prob = vars->prob;
- u32 mtu = psched_mtu(qdisc_dev(sch));
+ u32 mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 1, 1 << 20);
/* If there is still burst allowance left skip random early drop */
if (vars->burst_time > 0)
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 7/8] net/sched: drr: clamp quantum in change class
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
` (5 preceding siblings ...)
2026-08-29 8:12 ` [PATCH net v2 6/8] net/sched: pie: clamp psched_mtu in pie_drop_early Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths Jamal Hadi Salim
7 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
drr_change_class() rejects explicit quantum==0 but falls back to
psched_mtu() with no floor. With a crafted size table qdisc_pkt_len
reaches ~2 GiB, so quantum=1 (or a zero psched_mtu on a headerless
device) makes the deficit-refill loop spin under the qdisc lock.
Add clamp_t(u32, quantum, 256, 1<<20) after the zero reject and on the
fallback path. The explicit-zero reject is preserved.
Conditions to recreate the bug:
CONFIG_NET_SCH_DRR=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root drr
tc class add dev dummy0 parent 1: classid 1:1 drr quantum 1
Fixes: 13d2a1d2b032 ("pkt_sched: add DRR scheduler")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_drr.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 91b1ef824afa..8621d057edd9 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -82,8 +82,9 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
NL_SET_ERR_MSG(extack, "Specified DRR quantum cannot be zero");
return -EINVAL;
}
+ quantum = clamp_t(u32, quantum, 256, 1 << 20);
} else
- quantum = psched_mtu(qdisc_dev(sch));
+ quantum = clamp_t(u32, (u32)psched_mtu(qdisc_dev(sch)), 256, 1 << 20);
if (cl != NULL) {
if (tca[TCA_RATE]) {
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
` (6 preceding siblings ...)
2026-08-29 8:12 ` [PATCH net v2 7/8] net/sched: drr: clamp quantum in change class Jamal Hadi Salim
@ 2026-08-29 8:12 ` Jamal Hadi Salim
2026-08-30 18:03 ` Jakub Kicinski
7 siblings, 1 reply; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-29 8:12 UTC (permalink / raw)
To: netdev
Cc: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Victor Nogueira, vega,
stable, toke, chia-yu.chang, subramanian.vijay, petrm
ets_qdisc_change() falls back to psched_mtu() with no floor for bands
without an explicit quantum. With a crafted size table qdisc_pkt_len
reaches ~2 GiB, so a zero psched_mtu on a headerless device makes the
deficit-refill loop spin under the qdisc lock.
Move the floor into ets_quantum_parse() so explicitly configured quanta
are also clamped to [256, 1<<20], not just the fallback path.
Conditions to recreate the bug:
CONFIG_NET_SCH_ETS=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root ets bands 3 strict 2 quanta 1 1
Fixes: dcc68b4d8084 ("net: sch_ets: Add a new Qdisc")
Reported-by: vega@nebusec.ai
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: stable@vger.kernel.org
---
net/sched/sch_ets.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
index 25fcf4079fec..6cc902a03838 100644
--- a/net/sched/sch_ets.c
+++ b/net/sched/sch_ets.c
@@ -83,11 +83,7 @@ static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
unsigned int *quantum,
struct netlink_ext_ack *extack)
{
- *quantum = nla_get_u32(attr);
- if (!*quantum) {
- NL_SET_ERR_MSG(extack, "ETS quantum cannot be zero");
- return -EINVAL;
- }
+ *quantum = clamp_t(u32, nla_get_u32(attr), 256, 1 << 20);
return 0;
}
@@ -632,11 +628,13 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
return err;
}
/* If there are more bands than strict + quanta provided, the remaining
- * ones are ETS with quantum of MTU. Initialize the missing values here.
+ * ones are ETS with quantum of max(MTU, 256). Initialize the missing
+ * values here.
*/
for (i = nstrict; i < nbands; i++) {
if (!quanta[i])
- quanta[i] = psched_mtu(qdisc_dev(sch));
+ quanta[i] = clamp_t(u32, (u32)psched_mtu(qdisc_dev(sch)),
+ 256, 1 << 20);
}
/* Before commit, make sure we can allocate all new qdiscs */
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths
2026-08-29 8:12 ` [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths Jamal Hadi Salim
@ 2026-08-30 18:03 ` Jakub Kicinski
2026-08-30 18:59 ` Jamal Hadi Salim
0 siblings, 1 reply; 12+ messages in thread
From: Jakub Kicinski @ 2026-08-30 18:03 UTC (permalink / raw)
To: Jamal Hadi Salim
Cc: netdev, Jiri Pirko, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Victor Nogueira, vega, stable, toke, chia-yu.chang,
subramanian.vijay, petrm
On Sat, 29 Aug 2026 04:12:29 -0400 Jamal Hadi Salim wrote:
> ets_qdisc_change() falls back to psched_mtu() with no floor for bands
> without an explicit quantum. With a crafted size table qdisc_pkt_len
> reaches ~2 GiB, so a zero psched_mtu on a headerless device makes the
> deficit-refill loop spin under the qdisc lock.
>
> Move the floor into ets_quantum_parse() so explicitly configured quanta
> are also clamped to [256, 1<<20], not just the fallback path.
>
> Conditions to recreate the bug:
> CONFIG_NET_SCH_ETS=y. Requires CAP_NET_ADMIN (namespace-local via
> unshare -Urn suffices).
>
> tc qdisc add dev dummy0 root ets bands 3 strict 2 quanta 1 1
>
> Fixes: dcc68b4d8084 ("net: sch_ets: Add a new Qdisc")
> Reported-by: vega@nebusec.ai
> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
> Tested-by: Victor Nogueira <victor@mojatatu.com>
> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
> Cc: stable@vger.kernel.org
> ---
> net/sched/sch_ets.c | 12 +++++-------
> 1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
> index 25fcf4079fec..6cc902a03838 100644
> --- a/net/sched/sch_ets.c
> +++ b/net/sched/sch_ets.c
> @@ -83,11 +83,7 @@ static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
> unsigned int *quantum,
> struct netlink_ext_ack *extack)
> {
> - *quantum = nla_get_u32(attr);
> - if (!*quantum) {
> - NL_SET_ERR_MSG(extack, "ETS quantum cannot be zero");
> - return -EINVAL;
> - }
> + *quantum = clamp_t(u32, nla_get_u32(attr), 256, 1 << 20);
> return 0;
> }
>
> @@ -632,11 +628,13 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
> return err;
> }
> /* If there are more bands than strict + quanta provided, the remaining
> - * ones are ETS with quantum of MTU. Initialize the missing values here.
> + * ones are ETS with quantum of max(MTU, 256). Initialize the missing
> + * values here.
> */
> for (i = nstrict; i < nbands; i++) {
> if (!quanta[i])
> - quanta[i] = psched_mtu(qdisc_dev(sch));
> + quanta[i] = clamp_t(u32, (u32)psched_mtu(qdisc_dev(sch)),
> + 256, 1 << 20);
> }
>
> /* Before commit, make sure we can allocate all new qdiscs */
Does this run afoul of one of the tdc cases?
# not ok 39 41f5 - ETS offload where the sum of quanta wraps u32
# Could not match regex pattern. Verify command output:
# qdisc ets 8004: root refcnt 5 offloaded bands 3 quanta 1048576 256 256 priomap 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
https://github.com/p4tc-dev/tc-executor/blob/storage-dbg/artifacts/799938/1-tdc-sh/stdout
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths
2026-08-30 18:03 ` Jakub Kicinski
@ 2026-08-30 18:59 ` Jamal Hadi Salim
2026-09-01 21:36 ` Jamal Hadi Salim
0 siblings, 1 reply; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-08-30 18:59 UTC (permalink / raw)
To: Jakub Kicinski
Cc: netdev, Jiri Pirko, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Victor Nogueira, vega, stable, toke, chia-yu.chang,
subramanian.vijay, petrm
On Sun, Aug 30, 2026 at 2:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Sat, 29 Aug 2026 04:12:29 -0400 Jamal Hadi Salim wrote:
> > ets_qdisc_change() falls back to psched_mtu() with no floor for bands
> > without an explicit quantum. With a crafted size table qdisc_pkt_len
> > reaches ~2 GiB, so a zero psched_mtu on a headerless device makes the
> > deficit-refill loop spin under the qdisc lock.
> >
> > Move the floor into ets_quantum_parse() so explicitly configured quanta
> > are also clamped to [256, 1<<20], not just the fallback path.
> >
> > Conditions to recreate the bug:
> > CONFIG_NET_SCH_ETS=y. Requires CAP_NET_ADMIN (namespace-local via
> > unshare -Urn suffices).
> >
> > tc qdisc add dev dummy0 root ets bands 3 strict 2 quanta 1 1
> >
> > Fixes: dcc68b4d8084 ("net: sch_ets: Add a new Qdisc")
> > Reported-by: vega@nebusec.ai
> > Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
> > Tested-by: Victor Nogueira <victor@mojatatu.com>
> > Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
> > Cc: stable@vger.kernel.org
> > ---
> > net/sched/sch_ets.c | 12 +++++-------
> > 1 file changed, 5 insertions(+), 7 deletions(-)
> >
> > diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
> > index 25fcf4079fec..6cc902a03838 100644
> > --- a/net/sched/sch_ets.c
> > +++ b/net/sched/sch_ets.c
> > @@ -83,11 +83,7 @@ static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
> > unsigned int *quantum,
> > struct netlink_ext_ack *extack)
> > {
> > - *quantum = nla_get_u32(attr);
> > - if (!*quantum) {
> > - NL_SET_ERR_MSG(extack, "ETS quantum cannot be zero");
> > - return -EINVAL;
> > - }
> > + *quantum = clamp_t(u32, nla_get_u32(attr), 256, 1 << 20);
> > return 0;
> > }
> >
> > @@ -632,11 +628,13 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
> > return err;
> > }
> > /* If there are more bands than strict + quanta provided, the remaining
> > - * ones are ETS with quantum of MTU. Initialize the missing values here.
> > + * ones are ETS with quantum of max(MTU, 256). Initialize the missing
> > + * values here.
> > */
> > for (i = nstrict; i < nbands; i++) {
> > if (!quanta[i])
> > - quanta[i] = psched_mtu(qdisc_dev(sch));
> > + quanta[i] = clamp_t(u32, (u32)psched_mtu(qdisc_dev(sch)),
> > + 256, 1 << 20);
> > }
> >
> > /* Before commit, make sure we can allocate all new qdiscs */
>
> Does this run afoul of one of the tdc cases?
>
> # not ok 39 41f5 - ETS offload where the sum of quanta wraps u32
> # Could not match regex pattern. Verify command output:
> # qdisc ets 8004: root refcnt 5 offloaded bands 3 quanta 1048576 256 256 priomap 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
>
> https://github.com/p4tc-dev/tc-executor/blob/storage-dbg/artifacts/799938/1-tdc-sh/stdout
Yikes. I will resend with this fixed.
cheers.
jamal
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths
2026-08-30 18:59 ` Jamal Hadi Salim
@ 2026-09-01 21:36 ` Jamal Hadi Salim
0 siblings, 0 replies; 12+ messages in thread
From: Jamal Hadi Salim @ 2026-09-01 21:36 UTC (permalink / raw)
To: Jakub Kicinski
Cc: netdev, Jiri Pirko, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Victor Nogueira, vega, stable, toke, chia-yu.chang,
subramanian.vijay, petrm
On Sun, Aug 30, 2026 at 2:59 PM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
>
> On Sun, Aug 30, 2026 at 2:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
> >
> > On Sat, 29 Aug 2026 04:12:29 -0400 Jamal Hadi Salim wrote:
> > > ets_qdisc_change() falls back to psched_mtu() with no floor for bands
> > > without an explicit quantum. With a crafted size table qdisc_pkt_len
> > > reaches ~2 GiB, so a zero psched_mtu on a headerless device makes the
> > > deficit-refill loop spin under the qdisc lock.
> > >
> > > Move the floor into ets_quantum_parse() so explicitly configured quanta
> > > are also clamped to [256, 1<<20], not just the fallback path.
> > >
> > > Conditions to recreate the bug:
> > > CONFIG_NET_SCH_ETS=y. Requires CAP_NET_ADMIN (namespace-local via
> > > unshare -Urn suffices).
> > >
> > > tc qdisc add dev dummy0 root ets bands 3 strict 2 quanta 1 1
> > >
> > > Fixes: dcc68b4d8084 ("net: sch_ets: Add a new Qdisc")
> > > Reported-by: vega@nebusec.ai
> > > Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
> > > Tested-by: Victor Nogueira <victor@mojatatu.com>
> > > Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
> > > Cc: stable@vger.kernel.org
> > > ---
> > > net/sched/sch_ets.c | 12 +++++-------
> > > 1 file changed, 5 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
> > > index 25fcf4079fec..6cc902a03838 100644
> > > --- a/net/sched/sch_ets.c
> > > +++ b/net/sched/sch_ets.c
> > > @@ -83,11 +83,7 @@ static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
> > > unsigned int *quantum,
> > > struct netlink_ext_ack *extack)
> > > {
> > > - *quantum = nla_get_u32(attr);
> > > - if (!*quantum) {
> > > - NL_SET_ERR_MSG(extack, "ETS quantum cannot be zero");
> > > - return -EINVAL;
> > > - }
> > > + *quantum = clamp_t(u32, nla_get_u32(attr), 256, 1 << 20);
> > > return 0;
> > > }
> > >
> > > @@ -632,11 +628,13 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
> > > return err;
> > > }
> > > /* If there are more bands than strict + quanta provided, the remaining
> > > - * ones are ETS with quantum of MTU. Initialize the missing values here.
> > > + * ones are ETS with quantum of max(MTU, 256). Initialize the missing
> > > + * values here.
> > > */
> > > for (i = nstrict; i < nbands; i++) {
> > > if (!quanta[i])
> > > - quanta[i] = psched_mtu(qdisc_dev(sch));
> > > + quanta[i] = clamp_t(u32, (u32)psched_mtu(qdisc_dev(sch)),
> > > + 256, 1 << 20);
> > > }
> > >
> > > /* Before commit, make sure we can allocate all new qdiscs */
> >
> > Does this run afoul of one of the tdc cases?
> >
> > # not ok 39 41f5 - ETS offload where the sum of quanta wraps u32
> > # Could not match regex pattern. Verify command output:
> > # qdisc ets 8004: root refcnt 5 offloaded bands 3 quanta 1048576 256 256 priomap 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
> >
> > https://github.com/p4tc-dev/tc-executor/blob/storage-dbg/artifacts/799938/1-tdc-sh/stdout
>
> Yikes. I will resend with this fixed.
I was waiting for nipa sashiko to say something but nothing happened.
Gemini nipa had nothing meaningful to say - So i will send v3 with
just the tdc test fixed.
cheers,
jamal
> cheers.
> jamal
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-01 21:36 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <all>
2026-08-29 8:12 ` [PATCH net v2 0/8] net/sched: clamp quantum/psched_mtu in change paths Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 1/8] net/sched: fq: clamp quantum and initial_quantum in change path Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 2/8] net/sched: fq_pie: clamp quantum " Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 3/8] net/sched: sfq: " Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 4/8] net/sched: hhf: clamp quantum in change and init paths Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 5/8] net/sched: dualpi2: clamp psched_mtu at all call sites Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 6/8] net/sched: pie: clamp psched_mtu in pie_drop_early Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 7/8] net/sched: drr: clamp quantum in change class Jamal Hadi Salim
2026-08-29 8:12 ` [PATCH net v2 8/8] net/sched: ets: clamp quantum in parse and fallback paths Jamal Hadi Salim
2026-08-30 18:03 ` Jakub Kicinski
2026-08-30 18:59 ` Jamal Hadi Salim
2026-09-01 21:36 ` Jamal Hadi Salim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox