Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/3] pull-request: can 2026-10-01
@ 2026-10-01 15:14 Marc Kleine-Budde
  2026-10-01 15:14 ` [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization Marc Kleine-Budde
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Marc Kleine-Budde @ 2026-10-01 15:14 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuba, linux-can, kernel

Hello netdev-team,

this is a pull request of 3 patches for net/main.

The first patch is by zjamg and restores the skb header initialization
lost during the v7.0 release cycle.

Oliver Hartkopp contributes a patch for the CAN net layer to fix the
unique skb identifier regression under RPS, introduced in the v7.0
release cycle, which causes lost packets.

The last patch is by Ji-Ze Hong and fixes a struct size mismatch in
the f81604 CAN driver, which results in a TX starvation.

regards,
Marc

---

The following changes since commit e23a64eb244356ee47c0620f0722d51bd88db522:

  Merge tag 'nf-26-09-30' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf (2026-10-01 12:00:40 +0200)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git tags/linux-can-fixes-for-7.3-20261001

for you to fetch changes up to 7f85d1170575645f9f327062d78017a23b2714eb:

  usb: f81604: fix struct f81604_int_data size mismatch (2026-10-01 17:13:12 +0200)

----------------------------------------------------------------
linux-can-fixes-for-7.3-20261001

----------------------------------------------------------------
Ji-Ze Hong (Peter Hong) (1):
      usb: f81604: fix struct f81604_int_data size mismatch

Oliver Hartkopp (1):
      can: fix unique skb identifier regression under RPS

zjamg (1):
      can: dev: init_can_skb(): restore skb header initialization

 drivers/net/can/dev/skb.c    |  4 ++++
 drivers/net/can/usb/f81604.c |  2 +-
 drivers/net/can/vxcan.c      |  3 +++
 include/linux/can/core.h     |  3 ++-
 include/linux/can/skb.h      |  4 +++-
 include/net/can.h            |  2 ++
 net/can/af_can.c             | 47 +++++++++++++++++++++++++++++++++-----------
 net/can/gw.c                 |  3 +++
 net/can/isotp.c              | 16 +++++++++------
 net/can/raw.c                | 10 +++++++---
 10 files changed, 71 insertions(+), 23 deletions(-)

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

* [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization
  2026-10-01 15:14 [PATCH net 0/3] pull-request: can 2026-10-01 Marc Kleine-Budde
@ 2026-10-01 15:14 ` Marc Kleine-Budde
  2026-10-07  1:20   ` patchwork-bot+netdevbpf
  2026-10-01 15:14 ` [PATCH net 2/3] can: fix unique skb identifier regression under RPS Marc Kleine-Budde
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Marc Kleine-Budde @ 2026-10-01 15:14 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, zjamg, stable, Oliver Hartkopp,
	Quchaosheng, Shaunak Datar, Marc Kleine-Budde

From: zjamg <ndaugoing@gmail.com>

Commit 9f10374bb024 ("can: remove private CAN skb headroom infrastructure")
removed the skb_reset_mac_header()/skb_reset_network_header()/
skb_reset_transport_header() calls from init_can_skb(). As a result, RX
skbs from alloc_can_skb() and friends again carry mac_header = 0xFFFF.
When such an skb reaches packet_rcv_spkt() (SOCK_PACKET), the push length
calculation overflows and triggers skb_under_panic -> kernel BUG -> full
machine panic.

The same issue was originally reported in 2014 on linux-can and fixed by
commit 969439016d2c ("can: add missing initialisations in CAN related
skbuffs"). packet_rcv_spkt() itself has never been hardened: only
packet_rcv() and tpacket_rcv() gained dev_has_header() checks in
commit d549699048b4 ("net/packet: fix packet receive on L3 devices
without visible hard header").

Fixes: 9f10374bb024 ("can: remove private CAN skb headroom infrastructure")
Cc: stable@vger.kernel.org
Reviewed-by: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: zjamg <ndaugoing@gmail.com>
Tested-by: Quchaosheng <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20260917123716.63116-1-ndaugoing@gmail.com
Reported-by: Shaunak Datar <shaunakkdatar@gmail.com>
Closes: https://lore.kernel.org/all/20260918151606.765490-1-shaunakkdatar@gmail.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/dev/skb.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 95fcdc1026f8..14edec5afb57 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -210,6 +210,10 @@ static void init_can_skb(struct sk_buff *skb)
 {
 	skb->pkt_type = PACKET_BROADCAST;
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
 }
 
 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)

base-commit: e23a64eb244356ee47c0620f0722d51bd88db522
-- 
2.53.0


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

* [PATCH net 2/3] can: fix unique skb identifier regression under RPS
  2026-10-01 15:14 [PATCH net 0/3] pull-request: can 2026-10-01 Marc Kleine-Budde
  2026-10-01 15:14 ` [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization Marc Kleine-Budde
@ 2026-10-01 15:14 ` Marc Kleine-Budde
  2026-10-01 15:14 ` [PATCH net 3/3] usb: f81604: fix struct f81604_int_data size mismatch Marc Kleine-Budde
  2026-10-02  7:55 ` [PATCH net 0/3] pull-request: can 2026-10-01 Paolo Abeni
  3 siblings, 0 replies; 7+ messages in thread
From: Marc Kleine-Budde @ 2026-10-01 15:14 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, Joerg Willmann,
	stable, Marc Kleine-Budde

From: Oliver Hartkopp <socketcan@hartkopp.net>

Commit d4fb6514ff8e ("can: use skb hash instead of private variable in
headroom") moved the per-skb unique identifier used for raw_rcv()
duplicate detection into skb->hash.

With RPS enabled, get_rps_cpu() calls skb_get_hash() before the frame
reaches the CAN subsystem. Since CAN skbs have no L3/L4 headers, the
flow dissector assigns every CAN frame the same non-zero software
hash. can_set_skb_uid() only generated a new identifier when
skb->hash was 0, so it kept this constant hash. When the SLAB
allocator later reused the same skb address, raw_rcv() mistook the
next legitimate frame for a duplicate and dropped it.

Fix this by storing the CAN UID in the CAN skb extension
(struct can_skb_ext::can_skb_uid) instead of skb->hash, decoupling it
from any hash the network stack may compute. can_set_skb_uid() keeps
its "assign only if unset" behaviour, which preserves UIDs set before
transmission (e.g. by isotp to identify echo frames) across the local
loopback path.

Frames whose extension is shared with another clone (e.g. via tc mirred
or netem duplicate) are given a private extension copy before the UID
is assigned, so that independently received skb clones from real CAN
interfaces (can_skb_uid = 0) don't end up with the same UID.
The limitation that tc mirred/netem skb duplicates might be dropped in
raw_rcv for looped back isotp echo frame skbs is accepted. There is no
valid use-case for tc mirred or netem together with isotp which is not
capable to operate on different CAN interfaces simultaneously.
For routing and modifying CAN frames together with isotp use can-gw.

can-gw and vxcan additionally clear the UID of forwarded/duplicated
frames so each newly routed frame gets its own unique identifier.

Fixes: d4fb6514ff8e ("can: use skb hash instead of private variable in headroom")
Reported-by: Joerg Willmann <joe@clnt.de>
Closes: https://lore.kernel.org/linux-can/2859AD3D-C805-41A0-9036-C5E8EE152419@clnt.de/
Cc: stable@vger.kernel.org
Tested-by: Oliver Hartkopp <socketcan@hartkopp.net>
Tested-by: Joerg Willmann <joe@clnt.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261001115724.27192-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/vxcan.c  |  3 +++
 include/linux/can/core.h |  3 ++-
 include/linux/can/skb.h  |  4 +++-
 include/net/can.h        |  2 ++
 net/can/af_can.c         | 47 ++++++++++++++++++++++++++++++----------
 net/can/gw.c             |  3 +++
 net/can/isotp.c          | 16 +++++++++-----
 net/can/raw.c            | 10 ++++++---
 8 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
index 9e2e25d02471..51148a81d1d9 100644
--- a/drivers/net/can/vxcan.c
+++ b/drivers/net/can/vxcan.c
@@ -79,6 +79,9 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
 
 	/* reset CAN GW hop counter */
 	csx->can_gw_hops = 0;
+	/* start with new CAN skb UID in the other namespace */
+	csx->can_skb_uid = 0;
+
 	skb->pkt_type   = PACKET_BROADCAST;
 	skb->dev        = peer;
 	skb->ip_summed  = CHECKSUM_UNNECESSARY;
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 3287232e3cad..2de74c2b78b6 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -17,6 +17,7 @@
 #include <linux/can.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <net/can.h>
 
 #define DNAME(dev) ((dev) ? (dev)->name : "any")
 
@@ -58,7 +59,7 @@ extern void can_rx_unregister(struct net *net, struct net_device *dev,
 			      void *data);
 
 extern int can_send(struct sk_buff *skb, int loop);
-void can_set_skb_uid(struct sk_buff *skb);
+void can_set_skb_uid(struct can_skb_ext *csx);
 void can_sock_destruct(struct sock *sk);
 
 #endif /* !_CAN_CORE_H */
diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
index a70a02967071..5d27843862fc 100644
--- a/include/linux/can/skb.h
+++ b/include/linux/can/skb.h
@@ -43,8 +43,10 @@ static inline struct can_skb_ext *can_skb_ext_add(struct sk_buff *skb)
 	struct can_skb_ext *csx = skb_ext_add(skb, SKB_EXT_CAN);
 
 	/* skb_ext_add() returns uninitialized space */
-	if (csx)
+	if (csx) {
 		csx->can_gw_hops = 0;
+		csx->can_skb_uid = 0;
+	}
 
 	return csx;
 }
diff --git a/include/net/can.h b/include/net/can.h
index 6db9e826f0e0..2b8af2598732 100644
--- a/include/net/can.h
+++ b/include/net/can.h
@@ -17,12 +17,14 @@
  * @can_framelen: cached echo CAN frame length for bql
  * @can_gw_hops: can-gw CAN frame time-to-live counter
  * @can_ext_flags: CAN skb extensions flags
+ * @can_skb_uid: CAN skb UID for raw_rcv and isotp echo handling
  */
 struct can_skb_ext {
 	int	can_iif;
 	u16	can_framelen;
 	u8	can_gw_hops;
 	u8	can_ext_flags;
+	u32	can_skb_uid;
 };
 
 #endif /* _NET_CAN_H */
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 7bc86b176b4d..34fe3b28d576 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -641,13 +641,10 @@ static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buf
 	return matches;
 }
 
-void can_set_skb_uid(struct sk_buff *skb)
+void can_set_skb_uid(struct can_skb_ext *csx)
 {
-	/* create non-zero unique skb identifier together with *skb */
-	while (!(skb->hash))
-		skb->hash = atomic_inc_return(&skbcounter);
-
-	skb->sw_hash = 1;
+	while (!(csx->can_skb_uid))
+		csx->can_skb_uid = atomic_inc_return(&skbcounter);
 }
 EXPORT_SYMBOL(can_set_skb_uid);
 
@@ -662,8 +659,6 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
 	atomic_long_inc(&pkg_stats->rx_frames);
 	atomic_long_inc(&pkg_stats->rx_frames_delta);
 
-	can_set_skb_uid(skb);
-
 	rcu_read_lock();
 
 	/* deliver the packet to sockets listening on all devices */
@@ -687,8 +682,10 @@ 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)
 {
+	struct can_skb_ext *csx = can_skb_ext_find(skb);
+
 	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
-		     !can_skb_ext_find(skb) || !can_is_can_skb(skb))) {
+		     !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);
 
@@ -696,6 +693,14 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
 		return NET_RX_DROP;
 	}
 
+	/* create unshared CAN skb_extension for netem/mirred skb clones */
+	csx = skb_ext_add(skb, SKB_EXT_CAN);
+	if (unlikely(!csx)) {
+		kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM);
+		return NET_RX_DROP;
+	}
+
+	can_set_skb_uid(csx);
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
 }
@@ -703,8 +708,10 @@ 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)
 {
+	struct can_skb_ext *csx = can_skb_ext_find(skb);
+
 	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
-		     !can_skb_ext_find(skb) || !can_is_canfd_skb(skb))) {
+		     !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);
 
@@ -712,6 +719,14 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
 		return NET_RX_DROP;
 	}
 
+	/* create unshared CAN skb_extension for netem/mirred skb clones */
+	csx = skb_ext_add(skb, SKB_EXT_CAN);
+	if (unlikely(!csx)) {
+		kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM);
+		return NET_RX_DROP;
+	}
+
+	can_set_skb_uid(csx);
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
 }
@@ -719,8 +734,10 @@ 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)
 {
+	struct can_skb_ext *csx = can_skb_ext_find(skb);
+
 	if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
-		     !can_skb_ext_find(skb) || !can_is_canxl_skb(skb))) {
+		     !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);
 
@@ -728,6 +745,14 @@ static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
 		return NET_RX_DROP;
 	}
 
+	/* create unshared CAN skb_extension for netem/mirred skb clones */
+	csx = skb_ext_add(skb, SKB_EXT_CAN);
+	if (unlikely(!csx)) {
+		kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM);
+		return NET_RX_DROP;
+	}
+
+	can_set_skb_uid(csx);
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
 }
diff --git a/net/can/gw.c b/net/can/gw.c
index 0ec99f68aa45..5793cb2420ed 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -527,6 +527,9 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
 	/* put the incremented hop counter in the cloned skb */
 	ncsx->can_gw_hops = csx->can_gw_hops + 1;
 
+	/* force a new CAN UID generation for the routed frame */
+	ncsx->can_skb_uid = 0;
+
 	/* first processing of this CAN frame -> adjust to private hop limit */
 	if (gwj->limit_hops && ncsx->can_gw_hops == 1)
 		ncsx->can_gw_hops = max_hops - gwj->limit_hops + 1;
diff --git a/net/can/isotp.c b/net/can/isotp.c
index 155530aedce2..f5dc9d04bd68 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -891,7 +891,7 @@ static void isotp_send_cframe(struct isotp_sock *so)
 	csx->can_iif = dev->ifindex;
 
 	/* set uid in tx skb to identify CF echo frames */
-	can_set_skb_uid(skb);
+	can_set_skb_uid(csx);
 
 	cf = (struct canfd_frame *)skb->data;
 	skb_put_zero(skb, so->ll.mtu);
@@ -917,7 +917,7 @@ static void isotp_send_cframe(struct isotp_sock *so)
 		pr_notice_once("can-isotp: cfecho is %08X != 0\n", old_cfecho);
 
 	/* set consecutive frame echo tag */
-	WRITE_ONCE(so->cfecho, skb->hash);
+	WRITE_ONCE(so->cfecho, csx->can_skb_uid);
 
 	/* send frame with local echo enabled */
 	can_send_ret = can_send(skb, 1);
@@ -969,18 +969,22 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
 {
 	struct sock *sk = (struct sock *)data;
 	struct isotp_sock *so = isotp_sk(sk);
+	struct can_skb_ext *csx = can_skb_ext_find(skb);
 
 	/* only handle my own local echo CF/SF skb's (no FF!) */
 	if (skb->sk != sk)
 		return;
 
+	if (WARN_ON_ONCE(!csx))
+		return;
+
 	/* unlike isotp_rcv_fc()/isotp_rcv_cf(), not already under so->rx_lock
 	 * (no isotp_rcv() caller here), so take it ourselves
 	 */
 	spin_lock(&so->rx_lock);
 
 	/* so->cfecho may since belong to a new transfer; recheck under lock */
-	if (READ_ONCE(so->cfecho) != skb->hash)
+	if (READ_ONCE(so->cfecho) != csx->can_skb_uid)
 		goto out_unlock;
 
 	/* cancel local echo timeout */
@@ -1222,7 +1226,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 	csx->can_iif = dev->ifindex;
 
 	/* set uid in tx skb to identify CF echo frames */
-	can_set_skb_uid(skb);
+	can_set_skb_uid(csx);
 
 	so->tx.len = size;
 	so->tx.idx = 0;
@@ -1261,7 +1265,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 			cf->data[ae] |= size;
 
 		/* set CF echo tag for isotp_rcv_echo() (SF-mode) */
-		WRITE_ONCE(so->cfecho, skb->hash);
+		WRITE_ONCE(so->cfecho, csx->can_skb_uid);
 	} else {
 		/* send first frame */
 
@@ -1278,7 +1282,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 			so->txfc.bs = 0;
 
 			/* set CF echo tag for isotp_rcv_echo() (CF-mode) */
-			WRITE_ONCE(so->cfecho, skb->hash);
+			WRITE_ONCE(so->cfecho, csx->can_skb_uid);
 		} else {
 			/* standard flow control check */
 			new_state = ISOTP_WAIT_FIRST_FC;
diff --git a/net/can/raw.c b/net/can/raw.c
index 82d9c0499c95..0acd4f6c6dd6 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -77,7 +77,7 @@ MODULE_ALIAS("can-proto-1");
 
 struct uniqframe {
 	const struct sk_buff *skb;
-	u32 hash;
+	u32 can_skb_uid;
 	unsigned int join_rx_count;
 };
 
@@ -133,12 +133,16 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 	enum skb_drop_reason reason;
 	struct sockaddr_can *addr;
 	struct sk_buff *skb;
+	struct can_skb_ext *csx = can_skb_ext_find(oskb);
 	unsigned int *pflags;
 
 	/* check the received tx sock reference */
 	if (!ro->recv_own_msgs && oskb->sk == sk)
 		return;
 
+	if (WARN_ON_ONCE(!csx))
+		return;
+
 	/* make sure to not pass oversized frames to the socket */
 	if (!ro->fd_frames && can_is_canfd_skb(oskb))
 		return;
@@ -165,7 +169,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 
 	/* eliminate multiple filter matches for the same skb */
 	if (this_cpu_ptr(ro->uniq)->skb == oskb &&
-	    this_cpu_ptr(ro->uniq)->hash == oskb->hash) {
+	    this_cpu_ptr(ro->uniq)->can_skb_uid == csx->can_skb_uid) {
 		if (!ro->join_filters)
 			return;
 
@@ -175,7 +179,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 			return;
 	} else {
 		this_cpu_ptr(ro->uniq)->skb = oskb;
-		this_cpu_ptr(ro->uniq)->hash = oskb->hash;
+		this_cpu_ptr(ro->uniq)->can_skb_uid = csx->can_skb_uid;
 		this_cpu_ptr(ro->uniq)->join_rx_count = 1;
 		/* drop first frame to check all enabled filters? */
 		if (ro->join_filters && ro->count > 1)
-- 
2.53.0


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

* [PATCH net 3/3] usb: f81604: fix struct f81604_int_data size mismatch
  2026-10-01 15:14 [PATCH net 0/3] pull-request: can 2026-10-01 Marc Kleine-Budde
  2026-10-01 15:14 ` [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization Marc Kleine-Budde
  2026-10-01 15:14 ` [PATCH net 2/3] can: fix unique skb identifier regression under RPS Marc Kleine-Budde
@ 2026-10-01 15:14 ` Marc Kleine-Budde
  2026-10-05  9:30   ` Marc Kleine-Budde
  2026-10-02  7:55 ` [PATCH net 0/3] pull-request: can 2026-10-01 Paolo Abeni
  3 siblings, 1 reply; 7+ messages in thread
From: Marc Kleine-Budde @ 2026-10-01 15:14 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Ji-Ze Hong (Peter Hong), stable,
	Dynetrex, Admin, Greg Kroah-Hartman, Drew Willey,
	Marc Kleine-Budde

From: "Ji-Ze Hong (Peter Hong)" <peter_hong@fintek.com.tw>

The struct f81604_int_data defines 9 bytes of interrupt data:
- Byte 0: Status register (sr)
- Byte 1: Interrupt register (isrc)
- Byte 2: Interrupt enable register (ier)
- Byte 3: Arbitration lost capture (alc)
- Byte 4: Error code capture (ecc)
- Byte 5: Error warning limit register (ewlr)
- Byte 6: RX error counter (rxerr)
- Byte 7: TX error counter (txerr)
- Byte 8: Reserved (val)

The hardware sends exactly 9 bytes for the interrupt endpoint.
However, the struct was defined with __aligned(4) attribute which
caused the compiler to pad the struct to 12 bytes.

This causes a problem in f81604_read_int_callback() where the short
URB check compares urb->actual_length against sizeof(*data). When
sizeof(struct f81604_int_data) is 12 but the hardware only sends 9
bytes, the check fails and valid interrupt messages are discarded.

This results in the driver only being able to transmit once because
the TX complete interrupt is never processed.

Fix this by removing the __aligned(4) attribute so the struct size
matches the actual hardware data size of 9 bytes.

Fixes: 7299b1b39a25 ("can: usb: f81604: handle short interrupt urb messages properly")
Cc: stable@vger.kernel.org
Reported-by: Dynetrex, Admin <admin@dynetrex.com>
Closes: https://lore.kernel.org/all/A3834A07-5639-4779-844F-C5843DFC3928@dynetrex.com/
Signed-off-by: Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Tested-by: Drew Willey <dwilley@google.com>
Link: https://patch.msgid.link/20260824-f81604-fix-v2-1-fc9be5581394@fintek.com.tw
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/usb/f81604.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
index f12318268e46..4c147b9d6d69 100644
--- a/drivers/net/can/usb/f81604.c
+++ b/drivers/net/can/usb/f81604.c
@@ -169,7 +169,7 @@ struct f81604_int_data {
 	u8 rxerr;
 	u8 txerr;
 	u8 val;
-} __packed __aligned(4);
+} __packed;
 
 struct f81604_sff {
 	__be16 id;
-- 
2.53.0


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

* Re: [PATCH net 0/3] pull-request: can 2026-10-01
  2026-10-01 15:14 [PATCH net 0/3] pull-request: can 2026-10-01 Marc Kleine-Budde
                   ` (2 preceding siblings ...)
  2026-10-01 15:14 ` [PATCH net 3/3] usb: f81604: fix struct f81604_int_data size mismatch Marc Kleine-Budde
@ 2026-10-02  7:55 ` Paolo Abeni
  3 siblings, 0 replies; 7+ messages in thread
From: Paolo Abeni @ 2026-10-02  7:55 UTC (permalink / raw)
  To: Marc Kleine-Budde, netdev; +Cc: davem, kuba, linux-can, kernel

On 10/1/26 17:14, Marc Kleine-Budde wrote:
> this is a pull request of 3 patches for net/main.
> 
> The first patch is by zjamg and restores the skb header initialization
> lost during the v7.0 release cycle.
> 
> Oliver Hartkopp contributes a patch for the CAN net layer to fix the
> unique skb identifier regression under RPS, introduced in the v7.0
> release cycle, which causes lost packets.
> 
> The last patch is by Ji-Ze Hong and fixes a struct size mismatch in
> the f81604 CAN driver, which results in a TX starvation.
FTR, I appreciated a lot the effort in keeping this to the bare
minimum.

Many thanks,

Paolo


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

* Re: [PATCH net 3/3] usb: f81604: fix struct f81604_int_data size mismatch
  2026-10-01 15:14 ` [PATCH net 3/3] usb: f81604: fix struct f81604_int_data size mismatch Marc Kleine-Budde
@ 2026-10-05  9:30   ` Marc Kleine-Budde
  0 siblings, 0 replies; 7+ messages in thread
From: Marc Kleine-Budde @ 2026-10-05  9:30 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, linux-can, kernel, Ji-Ze Hong (Peter Hong), stable,
	Dynetrex, Admin, Greg Kroah-Hartman, Drew Willey

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

On 01.10.2026 17:14:25, Marc Kleine-Budde wrote:
> From: "Ji-Ze Hong (Peter Hong)" <peter_hong@fintek.com.tw>
>
> The struct f81604_int_data defines 9 bytes of interrupt data:
> - Byte 0: Status register (sr)
> - Byte 1: Interrupt register (isrc)
> - Byte 2: Interrupt enable register (ier)
> - Byte 3: Arbitration lost capture (alc)
> - Byte 4: Error code capture (ecc)
> - Byte 5: Error warning limit register (ewlr)
> - Byte 6: RX error counter (rxerr)
> - Byte 7: TX error counter (txerr)
> - Byte 8: Reserved (val)
>
> The hardware sends exactly 9 bytes for the interrupt endpoint.
> However, the struct was defined with __aligned(4) attribute which
> caused the compiler to pad the struct to 12 bytes.
>
> This causes a problem in f81604_read_int_callback() where the short
> URB check compares urb->actual_length against sizeof(*data). When
> sizeof(struct f81604_int_data) is 12 but the hardware only sends 9
> bytes, the check fails and valid interrupt messages are discarded.
>
> This results in the driver only being able to transmit once because
> the TX complete interrupt is never processed.
>
> Fix this by removing the __aligned(4) attribute so the struct size
> matches the actual hardware data size of 9 bytes.
>
> Fixes: 7299b1b39a25 ("can: usb: f81604: handle short interrupt urb messages properly")
> Cc: stable@vger.kernel.org
> Reported-by: Dynetrex, Admin <admin@dynetrex.com>
> Closes: https://lore.kernel.org/all/A3834A07-5639-4779-844F-C5843DFC3928@dynetrex.com/
> Signed-off-by: Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Tested-by: Drew Willey <dwilley@google.com>
> Link: https://patch.msgid.link/20260824-f81604-fix-v2-1-fc9be5581394@fintek.com.tw
> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

The netdev bots have found a "high" severity, which is a preexisting
issue, but not clearly flagged as such.

https://netdev-ai.bots.linux.dev/sashiko/#inline-kq9vc8hku

| Consequence: use-after-free of the freed netdev private data and of the
| embedded work_struct, which can corrupt memory or oops in the workqueue.
|
| Triggering path: interface up with CAN bus errors, arbitration loss or
| overruns (so clear_flags gets set) -> driver unbind, rmmod or disconnect
| -> unregister_netdev() -> f81604_close() -> cancel_work_sync() returns
| -> an interrupt URB completion in flight before usb_kill_anchored_urbs()
| calls f81604_handle_can_bus_errors() -> schedule_work() -> close returns
| -> free_candev() -> f81604_clear_reg_work() runs on freed memory. I
| checked that nothing between line 1078 and the free in
| f81604_disconnect() drains this work: close_candev() and
| usb_kill_anchored_urbs() do not flush it, and disconnect only calls
| unregister_netdev() and free_candev().
|
| Reachability: the race window is short, and triggering it needs
| privileged unbind or physical disconnect while bus errors are occurring.
| So it rates High rather than Critical, though the consequence is memory
| corruption. Pre-existing: git blame attributes f81604_close() entirely
| to 88da17436973. This patch does not add the ordering, but it re-enables
| the only producer of the work, which had been dead code since
| 7299b1b39a25. The commit message neither claims to fix this nor depends
| on it.

We have a patch for it pending, but not included in the PR, to keep it
to the absolute minimum.

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] 7+ messages in thread

* Re: [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization
  2026-10-01 15:14 ` [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization Marc Kleine-Budde
@ 2026-10-07  1:20   ` patchwork-bot+netdevbpf
  0 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-10-07  1:20 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: netdev, davem, kuba, linux-can, kernel, ndaugoing, stable,
	socketcan, quchaosheng000406, shaunakkdatar

Hello:

This series was applied to netdev/net.git (main)
by Marc Kleine-Budde <mkl@pengutronix.de>:

On Thu,  1 Oct 2026 17:14:23 +0200 you wrote:
> From: zjamg <ndaugoing@gmail.com>
> 
> Commit 9f10374bb024 ("can: remove private CAN skb headroom infrastructure")
> removed the skb_reset_mac_header()/skb_reset_network_header()/
> skb_reset_transport_header() calls from init_can_skb(). As a result, RX
> skbs from alloc_can_skb() and friends again carry mac_header = 0xFFFF.
> When such an skb reaches packet_rcv_spkt() (SOCK_PACKET), the push length
> calculation overflows and triggers skb_under_panic -> kernel BUG -> full
> machine panic.
> 
> [...]

Here is the summary with links:
  - [net,1/3] can: dev: init_can_skb(): restore skb header initialization
    https://git.kernel.org/netdev/net/c/0a04c0cb8606
  - [net,2/3] can: fix unique skb identifier regression under RPS
    https://git.kernel.org/netdev/net/c/7093c3b8314a
  - [net,3/3] usb: f81604: fix struct f81604_int_data size mismatch
    https://git.kernel.org/netdev/net/c/7f85d1170575

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2026-10-07  1:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-01 15:14 [PATCH net 0/3] pull-request: can 2026-10-01 Marc Kleine-Budde
2026-10-01 15:14 ` [PATCH net 1/3] can: dev: init_can_skb(): restore skb header initialization Marc Kleine-Budde
2026-10-07  1:20   ` patchwork-bot+netdevbpf
2026-10-01 15:14 ` [PATCH net 2/3] can: fix unique skb identifier regression under RPS Marc Kleine-Budde
2026-10-01 15:14 ` [PATCH net 3/3] usb: f81604: fix struct f81604_int_data size mismatch Marc Kleine-Budde
2026-10-05  9:30   ` Marc Kleine-Budde
2026-10-02  7:55 ` [PATCH net 0/3] pull-request: can 2026-10-01 Paolo Abeni

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