Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 0/12] pull-request: can-next 2026-10-18
@ 2026-10-18 16:41 Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuba, linux-can, kernel

Hello netdev-team,

this is a pull request of 12 patches for net-next/main.

The first patch is by Vincent Mailhol and drops CAN-XL frames on non
CAN-XL devices.

A patch by Sang-Heon Jeon removes a redundant NULL check before
netdev_hold() in the CAN RAW protocol.

Oliver Hartkopp's patch converts the unreliable ARPHRD_CAN type check
to the robust can_get_ml_priv().

A patch by Runyu Xiao for CAN proc resets the pkg_stats using atomics
individually. Oliver Hartkopp also contributes a patch for the CAN
proc to remove kernel pointers from the output.

A patch by Kaixuan Li for the CAN ISOTP protocol improves the check
for the correct CAN CC/FD frames.

Oliver Hartkopp series targets the CAN isotp, bcm and raw protocols
and fixes a use-after-free in the in isotp and bcm and converts the
raw protocol to the same locking scheme.

The next 3 patches are by Cunhao Lu and make CAN skb freeing safe in
any context in several CAN helper functions.

regards,
Marc

---

The following changes since commit 98c2ad4f5d805dbc1ea436a334ee59311806a48c:

  Merge branch 'ipv4-remove-netns-argument-from-fib_table_lookup' (2026-10-16 18:52:36 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git tags/linux-can-next-for-7.4-20261018

for you to fetch changes up to e9244db8f2baa66da454037e093524324ad174ee:

  Merge patch series "can: skb: make echo skb freeing safe in any IRQ context" (2026-10-18 18:32:55 +0200)

----------------------------------------------------------------
linux-can-next-for-7.4-20261018

----------------------------------------------------------------
Cunhao Lu (3):
      can: skb: make echo skb freeing safe in any IRQ context
      can: skb: make CAN skb allocation failure paths IRQ-safe
      can: dev: can_put_echo_skb(): free skb on invalid echo index

Kaixuan Li (1):
      can: isotp: check the frame type, not just the length

Marc Kleine-Budde (2):
      Merge patch series "can: take rtnl_lock() before leaving the notifier list"
      Merge patch series "can: skb: make echo skb freeing safe in any IRQ context"

Oliver Hartkopp (5):
      can: replace ARPHRD_CAN type checks with can_get_ml_priv()
      can: isotp: fix filter removal race between release and netns change
      can: bcm: fix filter removal race between release and netns change
      can: proc: remove pointers from CAN specific proc output
      can: raw: take rtnl_lock() before leaving the notifier list

Runyu Xiao (1):
      can: proc: reset pkg_stats atomics individually

Sang-Heon Jeon (1):
      can: raw: remove redundant NULL check before netdev_hold()

Vincent Mailhol (1):
      can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices

 Documentation/networking/can.rst | 16 ++++++----
 drivers/net/can/dev/skb.c        | 16 +++++-----
 include/linux/can/core.h         |  2 +-
 include/linux/can/dev.h          |  2 +-
 include/linux/can/skb.h          |  4 +--
 net/can/af_can.c                 | 21 ++++++-------
 net/can/af_can.h                 |  2 +-
 net/can/bcm.c                    | 68 +++++++++++++++++++---------------------
 net/can/gw.c                     |  9 +++---
 net/can/isotp.c                  | 34 +++++++++++++-------
 net/can/j1939/main.c             |  2 +-
 net/can/proc.c                   | 65 ++++++++++++++++++++++++++------------
 net/can/raw.c                    | 24 +++++++-------
 13 files changed, 150 insertions(+), 115 deletions(-)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:54   ` netdev-bot+sinfo
  2026-10-18 16:41 ` [PATCH net-next 02/12] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Vincent Mailhol, stable,
	Marc Kleine-Budde

From: Vincent Mailhol <mailhol@kernel.org>

Sending a PF_PACKET bypasses the CAN framework logic and can directly
reach a CAN driver's xmit() function. The PF_PACKET framework only
checks that skb->len does not exceed the net_device MTU.

For a CAN device that is not CAN XL capable, anything above CANFD_MTU
(72 bytes) is therefore dropped before it reaches the driver. However,
CAN XL frames are variable length. can_is_canxl_skb() accepts lengths in
the range CANXL_HDR_SIZE + CANXL_MIN_DLEN up to CANXL_MTU, i.e. 13 to
2060 bytes.

As a result, an ETH_P_CANXL skb with a length between 13 and 72 bytes
can pass both the MTU and the can_dropped_invalid_skb() checks.

A driver that does not support CAN XL will interpret canxl_frame->flags
as a length because of the overlap with can_frame->len. And because
CANXL_XLF is set, the resulting length is between 128 and 255. For
drivers that do not check can_frame->len before copying can_frame->data,
as most drivers do, this results in a buffer overflow of up to 247
bytes.

Drop ETH_P_CANXL skbs if the device does not have the CAN_CAP_XL
capability. Keep can_is_canxl_skb() for the validation of CAN XL skbs.

Closes: https://sashiko.dev/#/patchset/20260731-master-v5-0-5b27029dee20@qq.com?part=1
Fixes: fb08cba12b52 ("can: canxl: update CAN infrastructure for CAN XL frames")
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Link: https://patch.msgid.link/20260731-drop_canxl_frames-v1-1-7387b70353b3@kernel.org
Cc: stable@kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/dev/skb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 14edec5afb57..bc0787535b52 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
  */
 
+#include <linux/can/can-ml.h>
 #include <linux/can/dev.h>
 #include <linux/module.h>
 #include <net/can.h>
@@ -388,7 +389,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
 		break;
 
 	case ETH_P_CANXL:
-		if (!can_is_canxl_skb(skb))
+		if (!can_cap_enabled(dev, CAN_CAP_XL) || !can_is_canxl_skb(skb))
 			goto inval_skb;
 		break;
 

base-commit: 98c2ad4f5d805dbc1ea436a334ee59311806a48c
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 02/12] can: raw: remove redundant NULL check before netdev_hold()
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 03/12] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Sang-Heon Jeon, Oliver Hartkopp,
	Marc Kleine-Budde

From: Sang-Heon Jeon <ekffu200098@gmail.com>

netdev_hold() does nothing if dev is NULL, so the check before the call
is redundant.

So remove it. No functional change.

This is the result of running the Coccinelle script from
scripts/coccinelle/free/ifnulldev_put.cocci after commit f83b8a58695c
("coccinelle: ifnulldev_put: update outdated helper names").

Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260831052031.902699-1-ekffu200098@gmail.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/raw.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/can/raw.c b/net/can/raw.c
index 0acd4f6c6dd6..6944ebab3feb 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -529,8 +529,7 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
 		ro->bound = 1;
 		/* bind() ok -> hold a reference for new ro->dev */
 		ro->dev = dev;
-		if (ro->dev)
-			netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL);
+		netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL);
 	}
 
 out_put_dev:
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 03/12] can: replace ARPHRD_CAN type checks with can_get_ml_priv()
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 02/12] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 04/12] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, stable,
	Oleksij Rempel, Marc Kleine-Budde

From: Oliver Hartkopp <socketcan@hartkopp.net>

Commit 4e096a18867a ("net: introduce CAN specific pointer in the struct
net_device") introduced an explicit way to assign the midlayer private
pointer (dev->ml_priv) to named users like ML_PRIV_CAN. A valid pointer
returned by can_get_ml_priv() therefore identifies a real CAN device.

The referenced commit only converted the j1939 and proc code to this
check, while the other parts of the CAN subsystem still rely on
dev->type == ARPHRD_CAN.

The TUNSETLINK ioctl allows a down TUN/TAP device to set its hardware
type to ARPHRD_CAN while dev->ml_priv remains NULL. Such a repurposed
netdevice passes the ARPHRD_CAN checks in the CAN subsystem, which can
lead to a NULL pointer dereference of the CAN specific ml_priv. This
only requires owning a TUN/TAP device or CAP_NET_ADMIN in an
unprivileged user namespace.

can_rx_register() already rejects such a device since commit 8aa59e355949
("can: af_can: fix NULL pointer dereference in can_rx_register()"),
but can_rx_unregister() only checks dev->type and dereferences the NULL
ml_priv in can_dev_rcv_lists_find().

This path is reachable via isotp: isotp_bind() only checked for
ARPHRD_CAN and ignored the -ENODEV from can_rx_register(), so the socket
was marked as bound to the TUN device. A later isotp_release() or
NETDEV_UNREGISTER notification then crashes in can_rx_unregister().

Replace all remaining ARPHRD_CAN checks in net/can with
can_get_ml_priv(). For can_rx_register() and the can*_rcv() functions
this is a simplification without functional change.

Fixes: 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device")
Cc: stable@kernel.org
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261016093525.327367-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/af_can.c | 15 ++++++---------
 net/can/bcm.c    |  7 ++++---
 net/can/gw.c     |  7 ++++---
 net/can/isotp.c  |  5 +++--
 net/can/raw.c    |  4 ++--
 5 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/net/can/af_can.c b/net/can/af_can.c
index 34fe3b28d576..dc27ace43719 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -226,7 +226,7 @@ int can_send(struct sk_buff *skb, int loop)
 		goto inval_skb;
 	}
 
-	if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+	if (unlikely(!can_get_ml_priv(skb->dev))) {
 		err = -EPERM;
 		goto inval_skb;
 	}
@@ -452,7 +452,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
 
 	/* insert new receiver  (dev,canid,mask) -> (func,data) */
 
-	if (dev && (dev->type != ARPHRD_CAN || !can_get_ml_priv(dev)))
+	if (dev && !can_get_ml_priv(dev))
 		return -ENODEV;
 
 	if (dev && !net_eq(net, dev_net(dev)))
@@ -519,7 +519,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
 	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
 	struct can_dev_rcv_lists *dev_rcv_lists;
 
-	if (dev && dev->type != ARPHRD_CAN)
+	if (dev && !can_get_ml_priv(dev))
 		return;
 
 	if (dev && !net_eq(net, dev_net(dev)))
@@ -684,8 +684,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
 {
 	struct can_skb_ext *csx = can_skb_ext_find(skb);
 
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
-		     !csx || !can_is_can_skb(skb))) {
+	if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_can_skb(skb))) {
 		pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
 			     dev->type, skb->len);
 
@@ -710,8 +709,7 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
 {
 	struct can_skb_ext *csx = can_skb_ext_find(skb);
 
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
-		     !csx || !can_is_canfd_skb(skb))) {
+	if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canfd_skb(skb))) {
 		pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
 			     dev->type, skb->len);
 
@@ -736,8 +734,7 @@ static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
 {
 	struct can_skb_ext *csx = can_skb_ext_find(skb);
 
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
-		     !csx || !can_is_canxl_skb(skb))) {
+	if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canxl_skb(skb))) {
 		pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
 			     dev->type, skb->len);
 
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 3d637a1e0ac1..60406439a13f 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -54,6 +54,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/can.h>
+#include <linux/can/can-ml.h>
 #include <linux/can/core.h>
 #include <linux/can/skb.h>
 #include <linux/can/bcm.h>
@@ -1719,7 +1720,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 				goto out_release;
 			}
 
-			if (dev->type != ARPHRD_CAN) {
+			if (!can_get_ml_priv(dev)) {
 				dev_put(dev);
 				ret = -ENODEV;
 				goto out_release;
@@ -1867,7 +1868,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
 {
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
-	if (dev->type != ARPHRD_CAN)
+	if (!can_get_ml_priv(dev))
 		return NOTIFY_DONE;
 	if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
 		return NOTIFY_DONE;
@@ -2024,7 +2025,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
 			ret = -ENODEV;
 			goto fail;
 		}
-		if (dev->type != ARPHRD_CAN) {
+		if (!can_get_ml_priv(dev)) {
 			dev_put(dev);
 			ret = -ENODEV;
 			goto fail;
diff --git a/net/can/gw.c b/net/can/gw.c
index 5793cb2420ed..54bb5bd3242a 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -52,6 +52,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/can.h>
+#include <linux/can/can-ml.h>
 #include <linux/can/core.h>
 #include <linux/can/skb.h>
 #include <linux/can/gw.h>
@@ -612,7 +613,7 @@ static int cgw_notifier(struct notifier_block *nb,
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 	struct net *net = dev_net(dev);
 
-	if (dev->type != ARPHRD_CAN)
+	if (!can_get_ml_priv(dev))
 		return NOTIFY_DONE;
 
 	if (msg == NETDEV_UNREGISTER) {
@@ -1163,7 +1164,7 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh,
 	if (!gwj->src.dev)
 		goto out;
 
-	if (gwj->src.dev->type != ARPHRD_CAN)
+	if (!can_get_ml_priv(gwj->src.dev))
 		goto out;
 
 	gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
@@ -1171,7 +1172,7 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh,
 	if (!gwj->dst.dev)
 		goto out;
 
-	if (gwj->dst.dev->type != ARPHRD_CAN)
+	if (!can_get_ml_priv(gwj->dst.dev))
 		goto out;
 
 	/* is sending the skb back to the incoming interface intended? */
diff --git a/net/can/isotp.c b/net/can/isotp.c
index f5dc9d04bd68..6c28802c0605 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -65,6 +65,7 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/can.h>
+#include <linux/can/can-ml.h>
 #include <linux/can/core.h>
 #include <linux/can/skb.h>
 #include <linux/can/isotp.h>
@@ -1610,7 +1611,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
 		err = -ENODEV;
 		goto out;
 	}
-	if (dev->type != ARPHRD_CAN) {
+	if (!can_get_ml_priv(dev)) {
 		err = -ENODEV;
 		goto out_put_dev;
 	}
@@ -1897,7 +1898,7 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
 {
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
-	if (dev->type != ARPHRD_CAN)
+	if (!can_get_ml_priv(dev))
 		return NOTIFY_DONE;
 	if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
 		return NOTIFY_DONE;
diff --git a/net/can/raw.c b/net/can/raw.c
index 6944ebab3feb..ad611906b308 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -348,7 +348,7 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg,
 {
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
-	if (dev->type != ARPHRD_CAN)
+	if (!can_get_ml_priv(dev))
 		return NOTIFY_DONE;
 	if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
 		return NOTIFY_DONE;
@@ -491,7 +491,7 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
 			err = -ENODEV;
 			goto out;
 		}
-		if (dev->type != ARPHRD_CAN) {
+		if (!can_get_ml_priv(dev)) {
 			err = -ENODEV;
 			goto out_put_dev;
 		}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 04/12] can: isotp: fix filter removal race between release and netns change
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (2 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 03/12] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 05/12] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, Norbert Szetei,
	stable, Marc Kleine-Budde

From: Oliver Hartkopp <socketcan@hartkopp.net>

isotp_release() removes the socket from isotp_notifier_list before it
takes rtnl_lock(). As the netdev notifier chain runs under RTNL, a
socket that leaves the list in this window is skipped by isotp_notify()
and has to remove its CAN filters itself.

This fails when the bound device is moved to another network namespace
in this window: isotp_release() passes sock_net(sk) to
can_rx_unregister(), which silently returns when this namespace does not
match dev_net(dev) anymore. As can_rx_register() stores rcv->sk without
taking a reference, the remaining receivers point to the freed socket
and travel with the device into the new namespace:

  BUG: KASAN: use-after-free in isotp_rcv+0x1570/0x24d0
  Read of size 1 at addr ffff888118130552 by task isotp_ns_uaf/578
   can_rcv_filter+0x4af/0x8c0
   can_receive+0x28d/0x3c0
   can_rcv+0x2a9/0x310
   __netif_receive_skb_one_core+0x21a/0x260
   process_backlog+0x210/0x760

Take rtnl_lock() before removing the socket from the notifier list, so
that isotp_release() and isotp_notify() can not both skip the removal.

As the notifier chain is always invoked under RTNL (see ASSERT_RTNL() in
call_netdevice_notifiers_info()), isotp_busy_notifier can not point to
the released socket anymore. Replace the now dead busy-wait loop with a
WARN_ON_ONCE(). isotp_notifier_lock is still needed, as isotp_init()
adds new sockets to isotp_notifier_list without holding RTNL.

Additionally use dev_net(so->dev) for the can_rx_unregister() calls, as
the CAN filters live in the device's namespace. With the new locking
both namespaces are equal there, but dev_net(so->dev) is stable under
RTNL and always names the correct namespace.

Fixes: 20bab8b88baa ("can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER")
Reported-by: Norbert Szetei <norbert@doyensec.com>
Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261016091128.325332-2-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/isotp.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/net/can/isotp.c b/net/can/isotp.c
index 5e1c3971ebfc..17ff40a4708d 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -1488,16 +1488,17 @@ static int isotp_release(struct socket *sock)
 	/* forced SHUTDOWN may have skipped IDLE (gave up on a signal) */
 	wake_up_interruptible(&so->wait);
 
+	rtnl_lock();
+
+	/* The netdev notifier chain runs under RTNL, so isotp_notifier() can't
+	 * be walking isotp_notifier_list and point to this socket. The spinlock
+	 * is still needed as isotp_init() adds sockets without holding RTNL.
+	 */
 	spin_lock(&isotp_notifier_lock);
-	while (isotp_busy_notifier == so) {
-		spin_unlock(&isotp_notifier_lock);
-		schedule_timeout_uninterruptible(1);
-		spin_lock(&isotp_notifier_lock);
-	}
+	WARN_ON_ONCE(isotp_busy_notifier == so);
 	list_del(&so->notifier);
 	spin_unlock(&isotp_notifier_lock);
 
-	rtnl_lock();
 	lock_sock(sk);
 
 	/* remove current filters & unregister
@@ -1505,11 +1506,11 @@ static int isotp_release(struct socket *sock)
 	 */
 	if (so->bound && so->dev) {
 		if (isotp_register_rxid(so))
-			can_rx_unregister(net, so->dev, so->rxid,
+			can_rx_unregister(dev_net(so->dev), so->dev, so->rxid,
 					  SINGLE_MASK(so->rxid),
 					  isotp_rcv, sk);
 
-		can_rx_unregister(net, so->dev, so->txid,
+		can_rx_unregister(dev_net(so->dev), so->dev, so->txid,
 				  SINGLE_MASK(so->txid),
 				  isotp_rcv_echo, sk);
 		netdev_put(so->dev, &so->dev_tracker);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 05/12] can: proc: reset pkg_stats atomics individually
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (3 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 04/12] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change Marc Kleine-Budde
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Runyu Xiao, stable,
	Oliver Hartkopp, Marc Kleine-Budde

From: Runyu Xiao <runyu.xiao@seu.edu.cn>

Commit 80b5f90158d1 ("can: statistics: use atomic access in hot path")
converted several members of struct can_pkg_stats to atomic_long_t and
updated the hot TX/RX and procfs read paths to use atomic_long_*()
helpers. However, can_init_stats() still clears the whole struct with
memset().

can_init_stats() is reached from can_stat_update() in timer context and
also from the procfs reset path. Those paths can run while the TX/RX hot
paths are concurrently updating rx_frames, tx_frames, matches and their
*_delta counters. Hitting the whole-struct memset() in that window
performs plain writes to fields that otherwise follow an atomic_long_t
access contract, which can lose or mix live statistics updates.

This issue was found by source-level API-misuse analysis looking for
whole-object resets left behind after atomic_long_t conversions, then
manually audited on Linux v6.18.21.

Replace the whole-struct memset() with a helper that resets the
atomic_long_t counters via atomic_long_set() and clears the derived
scalar statistics explicitly. This preserves the existing reset
semantics for scalar fields while restoring atomic access discipline for
the live counters.

Build-tested by compiling net/can/proc.o on x86_64 netdev/main.
Runtime-tested with a QEMU + vcan setup on Linux v6.18.21 by driving
concurrent traffic and reset_stats reads, which reproduced inconsistent
exported statistics before the fix.

[Hartkopp] can_stat_update() also read the *_delta counters at the
beginning and cleared them with atomic_long_set() at the end. Increments
from the hot path in between were lost for both the current and the next
interval. Use atomic_long_xchg() to fetch and clear the *_delta counters
in one atomic step instead.

Fixes: 80b5f90158d1 ("can: statistics: use atomic access in hot path")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261016110905.422684-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/proc.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/net/can/proc.c b/net/can/proc.c
index de4d05ae3459..70104f13077e 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -76,16 +76,39 @@ static const char rx_list_name[][8] = {
  * af_can statistics stuff
  */
 
+static void can_reset_pkg_stats(struct can_pkg_stats *pkg_stats)
+{
+	atomic_long_set(&pkg_stats->rx_frames, 0);
+	atomic_long_set(&pkg_stats->tx_frames, 0);
+	atomic_long_set(&pkg_stats->matches, 0);
+
+	pkg_stats->total_rx_rate = 0;
+	pkg_stats->total_tx_rate = 0;
+	pkg_stats->total_rx_match_ratio = 0;
+
+	pkg_stats->current_rx_rate = 0;
+	pkg_stats->current_tx_rate = 0;
+	pkg_stats->current_rx_match_ratio = 0;
+
+	pkg_stats->max_rx_rate = 0;
+	pkg_stats->max_tx_rate = 0;
+	pkg_stats->max_rx_match_ratio = 0;
+
+	atomic_long_set(&pkg_stats->rx_frames_delta, 0);
+	atomic_long_set(&pkg_stats->tx_frames_delta, 0);
+	atomic_long_set(&pkg_stats->matches_delta, 0);
+}
+
 static void can_init_stats(struct net *net)
 {
 	struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
 	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
 	/*
-	 * This memset function is called from a timer context (when
+	 * This stats reset is called from a timer context (when
 	 * can_stattimer is active which is the default) OR in a process
 	 * context (reading the proc_fs when can_stattimer is disabled).
 	 */
-	memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
+	can_reset_pkg_stats(pkg_stats);
 	pkg_stats->jiffies_init = jiffies;
 
 	rcv_lists_stats->stats_reset++;
@@ -121,9 +144,10 @@ void can_stat_update(struct timer_list *t)
 	long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
 	long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
 	long matches = atomic_long_read(&pkg_stats->matches);
-	long rx_frames_delta = atomic_long_read(&pkg_stats->rx_frames_delta);
-	long tx_frames_delta = atomic_long_read(&pkg_stats->tx_frames_delta);
-	long matches_delta = atomic_long_read(&pkg_stats->matches_delta);
+	/* fetch and clear values for 'current rate' calculation */
+	long rx_frames_delta = atomic_long_xchg(&pkg_stats->rx_frames_delta, 0);
+	long tx_frames_delta = atomic_long_xchg(&pkg_stats->tx_frames_delta, 0);
+	long matches_delta = atomic_long_xchg(&pkg_stats->matches_delta, 0);
 
 	/* restart counting in timer context on user request */
 	if (user_reset)
@@ -172,11 +196,6 @@ void can_stat_update(struct timer_list *t)
 	if (pkg_stats->max_rx_match_ratio < pkg_stats->current_rx_match_ratio)
 		pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
 
-	/* clear values for 'current rate' calculation */
-	atomic_long_set(&pkg_stats->tx_frames_delta, 0);
-	atomic_long_set(&pkg_stats->rx_frames_delta, 0);
-	atomic_long_set(&pkg_stats->matches_delta, 0);
-
 	/* restart timer (one second) */
 	mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (4 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 05/12] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 18:37   ` Oliver Hartkopp
  2026-10-18 16:41 ` [PATCH net-next 07/12] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, Norbert Szetei,
	stable, Marc Kleine-Budde

From: Oliver Hartkopp <socketcan@hartkopp.net>

bcm_release() removes the socket from bcm_notifier_list before it takes
any lock that serializes against the netdev notifier chain, which runs
under RTNL. A socket that leaves the list in this window is skipped by
bcm_notify() and has to remove its CAN filters itself.

This fails when the bound device is moved to another network namespace
in this window: bcm_rx_unreg() reads dev_net(dev) without holding RTNL,
and can_rx_unregister() silently returns when this namespace does not
match dev_net(dev) anymore. The op is freed anyway and the remaining
receiver leads to a use-after-free in bcm_rx_handler().

Take rtnl_lock() before removing the socket from the notifier list, so
that bcm_release() and bcm_notify() can not both skip the removal and
dev_net(dev) is stable while the device specific filters are removed.
As the notifier chain is always invoked under RTNL, bcm_busy_notifier
can not point to the released socket anymore. Replace the now dead
busy-wait loop with a WARN_ON_ONCE().

RTNL is only held for the notifier list removal and the removal of the
device specific filters. Once the socket has left the notifier list,
bcm_notify() can not access it anymore. So the procfs entry, the tx_ops
and the filters for 'any' CAN device, which live in the socket's
namespace, are removed after RTNL has been released. This way a stalled
reader of the world-readable procfs entry can not hold up RTNL, and the
removal of the 'any' CAN device filters does not delay RTNL anymore.

Fixes: 8e8cda6d737d ("can: initial support for network namespaces")
Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Cc: Norbert Szetei <norbert@doyensec.com>
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261016091128.325332-3-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/bcm.c | 47 +++++++++++++++++++++--------------------------
 1 file changed, 21 insertions(+), 26 deletions(-)

diff --git a/net/can/bcm.c b/net/can/bcm.c
index 6759662e024c..fbc79da4e4fc 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1926,17 +1926,30 @@ static int bcm_release(struct socket *sock)
 
 	/* remove bcm_ops, timer, rx_unregister(), etc. */
 
+	rtnl_lock();
+
+	/* The netdev notifier chain runs under RTNL, so bcm_notifier() can't
+	 * be walking bcm_notifier_list and point to this socket. The spinlock
+	 * is still needed as bcm_init() adds sockets without holding RTNL.
+	 */
 	spin_lock(&bcm_notifier_lock);
-	while (bcm_busy_notifier == bo) {
-		spin_unlock(&bcm_notifier_lock);
-		schedule_timeout_uninterruptible(1);
-		spin_lock(&bcm_notifier_lock);
-	}
+	WARN_ON_ONCE(bcm_busy_notifier == bo);
 	list_del(&bo->notifier);
 	spin_unlock(&bcm_notifier_lock);
 
 	lock_sock(sk);
 
+	/* Remove the device specific subscriptions under RTNL */
+	list_for_each_entry(op, &bo->rx_ops, list)
+		if (op->ifindex && op->rx_reg_dev)
+			bcm_rx_unreg(op->rx_reg_dev, op);
+
+	rtnl_unlock();
+
+	/* bcm_notify() can not access this socket anymore. Release the other
+	 * resources without holding RTNL, e.g. remove_proc_entry() waits for
+	 * concurrent readers of the procfs entry.
+	 */
 #if IS_ENABLED(CONFIG_PROC_FS)
 	/* remove procfs entry */
 	if (net->can.bcmproc_dir && bo->bcm_proc_read)
@@ -1948,31 +1961,13 @@ static int bcm_release(struct socket *sock)
 		bcm_remove_op(op);
 	}
 
-	list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
-		/*
-		 * Don't care if we're bound or not (due to netdev problems)
-		 * can_rx_unregister() is always a save thing to do here.
-		 */
-		if (op->ifindex) {
-			/*
-			 * Only remove subscriptions that had not
-			 * been removed due to NETDEV_UNREGISTER
-			 * in bcm_notifier()
-			 *
-			 * op->rx_reg_dev is a tracked reference taken
-			 * when the subscription was registered, so it
-			 * stays valid here even if a concurrent
-			 * NETDEV_UNREGISTER already unlisted the device.
-			 */
-			if (op->rx_reg_dev)
-				bcm_rx_unreg(op->rx_reg_dev, op);
-		} else
+	/* 'any' CAN device subscriptions live in the socket's namespace */
+	list_for_each_entry(op, &bo->rx_ops, list)
+		if (!op->ifindex)
 			can_rx_unregister(net, NULL, op->can_id,
 					  REGMASK(op->can_id),
 					  bcm_rx_handler, op);
 
-	}
-
 	synchronize_rcu();
 
 	list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 07/12] can: proc: remove pointers from CAN specific proc output
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (5 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 08/12] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp,
	Sebastian Andrzej Siewior, Marc Kleine-Budde

From: Oliver Hartkopp <socketcan@hartkopp.net>

The proc content in /proc/net/can/ and /proc/net/can-bcm/ is intended to
check the internal filter lists (af_can, can_raw) and the efficiency and
functionality of can_bcm jobs. While exposing kernel addresses was
acceptable when this code was written the times have changed and multiple
attempts have been made to hash or remove such now sensitive data.

This patch removes the disclosure of pointers and instead provides the
function names and sock inode numbers when available. When the function
name can not be resolved (e.g. KALLSYMS=n or stripped module symbols)
%ps would fall back to the raw text address. Therefore (unknown) is
printed instead in this case. As there's no known tooling around the CAN
specific proc output breaking the ABI with this rework creates no issue.

Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261016103706.410678-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 Documentation/networking/can.rst | 16 ++++++++++------
 include/linux/can/core.h         |  2 +-
 net/can/af_can.c                 |  6 +++---
 net/can/af_can.h                 |  2 +-
 net/can/bcm.c                    | 14 +++++++-------
 net/can/gw.c                     |  2 +-
 net/can/isotp.c                  |  4 ++--
 net/can/j1939/main.c             |  2 +-
 net/can/proc.c                   | 26 ++++++++++++++++----------
 net/can/raw.c                    |  4 ++--
 10 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
index 536ff411da1d..51bc70748f75 100644
--- a/Documentation/networking/can.rst
+++ b/Documentation/networking/can.rst
@@ -1040,17 +1040,21 @@ As described in :ref:`socketcan-receive-lists` the SocketCAN core uses several f
 lists to deliver received CAN frames to CAN protocol modules. These
 receive lists, their filters and the count of filter matches can be
 checked in the appropriate receive list. All entries contain the
-device and a protocol module identifier::
+CAN network device, the filter (can_id/can_mask), the number of filter
+matches, the inode number of the subscribing socket and the name of the
+receive function. A sock_inode of 0 denotes a kernel internal subscriber
+without a socket (e.g. CAN gateway or J1939). When the function name can
+not be resolved (e.g. with CONFIG_KALLSYMS=n) "(unknown)" is printed::
 
     foo@bar:~$ cat /proc/net/can/rcvlist_all
 
     receive list 'rx_all':
-      (vcan3: no entry)
-      (vcan2: no entry)
-      (vcan1: no entry)
-      device   can_id   can_mask  function  userdata   matches  ident
-       vcan0     000    00000000  f88e6370  f6c6f400         0  raw
       (any: no entry)
+      device   can_id   can_mask   matches  sock_inode  function
+       vcan0     000    00000000         0       63586  raw_rcv [can_raw]
+      (vcan1: no entry)
+      (vcan2: no entry)
+      (vcan3: no entry)
 
 In this example an application requests any CAN traffic from vcan0::
 
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 2de74c2b78b6..effb5c31ef40 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -51,7 +51,7 @@ extern void can_proto_unregister(const struct can_proto *cp);
 int can_rx_register(struct net *net, struct net_device *dev,
 		    canid_t can_id, canid_t mask,
 		    void (*func)(struct sk_buff *, void *),
-		    void *data, char *ident, struct sock *sk);
+		    void *data, u64 ino, struct sock *sk);
 
 extern void can_rx_unregister(struct net *net, struct net_device *dev,
 			      canid_t can_id, canid_t mask,
diff --git a/net/can/af_can.c b/net/can/af_can.c
index dc27ace43719..d97f85fc3232 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -418,7 +418,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask,
  * @mask: CAN mask (see description)
  * @func: callback function on filter match
  * @data: returned parameter for callback function
- * @ident: string for calling module identification
+ * @ino: inode number of sock (0 = unknown)
  * @sk: socket pointer (might be NULL)
  *
  * Description:
@@ -443,7 +443,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask,
  */
 int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
 		    canid_t mask, void (*func)(struct sk_buff *, void *),
-		    void *data, char *ident, struct sock *sk)
+		    void *data, u64 ino, struct sock *sk)
 {
 	struct receiver *rcv;
 	struct hlist_head *rcv_list;
@@ -472,7 +472,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
 	atomic_long_set(&rcv->matches, 0);
 	rcv->func = func;
 	rcv->data = data;
-	rcv->ident = ident;
+	rcv->ino = ino;
 	rcv->sk = sk;
 
 	hlist_add_head_rcu(&rcv->list, rcv_list);
diff --git a/net/can/af_can.h b/net/can/af_can.h
index 87887014f562..6e593ed5db5f 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -55,7 +55,7 @@ struct receiver {
 	atomic_long_t matches;
 	void (*func)(struct sk_buff *skb, void *data);
 	void *data;
-	char *ident;
+	u64 ino;
 	struct sock *sk;
 	struct rcu_head rcu;
 };
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 60406439a13f..6759662e024c 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -221,9 +221,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
 	struct bcm_sock *bo = bcm_sk(sk);
 	struct bcm_op *op;
 
-	seq_printf(m, ">>> socket %pK", sk->sk_socket);
-	seq_printf(m, " / sk %pK", sk);
-	seq_printf(m, " / bo %pK", bo);
+	seq_printf(m, ">>> sock inode %s", bo->procname);
 	seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
 	seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
 	seq_printf(m, " <<<\n");
@@ -1537,7 +1535,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
 						      op->can_id,
 						      REGMASK(op->can_id),
 						      bcm_rx_handler, op,
-						      "bcm", sk);
+						      sock_i_ino(sk), sk);
 
 				/* keep a tracked reference so that a later
 				 * unregister can safely reach the device even
@@ -1561,7 +1559,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
 		} else {
 			err = can_rx_register(sock_net(sk), NULL, op->can_id,
 					      REGMASK(op->can_id),
-					      bcm_rx_handler, op, "bcm", sk);
+					      bcm_rx_handler, op,
+					      sock_i_ino(sk), sk);
 		}
 
 		if (err) {
@@ -2041,8 +2040,9 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
 
 #if IS_ENABLED(CONFIG_PROC_FS)
 	if (net->can.bcmproc_dir) {
-		/* unique socket address as filename */
-		sprintf(bo->procname, "%llu", sock_i_ino(sk));
+		/* use unique socket inode number as filename */
+		snprintf(bo->procname, sizeof(bo->procname),
+			 "%llu", sock_i_ino(sk));
 		bo->bcm_proc_read = proc_create_net_single(bo->procname, 0644,
 						     net->can.bcmproc_dir,
 						     bcm_proc_show, sk);
diff --git a/net/can/gw.c b/net/can/gw.c
index 54bb5bd3242a..8a5327d8a00e 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -580,7 +580,7 @@ static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
 {
 	return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
 			       gwj->ccgw.filter.can_mask, can_can_gw_rcv,
-			       gwj, "gw", NULL);
+			       gwj, 0, NULL);
 }
 
 static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
diff --git a/net/can/isotp.c b/net/can/isotp.c
index 6c28802c0605..1a272ce6a2bd 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -1626,14 +1626,14 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
 
 	if (isotp_register_rxid(so))
 		can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
-				isotp_rcv, sk, "isotp", sk);
+				isotp_rcv, sk, sock_i_ino(sk), sk);
 
 	/* no consecutive frame echo skb in flight */
 	WRITE_ONCE(so->cfecho, 0);
 
 	/* register for echo skb's */
 	can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
-			isotp_rcv_echo, sk, "isotpe", sk);
+			isotp_rcv_echo, sk, sock_i_ino(sk), sk);
 
 	/* switch to new settings */
 	so->ifindex = ifindex;
diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
index 5e5e6c228f22..d9384cf0e356 100644
--- a/net/can/j1939/main.c
+++ b/net/can/j1939/main.c
@@ -184,7 +184,7 @@ static int j1939_can_rx_register(struct j1939_priv *priv)
 
 	j1939_priv_get(priv);
 	ret = can_rx_register(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK,
-			      j1939_can_recv, priv, "j1939", NULL);
+			      j1939_can_recv, priv, 0, NULL);
 	if (ret < 0) {
 		j1939_priv_put(priv);
 		return ret;
diff --git a/net/can/proc.c b/net/can/proc.c
index 70104f13077e..0f1fa6564436 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -210,26 +210,32 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
 	struct receiver *r;
 
 	hlist_for_each_entry_rcu(r, rx_list, list) {
+		char symcheck[4];
 		char *fmt = (r->can_id & CAN_EFF_FLAG)?
-			"   %-5s  %08x  %08x  %pK  %pK  %8ld  %s\n" :
-			"   %-5s     %03x    %08x  %pK  %pK  %8ld  %s\n";
+			"  %6s  %08x  %08x  %8ld  %10llu" :
+			"  %6s     %03x    %08x  %8ld  %10llu";
 
 		seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
-			   r->func, r->data, atomic_long_read(&r->matches),
-			   r->ident);
+			   atomic_long_read(&r->matches), r->ino);
+
+		/* %ps falls back to the raw text address when the symbol
+		 * can not be resolved (KALLSYMS=n, stripped module symbols)
+		 */
+		snprintf(symcheck, sizeof(symcheck), "%ps", r->func);
+		if (strncmp(symcheck, "0x", 2))
+			seq_printf(m, "  %ps\n", r->func);
+		else
+			seq_puts(m, "  (unknown)\n");
 	}
 }
 
 static void can_print_recv_banner(struct seq_file *m)
 {
 	/*
-	 *                  can1.  00000000  00000000  00000000
-	 *                 .......          0  tp20
+	 *    device   can_id   can_mask   matches  sock_inode  function
+	 *     vcan0     000    00000000         0       43798  raw_rcv [can_raw]
 	 */
-	if (IS_ENABLED(CONFIG_64BIT))
-		seq_puts(m, "  device   can_id   can_mask      function          userdata       matches  ident\n");
-	else
-		seq_puts(m, "  device   can_id   can_mask  function  userdata   matches  ident\n");
+	seq_puts(m, "  device   can_id   can_mask   matches  sock_inode  function\n");
 }
 
 static int can_stats_proc_show(struct seq_file *m, void *v)
diff --git a/net/can/raw.c b/net/can/raw.c
index ad611906b308..dfea48768b23 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -226,7 +226,7 @@ static int raw_enable_filters(struct net *net, struct net_device *dev,
 	for (i = 0; i < count; i++) {
 		err = can_rx_register(net, dev, filter[i].can_id,
 				      filter[i].can_mask,
-				      raw_rcv, sk, "raw", sk);
+				      raw_rcv, sk, sock_i_ino(sk), sk);
 		if (err) {
 			/* clean up successfully registered filters */
 			while (--i >= 0)
@@ -247,7 +247,7 @@ static int raw_enable_errfilter(struct net *net, struct net_device *dev,
 
 	if (err_mask)
 		err = can_rx_register(net, dev, 0, err_mask | CAN_ERR_FLAG,
-				      raw_rcv, sk, "raw", sk);
+				      raw_rcv, sk, sock_i_ino(sk), sk);
 
 	return err;
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 08/12] can: raw: take rtnl_lock() before leaving the notifier list
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (6 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 07/12] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 09/12] can: isotp: check the frame type, not just the length Marc Kleine-Budde
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp,
	Marc Kleine-Budde

From: Oliver Hartkopp <socketcan@hartkopp.net>

raw_release() removes the socket from raw_notifier_list before it takes
rtnl_lock(). As the netdev notifier chain runs under RTNL, a socket that
leaves the list in this window is skipped by raw_notify() and has to
remove its CAN filters itself.

For raw this is not harmful: raw_release() removes the filters with
dev_net(ro->dev) under RTNL, so they are found even when the bound
device has been moved to another network namespace in this window. The
receivers only remain on the moved device until raw_release() gets
RTNL.

Take rtnl_lock() before removing the socket from the notifier list, so
that raw, isotp and bcm use the same locking scheme in their release
functions. As the notifier chain is always invoked under RTNL,
raw_busy_notifier can not point to the released socket anymore. Replace
the now dead busy-wait loop with a WARN_ON_ONCE().

Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261016091128.325332-4-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/raw.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/net/can/raw.c b/net/can/raw.c
index dfea48768b23..d95ce54a4c45 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -422,16 +422,17 @@ static int raw_release(struct socket *sock)
 	ro = raw_sk(sk);
 	net = sock_net(sk);
 
+	rtnl_lock();
+
+	/* The netdev notifier chain runs under RTNL, so raw_notifier() can't
+	 * be walking raw_notifier_list and point to this socket. The spinlock
+	 * is still needed as raw_init() adds sockets without holding RTNL.
+	 */
 	spin_lock(&raw_notifier_lock);
-	while (raw_busy_notifier == ro) {
-		spin_unlock(&raw_notifier_lock);
-		schedule_timeout_uninterruptible(1);
-		spin_lock(&raw_notifier_lock);
-	}
+	WARN_ON_ONCE(raw_busy_notifier == ro);
 	list_del(&ro->notifier);
 	spin_unlock(&raw_notifier_lock);
 
-	rtnl_lock();
 	lock_sock(sk);
 
 	/* remove current filters & unregister */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 09/12] can: isotp: check the frame type, not just the length
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (7 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 08/12] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 10/12] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Kaixuan Li, Oliver Hartkopp,
	Quchaosheng, stable, Marc Kleine-Budde

From: Kaixuan Li <kaixuanli0131@gmail.com>

isotp_rcv() separates Classic CAN from CAN FD by skb->len alone:

	if (skb->len != so->ll.mtu)
		return;

	cf = (struct canfd_frame *)skb->data;

A CAN XL frame with cxl->len 4 is CAN_MTU bytes, so it passes, and is then
read as a canfd_frame whose len comes out of canxl_frame.flags: at least
0x80.

Of the paths that follow, only the flow control one uses that length
without bounding it first, so check_pad() walks to 255 over a 16-byte
frame and the caller reports EBADMSG on an unrelated socket.

bcm_rx_handler(), j1939_can_recv(), can_can_gw_rcv() and raw_rcv() check
the frame type here, and can_dropped_invalid_skb() switches on
skb->protocol on the transmit side. isotp_rcv() is the gap.

Fixes: fb08cba12b52 ("can: canxl: update CAN infrastructure for CAN XL frames")
Signed-off-by: Kaixuan Li <kaixuanli0131@gmail.com>
Reviewed-by: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Quchaosheng <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20260920035626.2581040-1-kaixuanli0131@gmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 net/can/isotp.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/net/can/isotp.c b/net/can/isotp.c
index 1a272ce6a2bd..5e1c3971ebfc 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -756,6 +756,14 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
 	if (skb->len != so->ll.mtu)
 		return;
 
+	/* check for correct CAN CC/FD frame content */
+	if (so->ll.mtu == CAN_MTU) {
+		if (!can_is_can_skb(skb))
+			return;
+	} else if (!can_is_canfd_skb(skb)) {
+		return;
+	}
+
 	cf = (struct canfd_frame *)skb->data;
 
 	/* if enabled: check reception of my configured extended address */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 10/12] can: skb: make echo skb freeing safe in any IRQ context
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (8 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 09/12] can: isotp: check the frame type, not just the length Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 11/12] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 12/12] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuba, linux-can, kernel, Cunhao Lu, stable,
	Marc Kleine-Budde

From: Cunhao Lu <1579567540@qq.com>

can_put_echo_skb() can be called with hardware interrupts disabled. Its
direct drop paths use kfree_skb(), while can_create_echo_skb() uses
kfree_skb() when cloning fails and consume_skb() after a successful clone.
None of these helpers is safe in every IRQ context.

Use dev_kfree_skb_any() for all drop paths and dev_consume_skb_any() when
consuming a successfully cloned skb. This preserves the respective skb drop
and consumed semantics regardless of the caller IRQ context.

Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_E84809CF236D0137885E7E4E4D58340B3208@qq.com
Cc: stable@kernel.org
Fixes: ae64438be192 ("can: dev: fix skb drop check")
Fixes: 0ae89beb283a ("can: add destructor for self generated skbs")
Fixes: 3ccd4c6167d3 ("can: Unify droping of invalid tx skbs and netdev stats")
Fixes: 39549eef3587 ("can: CAN Network device driver and Netlink interface")
[mkl: also convert can_dropped_invalid_skb(), can_dev_dropped_skb()]
[mkl: add stable on Cc + add Fixes tags]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/dev/skb.c | 6 +++---
 include/linux/can/dev.h   | 2 +-
 include/linux/can/skb.h   | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index bc0787535b52..46c151eece8f 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -63,7 +63,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
 	    (skb->protocol != htons(ETH_P_CAN) &&
 	     skb->protocol != htons(ETH_P_CANFD) &&
 	     skb->protocol != htons(ETH_P_CANXL))) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		return 0;
 	}
 
@@ -91,7 +91,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
 	} else {
 		/* locking problem with netif_stop_queue() ?? */
 		netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		return -EBUSY;
 	}
 
@@ -403,7 +403,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
 	return false;
 
 inval_skb:
-	kfree_skb(skb);
+	dev_kfree_skb_any(skb);
 	dev->stats.tx_dropped++;
 	return true;
 }
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 6d0710d6f571..346faddee02e 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -176,7 +176,7 @@ static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_buff *s
 	return can_dropped_invalid_skb(dev, skb);
 
 invalid_skb:
-	kfree_skb(skb);
+	dev_kfree_skb_any(skb);
 	dev->stats.tx_dropped++;
 	return true;
 }
diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
index 5d27843862fc..87ace09c0d8b 100644
--- a/include/linux/can/skb.h
+++ b/include/linux/can/skb.h
@@ -78,12 +78,12 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
 
 	nskb = skb_clone(skb, GFP_ATOMIC);
 	if (unlikely(!nskb)) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		return NULL;
 	}
 
 	can_skb_set_owner(nskb, skb->sk);
-	consume_skb(skb);
+	dev_consume_skb_any(skb);
 	return nskb;
 }
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 11/12] can: skb: make CAN skb allocation failure paths IRQ-safe
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (9 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 10/12] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  2026-10-18 16:41 ` [PATCH net-next 12/12] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuba, linux-can, kernel, Cunhao Lu, Marc Kleine-Budde

From: Cunhao Lu <1579567540@qq.com>

The CAN skb allocation helpers are used from hardware interrupt receive
handlers. If can_skb_ext_add() fails, they release the newly allocated skb
with kfree_skb(), which is not safe in hardware interrupt context.

Use dev_kfree_skb_any() for the allocation failure paths in
alloc_can_skb(), alloc_canfd_skb(), and alloc_canxl_skb().

Fixes: 96ea3a1e2d31 ("can: add CAN skb extension infrastructure")
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_C825C17D442F801351CE2FBC4984064B4605@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/dev/skb.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 46c151eece8f..3e36c0368bae 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -228,7 +228,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
 
 	csx = can_skb_ext_add(skb);
 	if (!csx) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		goto out_error_cc;
 	}
 
@@ -259,7 +259,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
 
 	csx = can_skb_ext_add(skb);
 	if (!csx) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		goto out_error_fd;
 	}
 
@@ -297,7 +297,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev,
 
 	csx = can_skb_ext_add(skb);
 	if (!csx) {
-		kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 		goto out_error_xl;
 	}
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH net-next 12/12] can: dev: can_put_echo_skb(): free skb on invalid echo index
  2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
                   ` (10 preceding siblings ...)
  2026-10-18 16:41 ` [PATCH net-next 11/12] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
@ 2026-10-18 16:41 ` Marc Kleine-Budde
  11 siblings, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-18 16:41 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Cunhao Lu, stable,
	Vincent Mailhol, Marc Kleine-Budde

From: Cunhao Lu <1579567540@qq.com>

can_put_echo_skb() consumes the skb on all paths except when the echo
index is out of bounds. This leaves ownership with the caller on -EINVAL,
unlike the other error paths, and can leak the skb if the caller expects
consistent semantics.

Free the skb before returning -EINVAL so that all return paths consume it.

Fixes: 6411959c10fe ("can: dev: can_put_echo_skb(): don't crash kernel if can_priv::echo_skb is accessed out of bounds")
Cc: stable@vger.kernel.org
Reviewed-by: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_683AA16E643DE00211CD2FB62991264DC605@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

---

FAQ:

Q: `can_skb_init_valid()` directly modifies `skb->data` without checking if
   the SKB is cloned or shared. Is this violating SKB shared buffer rules and
   causing data corruption?

A: The finding about can_skb_init_valid() modifying skb->data on a
   potentially shared buffer is not relevant for this (correct) patch.

   The FDF-flag write in can_skb_init_valid() only matters for PF_PACKET
   use: PF_CAN allocators already set CANFD_FDF. The write exists to
   normalize frames for PF_PACKET observers (tcpdump/Wireshark) so they can
   distinguish classic CAN from CAN FD at the netdev level, and to
   compensate for PF_PACKET senders that omit the bit. That normalization
   is functionally required.

   The shared-buffer concern only becomes realistic through a specific
   chain: a PF_PACKET sender injects a CANFD-sized frame, the CAN driver's
   loopback puts an echo skb back into can_rcv(), and cgw (without
   modfuncs) clones it for forwarding to another interface. Only on that
   second can_skb_init_valid() call is the skb cloned. By then the bit was
   already set on the exclusive skb during the initial xmit path, so the
   flags |= CANFD_FDF write is strictly idempotent for any parallel
   consumer of the shared buffer - no memory-safety or
   information-disclosure consequence. It's a formal violation of the skb
   sharing rules without an observable effect, so the current code can stay
   as-is.

Link: https://lore.kernel.org/all/54a3cc01-abcf-4a33-b932-39bb1f68cdd5@hartkopp.net/
[mkl: convert Oliver's mail to FAQ section]
---
 drivers/net/can/dev/skb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 3e36c0368bae..738d5968dfa6 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -55,6 +55,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
 	if (idx >= priv->echo_skb_max) {
 		netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
 			   __func__, idx, priv->echo_skb_max);
+		dev_kfree_skb_any(skb);
 		return -EINVAL;
 	}
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
  2026-10-18 16:41 ` [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
@ 2026-10-18 16:54   ` netdev-bot+sinfo
  0 siblings, 0 replies; 17+ messages in thread
From: netdev-bot+sinfo @ 2026-10-18 16:54 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: netdev, davem, kuba, linux-can, kernel, Vincent Mailhol, stable

Hi!

This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:

 - How the issue was discovered, e.g. hit in production, hit during
   development, syzbot report, manual code inspection, LLM or static
   analysis tool scan.

 - Whether the issue was actually triggered, or is only theoretical
   (e.g. found by code inspection). If it was triggered please include
   the symptoms, like the stack trace or error messages.

Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.

The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change
  2026-10-18 16:41 ` [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change Marc Kleine-Budde
@ 2026-10-18 18:37   ` Oliver Hartkopp
  2026-10-19  8:30     ` Oliver Hartkopp
  2026-10-19  9:18     ` Marc Kleine-Budde
  0 siblings, 2 replies; 17+ messages in thread
From: Oliver Hartkopp @ 2026-10-18 18:37 UTC (permalink / raw)
  To: Marc Kleine-Budde, netdev
  Cc: davem, kuba, linux-can, kernel, Norbert Szetei, stable

Hello Marc,

sashiko-bot complained about problems with the rtnl_lock() usage in this 
bcm patch here:

https://lore.kernel.org/linux-can/99fed91f-dbc5-4029-8a34-7e0113acfe13@hartkopp.net/

This problem applies to all of these fixes:

[PATCH net-next 04/12] can: isotp: fix filter removal race between 
release and netns change
https://lore.kernel.org/linux-can/20261018164417.1540449-5-mkl@pengutronix.de/

[PATCH net-next 06/12] can: bcm: fix filter removal race between release 
and netns change
https://lore.kernel.org/linux-can/20261018164417.1540449-7-mkl@pengutronix.de/

[PATCH net-next 08/12] can: raw: take rtnl_lock() before leaving the 
notifier list
https://lore.kernel.org/linux-can/20261018164417.1540449-9-mkl@pengutronix.de/

They all correctly fix the race when moving CAN devices to other 
namespaces when releasing sockets - BUT with the cost of rtnl locks that 
can be triggered by unprivileged users.

"Taking RTNL in these release paths is no option: raw_bind(),
raw_setsockopt() and raw_release() already hold RTNL while adding and
removing up to CAN_RAW_FILTER_MAX filters per socket, which unprivileged
users can trigger repeatedly and which makes RTNL a global bottleneck."

This patch

[RFC PATCH can-next v2] can: protect the receive lists with a per-device 
lock
https://lore.kernel.org/linux-can/20261018180739.689750-1-socketcan@hartkopp.net/

replaces those three patches and removes the formerly required increased 
usage of rtnl_lock() by adding a new can_dev_rcv_lists::lock that is 
placed in ml_priv and is device specific (independently from namespaces).

I've worked on this patch the entire weekend and tested it extensively.

I would suggest to replace the three patches with that single one for an 
updated PR and let sashiko-bot take a final look at it.

Best regards,
Oliver

ps. I did your requested instrumentation and found a missing glitch 
which is the reason for the v2 patch. The v1 will get its sashiko review 
today at ~10pm due to the 24h embargo :-/

On 18.10.26 18:41, Marc Kleine-Budde wrote:
> From: Oliver Hartkopp <socketcan@hartkopp.net>
> 
> bcm_release() removes the socket from bcm_notifier_list before it takes
> any lock that serializes against the netdev notifier chain, which runs
> under RTNL. A socket that leaves the list in this window is skipped by
> bcm_notify() and has to remove its CAN filters itself.
> 
> This fails when the bound device is moved to another network namespace
> in this window: bcm_rx_unreg() reads dev_net(dev) without holding RTNL,
> and can_rx_unregister() silently returns when this namespace does not
> match dev_net(dev) anymore. The op is freed anyway and the remaining
> receiver leads to a use-after-free in bcm_rx_handler().
> 
> Take rtnl_lock() before removing the socket from the notifier list, so
> that bcm_release() and bcm_notify() can not both skip the removal and
> dev_net(dev) is stable while the device specific filters are removed.
> As the notifier chain is always invoked under RTNL, bcm_busy_notifier
> can not point to the released socket anymore. Replace the now dead
> busy-wait loop with a WARN_ON_ONCE().
> 
> RTNL is only held for the notifier list removal and the removal of the
> device specific filters. Once the socket has left the notifier list,
> bcm_notify() can not access it anymore. So the procfs entry, the tx_ops
> and the filters for 'any' CAN device, which live in the socket's
> namespace, are removed after RTNL has been released. This way a stalled
> reader of the world-readable procfs entry can not hold up RTNL, and the
> removal of the 'any' CAN device filters does not delay RTNL anymore.
> 
> Fixes: 8e8cda6d737d ("can: initial support for network namespaces")
> Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
> Cc: Norbert Szetei <norbert@doyensec.com>
> Cc: stable@vger.kernel.org
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
> Link: https://patch.msgid.link/20261016091128.325332-3-socketcan@hartkopp.net
> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
> ---
>   net/can/bcm.c | 47 +++++++++++++++++++++--------------------------
>   1 file changed, 21 insertions(+), 26 deletions(-)
> 
> diff --git a/net/can/bcm.c b/net/can/bcm.c
> index 6759662e024c..fbc79da4e4fc 100644
> --- a/net/can/bcm.c
> +++ b/net/can/bcm.c
> @@ -1926,17 +1926,30 @@ static int bcm_release(struct socket *sock)
>   
>   	/* remove bcm_ops, timer, rx_unregister(), etc. */
>   
> +	rtnl_lock();
> +
> +	/* The netdev notifier chain runs under RTNL, so bcm_notifier() can't
> +	 * be walking bcm_notifier_list and point to this socket. The spinlock
> +	 * is still needed as bcm_init() adds sockets without holding RTNL.
> +	 */
>   	spin_lock(&bcm_notifier_lock);
> -	while (bcm_busy_notifier == bo) {
> -		spin_unlock(&bcm_notifier_lock);
> -		schedule_timeout_uninterruptible(1);
> -		spin_lock(&bcm_notifier_lock);
> -	}
> +	WARN_ON_ONCE(bcm_busy_notifier == bo);
>   	list_del(&bo->notifier);
>   	spin_unlock(&bcm_notifier_lock);
>   
>   	lock_sock(sk);
>   
> +	/* Remove the device specific subscriptions under RTNL */
> +	list_for_each_entry(op, &bo->rx_ops, list)
> +		if (op->ifindex && op->rx_reg_dev)
> +			bcm_rx_unreg(op->rx_reg_dev, op);
> +
> +	rtnl_unlock();
> +
> +	/* bcm_notify() can not access this socket anymore. Release the other
> +	 * resources without holding RTNL, e.g. remove_proc_entry() waits for
> +	 * concurrent readers of the procfs entry.
> +	 */
>   #if IS_ENABLED(CONFIG_PROC_FS)
>   	/* remove procfs entry */
>   	if (net->can.bcmproc_dir && bo->bcm_proc_read)
> @@ -1948,31 +1961,13 @@ static int bcm_release(struct socket *sock)
>   		bcm_remove_op(op);
>   	}
>   
> -	list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
> -		/*
> -		 * Don't care if we're bound or not (due to netdev problems)
> -		 * can_rx_unregister() is always a save thing to do here.
> -		 */
> -		if (op->ifindex) {
> -			/*
> -			 * Only remove subscriptions that had not
> -			 * been removed due to NETDEV_UNREGISTER
> -			 * in bcm_notifier()
> -			 *
> -			 * op->rx_reg_dev is a tracked reference taken
> -			 * when the subscription was registered, so it
> -			 * stays valid here even if a concurrent
> -			 * NETDEV_UNREGISTER already unlisted the device.
> -			 */
> -			if (op->rx_reg_dev)
> -				bcm_rx_unreg(op->rx_reg_dev, op);
> -		} else
> +	/* 'any' CAN device subscriptions live in the socket's namespace */
> +	list_for_each_entry(op, &bo->rx_ops, list)
> +		if (!op->ifindex)
>   			can_rx_unregister(net, NULL, op->can_id,
>   					  REGMASK(op->can_id),
>   					  bcm_rx_handler, op);
>   
> -	}
> -
>   	synchronize_rcu();
>   
>   	list_for_each_entry_safe(op, next, &bo->rx_ops, list) {


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change
  2026-10-18 18:37   ` Oliver Hartkopp
@ 2026-10-19  8:30     ` Oliver Hartkopp
  2026-10-19  9:18     ` Marc Kleine-Budde
  1 sibling, 0 replies; 17+ messages in thread
From: Oliver Hartkopp @ 2026-10-19  8:30 UTC (permalink / raw)
  To: Marc Kleine-Budde, netdev
  Cc: davem, kuba, linux-can, kernel, Norbert Szetei, stable



On 18.10.26 20:37, Oliver Hartkopp wrote:
> Hello Marc,
> 
> sashiko-bot complained about problems with the rtnl_lock() usage in this 
> bcm patch here:
> 
> https://lore.kernel.org/linux-can/99fed91f- 
> dbc5-4029-8a34-7e0113acfe13@hartkopp.net/
> 
> This problem applies to all of these fixes:
> 
> [PATCH net-next 04/12] can: isotp: fix filter removal race between 
> release and netns change
> https://lore.kernel.org/linux-can/20261018164417.1540449-5- 
> mkl@pengutronix.de/
> 
> [PATCH net-next 06/12] can: bcm: fix filter removal race between release 
> and netns change
> https://lore.kernel.org/linux-can/20261018164417.1540449-7- 
> mkl@pengutronix.de/
> 
> [PATCH net-next 08/12] can: raw: take rtnl_lock() before leaving the 
> notifier list
> https://lore.kernel.org/linux-can/20261018164417.1540449-9- 
> mkl@pengutronix.de/
> 
> They all correctly fix the race when moving CAN devices to other 
> namespaces when releasing sockets - BUT with the cost of rtnl locks that 
> can be triggered by unprivileged users.
> 
> "Taking RTNL in these release paths is no option: raw_bind(),
> raw_setsockopt() and raw_release() already hold RTNL while adding and
> removing up to CAN_RAW_FILTER_MAX filters per socket, which unprivileged
> users can trigger repeatedly and which makes RTNL a global bottleneck."
> 
> This patch
> 
> [RFC PATCH can-next v2] can: protect the receive lists with a per-device 
> lock
> https://lore.kernel.org/linux-can/20261018180739.689750-1- 
> socketcan@hartkopp.net/
> 
> replaces those three patches and removes the formerly required increased 
> usage of rtnl_lock() by adding a new can_dev_rcv_lists::lock that is 
> placed in ml_priv and is device specific (independently from namespaces).
> 
> I've worked on this patch the entire weekend and tested it extensively.
> 
> I would suggest to replace the three patches with that single one for an 
> updated PR and let sashiko-bot take a final look at it.

I created a v3 series so that sashiko-bot gets a complete series that 
applies properly to mainline for an AI review:

https://lore.kernel.org/linux-can/20261019074244.50391-1-socketcan@hartkopp.net/

The relevant v3 patch 4/4 has some changes in the documentation only 
that should make sashiko-bot even more happy o_O

https://lore.kernel.org/linux-can/20261019074244.50391-5-socketcan@hartkopp.net/

Best regards,
Oliver

> 
> ps. I did your requested instrumentation and found a missing glitch 
> which is the reason for the v2 patch. The v1 will get its sashiko review 
> today at ~10pm due to the 24h embargo :-/
> 
> On 18.10.26 18:41, Marc Kleine-Budde wrote:
>> From: Oliver Hartkopp <socketcan@hartkopp.net>
>>
>> bcm_release() removes the socket from bcm_notifier_list before it takes
>> any lock that serializes against the netdev notifier chain, which runs
>> under RTNL. A socket that leaves the list in this window is skipped by
>> bcm_notify() and has to remove its CAN filters itself.
>>
>> This fails when the bound device is moved to another network namespace
>> in this window: bcm_rx_unreg() reads dev_net(dev) without holding RTNL,
>> and can_rx_unregister() silently returns when this namespace does not
>> match dev_net(dev) anymore. The op is freed anyway and the remaining
>> receiver leads to a use-after-free in bcm_rx_handler().
>>
>> Take rtnl_lock() before removing the socket from the notifier list, so
>> that bcm_release() and bcm_notify() can not both skip the removal and
>> dev_net(dev) is stable while the device specific filters are removed.
>> As the notifier chain is always invoked under RTNL, bcm_busy_notifier
>> can not point to the released socket anymore. Replace the now dead
>> busy-wait loop with a WARN_ON_ONCE().
>>
>> RTNL is only held for the notifier list removal and the removal of the
>> device specific filters. Once the socket has left the notifier list,
>> bcm_notify() can not access it anymore. So the procfs entry, the tx_ops
>> and the filters for 'any' CAN device, which live in the socket's
>> namespace, are removed after RTNL has been released. This way a stalled
>> reader of the world-readable procfs entry can not hold up RTNL, and the
>> removal of the 'any' CAN device filters does not delay RTNL anymore.
>>
>> Fixes: 8e8cda6d737d ("can: initial support for network namespaces")
>> Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4- 
>> CBAE2F301A8E@doyensec.com/
>> Cc: Norbert Szetei <norbert@doyensec.com>
>> Cc: stable@vger.kernel.org
>> Assisted-by: Claude:claude-opus-5-5
>> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
>> Link: https://patch.msgid.link/20261016091128.325332-3- 
>> socketcan@hartkopp.net
>> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
>> ---
>>   net/can/bcm.c | 47 +++++++++++++++++++++--------------------------
>>   1 file changed, 21 insertions(+), 26 deletions(-)
>>
>> diff --git a/net/can/bcm.c b/net/can/bcm.c
>> index 6759662e024c..fbc79da4e4fc 100644
>> --- a/net/can/bcm.c
>> +++ b/net/can/bcm.c
>> @@ -1926,17 +1926,30 @@ static int bcm_release(struct socket *sock)
>>       /* remove bcm_ops, timer, rx_unregister(), etc. */
>> +    rtnl_lock();
>> +
>> +    /* The netdev notifier chain runs under RTNL, so bcm_notifier() 
>> can't
>> +     * be walking bcm_notifier_list and point to this socket. The 
>> spinlock
>> +     * is still needed as bcm_init() adds sockets without holding RTNL.
>> +     */
>>       spin_lock(&bcm_notifier_lock);
>> -    while (bcm_busy_notifier == bo) {
>> -        spin_unlock(&bcm_notifier_lock);
>> -        schedule_timeout_uninterruptible(1);
>> -        spin_lock(&bcm_notifier_lock);
>> -    }
>> +    WARN_ON_ONCE(bcm_busy_notifier == bo);
>>       list_del(&bo->notifier);
>>       spin_unlock(&bcm_notifier_lock);
>>       lock_sock(sk);
>> +    /* Remove the device specific subscriptions under RTNL */
>> +    list_for_each_entry(op, &bo->rx_ops, list)
>> +        if (op->ifindex && op->rx_reg_dev)
>> +            bcm_rx_unreg(op->rx_reg_dev, op);
>> +
>> +    rtnl_unlock();
>> +
>> +    /* bcm_notify() can not access this socket anymore. Release the 
>> other
>> +     * resources without holding RTNL, e.g. remove_proc_entry() waits 
>> for
>> +     * concurrent readers of the procfs entry.
>> +     */
>>   #if IS_ENABLED(CONFIG_PROC_FS)
>>       /* remove procfs entry */
>>       if (net->can.bcmproc_dir && bo->bcm_proc_read)
>> @@ -1948,31 +1961,13 @@ static int bcm_release(struct socket *sock)
>>           bcm_remove_op(op);
>>       }
>> -    list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
>> -        /*
>> -         * Don't care if we're bound or not (due to netdev problems)
>> -         * can_rx_unregister() is always a save thing to do here.
>> -         */
>> -        if (op->ifindex) {
>> -            /*
>> -             * Only remove subscriptions that had not
>> -             * been removed due to NETDEV_UNREGISTER
>> -             * in bcm_notifier()
>> -             *
>> -             * op->rx_reg_dev is a tracked reference taken
>> -             * when the subscription was registered, so it
>> -             * stays valid here even if a concurrent
>> -             * NETDEV_UNREGISTER already unlisted the device.
>> -             */
>> -            if (op->rx_reg_dev)
>> -                bcm_rx_unreg(op->rx_reg_dev, op);
>> -        } else
>> +    /* 'any' CAN device subscriptions live in the socket's namespace */
>> +    list_for_each_entry(op, &bo->rx_ops, list)
>> +        if (!op->ifindex)
>>               can_rx_unregister(net, NULL, op->can_id,
>>                         REGMASK(op->can_id),
>>                         bcm_rx_handler, op);
>> -    }
>> -
>>       synchronize_rcu();
>>       list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
> 
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change
  2026-10-18 18:37   ` Oliver Hartkopp
  2026-10-19  8:30     ` Oliver Hartkopp
@ 2026-10-19  9:18     ` Marc Kleine-Budde
  1 sibling, 0 replies; 17+ messages in thread
From: Marc Kleine-Budde @ 2026-10-19  9:18 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: netdev, davem, kuba, linux-can, kernel, Norbert Szetei, stable

[-- Attachment #1: Type: text/plain, Size: 636 bytes --]

On 18.10.2026 20:37:41, Oliver Hartkopp wrote:
> ps. I did your requested instrumentation and found a missing glitch which is
> the reason for the v2 patch. The v1 will get its sashiko review today at
> ~10pm due to the 24h embargo :-/

Can you send a follow up patch, that adds the guarded_by stuff? And
include it if you re-spin the series.

regards,
Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde          |
Embedded Linux                   | https://www.pengutronix.de |
Vertretung Nürnberg              | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-9   |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-10-19  9:18 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-18 16:41 [PATCH net-next 0/12] pull-request: can-next 2026-10-18 Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 01/12] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
2026-10-18 16:54   ` netdev-bot+sinfo
2026-10-18 16:41 ` [PATCH net-next 02/12] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 03/12] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 04/12] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 05/12] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 06/12] can: bcm: fix filter removal race between release and netns change Marc Kleine-Budde
2026-10-18 18:37   ` Oliver Hartkopp
2026-10-19  8:30     ` Oliver Hartkopp
2026-10-19  9:18     ` Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 07/12] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 08/12] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 09/12] can: isotp: check the frame type, not just the length Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 10/12] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 11/12] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
2026-10-18 16:41 ` [PATCH net-next 12/12] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox