mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 17:10:13 +00:00
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: fb66df20a720 ("net/sched: taprio: extend minimum interval restriction to entire cycle too")
Reported-by: syzbot+398e1ee4ca2cac05fddb@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=398e1ee4ca2cac05fddb
Signed-off-by: Takamitsu Iwai <takamitz@amazon.co.jp>
Link: https://patch.msgid.link/20250728173149.45585-1-takamitz@amazon.co.jp
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d46e51f1c7
commit
ae8508b25d
@ -43,6 +43,11 @@ static struct static_key_false taprio_have_working_mqprio;
|
||||
#define TAPRIO_SUPPORTED_FLAGS \
|
||||
(TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST | TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD)
|
||||
#define TAPRIO_FLAGS_INVALID U32_MAX
|
||||
/* Minimum value for picos_per_byte to ensure non-zero duration
|
||||
* for minimum-sized Ethernet frames (ETH_ZLEN = 60).
|
||||
* 60 * 17 > PSEC_PER_NSEC (1000)
|
||||
*/
|
||||
#define TAPRIO_PICOS_PER_BYTE_MIN 17
|
||||
|
||||
struct sched_entry {
|
||||
/* Durations between this GCL entry and the GCL entry where the
|
||||
@ -1284,7 +1289,8 @@ static void taprio_start_sched(struct Qdisc *sch,
|
||||
}
|
||||
|
||||
static void taprio_set_picos_per_byte(struct net_device *dev,
|
||||
struct taprio_sched *q)
|
||||
struct taprio_sched *q,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ethtool_link_ksettings ecmd;
|
||||
int speed = SPEED_10;
|
||||
@ -1300,6 +1306,15 @@ static void taprio_set_picos_per_byte(struct net_device *dev,
|
||||
|
||||
skip:
|
||||
picos_per_byte = (USEC_PER_SEC * 8) / speed;
|
||||
if (picos_per_byte < TAPRIO_PICOS_PER_BYTE_MIN) {
|
||||
if (!extack)
|
||||
pr_warn("Link speed %d is too high. Schedule may be inaccurate.\n",
|
||||
speed);
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack,
|
||||
"Link speed %d is too high. Schedule may be inaccurate.",
|
||||
speed);
|
||||
picos_per_byte = TAPRIO_PICOS_PER_BYTE_MIN;
|
||||
}
|
||||
|
||||
atomic64_set(&q->picos_per_byte, picos_per_byte);
|
||||
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,
|
||||
if (dev != qdisc_dev(q->root))
|
||||
continue;
|
||||
|
||||
taprio_set_picos_per_byte(dev, q);
|
||||
taprio_set_picos_per_byte(dev, q, NULL);
|
||||
|
||||
stab = rtnl_dereference(q->root->stab);
|
||||
|
||||
@ -1844,7 +1859,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
|
||||
q->flags = taprio_flags;
|
||||
|
||||
/* Needed for length_to_duration() during netlink attribute parsing */
|
||||
taprio_set_picos_per_byte(dev, q);
|
||||
taprio_set_picos_per_byte(dev, q, extack);
|
||||
|
||||
err = taprio_parse_mqprio_opt(dev, mqprio, extack, q->flags);
|
||||
if (err < 0)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user