Skip to content

Commit ae8508b

Browse files
Takamitsu Iwaikuba-moo
authored andcommitted
net/sched: taprio: enforce minimum value for picos_per_byte
Syzbot reported a WARNING in taprio_get_start_time(). When link speed is 470,589 or greater, q->picos_per_byte becomes too small, causing length_to_duration(q, ETH_ZLEN) to return zero. This zero value leads to validation failures in fill_sched_entry() and parse_taprio_schedule(), allowing arbitrary values to be assigned to entry->interval and cycle_time. As a result, sched->cycle can become zero. Since SPEED_800000 is the largest defined speed in include/uapi/linux/ethtool.h, this issue can occur in realistic scenarios. To ensure length_to_duration() returns a non-zero value for minimum-sized Ethernet frames (ETH_ZLEN = 60), picos_per_byte must be at least 17 (60 * 17 > PSEC_PER_NSEC which is 1000). This patch enforces a minimum value of 17 for picos_per_byte when the calculated value would be lower, and adds a warning message to inform users that scheduling accuracy may be affected at very high link speeds. Fixes: fb66df2 ("net/sched: taprio: extend minimum interval restriction to entire cycle too") Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=398e1ee4ca2cac05fddb Signed-off-by: Takamitsu Iwai <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d46e51f commit ae8508b

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

net/sched/sch_taprio.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ static struct static_key_false taprio_have_working_mqprio;
4343
#define TAPRIO_SUPPORTED_FLAGS \
4444
(TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST | TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD)
4545
#define TAPRIO_FLAGS_INVALID U32_MAX
46+
/* Minimum value for picos_per_byte to ensure non-zero duration
47+
* for minimum-sized Ethernet frames (ETH_ZLEN = 60).
48+
* 60 * 17 > PSEC_PER_NSEC (1000)
49+
*/
50+
#define TAPRIO_PICOS_PER_BYTE_MIN 17
4651

4752
struct sched_entry {
4853
/* Durations between this GCL entry and the GCL entry where the
@@ -1284,7 +1289,8 @@ static void taprio_start_sched(struct Qdisc *sch,
12841289
}
12851290

12861291
static void taprio_set_picos_per_byte(struct net_device *dev,
1287-
struct taprio_sched *q)
1292+
struct taprio_sched *q,
1293+
struct netlink_ext_ack *extack)
12881294
{
12891295
struct ethtool_link_ksettings ecmd;
12901296
int speed = SPEED_10;
@@ -1300,6 +1306,15 @@ static void taprio_set_picos_per_byte(struct net_device *dev,
13001306

13011307
skip:
13021308
picos_per_byte = (USEC_PER_SEC * 8) / speed;
1309+
if (picos_per_byte < TAPRIO_PICOS_PER_BYTE_MIN) {
1310+
if (!extack)
1311+
pr_warn("Link speed %d is too high. Schedule may be inaccurate.\n",
1312+
speed);
1313+
NL_SET_ERR_MSG_FMT_MOD(extack,
1314+
"Link speed %d is too high. Schedule may be inaccurate.",
1315+
speed);
1316+
picos_per_byte = TAPRIO_PICOS_PER_BYTE_MIN;
1317+
}
13031318

13041319
atomic64_set(&q->picos_per_byte, picos_per_byte);
13051320
netdev_dbg(dev, "taprio: set %s's picos_per_byte to: %lld, linkspeed: %d\n",
@@ -1324,7 +1339,7 @@ static int taprio_dev_notifier(struct notifier_block *nb, unsigned long event,
13241339
if (dev != qdisc_dev(q->root))
13251340
continue;
13261341

1327-
taprio_set_picos_per_byte(dev, q);
1342+
taprio_set_picos_per_byte(dev, q, NULL);
13281343

13291344
stab = rtnl_dereference(q->root->stab);
13301345

@@ -1844,7 +1859,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
18441859
q->flags = taprio_flags;
18451860

18461861
/* Needed for length_to_duration() during netlink attribute parsing */
1847-
taprio_set_picos_per_byte(dev, q);
1862+
taprio_set_picos_per_byte(dev, q, extack);
18481863

18491864
err = taprio_parse_mqprio_opt(dev, mqprio, extack, q->flags);
18501865
if (err < 0)

0 commit comments

Comments
 (0)