Skip to contentSkip to conversation

can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()

PATCH In review Oliver Hartkopp 4 participants 7 messages Aug 19 – Aug 27

Subsystems (2)
lore
Share & tools
lore

Oliver Hartkopp

author maintainer
#0 lore raw

PATCH 1/1 can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()

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.

With this extension the CAN device specific ml_priv assignment became a robust indicator to identify a valid CAN device, when can_get_ml_priv() returns a valid pointer.

This has been used directly by the referenced commit in the CAN specific j1939 and proc code but not in the other parts of the CAN subsystem.

With the TUN/TAP driver a device's ARPHRD type can be controlled by userspace independently of its midlayer private data (ml_priv). The TUNSETLINK ioctl allows a down TUN/TAP device to overwrite its hardware type to become ARPHRD_CAN while dev->ml_priv remains NULL (uninitialized).

Instead of checking dev->type being the unreliable ARPHRD_CAN value convert the missing "valid CAN devices" checks to can_get_ml_priv().

Fixes 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device")
Cc Oleksij Rempel <[email protected]>
---
 net/can/af_can.c | 12 ++++++------
 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(+), 16 deletions(-)
net/can/af_can.c +6 -6
index be0661679ef8..1d30a622063c 100644
@@ -224,11 +224,11 @@ int can_send(struct sk_buff *skb, int loop)
 	if (unlikely(skb->len > READ_ONCE(skb->dev->mtu))) {
 		err = -EMSGSIZE;
 		goto inval_skb;
 	}
 
-	if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+	if (unlikely(!can_get_ml_priv(skb->dev))) {
 		err = -EPERM;
 		goto inval_skb;
 	}
 
 	if (unlikely(!(skb->dev->flags & IFF_UP))) {
@@ -450,11 +450,11 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
 	struct can_dev_rcv_lists *dev_rcv_lists;
 	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
 
 	/* 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)))
 		return -ENODEV;
 
@@ -517,11 +517,11 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
 	struct receiver *rcv = NULL;
 	struct hlist_head *rcv_list;
 	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)))
 		return;
 
@@ -685,11 +685,11 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
 }
 
 static int can_rcv(struct sk_buff *skb, struct net_device *dev,
 		   struct packet_type *pt, struct net_device *orig_dev)
 {
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
+	if (unlikely(!can_get_ml_priv(dev) ||
 		     !can_skb_ext_find(skb) || !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);
 
 		kfree_skb_reason(skb, SKB_DROP_REASON_CAN_RX_INVALID_FRAME);
@@ -701,11 +701,11 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
 }
 
 static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
 		     struct packet_type *pt, struct net_device *orig_dev)
 {
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
+	if (unlikely(!can_get_ml_priv(dev) ||
 		     !can_skb_ext_find(skb) || !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);
 
 		kfree_skb_reason(skb, SKB_DROP_REASON_CANFD_RX_INVALID_FRAME);
@@ -717,11 +717,11 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
 }
 
 static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
 		     struct packet_type *pt, struct net_device *orig_dev)
 {
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
+	if (unlikely(!can_get_ml_priv(dev) ||
 		     !can_skb_ext_find(skb) || !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);
 
 		kfree_skb_reason(skb, SKB_DROP_REASON_CANXL_RX_INVALID_FRAME);
net/can/bcm.c +4 -3
index dff8fab6b402..2f261c438f52 100644
@@ -52,10 +52,11 @@
 #include <linux/netdevice.h>
 #include <linux/socket.h>
 #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>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -1716,11 +1717,11 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 			if (!dev) {
 				ret = -ENODEV;
 				goto out_release;
 			}
 
-			if (dev->type != ARPHRD_CAN) {
+			if (!can_get_ml_priv(dev)) {
 				dev_put(dev);
 				ret = -ENODEV;
 				goto out_release;
 			}
 
@@ -1864,11 +1865,11 @@ static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
 static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
 			void *ptr)
 {
 	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;
 	if (unlikely(bcm_busy_notifier)) /* Check for reentrant bug. */
 		return NOTIFY_DONE;
@@ -2021,11 +2022,11 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
 		dev = dev_get_by_index(net, addr->can_ifindex);
 		if (!dev) {
 			ret = -ENODEV;
 			goto fail;
 		}
-		if (dev->type != ARPHRD_CAN) {
+		if (!can_get_ml_priv(dev)) {
 			dev_put(dev);
 			ret = -ENODEV;
 			goto fail;
 		}
 
net/can/gw.c +4 -3
index f1f59c0c6fd6..b946da2d0a60 100644
@@ -50,10 +50,11 @@
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #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>
 #include <net/can.h>
 #include <net/rtnetlink.h>
@@ -607,11 +608,11 @@ static int cgw_notifier(struct notifier_block *nb,
 			unsigned long msg, void *ptr)
 {
 	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) {
 		struct cgw_job *gwj = NULL;
 		struct hlist_node *nx;
@@ -1158,19 +1159,19 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh,
 	gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx);
 
 	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);
 
 	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? */
 	if (gwj->src.dev == gwj->dst.dev &&
 	    !(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK)) {
net/can/isotp.c +3 -2
index 35ae4f51a525..130a0dbec78c 100644
@@ -63,10 +63,11 @@
 #include <linux/netdevice.h>
 #include <linux/socket.h>
 #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>
 #include <linux/slab.h>
 #include <net/can.h>
@@ -1604,11 +1605,11 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
 	dev = dev_get_by_index(net, addr->can_ifindex);
 	if (!dev) {
 		err = -ENODEV;
 		goto out;
 	}
-	if (dev->type != ARPHRD_CAN) {
+	if (!can_get_ml_priv(dev)) {
 		err = -ENODEV;
 		goto out_put_dev;
 	}
 	if (READ_ONCE(dev->mtu) < so->ll.mtu) {
 		err = -EINVAL;
@@ -1891,11 +1892,11 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
 static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
 			  void *ptr)
 {
 	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;
 	if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */
 		return NOTIFY_DONE;
net/can/raw.c +2 -2
index 0a8b7c2fb4c9..b700e5fde07a 100644
@@ -342,11 +342,11 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
 static int raw_notifier(struct notifier_block *nb, unsigned long msg,
 			void *ptr)
 {
 	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;
 	if (unlikely(raw_busy_notifier)) /* Check for reentrant bug. */
 		return NOTIFY_DONE;
@@ -485,11 +485,11 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
 		dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
 		if (!dev) {
 			err = -ENODEV;
 			goto out;
 		}
-		if (dev->type != ARPHRD_CAN) {
+		if (!can_get_ml_priv(dev)) {
 			err = -ENODEV;
 			goto out_put_dev;
 		}
 
 		if (!(dev->flags & IFF_UP))
Signature · 1 line
2.53.0
#1 lore raw
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Data modification of shared/cloned SKBs in can_send() causes payload corruption for concurrent users. --

--- Patch [1]: [PATCH] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv() --- commit 57320b2cc995d1852816aaacf79460f42c05858d
Author: Oliver Hartkopp <[email protected]>

can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()

This commit updates the CAN subsystem to use can_get_ml_priv() for identifying valid CAN devices instead of relying on ARPHRD_CAN. This prevents issues with TUN/TAP devices that might overwrite their hardware type without properly initializing the midlayer private data.

net/can/af_can.c int can_send(struct sk_buff *skb, int loop) · line 228

Quoted 8 lines
net/can/af_can.c +0 -0
index 7bc86b176b4de..ef435f22ac933 100644
@@ -226,7 +226,7 @@ int can_send(struct sk_buff *skb, int loop)
 		goto inval_skb;
 	}
 

[Severity: High]
This is a pre-existing issue, but can modifying the SKB payload here cause data corruption for concurrent receivers?

Earlier in can_send(), the SKB data is directly modified without checking if it is shared:

	} else if (can_is_canfd_skb(skb)) {
		struct canfd_frame *cfd = (struct canfd_frame *)skb->data;

		skb->protocol = htons(ETH_P_CANFD);

		/* set CAN FD flag for CAN FD frames by default */
		cfd->flags |= CANFD_FDF;

When routing frames without data modifications, can_can_gw_rcv() creates a cloned SKB using skb_clone() and passes it to can_send():

net/can/gw.c:can_can_gw_rcv() {
	...
	nskb = skb_clone(skb, GFP_ATOMIC);
	...
	can_send(nskb, gwj->limit_hops);
}

Since skb_clone() shares the underlying data buffer, wouldn't modifying cfd->flags directly in can_send() corrupt the payload for other concurrent users of the original SKB?

Quoted 5 lines
net/can/af_can.c +1 -1
-	if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+	if (unlikely(!can_get_ml_priv(skb->dev))) {
 		err = -EPERM;
 		goto inval_skb;
 	}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
author maintainer
#2 lore raw
Quoted 54 lines · On 19.08.26 18:26, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Data modification of shared/cloned SKBs in can_send() causes payload corruption for concurrent users. --

--- Patch [1]: [PATCH] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv() --- commit 57320b2cc995d1852816aaacf79460f42c05858d
Author: Oliver Hartkopp <[email protected]>

can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()

This commit updates the CAN subsystem to use can_get_ml_priv() for identifying valid CAN devices instead of relying on ARPHRD_CAN. This prevents issues with TUN/TAP devices that might overwrite their hardware type without properly initializing the midlayer private data.

net/can/af_can.c int can_send(struct sk_buff *skb, int loop) · line 228

Quoted 8 lines
net/can/af_can.c +0 -0
index 7bc86b176b4de..ef435f22ac933 100644
@@ -226,7 +226,7 @@ int can_send(struct sk_buff *skb, int loop)
  		goto inval_skb;
  	}
 

[Severity: High]
This is a pre-existing issue, but can modifying the SKB payload here cause data corruption for concurrent receivers?

Earlier in can_send(), the SKB data is directly modified without checking if it is shared:

	} else if (can_is_canfd_skb(skb)) {
		struct canfd_frame *cfd = (struct canfd_frame *)skb->data;

		skb->protocol = htons(ETH_P_CANFD);

		/* set CAN FD flag for CAN FD frames by default */
		cfd->flags |= CANFD_FDF;

When routing frames without data modifications, can_can_gw_rcv() creates a cloned SKB using skb_clone() and passes it to can_send():

net/can/gw.c:can_can_gw_rcv() {
	...
	nskb = skb_clone(skb, GFP_ATOMIC);
	...
	can_send(nskb, gwj->limit_hops);
}
Quoted 4 lines

Since skb_clone() shares the underlying data buffer, wouldn't modifying cfd->flags directly in can_send() corrupt the payload for other concurrent users of the original SKB?

This is a common remark from Sashiko-bot when looking at this code.

No problem here.

Quoted 6 lines
Quoted 5 lines
net/can/af_can.c +1 -1
-	if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+	if (unlikely(!can_get_ml_priv(skb->dev))) {
  		err = -EPERM;
  		goto inval_skb;
  	}
author maintainer
#3 lore raw
In reply to Oliver Hartkopp

Hi Marc,

as you are currently filling your linux-can git repo, please take care of this (stable) patch too.

Do you think that these two patches below should be integrated into a net pull?

[can-next v2] can: proc: remove pointers from CAN specific proc output
https://lore.kernel.org/linux-can/[email protected]/

[can-next] can: remove Softing CANcard driver
https://lore.kernel.org/linux-can/[email protected]/

Best regards,
Oliver

Quoted 291 lines · Oliver Hartkopp

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.

With this extension the CAN device specific ml_priv assignment became a robust indicator to identify a valid CAN device, when can_get_ml_priv() returns a valid pointer.

This has been used directly by the referenced commit in the CAN specific j1939 and proc code but not in the other parts of the CAN subsystem.

With the TUN/TAP driver a device's ARPHRD type can be controlled by userspace independently of its midlayer private data (ml_priv). The TUNSETLINK ioctl allows a down TUN/TAP device to overwrite its hardware type to become ARPHRD_CAN while dev->ml_priv remains NULL (uninitialized).

Instead of checking dev->type being the unreliable ARPHRD_CAN value convert the missing "valid CAN devices" checks to can_get_ml_priv().

Fixes 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device")
Cc Oleksij Rempel <[email protected]>
---
  net/can/af_can.c | 12 ++++++------
  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(+), 16 deletions(-)
net/can/af_can.c +6 -6
index be0661679ef8..1d30a622063c 100644
@@ -224,11 +224,11 @@ int can_send(struct sk_buff *skb, int loop)
  	if (unlikely(skb->len > READ_ONCE(skb->dev->mtu))) {
  		err = -EMSGSIZE;
  		goto inval_skb;
  	}
 
-	if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+	if (unlikely(!can_get_ml_priv(skb->dev))) {
  		err = -EPERM;
  		goto inval_skb;
  	}
 
  	if (unlikely(!(skb->dev->flags & IFF_UP))) {
@@ -450,11 +450,11 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
  	struct can_dev_rcv_lists *dev_rcv_lists;
  	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
 
  	/* 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)))
  		return -ENODEV;
 
@@ -517,11 +517,11 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
  	struct receiver *rcv = NULL;
  	struct hlist_head *rcv_list;
  	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)))
  		return;
 
@@ -685,11 +685,11 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
  }
 
  static int can_rcv(struct sk_buff *skb, struct net_device *dev,
  		   struct packet_type *pt, struct net_device *orig_dev)
  {
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
+	if (unlikely(!can_get_ml_priv(dev) ||
  		     !can_skb_ext_find(skb) || !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);
 
  		kfree_skb_reason(skb, SKB_DROP_REASON_CAN_RX_INVALID_FRAME);
@@ -701,11 +701,11 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
  }
 
  static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
  		     struct packet_type *pt, struct net_device *orig_dev)
  {
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
+	if (unlikely(!can_get_ml_priv(dev) ||
  		     !can_skb_ext_find(skb) || !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);
 
  		kfree_skb_reason(skb, SKB_DROP_REASON_CANFD_RX_INVALID_FRAME);
@@ -717,11 +717,11 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
  }
 
  static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
  		     struct packet_type *pt, struct net_device *orig_dev)
  {
-	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
+	if (unlikely(!can_get_ml_priv(dev) ||
  		     !can_skb_ext_find(skb) || !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);
 
  		kfree_skb_reason(skb, SKB_DROP_REASON_CANXL_RX_INVALID_FRAME);
net/can/bcm.c +4 -3
index dff8fab6b402..2f261c438f52 100644
@@ -52,10 +52,11 @@
  #include <linux/netdevice.h>
  #include <linux/socket.h>
  #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>
  #include <linux/slab.h>
  #include <linux/workqueue.h>
@@ -1716,11 +1717,11 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
  			if (!dev) {
  				ret = -ENODEV;
  				goto out_release;
  			}
 
-			if (dev->type != ARPHRD_CAN) {
+			if (!can_get_ml_priv(dev)) {
  				dev_put(dev);
  				ret = -ENODEV;
  				goto out_release;
  			}
 
@@ -1864,11 +1865,11 @@ static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
  static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
  			void *ptr)
  {
  	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;
  	if (unlikely(bcm_busy_notifier)) /* Check for reentrant bug. */
  		return NOTIFY_DONE;
@@ -2021,11 +2022,11 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
  		dev = dev_get_by_index(net, addr->can_ifindex);
  		if (!dev) {
  			ret = -ENODEV;
  			goto fail;
  		}
-		if (dev->type != ARPHRD_CAN) {
+		if (!can_get_ml_priv(dev)) {
  			dev_put(dev);
  			ret = -ENODEV;
  			goto fail;
  		}
 
net/can/gw.c +4 -3
index f1f59c0c6fd6..b946da2d0a60 100644
@@ -50,10 +50,11 @@
  #include <linux/net.h>
  #include <linux/netdevice.h>
  #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>
  #include <net/can.h>
  #include <net/rtnetlink.h>
@@ -607,11 +608,11 @@ static int cgw_notifier(struct notifier_block *nb,
  			unsigned long msg, void *ptr)
  {
  	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) {
  		struct cgw_job *gwj = NULL;
  		struct hlist_node *nx;
@@ -1158,19 +1159,19 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh,
  	gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx);
 
  	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);
 
  	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? */
  	if (gwj->src.dev == gwj->dst.dev &&
  	    !(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK)) {
net/can/isotp.c +3 -2
index 35ae4f51a525..130a0dbec78c 100644
@@ -63,10 +63,11 @@
  #include <linux/netdevice.h>
  #include <linux/socket.h>
  #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>
  #include <linux/slab.h>
  #include <net/can.h>
@@ -1604,11 +1605,11 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
  	dev = dev_get_by_index(net, addr->can_ifindex);
  	if (!dev) {
  		err = -ENODEV;
  		goto out;
  	}
-	if (dev->type != ARPHRD_CAN) {
+	if (!can_get_ml_priv(dev)) {
  		err = -ENODEV;
  		goto out_put_dev;
  	}
  	if (READ_ONCE(dev->mtu) < so->ll.mtu) {
  		err = -EINVAL;
@@ -1891,11 +1892,11 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
  static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
  			  void *ptr)
  {
  	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;
  	if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */
  		return NOTIFY_DONE;
net/can/raw.c +2 -2
index 0a8b7c2fb4c9..b700e5fde07a 100644
@@ -342,11 +342,11 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
  static int raw_notifier(struct notifier_block *nb, unsigned long msg,
  			void *ptr)
  {
  	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;
  	if (unlikely(raw_busy_notifier)) /* Check for reentrant bug. */
  		return NOTIFY_DONE;
@@ -485,11 +485,11 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
  		dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
  		if (!dev) {
  			err = -ENODEV;
  			goto out;
  		}
-		if (dev->type != ARPHRD_CAN) {
+		if (!can_get_ml_priv(dev)) {
  			err = -ENODEV;
  			goto out_put_dev;
  		}
 
  		if (!(dev->flags & IFF_UP))
#4 lore raw
Quoted 2 lines · Oliver Hartkopp

as you are currently filling your linux-can git repo, please take care of this (stable) patch too.

done

Quoted 2 lines

Do you think that these two patches below should be integrated into a net pull?

"net" or "net-next"?

Quoted 2 lines

[can-next v2] can: proc: remove pointers from CAN specific proc output
https://lore.kernel.org/linux-can/[email protected]/

I've replied to that mail with some formatting nitpicks.

Quoted 2 lines

[can-next] can: remove Softing CANcard driver
https://lore.kernel.org/linux-can/[email protected]/

-> net-next material.

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 |

author maintainer
#5 lore raw

Hi Sebastian,

Quoted 8 lines · Marc Kleine-Budde

On 25.08.2026 16:55:39, Oliver Hartkopp wrote:

"net" or "net-next"?

Quoted 2 lines

[can-next v2] can: proc: remove pointers from CAN specific proc output
https://lore.kernel.org/linux-can/[email protected]/

what's your plan with your other %ps and pointer hiding changes?

Are you going for 7.3 or -next ?

Best regards,
Oliver

#6 lore raw
Quoted 1 line · Oliver Hartkopp

Hi Sebastian,

Hi,

Quoted 12 lines · Marc Kleine-Budde
Quoted 8 lines · Oliver Hartkopp

"net" or "net-next"?

Quoted 2 lines

[can-next v2] can: proc: remove pointers from CAN specific proc output
https://lore.kernel.org/linux-can/[email protected]/

what's your plan with your other %ps and pointer hiding changes?

Are you going for 7.3 or -next ?

-next, https://lore.kernel.org/all/[email protected]/

Quoted 2 lines

Best regards,
Oliver

Sebastian