From: Oliver Hartkopp With commit 890e5198a6e5 ("can: raw: use bitfields to store flags in struct raw_sock") the formerly separate integer values have been integrated into a single bitfield. This led to a read-modify-write operation when changing a flag in raw_setsockopt() which now needs a locking to prevent concurrent access. Instead of adding a lock/unlock hell in each of the flag manipulations this patch introduces a wrapper for a new raw_setsockopt_locked() function analogue to the isotp_setsockopt[_locked]() approach in net/can/isotp.c Fixes: 890e5198a6e5 ("can: raw: use bitfields to store flags in struct raw_sock") Reported-by: Eulgyu Kim Closes: https://lore.kernel.org/linux-can/20260503112200.22727-1-eulgyukim@snu.ac.kr/ Tested-by: Eulgyu Kim Signed-off-by: Oliver Hartkopp Reviewed-by: Vincent Mailhol Tested-by: Vincent Mailhol Link: https://patch.msgid.link/20260504111928.41856-1-socketcan@hartkopp.net [mkl: use Closes tag instead of Link] Signed-off-by: Marc Kleine-Budde --- net/can/raw.c | 66 +++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/net/can/raw.c b/net/can/raw.c index a26942e78e68..82d9c0499c95 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -562,8 +562,8 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr, return RAW_MIN_NAMELEN; } -static int raw_setsockopt(struct socket *sock, int level, int optname, - sockptr_t optval, unsigned int optlen) +static int raw_setsockopt_locked(struct socket *sock, int optname, + sockptr_t optval, unsigned int optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); @@ -575,9 +575,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, int flag; int err = 0; - if (level != SOL_CAN_RAW) - return -EINVAL; - switch (optname) { case CAN_RAW_FILTER: if (optlen % sizeof(struct can_filter) != 0) @@ -598,17 +595,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, return -EFAULT; } - rtnl_lock(); - lock_sock(sk); - dev = ro->dev; - if (ro->bound && dev) { - if (dev->reg_state != NETREG_REGISTERED) { - if (count > 1) - kfree(filter); - err = -ENODEV; - goto out_fil; - } + if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED) { + if (count > 1) + kfree(filter); + return -ENODEV; } if (ro->bound) { @@ -622,7 +613,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, if (err) { if (count > 1) kfree(filter); - goto out_fil; + return err; } /* remove old filter registrations */ @@ -642,11 +633,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, } ro->filter = filter; ro->count = count; - - out_fil: - release_sock(sk); - rtnl_unlock(); - break; case CAN_RAW_ERR_FILTER: @@ -658,16 +644,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, err_mask &= CAN_ERR_MASK; - rtnl_lock(); - lock_sock(sk); - dev = ro->dev; - if (ro->bound && dev) { - if (dev->reg_state != NETREG_REGISTERED) { - err = -ENODEV; - goto out_err; - } - } + if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED) + return -ENODEV; /* remove current error mask */ if (ro->bound) { @@ -676,7 +655,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, err_mask); if (err) - goto out_err; + return err; /* remove old err_mask registration */ raw_disable_errfilter(sock_net(sk), dev, sk, @@ -685,11 +664,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, /* link new err_mask to the socket */ ro->err_mask = err_mask; - - out_err: - release_sock(sk); - rtnl_unlock(); - break; case CAN_RAW_LOOPBACK: @@ -769,6 +743,26 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, return err; } +static int raw_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) +{ + struct sock *sk = sock->sk; + int err; + + if (level != SOL_CAN_RAW) + return -EINVAL; + + rtnl_lock(); + lock_sock(sk); + + err = raw_setsockopt_locked(sock, optname, optval, optlen); + + release_sock(sk); + rtnl_unlock(); + + return err; +} + static int raw_getsockopt(struct socket *sock, int level, int optname, sockopt_t *opt) { base-commit: b266bacba796ff5c4dcd2ae2fc08aacf7ab39153 -- 2.53.0 From: Lee Jones Commit f1b4e32aca08 ("can: bcm: use call_rcu() instead of costly synchronize_rcu()") removed the synchronize_rcu() call from bcm_delete_rx_op() and introduced the RX_NO_AUTOTIMER flag to prevent timers from being rearmed during deletion. However, it only applied this check to op->timer via bcm_rx_starttimer(). It missed the fact that op->thrtimer can also be rearmed by an in-flight bcm_rx_handler() (which runs as an RCU reader) via bcm_rx_update_and_send(). This allows op->thrtimer to be queued after bcm_remove_op() has already cancelled it, leading to a use-after-free when the timer fires on the deferred-freed struct bcm_op. Address the omission by checking the RX_NO_AUTOTIMER flag in bcm_rx_update_and_send() before starting op->thrtimer, effectively preventing it from being rearmed concurrently with teardown. Signed-off-by: Lee Jones Acked-by: Oliver Hartkopp Fixes: f1b4e32aca08 ("can: bcm: use call_rcu() instead of costly synchronize_rcu()") Link: https://patch.msgid.link/20260422102239.948594-1-lee@kernel.org Signed-off-by: Marc Kleine-Budde --- net/can/bcm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/can/bcm.c b/net/can/bcm.c index a4bef2c48a55..67e5b3149a8f 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -539,6 +539,12 @@ static void bcm_rx_update_and_send(struct bcm_op *op, if (hrtimer_active(&op->thrtimer)) return; + /* bcm_remove_op() may have cancelled thrtimer concurrently with this + * RCU-protected handler; do not rearm it. Mirrors bcm_rx_starttimer(). + */ + if (op->flags & RX_NO_AUTOTIMER) + return; + /* first reception with enabled throttling mode */ if (!op->kt_lastmsg) goto rx_changed_settime; -- 2.53.0 From: Alexander Hölzl In J1939 segmented transport, a CTS message with data byte 2 set to zero is interpreted as a hold message. This instructs the transmitter of the segmented message to hold the connection open but to delay sending. According to the J1939-21 standard, section 5.10.2.4 the timeout T4 after which an held open session is invalidated is 1050 ms, not 550 as implemented currently. The 550 ms are problematic if a device uses hold messages and assumes it can wait for more than 550 ms before it has to resend the hold message. Fix the RX timeout by changing the T4 timeout from 550 ms to 1050. Signed-off-by: Alexander Hölzl Acked-by: Oleksij Rempel Link: https://patch.msgid.link/20260421153152.87772-3-alexander.hoelzl@gmx.net [mkl: rewrap long lines in patch description, use imperative mood in last section] Signed-off-by: Marc Kleine-Budde --- net/can/j1939/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index df93d57907da..7ad56b5f17b9 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -1479,7 +1479,7 @@ j1939_xtp_rx_cts_one(struct j1939_session *session, struct sk_buff *skb) } } else { /* CTS(0) */ - j1939_tp_set_rxtimeout(session, 550); + j1939_tp_set_rxtimeout(session, 1050); } return; -- 2.53.0 From: Shuhao Fu j1939_priv.ents[].nusers is documented as protected by priv->lock, and its updates already happen under that lock. j1939_can_recv() also reads it under read_lock_bh(). However, j1939_session_skb_queue() and j1939_tp_send() still read priv->ents[da].nusers without taking the lock. Those transport-side checks decide whether to set J1939_ECU_LOCAL_DST, so they can race with j1939_local_ecu_get() and j1939_local_ecu_put() while userspace is binding or releasing sockets concurrently with TP traffic. This can misclassify TP/ETP sessions as local or remote and take the wrong transport path. Fix both transport paths by routing the destination-locality check through a helper that reads ents[].nusers under read_lock_bh(&priv->lock). Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol") Signed-off-by: Shuhao Fu Tested-by: Oleksij Rempel Acked-by: Oleksij Rempel Link: https://patch.msgid.link/20260419140614.GA4041240@chcpu16 Signed-off-by: Marc Kleine-Budde --- net/can/j1939/transport.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index 7ad56b5f17b9..25d96976d9d0 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -351,6 +351,18 @@ static void j1939_session_skb_drop_old(struct j1939_session *session) } } +static bool j1939_address_is_local(struct j1939_priv *priv, u8 addr) +{ + bool local = false; + + read_lock_bh(&priv->lock); + if (j1939_address_is_unicast(addr) && priv->ents[addr].nusers) + local = true; + read_unlock_bh(&priv->lock); + + return local; +} + void j1939_session_skb_queue(struct j1939_session *session, struct sk_buff *skb) { @@ -359,8 +371,7 @@ void j1939_session_skb_queue(struct j1939_session *session, j1939_ac_fixup(priv, skb); - if (j1939_address_is_unicast(skcb->addr.da) && - priv->ents[skcb->addr.da].nusers) + if (j1939_address_is_local(priv, skcb->addr.da)) skcb->flags |= J1939_ECU_LOCAL_DST; skcb->flags |= J1939_ECU_LOCAL_SRC; @@ -2038,8 +2049,7 @@ struct j1939_session *j1939_tp_send(struct j1939_priv *priv, return ERR_PTR(ret); /* fix DST flags, it may be used there soon */ - if (j1939_address_is_unicast(skcb->addr.da) && - priv->ents[skcb->addr.da].nusers) + if (j1939_address_is_local(priv, skcb->addr.da)) skcb->flags |= J1939_ECU_LOCAL_DST; /* src is always local, I'm sending ... */ -- 2.53.0 From: Stéphane Grosjean Following the sale of PEAK-System France by HMS-Networks, this update is intended to change all my @hms-networks.com email addresses to my new @peak-system.fr address. Signed-off-by: Stéphane Grosjean Link: https://patch.msgid.link/20260410124251.40506-1-stephane.grosjean@free.fr Signed-off-by: Marc Kleine-Budde --- .mailmap | 4 ++-- drivers/net/can/peak_canfd/peak_canfd.c | 2 +- drivers/net/can/peak_canfd/peak_canfd_user.h | 2 +- drivers/net/can/peak_canfd/peak_pciefd_main.c | 4 ++-- drivers/net/can/sja1000/peak_pci.c | 4 ++-- drivers/net/can/sja1000/peak_pcmcia.c | 4 ++-- drivers/net/can/usb/peak_usb/pcan_usb.c | 2 +- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 4 ++-- drivers/net/can/usb/peak_usb/pcan_usb_core.h | 2 +- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 2 +- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 2 +- drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 2 +- include/linux/can/dev/peak_canfd.h | 2 +- 13 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.mailmap b/.mailmap index 34acd34bbf9b..9af8e6979164 100644 --- a/.mailmap +++ b/.mailmap @@ -803,8 +803,8 @@ Sriram Yagnaraman Stanislav Fomichev Stanislav Fomichev Stefan Wahren -Stéphane Grosjean -Stéphane Grosjean +Stéphane Grosjean +Stéphane Grosjean Stéphane Witzmann Stephen Hemminger Stephen Hemminger diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index 06cb2629f66a..4fd1aefb780f 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -2,7 +2,7 @@ /* Copyright (C) 2007, 2011 Wolfgang Grandegger * * Copyright (C) 2016-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #include diff --git a/drivers/net/can/peak_canfd/peak_canfd_user.h b/drivers/net/can/peak_canfd/peak_canfd_user.h index 60c6542028cf..dc0ecb566a85 100644 --- a/drivers/net/can/peak_canfd/peak_canfd_user.h +++ b/drivers/net/can/peak_canfd/peak_canfd_user.h @@ -2,7 +2,7 @@ /* CAN driver for PEAK System micro-CAN based adapters * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #ifndef PEAK_CANFD_USER_H #define PEAK_CANFD_USER_H diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index 93558e33bc02..7c749301ea84 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_pci.c: * * Copyright (C) 2001-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #include @@ -19,7 +19,7 @@ #include "peak_canfd_user.h" -MODULE_AUTHOR("Stéphane Grosjean "); +MODULE_AUTHOR("Stéphane Grosjean "); MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCIe/M.2 FD family cards"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index 4cc4a1581dd1..69c61ccf621d 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -5,7 +5,7 @@ * Derived from the PCAN project file driver/src/pcan_pci.c: * * Copyright (C) 2001-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #include @@ -22,7 +22,7 @@ #include "sja1000.h" -MODULE_AUTHOR("Stéphane Grosjean "); +MODULE_AUTHOR("Stéphane Grosjean "); MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index 42a77d435b39..c3c2aa21da47 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_pccard.c * * Copyright (C) 2006-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #include #include @@ -19,7 +19,7 @@ #include #include "sja1000.h" -MODULE_AUTHOR("Stéphane Grosjean "); +MODULE_AUTHOR("Stéphane Grosjean "); MODULE_DESCRIPTION("CAN driver for PEAK-System PCAN-PC Cards"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 9278a1522aae..8fd058c32856 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_usb.c * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean * * Many thanks to Klaus Hitschler */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index cf48bb26d46d..c7933d1acc99 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_usb_core.c * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean * * Many thanks to Klaus Hitschler */ @@ -24,7 +24,7 @@ #include "pcan_usb_core.h" -MODULE_AUTHOR("Stéphane Grosjean "); +MODULE_AUTHOR("Stéphane Grosjean "); MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index d1c1897d47b9..65999f04f4b7 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_usb_core.c * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean * * Many thanks to Klaus Hitschler */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index eb4f5884ad73..ef9fd693e9bd 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -3,7 +3,7 @@ * CAN driver for PEAK System PCAN-USB FD / PCAN-USB Pro FD adapter * * Copyright (C) 2013-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #include #include diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 4bfa8d0fbb32..aefcded8e12a 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_usbpro.c * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #include #include diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index 162c7546d3a8..d669c9e610c7 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -4,7 +4,7 @@ * Derived from the PCAN project file driver/src/pcan_usbpro_fw.h * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #ifndef PCAN_USB_PRO_H #define PCAN_USB_PRO_H diff --git a/include/linux/can/dev/peak_canfd.h b/include/linux/can/dev/peak_canfd.h index d3788a3d0942..056e0efa649f 100644 --- a/include/linux/can/dev/peak_canfd.h +++ b/include/linux/can/dev/peak_canfd.h @@ -3,7 +3,7 @@ * CAN driver for PEAK System micro-CAN based adapters * * Copyright (C) 2003-2025 PEAK System-Technik GmbH - * Author: Stéphane Grosjean + * Author: Stéphane Grosjean */ #ifndef PUCAN_H #define PUCAN_H -- 2.53.0 From: Ciprian Marian Costea flexcan_chip_interrupts_enable() disables only the primary IRQ line while writing to the IMASK and CTRL registers. On multi-IRQ platforms (S32G2, MCF5441X), the additional IRQ lines (boff, err, secondary-mb) remain active so their handlers can fire while registers are inconsistent. Disable all registered IRQ lines around the IMASK/CTRL writes. This also fixes the resume path, which calls this function. Signed-off-by: Ciprian Marian Costea Link: https://patch.msgid.link/20260326135825.3428856-3-ciprianmarian.costea@oss.nxp.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan/flexcan-core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c index f5d22c61503f..b3bb9acc5a2c 100644 --- a/drivers/net/can/flexcan/flexcan-core.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -1430,14 +1430,28 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev) { const struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->regs; + u32 quirks = priv->devtype_data.quirks; u64 reg_imask; disable_irq(dev->irq); + if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) { + disable_irq(priv->irq_boff); + disable_irq(priv->irq_err); + } + if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) + disable_irq(priv->irq_secondary_mb); + priv->write(priv->reg_ctrl_default, ®s->ctrl); reg_imask = priv->rx_mask | priv->tx_mask; priv->write(upper_32_bits(reg_imask), ®s->imask2); priv->write(lower_32_bits(reg_imask), ®s->imask1); enable_irq(dev->irq); + if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) + enable_irq(priv->irq_secondary_mb); + if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) { + enable_irq(priv->irq_boff); + enable_irq(priv->irq_err); + } } static void flexcan_chip_interrupts_disable(const struct net_device *dev) -- 2.53.0