]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/sched: netem: validate slot configuration
authorStephen Hemminger <stephen@networkplumber.org>
Sat, 18 Apr 2026 03:19:42 +0000 (20:19 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 28 Apr 2026 00:30:28 +0000 (17:30 -0700)
Reject slot configurations that have no defensible meaning:

  - negative min_delay or max_delay
  - min_delay greater than max_delay
  - negative dist_delay or dist_jitter
  - negative max_packets or max_bytes

Negative or out-of-order delays underflow in get_slot_next(),
producing garbage intervals. Negative limits trip the per-slot
accounting (packets_left/bytes_left <= 0) on the first packet of
every slot, defeating the rate-limiting half of the slot feature.

Note that dist_jitter has been silently coerced to its absolute
value by get_slot() since the feature was introduced; rejecting
negatives here converts that silent coercion into -EINVAL. The
abs() can be removed in a follow-up.

Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/sched/sch_netem.c

index 556f9747f0e73101af74196c002687801887eb32..640b51be807aa535d53ff8b2b57f342c227e79d4 100644 (file)
@@ -827,6 +827,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
        return 0;
 }
 
+static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack)
+{
+       const struct tc_netem_slot *c = nla_data(attr);
+
+       if (c->min_delay < 0 || c->max_delay < 0) {
+               NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay");
+               return -EINVAL;
+       }
+       if (c->min_delay > c->max_delay) {
+               NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay");
+               return -EINVAL;
+       }
+       if (c->dist_delay < 0 || c->dist_jitter < 0) {
+               NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay");
+               return -EINVAL;
+       }
+       if (c->max_packets < 0 || c->max_bytes < 0) {
+               NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit");
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static void get_slot(struct netem_sched_data *q, const struct nlattr *attr)
 {
        const struct tc_netem_slot *c = nla_data(attr);
@@ -1040,6 +1063,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
                        goto table_free;
        }
 
+       if (tb[TCA_NETEM_SLOT]) {
+               ret = validate_slot(tb[TCA_NETEM_SLOT], extack);
+               if (ret)
+                       goto table_free;
+       }
+
        sch_tree_lock(sch);
        /* backup q->clg and q->loss_model */
        old_clg = q->clg;