net_sched: sch_sfq: reject invalid perturb period
authorEric Dumazet <edumazet@google.com>
Wed, 11 Jun 2025 08:35:01 +0000 (08:35 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 12 Jun 2025 15:03:08 +0000 (08:03 -0700)
Gerrard Tai reported that SFQ perturb_period has no range check yet,
and this can be used to trigger a race condition fixed in a separate patch.

We want to make sure ctl->perturb_period * HZ will not overflow
and is positive.

Tested:

tc qd add dev lo root sfq perturb -10   # negative value : error
Error: sch_sfq: invalid perturb period.

tc qd add dev lo root sfq perturb 1000000000 # too big : error
Error: sch_sfq: invalid perturb period.

tc qd add dev lo root sfq perturb 2000000 # acceptable value
tc -s -d qd sh dev lo
qdisc sfq 8005: root refcnt 2 limit 127p quantum 64Kb depth 127 flows 128 divisor 1024 perturb 2000000sec
 Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
 backlog 0b 0p requeues 0

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Gerrard Tai <gerrard.tai@starlabs.sg>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20250611083501.1810459-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/sched/sch_sfq.c

index 77fa02f2bfcd56a36815199aa2e7987943ea226f..a8cca549b5a2eb2407949560c2b6b658fb7a581f 100644 (file)
@@ -656,6 +656,14 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
                NL_SET_ERR_MSG_MOD(extack, "invalid quantum");
                return -EINVAL;
        }
+
+       if (ctl->perturb_period < 0 ||
+           ctl->perturb_period > INT_MAX / HZ) {
+               NL_SET_ERR_MSG_MOD(extack, "invalid perturb period");
+               return -EINVAL;
+       }
+       perturb_period = ctl->perturb_period * HZ;
+
        if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max,
                                        ctl_v1->Wlog, ctl_v1->Scell_log, NULL))
                return -EINVAL;
@@ -672,14 +680,12 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
        headdrop = q->headdrop;
        maxdepth = q->maxdepth;
        maxflows = q->maxflows;
-       perturb_period = q->perturb_period;
        quantum = q->quantum;
        flags = q->flags;
 
        /* update and validate configuration */
        if (ctl->quantum)
                quantum = ctl->quantum;
-       perturb_period = ctl->perturb_period * HZ;
        if (ctl->flows)
                maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
        if (ctl->divisor) {