taprio: Fix allowing too small intervals

It's possible that the user specifies an interval that couldn't allow
any packet to be transmitted. This also avoids the issue of the
hrtimer handler starving the other threads because it's running too
often.

The solution is to reject interval sizes that according to the current
link speed wouldn't allow any packet to be transmitted.

Reported-by: syzbot+8267241609ae8c23b248@syzkaller.appspotmail.com
Fixes: 5a781ccbd1 ("tc: Add support for configuring the taprio scheduler")
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vinicius Costa Gomes 2020-09-09 17:03:11 -07:00 committed by David S. Miller
parent 53467ecb6f
commit b5b73b26b3

View File

@ -777,9 +777,11 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = {
[TCA_TAPRIO_ATTR_TXTIME_DELAY] = { .type = NLA_U32 }, [TCA_TAPRIO_ATTR_TXTIME_DELAY] = { .type = NLA_U32 },
}; };
static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry, static int fill_sched_entry(struct taprio_sched *q, struct nlattr **tb,
struct sched_entry *entry,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
int min_duration = length_to_duration(q, ETH_ZLEN);
u32 interval = 0; u32 interval = 0;
if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD]) if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
@ -794,7 +796,10 @@ static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
interval = nla_get_u32( interval = nla_get_u32(
tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]); tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
if (interval == 0) { /* The interval should allow at least the minimum ethernet
* frame to go out.
*/
if (interval < min_duration) {
NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry"); NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry");
return -EINVAL; return -EINVAL;
} }
@ -804,8 +809,9 @@ static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
return 0; return 0;
} }
static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry, static int parse_sched_entry(struct taprio_sched *q, struct nlattr *n,
int index, struct netlink_ext_ack *extack) struct sched_entry *entry, int index,
struct netlink_ext_ack *extack)
{ {
struct nlattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { }; struct nlattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { };
int err; int err;
@ -819,10 +825,10 @@ static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry,
entry->index = index; entry->index = index;
return fill_sched_entry(tb, entry, extack); return fill_sched_entry(q, tb, entry, extack);
} }
static int parse_sched_list(struct nlattr *list, static int parse_sched_list(struct taprio_sched *q, struct nlattr *list,
struct sched_gate_list *sched, struct sched_gate_list *sched,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
@ -847,7 +853,7 @@ static int parse_sched_list(struct nlattr *list,
return -ENOMEM; return -ENOMEM;
} }
err = parse_sched_entry(n, entry, i, extack); err = parse_sched_entry(q, n, entry, i, extack);
if (err < 0) { if (err < 0) {
kfree(entry); kfree(entry);
return err; return err;
@ -862,7 +868,7 @@ static int parse_sched_list(struct nlattr *list,
return i; return i;
} }
static int parse_taprio_schedule(struct nlattr **tb, static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb,
struct sched_gate_list *new, struct sched_gate_list *new,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
@ -883,8 +889,8 @@ static int parse_taprio_schedule(struct nlattr **tb,
new->cycle_time = nla_get_s64(tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]); new->cycle_time = nla_get_s64(tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]);
if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]) if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST])
err = parse_sched_list( err = parse_sched_list(q, tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST],
tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], new, extack); new, extack);
if (err < 0) if (err < 0)
return err; return err;
@ -1473,7 +1479,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
goto free_sched; goto free_sched;
} }
err = parse_taprio_schedule(tb, new_admin, extack); err = parse_taprio_schedule(q, tb, new_admin, extack);
if (err < 0) if (err < 0)
goto free_sched; goto free_sched;