From c67732d067860850b767c81736b49f88a946bffb Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Tue, 23 Sep 2025 15:37:08 +0900 Subject: [PATCH 1/4] can: annotate mtu accesses with READ_ONCE() As hinted in commit 501a90c94510 ("inet: protect against too small mtu values."), net_device->mtu is vulnerable to race conditions if it is written and read without holding the RTNL. At the moment, all the writes are done while the interface is down, either in the devices' probe() function or in can_changelink(). So there are no such issues yet. But upcoming changes will allow to modify the MTU while the CAN XL devices are up. In preparation to the introduction of CAN XL, annotate all the net_device->mtu accesses which are not yet guarded by the RTNL with a READ_ONCE(). Note that all the write accesses are already either guarded by the RTNL or are already annotated and thus need no changes. Signed-off-by: Vincent Mailhol Link: https://patch.msgid.link/20250923-can-fix-mtu-v3-1-581bde113f52@kernel.org Signed-off-by: Marc Kleine-Budde --- net/can/af_can.c | 2 +- net/can/isotp.c | 2 +- net/can/raw.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/can/af_can.c b/net/can/af_can.c index b2387a46794a..770173d8db42 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -221,7 +221,7 @@ int can_send(struct sk_buff *skb, int loop) } /* Make sure the CAN frame can pass the selected CAN netdevice. */ - if (unlikely(skb->len > skb->dev->mtu)) { + if (unlikely(skb->len > READ_ONCE(skb->dev->mtu))) { err = -EMSGSIZE; goto inval_skb; } diff --git a/net/can/isotp.c b/net/can/isotp.c index dee1412b3c9c..74ee1e52249b 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1313,7 +1313,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) err = -ENODEV; goto out; } - if (dev->mtu < so->ll.mtu) { + if (READ_ONCE(dev->mtu) < so->ll.mtu) { dev_put(dev); err = -EINVAL; goto out; diff --git a/net/can/raw.c b/net/can/raw.c index bf65d67b5df0..a53853f5e9af 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -961,7 +961,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) err = -EINVAL; /* check for valid CAN (CC/FD/XL) frame content */ - txmtu = raw_check_txframe(ro, skb, dev->mtu); + txmtu = raw_check_txframe(ro, skb, READ_ONCE(dev->mtu)); if (!txmtu) goto free_skb; From 7c7da8aa3fd69b77e8efaa14b80bddd948547739 Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Tue, 23 Sep 2025 15:37:09 +0900 Subject: [PATCH 2/4] can: dev: turn can_set_static_ctrlmode() into a non-inline function can_set_static_ctrlmode() is declared as a static inline. But it is only called in the probe function of the devices and so does not really benefit from any kind of optimization. Transform it into a "normal" function by moving it to drivers/net/can/dev/dev.c Signed-off-by: Vincent Mailhol Link: https://patch.msgid.link/20250923-can-fix-mtu-v3-2-581bde113f52@kernel.org Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/dev.c | 21 +++++++++++++++++++++ include/linux/can/dev.h | 23 ++--------------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 99b78cbb2252..02bfed37cc93 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -347,6 +347,27 @@ int can_change_mtu(struct net_device *dev, int new_mtu) } EXPORT_SYMBOL_GPL(can_change_mtu); +/* helper to define static CAN controller features at device creation time */ +int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode) +{ + struct can_priv *priv = netdev_priv(dev); + + /* alloc_candev() succeeded => netdev_priv() is valid at this point */ + if (priv->ctrlmode_supported & static_mode) { + netdev_warn(dev, + "Controller features can not be supported and static at the same time\n"); + return -EINVAL; + } + priv->ctrlmode = static_mode; + + /* override MTU which was set by default in can_setup()? */ + if (static_mode & CAN_CTRLMODE_FD) + dev->mtu = CANFD_MTU; + + return 0; +} +EXPORT_SYMBOL_GPL(can_set_static_ctrlmode); + /* generic implementation of netdev_ops::ndo_eth_ioctl for CAN devices * supporting hardware timestamps */ diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 9a92cbe5b2cb..5dc58360c2d7 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -125,27 +125,6 @@ static inline s32 can_get_relative_tdco(const struct can_priv *priv) return (s32)priv->fd.tdc.tdco - sample_point_in_tc; } -/* helper to define static CAN controller features at device creation time */ -static inline int __must_check can_set_static_ctrlmode(struct net_device *dev, - u32 static_mode) -{ - struct can_priv *priv = netdev_priv(dev); - - /* alloc_candev() succeeded => netdev_priv() is valid at this point */ - if (priv->ctrlmode_supported & static_mode) { - netdev_warn(dev, - "Controller features can not be supported and static at the same time\n"); - return -EINVAL; - } - priv->ctrlmode = static_mode; - - /* override MTU which was set by default in can_setup()? */ - if (static_mode & CAN_CTRLMODE_FD) - dev->mtu = CANFD_MTU; - - return 0; -} - static inline u32 can_get_static_ctrlmode(struct can_priv *priv) { return priv->ctrlmode & ~priv->ctrlmode_supported; @@ -188,6 +167,8 @@ struct can_priv *safe_candev_priv(struct net_device *dev); int open_candev(struct net_device *dev); void close_candev(struct net_device *dev); int can_change_mtu(struct net_device *dev, int new_mtu); +int __must_check can_set_static_ctrlmode(struct net_device *dev, + u32 static_mode); int can_eth_ioctl_hwts(struct net_device *netdev, struct ifreq *ifr, int cmd); int can_ethtool_op_get_ts_info_hwts(struct net_device *dev, struct kernel_ethtool_ts_info *info); From 23049938605bda390f875ce20e0704252c2e5c3d Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Tue, 23 Sep 2025 15:37:10 +0900 Subject: [PATCH 3/4] can: populate the minimum and maximum MTU values By populating: net_device->min_mtu and net_device->max_mtu the net core infrastructure will automatically: 1. validate that the user's inputs are in range. 2. report those min and max MTU values through the netlink interface. Add can_set_default_mtu() which sets the default mtu value as well as the minimum and maximum values. The logic for the default mtu value remains unchanged: - CANFD_MTU if the device has a static CAN_CTRLMODE_FD. - CAN_MTU otherwise. Call can_set_default_mtu() each time the CAN_CTRLMODE_FD is modified. This will guarantee that the MTU value is always consistent with the control mode flags. With this, the checks done in can_change_mtu() become fully redundant and will be removed in an upcoming change and it is now possible to confirm the minimum and maximum MTU values on a physical CAN interface by doing: $ ip --details link show can0 The virtual interfaces (vcan and vxcan) are not impacted by this change. Signed-off-by: Vincent Mailhol Link: https://patch.msgid.link/20250923-can-fix-mtu-v3-3-581bde113f52@kernel.org [mkl: squashed https://patch.msgid.link/20250924143644.17622-2-mailhol@kernel.org] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/dev.c | 20 ++++++++++++++++++-- drivers/net/can/dev/netlink.c | 9 ++++----- include/linux/can/dev.h | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 02bfed37cc93..befdeb4c54c2 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -240,6 +240,8 @@ void can_setup(struct net_device *dev) { dev->type = ARPHRD_CAN; dev->mtu = CAN_MTU; + dev->min_mtu = CAN_MTU; + dev->max_mtu = CAN_MTU; dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 10; @@ -309,6 +311,21 @@ void free_candev(struct net_device *dev) } EXPORT_SYMBOL_GPL(free_candev); +void can_set_default_mtu(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (priv->ctrlmode & CAN_CTRLMODE_FD) { + dev->mtu = CANFD_MTU; + dev->min_mtu = CANFD_MTU; + dev->max_mtu = CANFD_MTU; + } else { + dev->mtu = CAN_MTU; + dev->min_mtu = CAN_MTU; + dev->max_mtu = CAN_MTU; + } +} + /* changing MTU and control mode for CAN/CANFD devices */ int can_change_mtu(struct net_device *dev, int new_mtu) { @@ -361,8 +378,7 @@ int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode) priv->ctrlmode = static_mode; /* override MTU which was set by default in can_setup()? */ - if (static_mode & CAN_CTRLMODE_FD) - dev->mtu = CANFD_MTU; + can_set_default_mtu(dev); return 0; } diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index d9f6ab3efb97..248f607e3864 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -223,17 +223,16 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= maskedflags; - /* CAN_CTRLMODE_FD can only be set when driver supports FD */ - if (priv->ctrlmode & CAN_CTRLMODE_FD) { - dev->mtu = CANFD_MTU; - } else { - dev->mtu = CAN_MTU; + /* Wipe potential leftovers from previous CAN FD config */ + if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { memset(&priv->fd.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); } + can_set_default_mtu(dev); + fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK; /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually * exclusive: make sure to turn the other one off diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 5dc58360c2d7..3354f70ed2c6 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -166,6 +166,7 @@ struct can_priv *safe_candev_priv(struct net_device *dev); int open_candev(struct net_device *dev); void close_candev(struct net_device *dev); +void can_set_default_mtu(struct net_device *dev); int can_change_mtu(struct net_device *dev, int new_mtu); int __must_check can_set_static_ctrlmode(struct net_device *dev, u32 static_mode); From b98aceb65e2c57df9646530e5f2b2531a661203f Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Tue, 23 Sep 2025 15:37:11 +0900 Subject: [PATCH 4/4] can: enable CAN XL for virtual CAN devices by default In commit 97edec3a11cf ("can: enable CAN FD for virtual CAN devices by default"), vcan and vxcan default MTU was set to CANFD_MTU by default. The reason was that users were confused on how to activate CAN FD on virtual interfaces. Following the introduction of CAN XL, the same logic should be applied. Set the MTU to CANXL_MTU by default. The users who really wish to use a Classical CAN only or a CAN FD virtual device can do respectively: $ ip link set vcan0 mtu 16 or $ ip link set vcan0 mtu 72 to force the old behaviour. Signed-off-by: Vincent Mailhol Link: https://patch.msgid.link/20250923-can-fix-mtu-v3-4-581bde113f52@kernel.org Signed-off-by: Marc Kleine-Budde --- drivers/net/can/vcan.c | 2 +- drivers/net/can/vxcan.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index f67e85807100..fdc662aea279 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -156,7 +156,7 @@ static const struct ethtool_ops vcan_ethtool_ops = { static void vcan_setup(struct net_device *dev) { dev->type = ARPHRD_CAN; - dev->mtu = CANFD_MTU; + dev->mtu = CANXL_MTU; dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 0; diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 99a78a757167..b2c19f8c5f8e 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -156,7 +156,7 @@ static void vxcan_setup(struct net_device *dev) struct can_ml_priv *can_ml; dev->type = ARPHRD_CAN; - dev->mtu = CANFD_MTU; + dev->mtu = CANXL_MTU; dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 0;