Commit 01801c35 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Jakub Kicinski
Browse files

net/sched: netem: validate slot configuration



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: 836af83b ("netem: support delivering packets in delayed time slots")
Signed-off-by: default avatarStephen Hemminger <stephen@networkplumber.org>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 986afaf8
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -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;