From: Sasha Levin Date: Sat, 13 Jun 2026 12:23:35 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=902ac0964ffc5749de62ed68a093c528329de659;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-5.10/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..a980985b8b --- /dev/null +++ b/queue-5.10/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From d7db62891616fca8cbf86b39553cec4fce195f99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index 241e5191f43c15..e471a5821b0de5 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -105,6 +105,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -112,6 +113,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-5.10/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-5.10/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..be38a3631c --- /dev/null +++ b/queue-5.10/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From 4779f49fbd08993627b7a084cb433d199a07abb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 9806bd56b95f12..387b48ba4aac71 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -964,6 +964,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-5.10/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-5.10/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..8c94187a73 --- /dev/null +++ b/queue-5.10/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From ec9b38617987261e634b36d1141217443774a149 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 4e5386cdb09cd5..f0e391afb511d2 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1779,6 +1779,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index f7100f5af37ca7..b2cd853ecb7e7b 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4633,7 +4633,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -4642,8 +4642,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index 2a48aa89c035b6..d105beeb15e118 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -740,12 +740,13 @@ EXPORT_SYMBOL(kernel_sendmsg_locked); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-5.10/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-5.10/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..b836c2c217 --- /dev/null +++ b/queue-5.10/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From 50826ba8a003340e7f6cd5f3a45f0f76c7f37645 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index e4e80c2b1ce400..6d672afc73d500 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3588,9 +3588,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-5.10/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-5.10/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..606d7eec1b --- /dev/null +++ b/queue-5.10/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From 85949cef1cfe4c6d979a696417e34af79dbdd9ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 1c69aa986633af..5fb74fbcb2f382 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1248,6 +1248,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-5.10/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-5.10/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..b245cfffd2 --- /dev/null +++ b/queue-5.10/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From 7c5728490616aa7ba54fbca3e7c6aaa1723e37d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index fdb7a5a12f0358..fb0398903e4f36 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -701,13 +701,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-5.10/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-5.10/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..d2420beadf --- /dev/null +++ b/queue-5.10/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From 68ed42e17436571b7eaa176efb626ae184e75db4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index 92b4a8689aae7a..6c20526f71a1e2 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-5.10/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..c3dbb55c8d --- /dev/null +++ b/queue-5.10/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From efe34074cd484539e65fd5ca60b1073778a0ee96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index 5bde436b875485..be8ff8b5355721 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -454,6 +454,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-5.10/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..9f32f535e8 --- /dev/null +++ b/queue-5.10/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From 3145492aabee802c365769d1761df28c6947915b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index d5f3b6260da0cf..bc8a5b6eccc336 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -701,14 +701,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1326,9 +1324,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 22e9ff592cd75f..55798e12fb3745 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -833,14 +833,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1229,9 +1227,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index df7cd3d285e4f0..da136d25701a9e 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -850,14 +850,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1246,9 +1244,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-5.10/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-5.10/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..703fb9c671 --- /dev/null +++ b/queue-5.10/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From 7b3200b343e5c199b0290fe018158edc4d414ce6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index 3049fff0b7f864..7bfccedbffe5aa 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -766,24 +766,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-5.10/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-5.10/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..99c8e5e6a0 --- /dev/null +++ b/queue-5.10/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From 292e4623e2cb91973d222968c0420b92d4bb6067 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index b6b46a8214a0a5..b3ee5f8238c44d 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-5.10/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-5.10/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..048bb25ad1 --- /dev/null +++ b/queue-5.10/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From 3339fec14802e88725413a070f5c500ce8915672 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 079b1bfc7d3106..3c7761199f200b 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1172,6 +1172,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 35ec2ba6e0..c1fe0bdd77 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -162,3 +162,16 @@ tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch kvm-arm64-remove-vpipt-i-cache-handling.patch arm64-tlb-allow-xzr-argument-to-tlbi-ops.patch arm64-tlb-optimize-arm64_workaround_repeat_tlbi.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch diff --git a/queue-5.10/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-5.10/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..52629eace8 --- /dev/null +++ b/queue-5.10/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From 248f2e82958ac419b70e8412d131b08734b199a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 5bcc5642ccf067..e17faf51f32553 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1124,15 +1124,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1720,12 +1711,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 + diff --git a/queue-5.15/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-5.15/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..3122d99b6a --- /dev/null +++ b/queue-5.15/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From 0bced9baeb701c8ec86a4edc8867740dbcb6002c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index 4f5093b36b3e36..077aae4b1bb332 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -105,6 +105,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -112,6 +113,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-5.15/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-5.15/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..fe2dfc9369 --- /dev/null +++ b/queue-5.15/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From 1d42a4f815b49f74e2a7b06dd82f55430c056653 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 3bc02ab9ceaca0..bc5db4a9dbfaf1 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -971,6 +971,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-5.15/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-5.15/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..28da0a7e6d --- /dev/null +++ b/queue-5.15/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From 267c75b24337ced877d6fb15332581886a806600 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index ee9c398dd8f25e..962acf4a644da9 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1868,6 +1868,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index a8d09eff26f11c..1d3784480834bb 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4814,7 +4814,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -4823,8 +4823,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index f3d0a8d66cceee..cc7ba4702d1380 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -795,12 +795,13 @@ EXPORT_SYMBOL(kernel_sendmsg_locked); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-5.15/net-mvpp2-add-metadata-support-for-xdp-mode.patch b/queue-5.15/net-mvpp2-add-metadata-support-for-xdp-mode.patch new file mode 100644 index 0000000000..ce5b2d5db5 --- /dev/null +++ b/queue-5.15/net-mvpp2-add-metadata-support-for-xdp-mode.patch @@ -0,0 +1,81 @@ +From 71a7cd84bd6f6d79af00c3a4520663106210b96f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Mar 2025 12:46:06 +0100 +Subject: net: mvpp2: Add metadata support for xdp mode + +From: Lorenzo Bianconi + +[ Upstream commit 9a45e193c88a55a536d7fd0ebfa29823d588c2cf ] + +Set metadata size building the skb from xdp_buff in mvpp2 driver +mvpp2 driver sets xdp headroom to: + +MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM + +where + +MVPP2_MH_SIZE 2 +MVPP2_SKB_HEADROOM min(max(XDP_PACKET_HEADROOM, NET_SKB_PAD), 224) + +so the headroom is large enough to contain xdp_frame and xdp metadata. +Please note this patch is just compiled tested. + +Reviewed-by: Michal Kubiak +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20250318-mvneta-xdp-meta-v2-2-b6075778f61f@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index d8a2268b88187a..d55c3f1526c38b 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3912,13 +3912,13 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + while (rx_done < rx_todo) { + struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); ++ u32 rx_status, timestamp, metasize = 0; + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; + unsigned int frag_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- u32 rx_status, timestamp; + int pool, rx_bytes, err, ret; + struct page *page; + void *data; +@@ -3981,7 +3981,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, +- rx_bytes, false); ++ rx_bytes, true); + + ret = mvpp2_run_xdp(port, xdp_prog, &xdp, pp, &ps); + +@@ -3997,6 +3997,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_bytes += rx_bytes; + continue; + } ++ ++ metasize = xdp.data - xdp.data_meta; + } + + skb = build_skb(data, frag_size); +@@ -4033,6 +4035,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); + skb_put(skb, rx_bytes); ++ if (metasize) ++ skb_metadata_set(skb, metasize); + skb->ip_summed = mvpp2_rx_csum(port, rx_status); + skb->protocol = eth_type_trans(skb, dev); + +-- +2.53.0 + diff --git a/queue-5.15/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch b/queue-5.15/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch new file mode 100644 index 0000000000..b7555b277c --- /dev/null +++ b/queue-5.15/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch @@ -0,0 +1,106 @@ +From 61455619f170d82a8029b062f11cd1d5e3e4e088 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:43 +0200 +Subject: net: mvpp2: build skb from XDP-adjusted data on XDP_PASS + +From: Til Kaiser + +[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ] + +When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() +and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets +derived from the original RX descriptor. Packet geometry changes made by +the XDP program are therefore discarded before the skb reaches the stack. + +Update rx_offset and rx_bytes from xdp.data and xdp.data_end for +XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen +by XDP, and makes RX byte accounting for XDP_PASS follow the length of the +skb passed to the network stack. + +Keep a separate rx_sync_size for page-pool recycling on skb allocation +failure, which must stay tied to the received buffer range. + +Non-PASS verdicts continue to account the descriptor length because no skb +is passed up in those cases. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-5-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 04002548a46327..c4951eb88241b0 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3916,10 +3916,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; +- unsigned int frag_size; ++ unsigned int frag_size, rx_sync_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- int pool, rx_bytes, err, ret; ++ int pool, rx_bytes, rx_offset, err, ret; + struct page *page; + void *data; + +@@ -3932,6 +3932,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + rx_status = mvpp2_rxdesc_status_get(port, rx_desc); + rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc); + rx_bytes -= MVPP2_MH_SIZE; ++ rx_sync_size = rx_bytes + MVPP2_MH_SIZE; ++ rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM; + dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc); + + pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> +@@ -3947,7 +3949,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, + MVPP2_SKB_HEADROOM, +- rx_bytes + MVPP2_MH_SIZE, ++ rx_sync_size, + dma_dir); + + /* Buffer header not supported */ +@@ -3998,6 +4000,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + } + ++ rx_sync_size = max_t(unsigned int, rx_sync_size, ++ xdp.data_end - xdp.data_hard_start - ++ MVPP2_SKB_HEADROOM); ++ ++ /* Update offset and length to reflect any XDP adjustments. */ ++ rx_offset = xdp.data - data; ++ rx_bytes = xdp.data_end - xdp.data; ++ + metasize = xdp.data - xdp.data_meta; + } + +@@ -4006,8 +4016,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + netdev_warn(port->dev, "skb build failed\n"); + if (pp) { + page_pool_put_page(pp, virt_to_head_page(data), +- rx_bytes + MVPP2_MH_SIZE, +- true); ++ rx_sync_size, true); + } else { + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, +@@ -4037,7 +4046,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + +- skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); ++ skb_reserve(skb, rx_offset); + skb_put(skb, rx_bytes); + if (metasize) + skb_metadata_set(skb, metasize); +-- +2.53.0 + diff --git a/queue-5.15/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch b/queue-5.15/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch new file mode 100644 index 0000000000..450451e52c --- /dev/null +++ b/queue-5.15/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch @@ -0,0 +1,46 @@ +From a7374a3523c2b59d67825e86ffb4d4bbfbd87c6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:41 +0200 +Subject: net: mvpp2: limit XDP frame size to the RX buffer + +From: Til Kaiser + +[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ] + +mvpp2 has short and long BM pools, and short pool buffers can be smaller +than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with +PAGE_SIZE as frame size. + +XDP helpers use frame_sz to validate tail growth and to derive the hard +end of the data area. Advertising PAGE_SIZE for short buffers can let +bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting +memory or later tripping skb tailroom checks. + +Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches +the actual buffer backing the packet. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-3-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index ad6325c80f9868..d8a2268b88187a 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3978,7 +3978,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + xdp_rxq = &rxq->xdp_rxq_long; + +- xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq); ++ xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, + rx_bytes, false); +-- +2.53.0 + diff --git a/queue-5.15/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch b/queue-5.15/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch new file mode 100644 index 0000000000..ec24d4d729 --- /dev/null +++ b/queue-5.15/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch @@ -0,0 +1,126 @@ +From 140d90ef1f63f7f3f490323e8f4f44459212fe5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:42 +0200 +Subject: net: mvpp2: refill RX buffers before XDP or skb use + +From: Til Kaiser + +[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ] + +The RX error path returns the current descriptor buffer to the hardware +BM pool. That is only valid while the driver still owns the buffer. + +mvpp2_rx_refill() can fail after the current buffer has been handed to +XDP or attached to an skb. In those cases mvpp2_run_xdp() may have +recycled, redirected, or queued the page for XDP_TX, and an skb free also +retires the data buffer. Returning such a buffer to BM lets hardware DMA +into memory that is no longer owned by the RX ring. + +Refill the BM pool before handing the current buffer to XDP or to the +skb. If the allocation fails there, drop the packet and return the +still-owned current buffer to BM, preserving the pool depth. Once the +refill succeeds, later local drops retire/free the current buffer instead +of returning it to BM. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-4-mail@tk154.de +Signed-off-by: Paolo Abeni +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- + 1 file changed, 24 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index d55c3f1526c38b..04002548a46327 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3970,6 +3970,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + frag_size = bm_pool->frag_size; + ++ err = mvpp2_rx_refill(port, bm_pool, pp, pool); ++ if (err) { ++ netdev_err(port->dev, "failed to refill BM pools\n"); ++ goto err_drop_frame; ++ } ++ + if (xdp_prog) { + struct xdp_rxq_info *xdp_rxq; + +@@ -3987,12 +3993,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + if (ret) { + xdp_ret |= ret; +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- goto err_drop_frame; +- } +- + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + continue; +@@ -4004,8 +4004,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb = build_skb(data, frag_size); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); +- goto err_drop_frame; ++ if (pp) { ++ page_pool_put_page(pp, virt_to_head_page(data), ++ rx_bytes + MVPP2_MH_SIZE, ++ true); ++ } else { ++ dma_unmap_single_attrs(dev->dev.parent, dma_addr, ++ bm_pool->buf_size, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ mvpp2_frag_free(bm_pool, pp, data); ++ } ++ goto err_drop_frame_retired; + } ++ if (pp) ++ skb_mark_for_recycle(skb); + + /* If we have RX hardware timestamping enabled, grab the + * timestamp from the queue and convert. +@@ -4016,16 +4029,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb_hwtstamps(skb)); + } + +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- dev_kfree_skb_any(skb); +- goto err_drop_frame; +- } +- +- if (pp) +- skb_mark_for_recycle(skb); +- else ++ if (!pp) + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); +@@ -4044,13 +4048,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + + err_drop_frame: +- dev->stats.rx_errors++; +- mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + if (rx_status & MVPP2_RXD_BUF_HDR) + mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status); + else + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); ++err_drop_frame_retired: ++ dev->stats.rx_errors++; ++ mvpp2_rx_error(port, rx_desc); + } + + if (xdp_ret & MVPP2_XDP_REDIR) +-- +2.53.0 + diff --git a/queue-5.15/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-5.15/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..34831ff124 --- /dev/null +++ b/queue-5.15/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From 66e38a95cf22fb4e71c45cf03217a4766ef5d58f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index fdfdd55fdb1dcf..ad6325c80f9868 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3945,9 +3945,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-5.15/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-5.15/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..07b3a6535c --- /dev/null +++ b/queue-5.15/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From a4faecb8eb6c80d91a81fce3b764b9ab08b12b16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 16ee704bab04db..0202111cda3531 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1261,6 +1261,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-5.15/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-5.15/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..fe89e53d77 --- /dev/null +++ b/queue-5.15/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From 8f4d2989cbae29554c25cabdb0f015f8ef48f0c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index 431fd1f2b80c18..6f4b901afc330c 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -702,13 +702,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-5.15/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-5.15/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..2fd2b15a65 --- /dev/null +++ b/queue-5.15/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From ecbf267876e4dd48e30965ed4014312b4c8a4d53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index 4190b90ff3b18a..1909cd440a4b66 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nf_log-validate-mac-header-was-set-before-.patch b/queue-5.15/netfilter-nf_log-validate-mac-header-was-set-before-.patch new file mode 100644 index 0000000000..c39c1513aa --- /dev/null +++ b/queue-5.15/netfilter-nf_log-validate-mac-header-was-set-before-.patch @@ -0,0 +1,70 @@ +From b885b3d9b504d2d8f2b649cbb5499054775267d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:55:02 -0700 +Subject: netfilter: nf_log: validate MAC header was set before dumping it + +From: Xiang Mei + +[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ] + +The fallback path of dump_mac_header() guards the MAC header access +only with "skb->mac_header != skb->network_header", without checking +skb_mac_header_was_set(). When the MAC header is unset, mac_header is +0xffff, so the test passes and skb_mac_header(skb) returns +skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads +dev->hard_header_len bytes out of bounds into the kernel log. + +This is reachable via the netdev logger: nf_log_unknown_packet() calls +dump_mac_header() unconditionally, and an skb sent through AF_PACKET +with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still +unset (__dev_queue_xmit(), which would reset it, is bypassed). + +Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already +uses, and replace the open-coded MAC header length test with +skb_mac_header_len(). Only skbs with an unset MAC header are affected; +valid ones are dumped as before. + + BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) + Read of size 1 at addr ffff88800ea49d3f by task exploit/148 + Call Trace: + kasan_report (mm/kasan/report.c:595) + dump_mac_header (net/netfilter/nf_log_syslog.c:831) + nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) + nf_log_packet (net/netfilter/nf_log.c:260) + nft_log_eval (net/netfilter/nft_log.c:60) + nft_do_chain (net/netfilter/nf_tables_core.c:285) + nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) + nf_hook_slow (net/netfilter/core.c:619) + nf_hook_direct_egress (net/packet/af_packet.c:257) + packet_xmit (net/packet/af_packet.c:280) + packet_sendmsg (net/packet/af_packet.c:3114) + __sys_sendto (net/socket.c:2265) + +Fixes: 7eb9282cd0ef ("netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_log_syslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 7000e069bc0760..2b0edb22ba511b 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -793,8 +793,8 @@ static void dump_ipv4_mac_header(struct nf_log_buf *m, + + fallback: + nf_log_buf_add(m, "MAC="); +- if (dev->hard_header_len && +- skb->mac_header != skb->network_header) { ++ if (dev->hard_header_len && skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) != 0) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-5.15/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..bf11b7d6ed --- /dev/null +++ b/queue-5.15/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From 5441fe681499189272b2aa331798743770a78963 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index 7c2931e024bb05..e8978a0aa7408f 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -454,6 +454,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-5.15/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..a835940ac7 --- /dev/null +++ b/queue-5.15/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From d476e361edf80b4abe1bd3c335b2f148db253f47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 92bc90ee767484..2c39529769f19a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -701,14 +701,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1326,9 +1324,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index aee7cd584c9262..15a9e303a15317 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -833,14 +833,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1229,9 +1227,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index afd22ea9f555ba..f2de34f0de239c 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -850,14 +850,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1246,9 +1244,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-5.15/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-5.15/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..86b79607d1 --- /dev/null +++ b/queue-5.15/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From e54bf64f9c25d4ea7cbd93c65a4e5dc922425d29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index 566ba4397ee400..4c4b91ce446dfa 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -764,24 +764,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-5.15/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-5.15/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..478d2b6a45 --- /dev/null +++ b/queue-5.15/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From 9fc065cb461f330c97e2d33c0f96a35de41dd190 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index b6b46a8214a0a5..b3ee5f8238c44d 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-5.15/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-5.15/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..6505f51998 --- /dev/null +++ b/queue-5.15/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From a710c9f54c25cd74a2aa0a7b4e751a04679fbc6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 182898cb754a52..70530cbe57d0a7 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1197,6 +1197,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index d4012ed00d..bef20d9655 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -179,3 +179,21 @@ tun-free-page-on-build_skb-failure-in-tun_xdp_one.patch kvm-arm64-remove-vpipt-i-cache-handling.patch arm64-tlb-allow-xzr-argument-to-tlbi-ops.patch arm64-tlb-optimize-arm64_workaround_repeat_tlbi.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nf_log-validate-mac-header-was-set-before-.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch +net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch +net-mvpp2-add-metadata-support-for-xdp-mode.patch +net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch +net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch diff --git a/queue-5.15/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-5.15/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..0db7fec80d --- /dev/null +++ b/queue-5.15/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From 3db0021eb5bb898a520fc8d8c37cba8219be0d3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 6c52ba6cbb5b7e..d8348730e2d0e6 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1124,15 +1124,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1720,12 +1711,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 + diff --git a/queue-6.1/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch b/queue-6.1/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch new file mode 100644 index 0000000000..caf1dc99ad --- /dev/null +++ b/queue-6.1/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch @@ -0,0 +1,52 @@ +From 9fd752a8bc740a0a4ac0f9010065ff0030c9061c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:12:44 +0100 +Subject: ASoC: wm_adsp: Fix NULL dereference when removing firmware controls + +From: Richard Fitzgerald + +[ Upstream commit 7d3fb78b550301e43fdc60312aed733069694426 ] + +In wm_adsp_control_remove() check that the priv pointer is not NULL +before attempting to cleanup what it points to. + +When cs_dsp creates a control it calls wm_adsp_control_add_cb() so that +wm_adsp can create its own private control data. There are two cases +where private data is not created: + +1. The control is a SYSTEM control, so an ALSA control is not created. + +2. The codec driver has registered a control_add() callback that + hides the control, so wm_adsp_control_add() is not called. + +When cs_dsp_remove destroys its control list it calls +wm_adsp_control_remove() for each control. But wm_adsp_control_remove() +was attempting to cleanup the private data pointed to by cs_ctl->priv +without checking the pointer for NULL. + +Signed-off-by: Richard Fitzgerald +Fixes: 0700bc2fb94c ("ASoC: wm_adsp: Separate generic cs_dsp_coeff_ctl handling") +Link: https://patch.msgid.link/20260604101244.1402862-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wm_adsp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c +index 47a4c363227ccd..bc9798ea5a25e2 100644 +--- a/sound/soc/codecs/wm_adsp.c ++++ b/sound/soc/codecs/wm_adsp.c +@@ -666,6 +666,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) + { + struct wm_coeff_ctl *ctl = cs_ctl->priv; + ++ if (!ctl) ++ return; ++ + cancel_work_sync(&ctl->work); + + kfree(ctl->name); +-- +2.53.0 + diff --git a/queue-6.1/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch b/queue-6.1/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch new file mode 100644 index 0000000000..e22b1222f6 --- /dev/null +++ b/queue-6.1/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch @@ -0,0 +1,61 @@ +From eee00014b084e23b43276c79b649cfe10f5e49b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jun 2026 08:10:47 -0400 +Subject: iomap: don't revert iov_iter on partially completed buffered writes + +From: Brian Foster + +Gregg reports that the iomap retry behavior for nonblocking (nowait) +append writes is broken. The problem occurs when an append write is +first submitted in non-blocking mode (i.e. via io_uring), partially +completes before hitting -EAGAIN, and then is resubmitted from +blocking context. + +The specific problem is that at least one iteration of the loop in +iomap_write_iter() completes in non-blocking context and thus has +bumped i_size. The next iteration hits -EAGAIN, reverts the iov_iter +and returns. io_uring retries the entire append write from blocking +context, but since i_size has already been increased, the data that +was partially written on the first attempt is rewritten at the new +i_size. This is essentially an intra-write data corruption since the +data written to the file does not reflect the write from userspace. + +This problem is already fixed on master as of commit 1a1a3b574b97 +("iomap: advance the iter directly on buffered writes"). That commit +was primarily intended to clean up iomap iter state tracking, but it +also happened to remove the iov_iter revert and thus accidentally +fix this problem as well. Without the revert, iomap will commit +partial progress internally and loop once more before it more than +likely hits -EAGAIN and returns partial progress consistent with the +inode updates. This means the blocking retry from io_uring will pick +up where the first attempt left off at the current i_size and +perform the remainder of the write correctly. + +Cc: +Fixes: 18e419f6e80a ("iomap: Return -EAGAIN from iomap_write_iter()") +Reported-by: Gregg Leventhal +Reported-by: Eric Hagberg +Signed-off-by: Brian Foster +Signed-off-by: Sasha Levin +--- + fs/iomap/buffered-io.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index c3408ba636632a..243cb2ec76ed2e 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -821,10 +821,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) + length -= status; + } while (iov_iter_count(i) && length); + +- if (status == -EAGAIN) { +- iov_iter_revert(i, written); +- return -EAGAIN; +- } + return written ? written : status; + } + +-- +2.53.0 + diff --git a/queue-6.1/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-6.1/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..ada7bd2fa5 --- /dev/null +++ b/queue-6.1/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From c3461d0c67643eba2fb2fc290a1d4eb0fbd5674c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index ead8f1ecd8271b..8808067df5168c 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -105,6 +105,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -112,6 +113,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-6.1/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-6.1/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..e85b62b9b1 --- /dev/null +++ b/queue-6.1/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From e9e9067dfcd4f9247b7c3b5098e553ed6da206fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index eb4c8e2a2b12e0..aa88a41034d920 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -965,6 +965,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-6.1/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-6.1/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..b9f914bd53 --- /dev/null +++ b/queue-6.1/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From 5596e4c6b61d8c59ef1e9823b05b9b982bcaf653 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 2d34dd5941e795..1e7096e9bc4842 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1945,6 +1945,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index f1f5b2b25f8522..f41dd20991c3df 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4810,7 +4810,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -4819,8 +4819,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index 701389e2f22b3a..f2b4cf9b09a322 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -807,12 +807,13 @@ EXPORT_SYMBOL(kernel_sendmsg_locked); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-6.1/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch b/queue-6.1/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch new file mode 100644 index 0000000000..40c86818e9 --- /dev/null +++ b/queue-6.1/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch @@ -0,0 +1,61 @@ +From a88f4a07384e27b78fd94cc9719dd82c082c3b9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:10:44 +0800 +Subject: net/mlx4: avoid GCC 10 __bad_copy_from() false positive + +From: Yao Sang + +[ Upstream commit 2365343f4aad3e1b1e7a2e87e98cf66d5e590589 ] + +mlx4_init_user_cqes() fills a scratch buffer with the CQE +initialization pattern and then copies from that buffer to userspace. + +In the single-copy path, the copy length is array_size(entries, +cqe_size), but the scratch buffer is allocated with PAGE_SIZE. GCC 10 +does not carry the branch invariant strongly enough through the object +size checks and falsely triggers __bad_copy_from(). + +Size the scratch buffer to the actual copy length for the active path, +keep array_size() for the single-copy case, and retain a WARN_ON_ONCE() +guard for the PAGE_SIZE invariant before allocating the buffer. + +Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()") +Signed-off-by: Yao Sang +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx4/cq.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c +index 4d4f9cf9facb87..fb83d8af8dcb9c 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/cq.c ++++ b/drivers/net/ethernet/mellanox/mlx4/cq.c +@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) + static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + { + int entries_per_copy = PAGE_SIZE / cqe_size; ++ size_t copy_bytes; + void *init_ents; + int err = 0; + int i; +@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + buf += PAGE_SIZE; + } + } else { ++ copy_bytes = array_size(entries, cqe_size); ++ if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE)) { ++ err = -EINVAL; ++ goto out; ++ } ++ + err = copy_to_user((void __user *)buf, init_ents, +- array_size(entries, cqe_size)) ? ++ copy_bytes) ? + -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/net-mvpp2-add-metadata-support-for-xdp-mode.patch b/queue-6.1/net-mvpp2-add-metadata-support-for-xdp-mode.patch new file mode 100644 index 0000000000..802e31abf4 --- /dev/null +++ b/queue-6.1/net-mvpp2-add-metadata-support-for-xdp-mode.patch @@ -0,0 +1,81 @@ +From ae9fafa2bc96aa2e28cd46e941de3daac4045471 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Mar 2025 12:46:06 +0100 +Subject: net: mvpp2: Add metadata support for xdp mode + +From: Lorenzo Bianconi + +[ Upstream commit 9a45e193c88a55a536d7fd0ebfa29823d588c2cf ] + +Set metadata size building the skb from xdp_buff in mvpp2 driver +mvpp2 driver sets xdp headroom to: + +MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM + +where + +MVPP2_MH_SIZE 2 +MVPP2_SKB_HEADROOM min(max(XDP_PACKET_HEADROOM, NET_SKB_PAD), 224) + +so the headroom is large enough to contain xdp_frame and xdp metadata. +Please note this patch is just compiled tested. + +Reviewed-by: Michal Kubiak +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20250318-mvneta-xdp-meta-v2-2-b6075778f61f@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 8403fc4e9e7176..4c299d8bb2392c 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3915,13 +3915,13 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + while (rx_done < rx_todo) { + struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); ++ u32 rx_status, timestamp, metasize = 0; + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; + unsigned int frag_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- u32 rx_status, timestamp; + int pool, rx_bytes, err, ret; + struct page *page; + void *data; +@@ -3984,7 +3984,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, +- rx_bytes, false); ++ rx_bytes, true); + + ret = mvpp2_run_xdp(port, xdp_prog, &xdp, pp, &ps); + +@@ -4000,6 +4000,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_bytes += rx_bytes; + continue; + } ++ ++ metasize = xdp.data - xdp.data_meta; + } + + skb = build_skb(data, frag_size); +@@ -4036,6 +4038,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); + skb_put(skb, rx_bytes); ++ if (metasize) ++ skb_metadata_set(skb, metasize); + skb->ip_summed = mvpp2_rx_csum(port, rx_status); + skb->protocol = eth_type_trans(skb, dev); + +-- +2.53.0 + diff --git a/queue-6.1/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch b/queue-6.1/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch new file mode 100644 index 0000000000..3962650610 --- /dev/null +++ b/queue-6.1/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch @@ -0,0 +1,106 @@ +From 70ddb1c77b65308662aa36d0578c3afe49d38308 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:43 +0200 +Subject: net: mvpp2: build skb from XDP-adjusted data on XDP_PASS + +From: Til Kaiser + +[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ] + +When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() +and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets +derived from the original RX descriptor. Packet geometry changes made by +the XDP program are therefore discarded before the skb reaches the stack. + +Update rx_offset and rx_bytes from xdp.data and xdp.data_end for +XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen +by XDP, and makes RX byte accounting for XDP_PASS follow the length of the +skb passed to the network stack. + +Keep a separate rx_sync_size for page-pool recycling on skb allocation +failure, which must stay tied to the received buffer range. + +Non-PASS verdicts continue to account the descriptor length because no skb +is passed up in those cases. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-5-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index fc16e577a10376..675616142c4f47 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3919,10 +3919,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; +- unsigned int frag_size; ++ unsigned int frag_size, rx_sync_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- int pool, rx_bytes, err, ret; ++ int pool, rx_bytes, rx_offset, err, ret; + struct page *page; + void *data; + +@@ -3935,6 +3935,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + rx_status = mvpp2_rxdesc_status_get(port, rx_desc); + rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc); + rx_bytes -= MVPP2_MH_SIZE; ++ rx_sync_size = rx_bytes + MVPP2_MH_SIZE; ++ rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM; + dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc); + + pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> +@@ -3950,7 +3952,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, + MVPP2_SKB_HEADROOM, +- rx_bytes + MVPP2_MH_SIZE, ++ rx_sync_size, + dma_dir); + + /* Buffer header not supported */ +@@ -4001,6 +4003,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + } + ++ rx_sync_size = max_t(unsigned int, rx_sync_size, ++ xdp.data_end - xdp.data_hard_start - ++ MVPP2_SKB_HEADROOM); ++ ++ /* Update offset and length to reflect any XDP adjustments. */ ++ rx_offset = xdp.data - data; ++ rx_bytes = xdp.data_end - xdp.data; ++ + metasize = xdp.data - xdp.data_meta; + } + +@@ -4009,8 +4019,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + netdev_warn(port->dev, "skb build failed\n"); + if (pp) { + page_pool_put_page(pp, virt_to_head_page(data), +- rx_bytes + MVPP2_MH_SIZE, +- true); ++ rx_sync_size, true); + } else { + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, +@@ -4040,7 +4049,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + +- skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); ++ skb_reserve(skb, rx_offset); + skb_put(skb, rx_bytes); + if (metasize) + skb_metadata_set(skb, metasize); +-- +2.53.0 + diff --git a/queue-6.1/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch b/queue-6.1/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch new file mode 100644 index 0000000000..e6a1047871 --- /dev/null +++ b/queue-6.1/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch @@ -0,0 +1,46 @@ +From 6919a53c7d4cfc5f5e91b59206a2e12880a7384d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:41 +0200 +Subject: net: mvpp2: limit XDP frame size to the RX buffer + +From: Til Kaiser + +[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ] + +mvpp2 has short and long BM pools, and short pool buffers can be smaller +than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with +PAGE_SIZE as frame size. + +XDP helpers use frame_sz to validate tail growth and to derive the hard +end of the data area. Advertising PAGE_SIZE for short buffers can let +bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting +memory or later tripping skb tailroom checks. + +Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches +the actual buffer backing the packet. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-3-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 62d72f5ed01295..8403fc4e9e7176 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3981,7 +3981,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + xdp_rxq = &rxq->xdp_rxq_long; + +- xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq); ++ xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, + rx_bytes, false); +-- +2.53.0 + diff --git a/queue-6.1/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch b/queue-6.1/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch new file mode 100644 index 0000000000..5f032df8ca --- /dev/null +++ b/queue-6.1/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch @@ -0,0 +1,126 @@ +From 00b2a5060375b7f736833890604d4ec33fab30f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:42 +0200 +Subject: net: mvpp2: refill RX buffers before XDP or skb use + +From: Til Kaiser + +[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ] + +The RX error path returns the current descriptor buffer to the hardware +BM pool. That is only valid while the driver still owns the buffer. + +mvpp2_rx_refill() can fail after the current buffer has been handed to +XDP or attached to an skb. In those cases mvpp2_run_xdp() may have +recycled, redirected, or queued the page for XDP_TX, and an skb free also +retires the data buffer. Returning such a buffer to BM lets hardware DMA +into memory that is no longer owned by the RX ring. + +Refill the BM pool before handing the current buffer to XDP or to the +skb. If the allocation fails there, drop the packet and return the +still-owned current buffer to BM, preserving the pool depth. Once the +refill succeeds, later local drops retire/free the current buffer instead +of returning it to BM. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-4-mail@tk154.de +Signed-off-by: Paolo Abeni +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- + 1 file changed, 24 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 4c299d8bb2392c..fc16e577a10376 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3973,6 +3973,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + frag_size = bm_pool->frag_size; + ++ err = mvpp2_rx_refill(port, bm_pool, pp, pool); ++ if (err) { ++ netdev_err(port->dev, "failed to refill BM pools\n"); ++ goto err_drop_frame; ++ } ++ + if (xdp_prog) { + struct xdp_rxq_info *xdp_rxq; + +@@ -3990,12 +3996,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + if (ret) { + xdp_ret |= ret; +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- goto err_drop_frame; +- } +- + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + continue; +@@ -4007,8 +4007,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb = build_skb(data, frag_size); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); +- goto err_drop_frame; ++ if (pp) { ++ page_pool_put_page(pp, virt_to_head_page(data), ++ rx_bytes + MVPP2_MH_SIZE, ++ true); ++ } else { ++ dma_unmap_single_attrs(dev->dev.parent, dma_addr, ++ bm_pool->buf_size, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ mvpp2_frag_free(bm_pool, pp, data); ++ } ++ goto err_drop_frame_retired; + } ++ if (pp) ++ skb_mark_for_recycle(skb); + + /* If we have RX hardware timestamping enabled, grab the + * timestamp from the queue and convert. +@@ -4019,16 +4032,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb_hwtstamps(skb)); + } + +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- dev_kfree_skb_any(skb); +- goto err_drop_frame; +- } +- +- if (pp) +- skb_mark_for_recycle(skb); +- else ++ if (!pp) + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); +@@ -4047,13 +4051,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + + err_drop_frame: +- dev->stats.rx_errors++; +- mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + if (rx_status & MVPP2_RXD_BUF_HDR) + mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status); + else + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); ++err_drop_frame_retired: ++ dev->stats.rx_errors++; ++ mvpp2_rx_error(port, rx_desc); + } + + if (xdp_ret & MVPP2_XDP_REDIR) +-- +2.53.0 + diff --git a/queue-6.1/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-6.1/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..2fbdad5b9f --- /dev/null +++ b/queue-6.1/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From 571d3846ba606a9a4f508e02fc5525acee972cd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index b42c2c498faa2e..62d72f5ed01295 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3948,9 +3948,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-6.1/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-6.1/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..3bffb4528e --- /dev/null +++ b/queue-6.1/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From a31eab113ac2c300d3cf21c31fa74577e9f042f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index c751d6b36febd1..0c0d89470145a1 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1263,6 +1263,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-6.1/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-6.1/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..d2ea471db7 --- /dev/null +++ b/queue-6.1/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From 8a33c0cfd0df7e96d9d8f6f72f9cccb14b181cc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index 3831eb25e240ae..8cedf26d78ee02 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -702,13 +702,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-6.1/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-6.1/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..fc902421ab --- /dev/null +++ b/queue-6.1/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From 83eee2a46bc2b026bdfec6b4ca51e718a139d6b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index 4190b90ff3b18a..1909cd440a4b66 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch b/queue-6.1/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch new file mode 100644 index 0000000000..7079489472 --- /dev/null +++ b/queue-6.1/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch @@ -0,0 +1,150 @@ +From a93803048fade3b7afd9ec7aa176ecd175ac2831 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 00:38:17 -0700 +Subject: netfilter: nf_conntrack: destroy stale expectfn expectations on + unregister + +From: Weiming Shi + +[ Upstream commit c3009418f9fa1dcb3eb86f4d8c92583537b5faa3 ] + +NAT helpers such as nf_nat_h323 store a raw pointer to module text in +exp->expectfn (e.g. ip_nat_q931_expect). nf_ct_helper_expectfn_unregister() +only unlinks the callback descriptor and never walks the expectation table, +so an expectation pending at module removal survives with a dangling +exp->expectfn into freed module text. + +When the expected connection arrives, init_conntrack() invokes +exp->expectfn(), now a stale pointer into the unloaded module. Reproduced +on a KASAN build by loading the H.323 helpers, creating a Q.931 +expectation, unloading nf_nat_h323, then connecting to the expected port: + + Oops: int3: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:0xffffffffa06102d1 + init_conntrack.isra.0 (net/netfilter/nf_conntrack_core.c:1862) + nf_conntrack_in (net/netfilter/nf_conntrack_core.c:2049) + ipv4_conntrack_local (net/netfilter/nf_conntrack_proto.c:223) + nf_hook_slow (net/netfilter/core.c:619) + __ip_local_out (net/ipv4/ip_output.c:120) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1715) + tcp_connect (net/ipv4/tcp_output.c:4374) + tcp_v4_connect (net/ipv4/tcp_ipv4.c:345) + __sys_connect (net/socket.c:2167) + Modules linked in: nf_conntrack_h323 [last unloaded: nf_nat_h323] + +Reaching the dangling state requires CAP_SYS_MODULE in the initial user +namespace to remove a NAT helper that still has live expectations, so this +is a robustness fix; leaving an expectation pointing at freed text is wrong +regardless. + +Add nf_ct_helper_expectfn_destroy(), which walks the expectation table and +drops every expectation whose ->expectfn matches the descriptor being torn +down. Call it from each NAT helper's exit path after the existing RCU grace +period, so no expectation outlives the code it points at and no extra +synchronize_rcu() is introduced. With the fix, the same reproducer runs to +completion without the Oops. + +Fixes: f587de0e2feb ("[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Weiming Shi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_helper.h | 1 + + net/ipv4/netfilter/nf_nat_h323.c | 2 ++ + net/netfilter/nf_conntrack_helper.c | 19 +++++++++++++++++++ + net/netfilter/nf_nat_core.c | 2 ++ + net/netfilter/nf_nat_sip.c | 1 + + 5 files changed, 25 insertions(+) + +diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h +index 9939c366f720d4..2435039434ea9d 100644 +--- a/include/net/netfilter/nf_conntrack_helper.h ++++ b/include/net/netfilter/nf_conntrack_helper.h +@@ -152,6 +152,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct, + + void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); + void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n); + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name); + struct nf_ct_helper_expectfn * +diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c +index faee20af485613..10e1b0837731b7 100644 +--- a/net/ipv4/netfilter/nf_nat_h323.c ++++ b/net/ipv4/netfilter/nf_nat_h323.c +@@ -555,6 +555,8 @@ static void __exit nf_nat_h323_fini(void) + nf_ct_helper_expectfn_unregister(&q931_nat); + nf_ct_helper_expectfn_unregister(&callforwarding_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&q931_nat); ++ nf_ct_helper_expectfn_destroy(&callforwarding_nat); + } + + /****************************************************************************/ +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 6a2ad31ac62f12..8e72c3d4db4ad1 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -286,6 +286,25 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) + } + EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); + ++static bool expect_iter_expectfn(struct nf_conntrack_expect *exp, void *data) ++{ ++ const struct nf_ct_helper_expectfn *n = data; ++ ++ /* Relies on registered expectfn descriptors having unique ->expectfn ++ * pointers, which holds for the in-tree NAT helpers. ++ */ ++ return exp->expectfn == n->expectfn; ++} ++ ++/* Destroy expectations still pointing at @n->expectfn; call after the ++ * caller's RCU grace period so none outlives the (often modular) callback. ++ */ ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n) ++{ ++ nf_ct_expect_iterate_destroy(expect_iter_expectfn, (void *)n); ++} ++EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_destroy); ++ + /* Caller should hold the rcu lock */ + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 6b683ff015b9cc..cf7c06b79d5614 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1157,6 +1157,7 @@ static int __init nf_nat_init(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + nf_ct_helper_expectfn_unregister(&follow_master_nat); + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + unregister_pernet_subsys(&nat_net_ops); + kvfree(nf_nat_bysource); + } +@@ -1174,6 +1175,7 @@ static void __exit nf_nat_cleanup(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + kvfree(nf_nat_bysource); + unregister_pernet_subsys(&nat_net_ops); + } +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 9fbfc6bff0c221..00838c0cc5bb28 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -655,6 +655,7 @@ static void __exit nf_nat_sip_fini(void) + RCU_INIT_POINTER(nf_nat_sip_hooks, NULL); + nf_ct_helper_expectfn_unregister(&sip_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&sip_nat); + } + + static const struct nf_nat_sip_hooks sip_hooks = { +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nf_log-validate-mac-header-was-set-before-.patch b/queue-6.1/netfilter-nf_log-validate-mac-header-was-set-before-.patch new file mode 100644 index 0000000000..182884bd77 --- /dev/null +++ b/queue-6.1/netfilter-nf_log-validate-mac-header-was-set-before-.patch @@ -0,0 +1,70 @@ +From 2c17ceb139ad598981338457a15c157f782271bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:55:02 -0700 +Subject: netfilter: nf_log: validate MAC header was set before dumping it + +From: Xiang Mei + +[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ] + +The fallback path of dump_mac_header() guards the MAC header access +only with "skb->mac_header != skb->network_header", without checking +skb_mac_header_was_set(). When the MAC header is unset, mac_header is +0xffff, so the test passes and skb_mac_header(skb) returns +skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads +dev->hard_header_len bytes out of bounds into the kernel log. + +This is reachable via the netdev logger: nf_log_unknown_packet() calls +dump_mac_header() unconditionally, and an skb sent through AF_PACKET +with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still +unset (__dev_queue_xmit(), which would reset it, is bypassed). + +Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already +uses, and replace the open-coded MAC header length test with +skb_mac_header_len(). Only skbs with an unset MAC header are affected; +valid ones are dumped as before. + + BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) + Read of size 1 at addr ffff88800ea49d3f by task exploit/148 + Call Trace: + kasan_report (mm/kasan/report.c:595) + dump_mac_header (net/netfilter/nf_log_syslog.c:831) + nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) + nf_log_packet (net/netfilter/nf_log.c:260) + nft_log_eval (net/netfilter/nft_log.c:60) + nft_do_chain (net/netfilter/nf_tables_core.c:285) + nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) + nf_hook_slow (net/netfilter/core.c:619) + nf_hook_direct_egress (net/packet/af_packet.c:257) + packet_xmit (net/packet/af_packet.c:280) + packet_sendmsg (net/packet/af_packet.c:3114) + __sys_sendto (net/socket.c:2265) + +Fixes: 7eb9282cd0ef ("netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_log_syslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 58402226045e84..09b9152e9e5492 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -799,8 +799,8 @@ static void dump_mac_header(struct nf_log_buf *m, + + fallback: + nf_log_buf_add(m, "MAC="); +- if (dev->hard_header_len && +- skb->mac_header != skb->network_header) { ++ if (dev->hard_header_len && skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) != 0) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-6.1/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..7762c0e6c7 --- /dev/null +++ b/queue-6.1/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From 5f0b506efff4cd41ff330f4c98e0c39a749e0dc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index 60d18bd60d821e..a7cb4dd6205e9f 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -531,6 +531,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-6.1/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..090d3d47ba --- /dev/null +++ b/queue-6.1/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From 70a35aee774cd42cd42e5bd1a2a0b4b7bf843b69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 564054123772a1..eeb48265208a2b 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -702,14 +702,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1327,9 +1325,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index a6208efcfccfce..055d5e28a44f46 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -834,14 +834,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1230,9 +1228,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index b844e519da1b4e..333115dff69ae7 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -850,14 +850,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1246,9 +1244,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-6.1/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-6.1/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..e812302a85 --- /dev/null +++ b/queue-6.1/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From e033f44bab1132c07c4d8231ce095cb23111c585 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index 9996883bf2b78d..6007cb000da678 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -764,24 +764,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-6.1/r8152-block-future-register-access-if-register-acces.patch b/queue-6.1/r8152-block-future-register-access-if-register-acces.patch new file mode 100644 index 0000000000..154e0ef09a --- /dev/null +++ b/queue-6.1/r8152-block-future-register-access-if-register-acces.patch @@ -0,0 +1,409 @@ +From 18083fee3edce7c1e3d1601dd1e64c8a39e3782b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 14:06:59 -0700 +Subject: r8152: Block future register access if register access fails + +From: Douglas Anderson + +[ Upstream commit d9962b0d42029bcb40fe3c38bce06d1870fa4df4 ] + +Even though the functions to read/write registers can fail, most of +the places in the r8152 driver that read/write register values don't +check error codes. The lack of error code checking is problematic in +at least two ways. + +The first problem is that the r8152 driver often uses code patterns +similar to this: + x = read_register() + x = x | SOME_BIT; + write_register(x); + +...with the above pattern, if the read_register() fails and returns +garbage then we'll end up trying to write modified garbage back to the +Realtek adapter. If the write_register() succeeds that's bad. Note +that as of commit f53a7ad18959 ("r8152: Set memory to all 0xFFs on +failed reg reads") the "garbage" returned by read_register() will at +least be consistent garbage, but it is still garbage. + +It turns out that this problem is very serious. Writing garbage to +some of the hardware registers on the Ethernet adapter can put the +adapter in such a bad state that it needs to be power cycled (fully +unplugged and plugged in again) before it can enumerate again. + +The second problem is that the r8152 driver generally has functions +that are long sequences of register writes. Assuming everything will +be OK if a random register write fails in the middle isn't a great +assumption. + +One might wonder if the above two problems are real. You could ask if +we would really have a successful write after a failed read. It turns +out that the answer appears to be "yes, this can happen". In fact, +we've seen at least two distinct failure modes where this happens. + +On a sc7180-trogdor Chromebook if you drop into kdb for a while and +then resume, you can see: +1. We get a "Tx timeout" +2. The "Tx timeout" queues up a USB reset. +3. In rtl8152_pre_reset() we try to reinit the hardware. +4. The first several (2-9) register accesses fail with a timeout, then + things recover. + +The above test case was actually fixed by the patch ("r8152: Increase +USB control msg timeout to 5000ms as per spec") but at least shows +that we really can see successful calls after failed ones. + +On a different (AMD) based Chromebook with a particular adapter, we +found that during reboot tests we'd also sometimes get a transitory +failure. In this case we saw -EPIPE being returned sometimes. Retrying +worked, but retrying is not always safe for all register accesses +since reading/writing some registers might have side effects (like +registers that clear on read). + +Let's fully lock out all register access if a register access fails. +When we do this, we'll try to queue up a USB reset and try to unlock +register access after the reset. This is slightly tricker than it +sounds since the r8152 driver has an optimized reset sequence that +only works reliably after probe happens. In order to handle this, we +avoid the optimized reset if probe didn't finish. Instead, we simply +retry the probe routine in this case. + +When locking out access, we'll use the existing infrastructure that +the driver was using when it detected we were unplugged. This keeps us +from getting stuck in delay loops in some parts of the driver. + +Signed-off-by: Douglas Anderson +Reviewed-by: Grant Grundler +Signed-off-by: David S. Miller +Stable-dep-of: 19440600e729 ("r8152: handle the return value of usb_reset_device()") +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 207 ++++++++++++++++++++++++++++++++++------ + 1 file changed, 176 insertions(+), 31 deletions(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index f730f6a797e767..e8a69d3d418379 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -772,6 +772,9 @@ enum rtl8152_flags { + SCHEDULE_TASKLET, + GREEN_ETHERNET, + RX_EPROTO, ++ IN_PRE_RESET, ++ PROBED_WITH_NO_ERRORS, ++ PROBE_SHOULD_RETRY, + }; + + #define DEVICE_ID_LENOVO_USB_C_TRAVEL_HUB 0x721e +@@ -952,6 +955,8 @@ struct r8152 { + u8 version; + u8 duplex; + u8 autoneg; ++ ++ unsigned int reg_access_reset_count; + }; + + /** +@@ -1199,6 +1204,96 @@ static unsigned int agg_buf_sz = 16384; + + #define RTL_LIMITED_TSO_SIZE (size_to_mtu(agg_buf_sz) - sizeof(struct tx_desc)) + ++/* If register access fails then we block access and issue a reset. If this ++ * happens too many times in a row without a successful access then we stop ++ * trying to reset and just leave access blocked. ++ */ ++#define REGISTER_ACCESS_MAX_RESETS 3 ++ ++static void rtl_set_inaccessible(struct r8152 *tp) ++{ ++ set_bit(RTL8152_INACCESSIBLE, &tp->flags); ++ smp_mb__after_atomic(); ++} ++ ++static void rtl_set_accessible(struct r8152 *tp) ++{ ++ clear_bit(RTL8152_INACCESSIBLE, &tp->flags); ++ smp_mb__after_atomic(); ++} ++ ++static ++int r8152_control_msg(struct r8152 *tp, unsigned int pipe, __u8 request, ++ __u8 requesttype, __u16 value, __u16 index, void *data, ++ __u16 size, const char *msg_tag) ++{ ++ struct usb_device *udev = tp->udev; ++ int ret; ++ ++ if (test_bit(RTL8152_INACCESSIBLE, &tp->flags)) ++ return -ENODEV; ++ ++ ret = usb_control_msg(udev, pipe, request, requesttype, ++ value, index, data, size, ++ USB_CTRL_GET_TIMEOUT); ++ ++ /* No need to issue a reset to report an error if the USB device got ++ * unplugged; just return immediately. ++ */ ++ if (ret == -ENODEV) ++ return ret; ++ ++ /* If the write was successful then we're done */ ++ if (ret >= 0) { ++ tp->reg_access_reset_count = 0; ++ return ret; ++ } ++ ++ dev_err(&udev->dev, ++ "Failed to %s %d bytes at %#06x/%#06x (%d)\n", ++ msg_tag, size, value, index, ret); ++ ++ /* Block all future register access until we reset. Much of the code ++ * in the driver doesn't check for errors. Notably, many parts of the ++ * driver do a read/modify/write of a register value without ++ * confirming that the read succeeded. Writing back modified garbage ++ * like this can fully wedge the adapter, requiring a power cycle. ++ */ ++ rtl_set_inaccessible(tp); ++ ++ /* If probe hasn't yet finished, then we'll request a retry of the ++ * whole probe routine if we get any control transfer errors. We ++ * never have to clear this bit since we free/reallocate the whole "tp" ++ * structure if we retry probe. ++ */ ++ if (!test_bit(PROBED_WITH_NO_ERRORS, &tp->flags)) { ++ set_bit(PROBE_SHOULD_RETRY, &tp->flags); ++ return ret; ++ } ++ ++ /* Failing to access registers in pre-reset is not surprising since we ++ * wouldn't be resetting if things were behaving normally. The register ++ * access we do in pre-reset isn't truly mandatory--we're just reusing ++ * the disable() function and trying to be nice by powering the ++ * adapter down before resetting it. Thus, if we're in pre-reset, ++ * we'll return right away and not try to queue up yet another reset. ++ * We know the post-reset is already coming. ++ */ ++ if (test_bit(IN_PRE_RESET, &tp->flags)) ++ return ret; ++ ++ if (tp->reg_access_reset_count < REGISTER_ACCESS_MAX_RESETS) { ++ usb_queue_reset_device(tp->intf); ++ tp->reg_access_reset_count++; ++ } else if (tp->reg_access_reset_count == REGISTER_ACCESS_MAX_RESETS) { ++ dev_err(&udev->dev, ++ "Tried to reset %d times; giving up.\n", ++ REGISTER_ACCESS_MAX_RESETS); ++ } ++ ++ return ret; ++} ++ + static + int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) + { +@@ -1209,9 +1304,10 @@ int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) + if (!tmp) + return -ENOMEM; + +- ret = usb_control_msg(tp->udev, tp->pipe_ctrl_in, +- RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, +- value, index, tmp, size, USB_CTRL_GET_TIMEOUT); ++ ret = r8152_control_msg(tp, tp->pipe_ctrl_in, ++ RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, ++ value, index, tmp, size, "read"); ++ + if (ret < 0) + memset(data, 0xff, size); + else +@@ -1232,9 +1328,9 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) + if (!tmp) + return -ENOMEM; + +- ret = usb_control_msg(tp->udev, tp->pipe_ctrl_out, +- RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, +- value, index, tmp, size, USB_CTRL_SET_TIMEOUT); ++ ret = r8152_control_msg(tp, tp->pipe_ctrl_out, ++ RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, ++ value, index, tmp, size, "write"); + + kfree(tmp); + +@@ -1243,10 +1339,8 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) + + static void rtl_set_unplug(struct r8152 *tp) + { +- if (tp->udev->state == USB_STATE_NOTATTACHED) { +- set_bit(RTL8152_INACCESSIBLE, &tp->flags); +- smp_mb__after_atomic(); +- } ++ if (tp->udev->state == USB_STATE_NOTATTACHED) ++ rtl_set_inaccessible(tp); + } + + static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, +@@ -8295,7 +8389,7 @@ static int rtl8152_pre_reset(struct usb_interface *intf) + struct r8152 *tp = usb_get_intfdata(intf); + struct net_device *netdev; + +- if (!tp) ++ if (!tp || !test_bit(PROBED_WITH_NO_ERRORS, &tp->flags)) + return 0; + + netdev = tp->netdev; +@@ -8310,7 +8404,9 @@ static int rtl8152_pre_reset(struct usb_interface *intf) + napi_disable(&tp->napi); + if (netif_carrier_ok(netdev)) { + mutex_lock(&tp->control); ++ set_bit(IN_PRE_RESET, &tp->flags); + tp->rtl_ops.disable(tp); ++ clear_bit(IN_PRE_RESET, &tp->flags); + mutex_unlock(&tp->control); + } + +@@ -8323,9 +8419,11 @@ static int rtl8152_post_reset(struct usb_interface *intf) + struct net_device *netdev; + struct sockaddr sa; + +- if (!tp) ++ if (!tp || !test_bit(PROBED_WITH_NO_ERRORS, &tp->flags)) + return 0; + ++ rtl_set_accessible(tp); ++ + /* reset the MAC address in case of policy change */ + if (determine_ethernet_addr(tp, &sa) >= 0) { + rtnl_lock(); +@@ -9527,17 +9625,29 @@ static u8 __rtl_get_hw_ver(struct usb_device *udev) + __le32 *tmp; + u8 version; + int ret; ++ int i; + + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return 0; + +- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), +- RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, +- PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), +- USB_CTRL_GET_TIMEOUT); +- if (ret > 0) +- ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK; ++ /* Retry up to 3 times in case there is a transitory error. We do this ++ * since retrying a read of the version is always safe and this ++ * function doesn't take advantage of r8152_control_msg(). ++ */ ++ for (i = 0; i < 3; i++) { ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, ++ PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), ++ USB_CTRL_GET_TIMEOUT); ++ if (ret > 0) { ++ ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK; ++ break; ++ } ++ } ++ ++ if (i != 0 && ret > 0) ++ dev_warn(&udev->dev, "Needed %d retries to read version\n", i); + + kfree(tmp); + +@@ -9636,25 +9746,14 @@ static bool rtl8152_supports_lenovo_macpassthru(struct usb_device *udev) + return 0; + } + +-static int rtl8152_probe(struct usb_interface *intf, +- const struct usb_device_id *id) ++static int rtl8152_probe_once(struct usb_interface *intf, ++ const struct usb_device_id *id, u8 version) + { + struct usb_device *udev = interface_to_usbdev(intf); + struct r8152 *tp; + struct net_device *netdev; +- u8 version; + int ret; + +- if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) +- return -ENODEV; +- +- if (!rtl_check_vendor_ok(intf)) +- return -ENODEV; +- +- version = rtl8152_get_version(intf); +- if (version == RTL_VER_UNKNOWN) +- return -ENODEV; +- + usb_reset_device(udev); + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { +@@ -9818,10 +9917,20 @@ static int rtl8152_probe(struct usb_interface *intf, + else + device_set_wakeup_enable(&udev->dev, false); + ++ /* If we saw a control transfer error while probing then we may ++ * want to try probe() again. Consider this an error. ++ */ ++ if (test_bit(PROBE_SHOULD_RETRY, &tp->flags)) ++ goto out2; ++ ++ set_bit(PROBED_WITH_NO_ERRORS, &tp->flags); + netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); + + return 0; + ++out2: ++ unregister_netdev(netdev); ++ + out1: + tasklet_kill(&tp->tx_tl); + cancel_delayed_work_sync(&tp->hw_phy_work); +@@ -9830,10 +9939,46 @@ static int rtl8152_probe(struct usb_interface *intf, + rtl8152_release_firmware(tp); + usb_set_intfdata(intf, NULL); + out: ++ if (test_bit(PROBE_SHOULD_RETRY, &tp->flags)) ++ ret = -EAGAIN; ++ + free_netdev(netdev); + return ret; + } + ++#define RTL8152_PROBE_TRIES 3 ++ ++static int rtl8152_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ u8 version; ++ int ret; ++ int i; ++ ++ if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) ++ return -ENODEV; ++ ++ if (!rtl_check_vendor_ok(intf)) ++ return -ENODEV; ++ ++ version = rtl8152_get_version(intf); ++ if (version == RTL_VER_UNKNOWN) ++ return -ENODEV; ++ ++ for (i = 0; i < RTL8152_PROBE_TRIES; i++) { ++ ret = rtl8152_probe_once(intf, id, version); ++ if (ret != -EAGAIN) ++ break; ++ } ++ if (ret == -EAGAIN) { ++ dev_err(&intf->dev, ++ "r8152 failed probe after %d tries; giving up\n", i); ++ return -ENODEV; ++ } ++ ++ return ret; ++} ++ + static void rtl8152_disconnect(struct usb_interface *intf) + { + struct r8152 *tp = usb_get_intfdata(intf); +-- +2.53.0 + diff --git a/queue-6.1/r8152-handle-the-return-value-of-usb_reset_device.patch b/queue-6.1/r8152-handle-the-return-value-of-usb_reset_device.patch new file mode 100644 index 0000000000..5afbb0ec36 --- /dev/null +++ b/queue-6.1/r8152-handle-the-return-value-of-usb_reset_device.patch @@ -0,0 +1,44 @@ +From 50f11c2e6edffc77ecadd2914f58b1f652dc6559 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 17:22:47 +0800 +Subject: r8152: handle the return value of usb_reset_device() + +From: Chih Kai Hsu + +[ Upstream commit 19440600e729d4f74a42591a872099cf25c7d28a ] + +If usb_reset_device() returns a negative error code, stop the +process of probing. + +Fixes: 10c3271712f5 ("r8152: disable the ECM mode") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260604092247.27158-450-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index e8a69d3d418379..c0f7a15e406fee 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -9754,7 +9754,12 @@ static int rtl8152_probe_once(struct usb_interface *intf, + struct net_device *netdev; + int ret; + +- usb_reset_device(udev); ++ ret = usb_reset_device(udev); ++ if (ret < 0) { ++ dev_err(&intf->dev, "USB reset failed, errno=%d\n", ret); ++ return ret; ++ } ++ + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { + dev_err(&intf->dev, "Out of memory\n"); +-- +2.53.0 + diff --git a/queue-6.1/r8152-reduce-the-control-transfer-of-rtl8152_get_ver.patch b/queue-6.1/r8152-reduce-the-control-transfer-of-rtl8152_get_ver.patch new file mode 100644 index 0000000000..ff6ed08c02 --- /dev/null +++ b/queue-6.1/r8152-reduce-the-control-transfer-of-rtl8152_get_ver.patch @@ -0,0 +1,57 @@ +From 6f1fc466faaa20bcd9c1c90a3952eaadf4f56568 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Jan 2023 15:40:43 +0800 +Subject: r8152: reduce the control transfer of rtl8152_get_version() + +From: Hayes Wang + +[ Upstream commit 02767440e1dda9861a11ca1dbe0f19a760b1d5c2 ] + +Reduce the control transfer by moving calling rtl8152_get_version() in +rtl8152_probe(). This could prevent from calling rtl8152_get_version() +for unnecessary situations. For example, after setting config #2 for the +device, there are two interfaces and rtl8152_probe() may be called +twice. However, we don't need to call rtl8152_get_version() for this +situation. + +Signed-off-by: Hayes Wang +Signed-off-by: Jakub Kicinski +Stable-dep-of: 19440600e729 ("r8152: handle the return value of usb_reset_device()") +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 98e30291b0500b..f730f6a797e767 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -9640,20 +9640,21 @@ static int rtl8152_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { + struct usb_device *udev = interface_to_usbdev(intf); +- u8 version = rtl8152_get_version(intf); + struct r8152 *tp; + struct net_device *netdev; ++ u8 version; + int ret; + +- if (version == RTL_VER_UNKNOWN) +- return -ENODEV; +- + if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) + return -ENODEV; + + if (!rtl_check_vendor_ok(intf)) + return -ENODEV; + ++ version = rtl8152_get_version(intf); ++ if (version == RTL_VER_UNKNOWN) ++ return -ENODEV; ++ + usb_reset_device(udev); + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { +-- +2.53.0 + diff --git a/queue-6.1/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-6.1/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..b2cf327917 --- /dev/null +++ b/queue-6.1/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From a8876c0734d785a00a9259a169ba42275c836105 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index b6b46a8214a0a5..b3ee5f8238c44d 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-6.1/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-6.1/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..322c5929b3 --- /dev/null +++ b/queue-6.1/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From 2dc72968d8d246492fb1ef6bcb469fd15222ebee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 182898cb754a52..70530cbe57d0a7 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1197,6 +1197,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 07b90fdede..e8ca96465e 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -235,3 +235,29 @@ tap-free-page-on-error-paths-in-tap_get_user_xdp.patch kvm-arm64-remove-vpipt-i-cache-handling.patch arm64-tlb-allow-xzr-argument-to-tlbi-ops.patch arm64-tlb-optimize-arm64_workaround_repeat_tlbi.patch +iomap-don-t-revert-iov_iter-on-partially-completed-b.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch +tcp-restrict-so_attach_filter-to-priv-users.patch +net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +r8152-reduce-the-control-transfer-of-rtl8152_get_ver.patch +r8152-block-future-register-access-if-register-acces.patch +r8152-handle-the-return-value-of-usb_reset_device.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nf_log-validate-mac-header-was-set-before-.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch +net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch +net-mvpp2-add-metadata-support-for-xdp-mode.patch +net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch +net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch diff --git a/queue-6.1/tcp-restrict-so_attach_filter-to-priv-users.patch b/queue-6.1/tcp-restrict-so_attach_filter-to-priv-users.patch new file mode 100644 index 0000000000..d23a8d5aa1 --- /dev/null +++ b/queue-6.1/tcp-restrict-so_attach_filter-to-priv-users.patch @@ -0,0 +1,58 @@ +From 6e6cbe7fb7e97b3567fa3c2cc312f85d125ed771 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:21:34 +0000 +Subject: tcp: restrict SO_ATTACH_FILTER to priv users + +From: Eric Dumazet + +[ Upstream commit 5d39580f68e6ddeedd15e587282207489dfb3da2 ] + +This patch restricts the use of SO_ATTACH_FILTER (cBPF) on TCP sockets +to users with CAP_NET_ADMIN capability. + +This blocks potential side-channel attack where an unprivileged application +attaches a filter to leak TCP sequence/acknowledgment numbers. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Eric Dumazet +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Cc: Willem de Bruijn +Cc: Alexei Starovoitov +Cc: Daniel Borkmann +Cc: Andrii Nakryiko +Cc: Martin KaFai Lau +Cc: Eduard Zingerman +Cc: Kumar Kartikeya Dwivedi +Cc: Song Liu +Cc: Yonghong Song +Cc: Jiri Olsa +Cc: John Fastabend +Cc: Stanislav Fomichev +Acked-by: Daniel Borkmann +Reviewed-by: Willem de Bruijn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 62411c8870e855..5f79f0b78321c8 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1294,6 +1294,11 @@ int sk_setsockopt(struct sock *sk, int level, int optname, + case SO_ATTACH_FILTER: { + struct sock_fprog fprog; + ++ if (sk_is_tcp(sk) && ++ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ break; ++ } + ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); + if (!ret) + ret = sk_attach_filter(&fprog, sk); +-- +2.53.0 + diff --git a/queue-6.1/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-6.1/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..2471a5fbac --- /dev/null +++ b/queue-6.1/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From 59dea7d990068f4d89c2828c6a2d971547058813 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index cebbb47f701f47..aeb994f96192cd 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1124,15 +1124,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1723,12 +1714,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 + diff --git a/queue-6.12/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch b/queue-6.12/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch new file mode 100644 index 0000000000..294cbf374c --- /dev/null +++ b/queue-6.12/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch @@ -0,0 +1,52 @@ +From 660cca34c8f2c47f6619bcc86880694b4c25b7c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:12:44 +0100 +Subject: ASoC: wm_adsp: Fix NULL dereference when removing firmware controls + +From: Richard Fitzgerald + +[ Upstream commit 7d3fb78b550301e43fdc60312aed733069694426 ] + +In wm_adsp_control_remove() check that the priv pointer is not NULL +before attempting to cleanup what it points to. + +When cs_dsp creates a control it calls wm_adsp_control_add_cb() so that +wm_adsp can create its own private control data. There are two cases +where private data is not created: + +1. The control is a SYSTEM control, so an ALSA control is not created. + +2. The codec driver has registered a control_add() callback that + hides the control, so wm_adsp_control_add() is not called. + +When cs_dsp_remove destroys its control list it calls +wm_adsp_control_remove() for each control. But wm_adsp_control_remove() +was attempting to cleanup the private data pointed to by cs_ctl->priv +without checking the pointer for NULL. + +Signed-off-by: Richard Fitzgerald +Fixes: 0700bc2fb94c ("ASoC: wm_adsp: Separate generic cs_dsp_coeff_ctl handling") +Link: https://patch.msgid.link/20260604101244.1402862-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wm_adsp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c +index e69283195f362f..5d5d1c0c9b936b 100644 +--- a/sound/soc/codecs/wm_adsp.c ++++ b/sound/soc/codecs/wm_adsp.c +@@ -674,6 +674,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) + { + struct wm_coeff_ctl *ctl = cs_ctl->priv; + ++ if (!ctl) ++ return; ++ + cancel_work_sync(&ctl->work); + + kfree(ctl->name); +-- +2.53.0 + diff --git a/queue-6.12/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch b/queue-6.12/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch new file mode 100644 index 0000000000..5252a7dfd4 --- /dev/null +++ b/queue-6.12/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch @@ -0,0 +1,45 @@ +From 5fa724b94c77a6647f71a7bb053717938b04d6ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 20:37:08 +0800 +Subject: dma-debug: fix physical address retrieval in + debug_dma_sync_sg_for_device + +From: Li RongQing + +[ Upstream commit 9bfaa86b405381326c971984fd6da184c289713f ] + +In debug_dma_sync_sg_for_device(), when iterating over a scatterlist, +the debug entry population mistakenly uses the head of the scatterlist +'sg' to fetch the physical address via sg_phys(), instead of using the +current iterator variable 's'. + +This causes dma-debug to track the physical address of the very first +scatterlist entry for all subsequent entries in the list. + +Fix this by passing the correct loop iterator 's' to sg_phys() + +Fixes: 9d4f645a1fd49ee ("dma-debug: store a phys_addr_t in struct dma_debug_entry") +Signed-off-by: Li RongQing +Signed-off-by: Marek Szyprowski +Link: https://lore.kernel.org/r/20260603123708.1665-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + kernel/dma/debug.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c +index 035dda07ab0d08..b1192cff035924 100644 +--- a/kernel/dma/debug.c ++++ b/kernel/dma/debug.c +@@ -1573,7 +1573,7 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + struct dma_debug_entry ref = { + .type = dma_debug_sg, + .dev = dev, +- .paddr = sg_phys(sg), ++ .paddr = sg_phys(s), + .dev_addr = sg_dma_address(s), + .size = sg_dma_len(s), + .direction = direction, +-- +2.53.0 + diff --git a/queue-6.12/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch b/queue-6.12/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch new file mode 100644 index 0000000000..894654fec8 --- /dev/null +++ b/queue-6.12/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch @@ -0,0 +1,85 @@ +From 2b7ce7615d2f7b88c34eb5bb8b1b7fe1b4a725f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:43:34 +0800 +Subject: gpio: mvebu: fix NULL pointer dereference in suspend/resume + +From: Yun Zhou + +[ Upstream commit b9ad50d7505ebd48282ec3630258dc820fc85c81 ] + +mvebu_pwm_suspend() and mvebu_pwm_resume() are called for all GPIO +banks during suspend/resume, but not all banks have PWM functionality. +GPIO banks without PWM have mvchip->mvpwm set to NULL. + +Calling mvebu_pwm_suspend() with mvpwm == NULL causes a NULL pointer +dereference when it tries to access mvpwm->blink_select. + + Unable to handle kernel NULL pointer dereference at virtual address 00000020 when write + [00000020] *pgd=00000000 + Internal error: Oops: 815 [#1] PREEMPT ARM + Modules linked in: + CPU: 0 UID: 0 PID: 406 Comm: sh Not tainted 6.12.74-rt12-yocto-standard-g4e96f98fb7db-dirty #353 + Hardware name: Marvell Armada 370/XP (Device Tree) + PC is at regmap_mmio_read+0x38/0x54 + LR is at regmap_mmio_read+0x38/0x54 + pc : [] lr : [] psr: 200f0013 + sp : f0c11d10 ip : 00000000 fp : c100d2f0 + r10: c14fb854 r9 : 00000000 r8 : 00000000 + r7 : c1799c00 r6 : 00000020 r5 : 00000020 r4 : c179c7c0 + r3 : f0a231a0 r2 : 00000020 r1 : 00000020 r0 : 00000000 + Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none + Control: 10c5387d Table: 135ec059 DAC: 00000051 + Call trace: + regmap_mmio_read from _regmap_bus_reg_read+0x78/0xac + _regmap_bus_reg_read from _regmap_read+0x60/0x154 + _regmap_read from regmap_read+0x3c/0x60 + regmap_read from mvebu_gpio_suspend+0xa4/0x14c + mvebu_gpio_suspend from dpm_run_callback+0x54/0x180 + dpm_run_callback from device_suspend+0x124/0x630 + device_suspend from dpm_suspend+0x124/0x270 + dpm_suspend from dpm_suspend_start+0x64/0x6c + dpm_suspend_start from suspend_devices_and_enter+0x140/0x8e8 + suspend_devices_and_enter from pm_suspend+0x2fc/0x308 + pm_suspend from state_store+0x6c/0xc8 + state_store from kernfs_fop_write_iter+0x10c/0x1f8 + kernfs_fop_write_iter from vfs_write+0x270/0x468 + vfs_write from ksys_write+0x70/0xf0 + ksys_write from ret_fast_syscall+0x0/0x54 + +Add a NULL check for mvchip->mvpwm before calling the PWM +suspend/resume functions. + +Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support") +Signed-off-by: Yun Zhou +Link: https://patch.msgid.link/20260608084334.2960803-1-yun.zhou@windriver.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mvebu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c +index 8cfd3a89c0184d..c85ab356bc72a9 100644 +--- a/drivers/gpio/gpio-mvebu.c ++++ b/drivers/gpio/gpio-mvebu.c +@@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_suspend(mvchip); + + return 0; +@@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_resume(mvchip); + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/gpio-zynq-fix-runtime-pm-leak-on-remove.patch b/queue-6.12/gpio-zynq-fix-runtime-pm-leak-on-remove.patch new file mode 100644 index 0000000000..0c0b2f0e1a --- /dev/null +++ b/queue-6.12/gpio-zynq-fix-runtime-pm-leak-on-remove.patch @@ -0,0 +1,39 @@ +From a37f9cf60ced2d195b1c96cbc77dd73581a66650 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:33:13 +0800 +Subject: gpio: zynq: fix runtime PM leak on remove + +From: Ruoyu Wang + +[ Upstream commit 6edb934de9bda3b7abcec856eaee6fc8b4278dd1 ] + +pm_runtime_get_sync() increments the runtime PM usage counter even when it +returns an error. zynq_gpio_remove() uses it to keep the controller active +while removing the GPIO chip, but never drops the usage counter again. + +Balance the get with pm_runtime_put_noidle() after disabling runtime PM. + +Fixes: 3242ba117e9b ("gpio: Add driver for Zynq GPIO controller") +Signed-off-by: Ruoyu Wang +Link: https://patch.msgid.link/20260609073313.5-1-ruoyuw560@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-zynq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c +index cc53e6940ad7e6..50fa4938161dde 100644 +--- a/drivers/gpio/gpio-zynq.c ++++ b/drivers/gpio/gpio-zynq.c +@@ -1015,6 +1015,7 @@ static void zynq_gpio_remove(struct platform_device *pdev) + gpiochip_remove(&gpio->chip); + device_set_wakeup_capable(&pdev->dev, 0); + pm_runtime_disable(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); + } + + static struct platform_driver zynq_gpio_driver = { +-- +2.53.0 + diff --git a/queue-6.12/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch b/queue-6.12/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch new file mode 100644 index 0000000000..49fcd2ed55 --- /dev/null +++ b/queue-6.12/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch @@ -0,0 +1,61 @@ +From 69f85fcb83ec012b74fcc5b43100e7a4f2f4b26d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jun 2026 08:10:47 -0400 +Subject: iomap: don't revert iov_iter on partially completed buffered writes + +From: Brian Foster + +Gregg reports that the iomap retry behavior for nonblocking (nowait) +append writes is broken. The problem occurs when an append write is +first submitted in non-blocking mode (i.e. via io_uring), partially +completes before hitting -EAGAIN, and then is resubmitted from +blocking context. + +The specific problem is that at least one iteration of the loop in +iomap_write_iter() completes in non-blocking context and thus has +bumped i_size. The next iteration hits -EAGAIN, reverts the iov_iter +and returns. io_uring retries the entire append write from blocking +context, but since i_size has already been increased, the data that +was partially written on the first attempt is rewritten at the new +i_size. This is essentially an intra-write data corruption since the +data written to the file does not reflect the write from userspace. + +This problem is already fixed on master as of commit 1a1a3b574b97 +("iomap: advance the iter directly on buffered writes"). That commit +was primarily intended to clean up iomap iter state tracking, but it +also happened to remove the iov_iter revert and thus accidentally +fix this problem as well. Without the revert, iomap will commit +partial progress internally and loop once more before it more than +likely hits -EAGAIN and returns partial progress consistent with the +inode updates. This means the blocking retry from io_uring will pick +up where the first attempt left off at the current i_size and +perform the remainder of the write correctly. + +Cc: +Fixes: 18e419f6e80a ("iomap: Return -EAGAIN from iomap_write_iter()") +Reported-by: Gregg Leventhal +Reported-by: Eric Hagberg +Signed-off-by: Brian Foster +Signed-off-by: Sasha Levin +--- + fs/iomap/buffered-io.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index 0178292c186485..5f885286b2f4a0 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -1037,10 +1037,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) + } + } while (iov_iter_count(i) && length); + +- if (status == -EAGAIN) { +- iov_iter_revert(i, total_written); +- return -EAGAIN; +- } + return total_written ? total_written : status; + } + +-- +2.53.0 + diff --git a/queue-6.12/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-6.12/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..3930493147 --- /dev/null +++ b/queue-6.12/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From 1f0ee433668038cf7e20d1efd74496a942ea72b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index 2ac88593a95427..6fe696939d041e 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -105,6 +105,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -112,6 +113,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-6.12/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch b/queue-6.12/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch new file mode 100644 index 0000000000..ab5b2da23a --- /dev/null +++ b/queue-6.12/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch @@ -0,0 +1,89 @@ +From af07db0cc2273db4b62267b4e031dd6ea537c949 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 17:54:48 +0300 +Subject: ipv6: Fix a potential NPD in cleanup_prefix_route() + +From: Ido Schimmel + +[ Upstream commit b70c687b7cf267fb08586667a3946c8851cad672 ] + +addrconf_get_prefix_route() can return the fib6_null_entry sentinel +entry which has a NULL fib6_table pointer. Therefore, before setting the +route's expiration time, check that we are not working with this entry, +as otherwise a NPD will be triggered [1]. + +Note that the other callers of addrconf_get_prefix_route() are not +susceptible to this bug: + +1. addrconf_prefix_rcv(): Requests a route with the 'RTF_ADDRCONF | + RTF_PREFIX_RT' flags which are not set on fib6_null_entry. + +2. modify_prefix_route(): Fixed by commit a747e02430df ("ipv6: avoid + possible NULL deref in modify_prefix_route()"). + +3. __ipv6_ifa_notify(): Calls ip6_del_rt() which specifically checks for + fib6_null_entry and returns an error. + +[1] +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] SMP KASAN +KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037] +[...] +Call Trace: + +__kasan_check_byte (mm/kasan/common.c:573) +lock_acquire.part.0 (kernel/locking/lockdep.c:5842 (discriminator 1)) +_raw_spin_lock_bh (kernel/locking/spinlock.c:182 (discriminator 1)) +cleanup_prefix_route (net/ipv6/addrconf.c:1280) +ipv6_del_addr (net/ipv6/addrconf.c:1342) +inet6_addr_del.isra.0 (net/ipv6/addrconf.c:3119) +inet6_rtm_deladdr (net/ipv6/addrconf.c:4812) +rtnetlink_rcv_msg (net/core/rtnetlink.c:6997) +netlink_rcv_skb (net/netlink/af_netlink.c:2555) +netlink_unicast (net/netlink/af_netlink.c:1344) +netlink_sendmsg (net/netlink/af_netlink.c:1899) +__sock_sendmsg (net/socket.c:802 (discriminator 4)) +____sys_sendmsg (net/socket.c:2698) +___sys_sendmsg (net/socket.c:2752) +__sys_sendmsg (net/socket.c:2784) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 5eb902b8e719 ("net/ipv6: Remove expired routes with a separated list of routes.") +Reported-by: Ji'an Zhou +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260609145448.768318-1-idosch@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index e104ec8efe1c0c..c6fcdb60dfee14 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1259,6 +1259,7 @@ static void + cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + bool del_rt, bool del_peer) + { ++ struct net *net = dev_net(ifp->idev->dev); + struct fib6_table *table; + struct fib6_info *f6i; + +@@ -1267,9 +1268,10 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + ifp->idev->dev, 0, RTF_DEFAULT, true); + if (f6i) { + if (del_rt) +- ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); ++ ip6_del_rt(net, f6i, false); + else { +- if (!(f6i->fib6_flags & RTF_EXPIRES)) { ++ if (f6i != net->ipv6.fib6_null_entry && ++ !(f6i->fib6_flags & RTF_EXPIRES)) { + table = f6i->fib6_table; + spin_lock_bh(&table->tb6_lock); + +-- +2.53.0 + diff --git a/queue-6.12/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-6.12/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..fcad85e4df --- /dev/null +++ b/queue-6.12/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From fa97f62f7395c19518cca3dd7ab4a41b62c4398c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 3c15a0ae228e21..5c1982358aca5e 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -968,6 +968,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-6.12/net-add-pskb_may_pull-to-skb_gro_receive_list.patch b/queue-6.12/net-add-pskb_may_pull-to-skb_gro_receive_list.patch new file mode 100644 index 0000000000..4020ddcf94 --- /dev/null +++ b/queue-6.12/net-add-pskb_may_pull-to-skb_gro_receive_list.patch @@ -0,0 +1,57 @@ +From 14ded45002a80124470c8f7dfe7db0d3e020c4c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:46:25 +0000 +Subject: net: add pskb_may_pull() to skb_gro_receive_list() + +From: HanQuan + +[ Upstream commit f2bb3434544454099a5b6dec213567267b05d79d ] + +skb_gro_receive_list() calls skb_pull(skb, skb_gro_offset(skb)) without +first ensuring the data is in the linear area via pskb_may_pull(). When +the skb arrives via napi_gro_frags(), skb_headlen can be 0 (all data in +page fragments) while skb_gro_offset is non-zero (after IP+TCP header +parsing). The skb_pull() then decrements skb->len by skb_gro_offset +but skb->data_len stays unchanged, hitting BUG_ON(skb->len < skb->data_len) +in __skb_pull(). + +The UDP fraglist GRO path already contains this guard at +udp_offload.c:749. Adding it to skb_gro_receive_list() itself provides +centralized protection for all callers (TCP, UDP, and any future +protocols), and ensures the precondition of skb_pull() is satisfied +before it is called. + +On pskb_may_pull() failure, set NAPI_GRO_CB(skb)->flush = 1 so the +skb is not held as a new GRO head and is instead delivered through the +normal receive path, matching the UDP handling. + +Fixes: 8d95dc474f85 ("net: add code for TCP fraglist GRO") +Reported-by: HanQuan +Reported-by: MingXuan +Signed-off-by: HanQuan +Reviewed-by: Eric Dumazet +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/gro.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/gro.c b/net/core/gro.c +index e4cebf162efb70..4e7b9848771edc 100644 +--- a/net/core/gro.c ++++ b/net/core/gro.c +@@ -233,6 +233,11 @@ int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) + if (unlikely(p->len + skb->len >= 65536)) + return -E2BIG; + ++ if (!pskb_may_pull(skb, skb_gro_offset(skb))) { ++ NAPI_GRO_CB(skb)->flush = 1; ++ return -ENOMEM; ++ } ++ + if (NAPI_GRO_CB(p)->last == p) + skb_shinfo(p)->frag_list = skb; + else +-- +2.53.0 + diff --git a/queue-6.12/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-6.12/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..8b98fe1c7b --- /dev/null +++ b/queue-6.12/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From 3e6310ef102ee1238c3fa73a3ccfc8d77c41e166 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 6edd9cac500675..0d77a87929f938 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1806,6 +1806,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index fba5f06b94d9d6..4be699bd3a17f7 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -5384,7 +5384,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -5393,8 +5393,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index 878155076bc0f8..5c5dd9f6605a94 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -804,12 +804,13 @@ EXPORT_SYMBOL(kernel_sendmsg_locked); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-6.12/net-ibm-emac-fix-use-after-free-during-device-remova.patch b/queue-6.12/net-ibm-emac-fix-use-after-free-during-device-remova.patch new file mode 100644 index 0000000000..e2248f976e --- /dev/null +++ b/queue-6.12/net-ibm-emac-fix-use-after-free-during-device-remova.patch @@ -0,0 +1,73 @@ +From 7cdf59dd61e0b808753cd6da2b584610d62f2e13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 15:12:17 -0700 +Subject: net: ibm: emac: Fix use-after-free during device removal + +From: Rosen Penev + +[ Upstream commit a0130d682222ae21afc395aead7cd2d87e1a8358 ] + +The driver was using devm_register_netdev() which causes unregister_netdev() +to be deferred until the devres cleanup phase, which runs after emac_remove() +returns. This creates a use-after-free window where: + +1. emac_remove() is called, which tears down hardware (cancels work, detaches + modules, unregisters from MAL) +2. emac_remove() returns +3. devres cleanup runs and finally calls unregister_netdev() + +During step 3, the network stack might still process packets, triggering +emac_irq(), emac_poll(), or other handlers that access now-freed hardware +resources (dev->emacp, dev->mal, etc.). + +Fix this by replacing devm_register_netdev() with manual register_netdev() +and calling unregister_netdev() at the beginning of emac_remove(), before +any hardware teardown. This ensures the network device is fully stopped and +unregistered before hardware resources are released. + +The change is safe because: +- dev->ndev is assigned very early in probe (before any error paths that + could bypass emac_remove) +- platform_set_drvdata() is only called after successful registration, so + emac_remove() only runs for fully registered devices +- unregister_netdev() is idempotent and safe to call on any registered device + +Fixes: a4dd8535a527 ("net: ibm: emac: use devm for register_netdev") +Signed-off-by: Rosen Penev +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ibm/emac/core.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c +index dac570f3c11036..0db3f558c95bb1 100644 +--- a/drivers/net/ethernet/ibm/emac/core.c ++++ b/drivers/net/ethernet/ibm/emac/core.c +@@ -3147,7 +3147,7 @@ static int emac_probe(struct platform_device *ofdev) + + netif_carrier_off(ndev); + +- err = devm_register_netdev(&ofdev->dev, ndev); ++ err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "%pOF: failed to register net device (%d)!\n", + np, err); +@@ -3200,6 +3200,13 @@ static void emac_remove(struct platform_device *ofdev) + + DBG(dev, "remove" NL); + ++ /* Unregister network device before tearing down hardware ++ * to prevent use-after-free during deferred cleanup. This ensures ++ * the network stack stops all operations before hardware resources ++ * are released. ++ */ ++ unregister_netdev(dev->ndev); ++ + cancel_work_sync(&dev->reset_work); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) +-- +2.53.0 + diff --git a/queue-6.12/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch b/queue-6.12/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch new file mode 100644 index 0000000000..9a1e96a1f1 --- /dev/null +++ b/queue-6.12/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch @@ -0,0 +1,61 @@ +From 66959d551777d4bac9fa630a65b0055a0e2f2606 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:10:44 +0800 +Subject: net/mlx4: avoid GCC 10 __bad_copy_from() false positive + +From: Yao Sang + +[ Upstream commit 2365343f4aad3e1b1e7a2e87e98cf66d5e590589 ] + +mlx4_init_user_cqes() fills a scratch buffer with the CQE +initialization pattern and then copies from that buffer to userspace. + +In the single-copy path, the copy length is array_size(entries, +cqe_size), but the scratch buffer is allocated with PAGE_SIZE. GCC 10 +does not carry the branch invariant strongly enough through the object +size checks and falsely triggers __bad_copy_from(). + +Size the scratch buffer to the actual copy length for the active path, +keep array_size() for the single-copy case, and retain a WARN_ON_ONCE() +guard for the PAGE_SIZE invariant before allocating the buffer. + +Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()") +Signed-off-by: Yao Sang +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx4/cq.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c +index e130e7259275a3..5c55971abbf072 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/cq.c ++++ b/drivers/net/ethernet/mellanox/mlx4/cq.c +@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) + static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + { + int entries_per_copy = PAGE_SIZE / cqe_size; ++ size_t copy_bytes; + void *init_ents; + int err = 0; + int i; +@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + buf += PAGE_SIZE; + } + } else { ++ copy_bytes = array_size(entries, cqe_size); ++ if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE)) { ++ err = -EINVAL; ++ goto out; ++ } ++ + err = copy_to_user((void __user *)buf, init_ents, +- array_size(entries, cqe_size)) ? ++ copy_bytes) ? + -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch b/queue-6.12/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch new file mode 100644 index 0000000000..2477aa89e9 --- /dev/null +++ b/queue-6.12/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch @@ -0,0 +1,221 @@ +From 28c6cc5c3e9a08a2456405a90f9871e5f90372e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:58:49 +0300 +Subject: net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list + +From: Dragos Tatulea + +[ Upstream commit 894e036a24a26a6dd7b17d8d3fb5c53ab48a6074 ] + +mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using +the PF's log_max_current_uc/mc_list capabilities. When querying a VF +vport with a larger configured max (via devlink), the firmware response +can overflow this buffer: + + BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 + + CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) + Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] + Call Trace: + + dump_stack_lvl+0x69/0xa0 + print_report+0x176/0x4e4 + kasan_report+0xc8/0x100 + mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] + esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] + esw_vport_change_handler+0x6a/0x90 [mlx5_core] + process_one_work+0x87f/0x15e0 + worker_thread+0x62b/0x1020 + kthread+0x375/0x490 + ret_from_fork+0x4dc/0x810 + ret_from_fork_asm+0x11/0x20 + + +Fix by querying the vport's own HCA caps to size the buffer correctly. +Refactor the function to allocate and return the MAC list internally, +removing the caller's dependency on knowing the correct max. + +Fixes: e16aea2744ab ("net/mlx5: Introduce access functions to modify/query vport mac lists") +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135849.458060-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +--- + .../net/ethernet/mellanox/mlx5/core/vport.c | 72 ++++++++++++++----- + include/linux/mlx5/vport.h | 4 +- + 3 files changed, 59 insertions(+), 30 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +index 864e88f0577145..383ca082e8419d 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, int list_type) + { + bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC; +- u8 (*mac_list)[ETH_ALEN]; ++ u8 (*mac_list)[ETH_ALEN] = NULL; + struct l2addr_node *node; + struct vport_addr *addr; + struct hlist_head *hash; + struct hlist_node *tmp; +- int size; ++ int size = 0; + int err; + int hi; + int i; + +- size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) : +- MLX5_MAX_MC_PER_VPORT(esw->dev); +- +- mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL); +- if (!mac_list) +- return; +- + hash = is_uc ? vport->uc_list : vport->mc_list; + + for_each_l2hash_node(node, tmp, hash, hi) { +@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + goto out; + + err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type, +- mac_list, &size); ++ &mac_list, &size); + if (err) + goto out; + esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n", +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +index b04024d0ae676c..fdee284835e001 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +@@ -250,35 +250,63 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu) + } + EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mtu); + ++static int mlx5_vport_max_mac_list_size(struct mlx5_core_dev *dev, u16 vport, ++ enum mlx5_list_type list_type) ++{ ++ void *query_ctx, *hca_caps; ++ int ret = 0; ++ ++ if (!vport && !mlx5_core_is_ecpf(dev)) ++ return list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : ++ 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ ++ query_ctx = kzalloc(MLX5_ST_SZ_BYTES(query_hca_cap_out), GFP_KERNEL); ++ if (!query_ctx) ++ return -ENOMEM; ++ ++ ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_ctx); ++ if (ret) ++ goto out; ++ ++ hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); ++ ret = list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_uc_list) : ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_mc_list); ++ ++out: ++ kfree(query_ctx); ++ ++ return ret; ++} ++ + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size) ++ u8 (**addr_list)[ETH_ALEN], ++ int *addr_list_size) + { + u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {0}; ++ int allowed_list_size; + void *nic_vport_ctx; + int max_list_size; +- int req_list_size; + int out_sz; + void *out; + int err; + int i; + +- req_list_size = *list_size; ++ if (!addr_list || !addr_list_size) ++ return -EINVAL; + +- max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ? +- 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : +- 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ *addr_list = NULL; ++ *addr_list_size = 0; + +- if (req_list_size > max_list_size) { +- mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n", +- req_list_size, max_list_size); +- req_list_size = max_list_size; +- } ++ max_list_size = mlx5_vport_max_mac_list_size(dev, vport, list_type); ++ if (max_list_size < 0) ++ return max_list_size; + + out_sz = MLX5_ST_SZ_BYTES(query_nic_vport_context_out) + +- req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); ++ max_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); + + out = kvzalloc(out_sz, GFP_KERNEL); + if (!out) +@@ -297,16 +325,24 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + + nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out, + nic_vport_context); +- req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, +- allowed_list_size); ++ allowed_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, ++ allowed_list_size); ++ if (!allowed_list_size) ++ goto out; ++ ++ *addr_list = kcalloc(allowed_list_size, ETH_ALEN, GFP_KERNEL); ++ if (!*addr_list) { ++ err = -ENOMEM; ++ goto out; ++ } + +- *list_size = req_list_size; +- for (i = 0; i < req_list_size; i++) { ++ for (i = 0; i < allowed_list_size; i++) { + u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context, + nic_vport_ctx, + current_uc_mac_address[i]) + 2; +- ether_addr_copy(addr_list[i], mac_addr); ++ ether_addr_copy((*addr_list)[i], mac_addr); + } ++ *addr_list_size = allowed_list_size; + out: + kvfree(out); + return err; +diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h +index c36cc6d829267e..80992c370fb074 100644 +--- a/include/linux/mlx5/vport.h ++++ b/include/linux/mlx5/vport.h +@@ -95,8 +95,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size); ++ u8 (**mac_list)[ETH_ALEN], ++ int *mac_list_size); + int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev, + enum mlx5_list_type list_type, + u8 addr_list[][ETH_ALEN], +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch b/queue-6.12/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch new file mode 100644 index 0000000000..94e7105fcf --- /dev/null +++ b/queue-6.12/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch @@ -0,0 +1,71 @@ +From 81a013c079f8f91d1d12898ad7332a7b05b683bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 18:21:12 +0800 +Subject: net/mlx5: Use effective affinity mask for IRQ selection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fushuai Wang + +[ Upstream commit a7767290e77ca2e926b49f8bfa29daa12262c612 ] + +When a sf is created after a CPU has been taken offline, the IRQ pool may +contain IRQs with affinity masks that include the offline CPU. Since only +online CPUs should be considered for IRQ placement, cpumask_subset() check +would fail because the iter_mask contains offline CPUs that are not present +in req_mask, causing sf creation to fail. + +This is an example: + 1. When mlx5 driver loads, it initializes the IRQ pools. + For sf_ctrl_pool with ≤64 sf: + - xa_num_irqs = {N, N} (There is only one slot) + 2. When the first SF is created: + - The ctrl IRQ is allocated with mask=cpu_online_mask={0-191} + 2. We take CPU 20 offline + 3. Existing ctl irq still have mask={0-191} + 4. Create a new SF: + - req_mask={0-19,21-191} + - iter_mask={0-191} + - {0-191} is NOT a subset of {0-19,21-191} + - least_loaded_irq=NULL + 5. Try to allocate a new irq via irq_pool_request_irq() + 6. xa_alloc() fails because the pool is full(There is only one slot) + 7. sf creation fails with error + +Use irq_get_effective_affinity_mask() instead, which returns the IRQ's +actual effective affinity that already excludes offline CPUs. + +Fixes: 061f5b23588a ("net/mlx5: SF, Use all available cpu for setting cpu affinity") +Suggested-by: Shay Drory +Signed-off-by: Fushuai Wang +Reviewed-by: Shay Drory +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260605102112.91772-1-fushuai.wang@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +index 2691d88cdee1f7..589051ffb49d3a 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +@@ -94,9 +94,12 @@ irq_pool_find_least_loaded(struct mlx5_irq_pool *pool, const struct cpumask *req + + lockdep_assert_held(&pool->lock); + xa_for_each_range(&pool->irqs, index, iter, start, end) { +- struct cpumask *iter_mask = mlx5_irq_get_affinity_mask(iter); + int iter_refcount = mlx5_irq_read_locked(iter); ++ const struct cpumask *iter_mask; + ++ iter_mask = irq_get_effective_affinity_mask(mlx5_irq_get_irq(iter)); ++ if (!iter_mask) ++ continue; + if (!cpumask_subset(iter_mask, req_mask)) + /* skip IRQs with a mask which is not subset of req_mask */ + continue; +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch b/queue-6.12/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch new file mode 100644 index 0000000000..76e9762d9a --- /dev/null +++ b/queue-6.12/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch @@ -0,0 +1,69 @@ +From f1bcc44a23790f55a7690d9bb23e6a96fa03247e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:54:46 +0300 +Subject: net/mlx5e: xsk: Fix DMA and xdp_frame leak on XDP_TX xmit failure + +From: Dragos Tatulea + +[ Upstream commit b69004f5a6ad32da84d8aa5b23b9c0caafe6252e ] + +In the XSK branch of mlx5e_xmit_xdp_buff(), when sq->xmit_xdp_frame() +returns false (e.g. XDPSQ is full), the function returns without +unmapping the DMA address or freeing the xdp_frame allocated by +xdp_convert_zc_to_xdp_frame(). The xdpi_fifo push only happens on +success, so the completion path cannot recover these entries. + +With CONFIG_DMA_API_DEBUG=y, the leak surfaces on driver unbind: + + DMA-API: pci 0000:08:00.0: device driver has pending DMA + allocations while released from device [count=1116] + One of leaked entries details: [device address=0x000000010ffd7028] + [size=1534 bytes] [mapped with DMA_TO_DEVICE] [mapped as phy] + WARNING: kernel/dma/debug.c:881 at dma_debug_device_change+0x127/0x180 + ... + DMA-API: Mapped at: + debug_dma_map_phys+0x4b/0xd0 + dma_map_phys+0xfd/0x2d0 + mlx5e_xdp_handle+0x5ae/0xac0 [mlx5_core] + mlx5e_xsk_skb_from_cqe_mpwrq_linear+0xc4/0x170 [mlx5_core] + mlx5e_handle_rx_cqe_mpwrq+0xc1/0x290 [mlx5_core] + +Add the missing unmap + xdp_return_frame, matching the cleanup already +done in mlx5e_xdp_xmit(). has_frags is rejected earlier in this branch, +so no per-frag unmap is needed. + +Fixes: 84a0a2310d6d ("net/mlx5e: XDP_TX from UMEM support") +Signed-off-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135446.456119-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +index 14192da4b8ed0d..d4d2de017a504d 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +@@ -102,9 +102,15 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq, + + xdptxd->dma_addr = dma_addr; + +- if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, +- mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL))) ++ if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, ++ mlx5e_xmit_xdp_frame_mpwqe, ++ mlx5e_xmit_xdp_frame, ++ sq, xdptxd, 0, NULL))) { ++ dma_unmap_single(sq->pdev, dma_addr, xdptxd->len, ++ DMA_TO_DEVICE); ++ xdp_return_frame(xdpf); + return false; ++ } + + /* xmit_mode == MLX5E_XDP_XMIT_MODE_FRAME */ + mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, +-- +2.53.0 + diff --git a/queue-6.12/net-mvpp2-add-metadata-support-for-xdp-mode.patch b/queue-6.12/net-mvpp2-add-metadata-support-for-xdp-mode.patch new file mode 100644 index 0000000000..2a3e2f248f --- /dev/null +++ b/queue-6.12/net-mvpp2-add-metadata-support-for-xdp-mode.patch @@ -0,0 +1,81 @@ +From cd8e9a14d051e7122a4d2472b737ae64e99ff55b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Mar 2025 12:46:06 +0100 +Subject: net: mvpp2: Add metadata support for xdp mode + +From: Lorenzo Bianconi + +[ Upstream commit 9a45e193c88a55a536d7fd0ebfa29823d588c2cf ] + +Set metadata size building the skb from xdp_buff in mvpp2 driver +mvpp2 driver sets xdp headroom to: + +MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM + +where + +MVPP2_MH_SIZE 2 +MVPP2_SKB_HEADROOM min(max(XDP_PACKET_HEADROOM, NET_SKB_PAD), 224) + +so the headroom is large enough to contain xdp_frame and xdp metadata. +Please note this patch is just compiled tested. + +Reviewed-by: Michal Kubiak +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20250318-mvneta-xdp-meta-v2-2-b6075778f61f@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index d5d2cbe127b0e7..e43d844b14aaef 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3928,13 +3928,13 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + while (rx_done < rx_todo) { + struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); ++ u32 rx_status, timestamp, metasize = 0; + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; + unsigned int frag_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- u32 rx_status, timestamp; + int pool, rx_bytes, err, ret; + struct page *page; + void *data; +@@ -3997,7 +3997,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, +- rx_bytes, false); ++ rx_bytes, true); + + ret = mvpp2_run_xdp(port, xdp_prog, &xdp, pp, &ps); + +@@ -4013,6 +4013,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_bytes += rx_bytes; + continue; + } ++ ++ metasize = xdp.data - xdp.data_meta; + } + + if (frag_size) +@@ -4052,6 +4054,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); + skb_put(skb, rx_bytes); ++ if (metasize) ++ skb_metadata_set(skb, metasize); + skb->ip_summed = mvpp2_rx_csum(port, rx_status); + skb->protocol = eth_type_trans(skb, dev); + +-- +2.53.0 + diff --git a/queue-6.12/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch b/queue-6.12/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch new file mode 100644 index 0000000000..ddd2965b6e --- /dev/null +++ b/queue-6.12/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch @@ -0,0 +1,106 @@ +From 045d23f9bcea62d8579181c0e45ec4ecb45b26ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:43 +0200 +Subject: net: mvpp2: build skb from XDP-adjusted data on XDP_PASS + +From: Til Kaiser + +[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ] + +When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() +and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets +derived from the original RX descriptor. Packet geometry changes made by +the XDP program are therefore discarded before the skb reaches the stack. + +Update rx_offset and rx_bytes from xdp.data and xdp.data_end for +XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen +by XDP, and makes RX byte accounting for XDP_PASS follow the length of the +skb passed to the network stack. + +Keep a separate rx_sync_size for page-pool recycling on skb allocation +failure, which must stay tied to the received buffer range. + +Non-PASS verdicts continue to account the descriptor length because no skb +is passed up in those cases. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-5-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 2c517f6ca39c40..325a3a657249df 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3932,10 +3932,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; +- unsigned int frag_size; ++ unsigned int frag_size, rx_sync_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- int pool, rx_bytes, err, ret; ++ int pool, rx_bytes, rx_offset, err, ret; + struct page *page; + void *data; + +@@ -3948,6 +3948,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + rx_status = mvpp2_rxdesc_status_get(port, rx_desc); + rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc); + rx_bytes -= MVPP2_MH_SIZE; ++ rx_sync_size = rx_bytes + MVPP2_MH_SIZE; ++ rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM; + dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc); + + pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> +@@ -3963,7 +3965,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, + MVPP2_SKB_HEADROOM, +- rx_bytes + MVPP2_MH_SIZE, ++ rx_sync_size, + dma_dir); + + /* Buffer header not supported */ +@@ -4014,6 +4016,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + } + ++ rx_sync_size = max_t(unsigned int, rx_sync_size, ++ xdp.data_end - xdp.data_hard_start - ++ MVPP2_SKB_HEADROOM); ++ ++ /* Update offset and length to reflect any XDP adjustments. */ ++ rx_offset = xdp.data - data; ++ rx_bytes = xdp.data_end - xdp.data; ++ + metasize = xdp.data - xdp.data_meta; + } + +@@ -4025,8 +4035,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + netdev_warn(port->dev, "skb build failed\n"); + if (pp) { + page_pool_put_page(pp, virt_to_head_page(data), +- rx_bytes + MVPP2_MH_SIZE, +- true); ++ rx_sync_size, true); + } else { + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, +@@ -4056,7 +4065,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + +- skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); ++ skb_reserve(skb, rx_offset); + skb_put(skb, rx_bytes); + if (metasize) + skb_metadata_set(skb, metasize); +-- +2.53.0 + diff --git a/queue-6.12/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch b/queue-6.12/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch new file mode 100644 index 0000000000..61172b0400 --- /dev/null +++ b/queue-6.12/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch @@ -0,0 +1,46 @@ +From 197cbb46650742088a2b368f470a26308b779d9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:41 +0200 +Subject: net: mvpp2: limit XDP frame size to the RX buffer + +From: Til Kaiser + +[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ] + +mvpp2 has short and long BM pools, and short pool buffers can be smaller +than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with +PAGE_SIZE as frame size. + +XDP helpers use frame_sz to validate tail growth and to derive the hard +end of the data area. Advertising PAGE_SIZE for short buffers can let +bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting +memory or later tripping skb tailroom checks. + +Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches +the actual buffer backing the packet. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-3-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 4aaa661f78f288..d5d2cbe127b0e7 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3994,7 +3994,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + xdp_rxq = &rxq->xdp_rxq_long; + +- xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq); ++ xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, + rx_bytes, false); +-- +2.53.0 + diff --git a/queue-6.12/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch b/queue-6.12/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch new file mode 100644 index 0000000000..4104751d52 --- /dev/null +++ b/queue-6.12/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch @@ -0,0 +1,126 @@ +From 05741e4ed5abacde3d97c7b9e2661a318a1824b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:42 +0200 +Subject: net: mvpp2: refill RX buffers before XDP or skb use + +From: Til Kaiser + +[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ] + +The RX error path returns the current descriptor buffer to the hardware +BM pool. That is only valid while the driver still owns the buffer. + +mvpp2_rx_refill() can fail after the current buffer has been handed to +XDP or attached to an skb. In those cases mvpp2_run_xdp() may have +recycled, redirected, or queued the page for XDP_TX, and an skb free also +retires the data buffer. Returning such a buffer to BM lets hardware DMA +into memory that is no longer owned by the RX ring. + +Refill the BM pool before handing the current buffer to XDP or to the +skb. If the allocation fails there, drop the packet and return the +still-owned current buffer to BM, preserving the pool depth. Once the +refill succeeds, later local drops retire/free the current buffer instead +of returning it to BM. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-4-mail@tk154.de +Signed-off-by: Paolo Abeni +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- + 1 file changed, 24 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index e43d844b14aaef..2c517f6ca39c40 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3986,6 +3986,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + frag_size = bm_pool->frag_size; + ++ err = mvpp2_rx_refill(port, bm_pool, pp, pool); ++ if (err) { ++ netdev_err(port->dev, "failed to refill BM pools\n"); ++ goto err_drop_frame; ++ } ++ + if (xdp_prog) { + struct xdp_rxq_info *xdp_rxq; + +@@ -4003,12 +4009,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + if (ret) { + xdp_ret |= ret; +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- goto err_drop_frame; +- } +- + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + continue; +@@ -4023,8 +4023,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb = slab_build_skb(data); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); +- goto err_drop_frame; ++ if (pp) { ++ page_pool_put_page(pp, virt_to_head_page(data), ++ rx_bytes + MVPP2_MH_SIZE, ++ true); ++ } else { ++ dma_unmap_single_attrs(dev->dev.parent, dma_addr, ++ bm_pool->buf_size, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ mvpp2_frag_free(bm_pool, pp, data); ++ } ++ goto err_drop_frame_retired; + } ++ if (pp) ++ skb_mark_for_recycle(skb); + + /* If we have RX hardware timestamping enabled, grab the + * timestamp from the queue and convert. +@@ -4035,16 +4048,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb_hwtstamps(skb)); + } + +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- dev_kfree_skb_any(skb); +- goto err_drop_frame; +- } +- +- if (pp) +- skb_mark_for_recycle(skb); +- else ++ if (!pp) + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); +@@ -4063,13 +4067,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + + err_drop_frame: +- dev->stats.rx_errors++; +- mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + if (rx_status & MVPP2_RXD_BUF_HDR) + mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status); + else + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); ++err_drop_frame_retired: ++ dev->stats.rx_errors++; ++ mvpp2_rx_error(port, rx_desc); + } + + if (xdp_ret & MVPP2_XDP_REDIR) +-- +2.53.0 + diff --git a/queue-6.12/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-6.12/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..f988667671 --- /dev/null +++ b/queue-6.12/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From 4c6459f690a8466c0b22eee3f9f3af9fff6cc332 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 51e35c4d9ea972..4aaa661f78f288 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3961,9 +3961,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-6.12/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-6.12/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..a81fba9b27 --- /dev/null +++ b/queue-6.12/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From 9d6be8de6d6e1a625cbfd2188aaf782403920d82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 607b5ca70ea547..260d1af64afc90 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1286,6 +1286,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-6.12/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch b/queue-6.12/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch new file mode 100644 index 0000000000..e0c064df4c --- /dev/null +++ b/queue-6.12/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch @@ -0,0 +1,53 @@ +From 93f506689ddb4114ce02fa538d5fe07c1e710e36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:15 +0200 +Subject: net: phy: clean the sfp upstream if phy probing fails + +From: Maxime Chevallier + +[ Upstream commit 48774e87bbaa0056819d4b52301e4692e50e3252 ] + +Sashiko reported that we don't call sfp_bus_del_upstream() in the probe +failure path, so let's add it, otherwise the sfp-bus is left with a +dangling 'upstream' field, that may be used later on during SFP events. + +This issue existed before the generic phylib sfp support, back when +drivers were calling phy_sfp_probe themselves. + +Reviewed-by: Nicolai Buchwitz +Fixes: 298e54fa810e ("net: phy: add core phylib sfp support") +Signed-off-by: Maxime Chevallier +Link: https://patch.msgid.link/20260604092819.723505-2-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index eb478e4961cb9b..f2d067b907bf99 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1508,6 +1508,9 @@ int phy_sfp_probe(struct phy_device *phydev, + + ret = sfp_bus_add_upstream(bus, phydev, ops); + sfp_bus_put(bus); ++ ++ if (ret) ++ phydev->sfp_bus = NULL; + } + return ret; + } +@@ -3672,6 +3675,9 @@ static int phy_probe(struct device *dev) + return 0; + + out: ++ sfp_bus_del_upstream(phydev->sfp_bus); ++ phydev->sfp_bus = NULL; ++ + if (!phydev->is_on_sfp_module) + phy_led_triggers_unregister(phydev); + +-- +2.53.0 + diff --git a/queue-6.12/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-6.12/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..af503b6e3a --- /dev/null +++ b/queue-6.12/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From aa8d99f840e6bf92d7d9e27474036cce12c3464d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index b703e4c6458532..2c009793f1931d 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -707,13 +707,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-6.12/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-6.12/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..d2c5795394 --- /dev/null +++ b/queue-6.12/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From 9ac8441f6c16d695a96dca64a845efa247b4a0cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index 4190b90ff3b18a..1909cd440a4b66 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-6.12/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch b/queue-6.12/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch new file mode 100644 index 0000000000..090fdce101 --- /dev/null +++ b/queue-6.12/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch @@ -0,0 +1,48 @@ +From c60cd7d1aa7fa85b7c9dd4b5577212f646f92da8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 18:21:24 -0700 +Subject: netdev: fix double-free in netdev_nl_bind_rx_doit() + +From: Jakub Kicinski + +[ Upstream commit c849de7d8757a7af801fc4a4058f71d481d367f2 ] + +Sashiko flags that genlmsg_reply() always consumes the skb. +The error path calls nlmsg_free(rsp) so we can't jump directly +to it. Let's not unbind, just propagate the error to the user. +This is the typical way of handling genlmsg_reply() failures. +They shouldn't happen unless user does something silly like +calling the kernel with an already-full rcvbuf. + +Reported-by: Sashiko +Fixes: 170aafe35cb9 ("netdev: support binding dma-buf to netdevice") +Reviewed-by: Bobby Eshleman +Acked-by: Daniel Borkmann +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/netdev-genl.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c +index 0fe537781bc4d9..6d4db55e90ed5a 100644 +--- a/net/core/netdev-genl.c ++++ b/net/core/netdev-genl.c +@@ -854,12 +854,10 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) + genlmsg_end(rsp, hdr); + + err = genlmsg_reply(rsp, info); +- if (err) +- goto err_unbind; + + rtnl_unlock(); + +- return 0; ++ return err < 0 ? err : 0; + + err_unbind: + net_devmem_unbind_dmabuf(binding); +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch b/queue-6.12/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch new file mode 100644 index 0000000000..3d3f77cd32 --- /dev/null +++ b/queue-6.12/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch @@ -0,0 +1,150 @@ +From 3826e8d50dc503a48baef6af94517d64cfdd8c40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 00:38:17 -0700 +Subject: netfilter: nf_conntrack: destroy stale expectfn expectations on + unregister + +From: Weiming Shi + +[ Upstream commit c3009418f9fa1dcb3eb86f4d8c92583537b5faa3 ] + +NAT helpers such as nf_nat_h323 store a raw pointer to module text in +exp->expectfn (e.g. ip_nat_q931_expect). nf_ct_helper_expectfn_unregister() +only unlinks the callback descriptor and never walks the expectation table, +so an expectation pending at module removal survives with a dangling +exp->expectfn into freed module text. + +When the expected connection arrives, init_conntrack() invokes +exp->expectfn(), now a stale pointer into the unloaded module. Reproduced +on a KASAN build by loading the H.323 helpers, creating a Q.931 +expectation, unloading nf_nat_h323, then connecting to the expected port: + + Oops: int3: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:0xffffffffa06102d1 + init_conntrack.isra.0 (net/netfilter/nf_conntrack_core.c:1862) + nf_conntrack_in (net/netfilter/nf_conntrack_core.c:2049) + ipv4_conntrack_local (net/netfilter/nf_conntrack_proto.c:223) + nf_hook_slow (net/netfilter/core.c:619) + __ip_local_out (net/ipv4/ip_output.c:120) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1715) + tcp_connect (net/ipv4/tcp_output.c:4374) + tcp_v4_connect (net/ipv4/tcp_ipv4.c:345) + __sys_connect (net/socket.c:2167) + Modules linked in: nf_conntrack_h323 [last unloaded: nf_nat_h323] + +Reaching the dangling state requires CAP_SYS_MODULE in the initial user +namespace to remove a NAT helper that still has live expectations, so this +is a robustness fix; leaving an expectation pointing at freed text is wrong +regardless. + +Add nf_ct_helper_expectfn_destroy(), which walks the expectation table and +drops every expectation whose ->expectfn matches the descriptor being torn +down. Call it from each NAT helper's exit path after the existing RCU grace +period, so no expectation outlives the code it points at and no extra +synchronize_rcu() is introduced. With the fix, the same reproducer runs to +completion without the Oops. + +Fixes: f587de0e2feb ("[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Weiming Shi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_helper.h | 1 + + net/ipv4/netfilter/nf_nat_h323.c | 2 ++ + net/netfilter/nf_conntrack_helper.c | 19 +++++++++++++++++++ + net/netfilter/nf_nat_core.c | 2 ++ + net/netfilter/nf_nat_sip.c | 1 + + 5 files changed, 25 insertions(+) + +diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h +index de2f956abf3480..24cf3d2d97450f 100644 +--- a/include/net/netfilter/nf_conntrack_helper.h ++++ b/include/net/netfilter/nf_conntrack_helper.h +@@ -155,6 +155,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct, + + void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); + void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n); + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name); + struct nf_ct_helper_expectfn * +diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c +index faee20af485613..10e1b0837731b7 100644 +--- a/net/ipv4/netfilter/nf_nat_h323.c ++++ b/net/ipv4/netfilter/nf_nat_h323.c +@@ -555,6 +555,8 @@ static void __exit nf_nat_h323_fini(void) + nf_ct_helper_expectfn_unregister(&q931_nat); + nf_ct_helper_expectfn_unregister(&callforwarding_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&q931_nat); ++ nf_ct_helper_expectfn_destroy(&callforwarding_nat); + } + + /****************************************************************************/ +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index a715304a53d8c2..9150bcfd7ca83b 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -283,6 +283,25 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) + } + EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); + ++static bool expect_iter_expectfn(struct nf_conntrack_expect *exp, void *data) ++{ ++ const struct nf_ct_helper_expectfn *n = data; ++ ++ /* Relies on registered expectfn descriptors having unique ->expectfn ++ * pointers, which holds for the in-tree NAT helpers. ++ */ ++ return exp->expectfn == n->expectfn; ++} ++ ++/* Destroy expectations still pointing at @n->expectfn; call after the ++ * caller's RCU grace period so none outlives the (often modular) callback. ++ */ ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n) ++{ ++ nf_ct_expect_iterate_destroy(expect_iter_expectfn, (void *)n); ++} ++EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_destroy); ++ + /* Caller should hold the rcu lock */ + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 746acd124ea285..6ba7733355df39 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1353,6 +1353,7 @@ static int __init nf_nat_init(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + nf_ct_helper_expectfn_unregister(&follow_master_nat); + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + unregister_pernet_subsys(&nat_net_ops); + kvfree(nf_nat_bysource); + } +@@ -1370,6 +1371,7 @@ static void __exit nf_nat_cleanup(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + kvfree(nf_nat_bysource); + unregister_pernet_subsys(&nat_net_ops); + } +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 9fbfc6bff0c221..00838c0cc5bb28 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -655,6 +655,7 @@ static void __exit nf_nat_sip_fini(void) + RCU_INIT_POINTER(nf_nat_sip_hooks, NULL); + nf_ct_helper_expectfn_unregister(&sip_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&sip_nat); + } + + static const struct nf_nat_sip_hooks sip_hooks = { +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nf_log-validate-mac-header-was-set-before-.patch b/queue-6.12/netfilter-nf_log-validate-mac-header-was-set-before-.patch new file mode 100644 index 0000000000..3dfb4d43b9 --- /dev/null +++ b/queue-6.12/netfilter-nf_log-validate-mac-header-was-set-before-.patch @@ -0,0 +1,70 @@ +From e6acecfdb03a55bf856d0e9c6a48b3f791f00b24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:55:02 -0700 +Subject: netfilter: nf_log: validate MAC header was set before dumping it + +From: Xiang Mei + +[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ] + +The fallback path of dump_mac_header() guards the MAC header access +only with "skb->mac_header != skb->network_header", without checking +skb_mac_header_was_set(). When the MAC header is unset, mac_header is +0xffff, so the test passes and skb_mac_header(skb) returns +skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads +dev->hard_header_len bytes out of bounds into the kernel log. + +This is reachable via the netdev logger: nf_log_unknown_packet() calls +dump_mac_header() unconditionally, and an skb sent through AF_PACKET +with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still +unset (__dev_queue_xmit(), which would reset it, is bypassed). + +Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already +uses, and replace the open-coded MAC header length test with +skb_mac_header_len(). Only skbs with an unset MAC header are affected; +valid ones are dumped as before. + + BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) + Read of size 1 at addr ffff88800ea49d3f by task exploit/148 + Call Trace: + kasan_report (mm/kasan/report.c:595) + dump_mac_header (net/netfilter/nf_log_syslog.c:831) + nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) + nf_log_packet (net/netfilter/nf_log.c:260) + nft_log_eval (net/netfilter/nft_log.c:60) + nft_do_chain (net/netfilter/nf_tables_core.c:285) + nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) + nf_hook_slow (net/netfilter/core.c:619) + nf_hook_direct_egress (net/packet/af_packet.c:257) + packet_xmit (net/packet/af_packet.c:280) + packet_sendmsg (net/packet/af_packet.c:3114) + __sys_sendto (net/socket.c:2265) + +Fixes: 7eb9282cd0ef ("netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_log_syslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 58402226045e84..09b9152e9e5492 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -799,8 +799,8 @@ static void dump_mac_header(struct nf_log_buf *m, + + fallback: + nf_log_buf_add(m, "MAC="); +- if (dev->hard_header_len && +- skb->mac_header != skb->network_header) { ++ if (dev->hard_header_len && skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) != 0) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-6.12/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..5844c6b12b --- /dev/null +++ b/queue-6.12/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From c506d612b1d984e3fba9f3f7a88aa349a6b8479a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index c74012c9912554..1fc2a948d00afc 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -530,6 +530,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-revalidate-bridge-ports.patch b/queue-6.12/netfilter-revalidate-bridge-ports.patch new file mode 100644 index 0000000000..d8947148cd --- /dev/null +++ b/queue-6.12/netfilter-revalidate-bridge-ports.patch @@ -0,0 +1,239 @@ +From 1e362948a49353f7fa76102482f9145746e2cb87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 17:04:25 +0200 +Subject: netfilter: revalidate bridge ports + +From: Florian Westphal + +[ Upstream commit ccb9fd4b87538ccf19ccff78ee26700526d94867 ] + +ebt_redirect_tg() dereferences br_port_get_rcu() return without a +NULL check, causing a kernel panic when the bridge port has been +removed between the original hook invocation and an NFQUEUE +reinject. + +A mere NULL check isn't sufficient, however. As sashiko review +points out userspace can not only remove the port from the bridge, +it could also place the device in a different virtual device, e.g. +macvlan. + +If this happens, we must drop the packet, there is no way for us to +reinject it into the bridge path. + +Switch to _upper API, we don't need the bridge port structure. +Also, this fix keeps another bug intact: + +Both nfnetlink_log and nfnetlink_queue use CONFIG_BRIDGE_NETFILTER +too aggressive, which prevents certain logging features when queueing +in bridge family: NETFILTER_FAMILY_BRIDGE can be enabled while the old +CONFIG_BRIDGE_NETFILTER cruft is off. + +Fixes tag is a common ancestor, this was always broken. + +Fixes: f350a0a87374 ("bridge: use rx_handler_data pointer to store net_bridge_port pointer") +Reported-by: Ji'an Zhou +Assisted-by: Claude:claude-sonnet-4-6 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_dnat.c | 4 +- + net/bridge/netfilter/ebt_redirect.c | 16 +++++--- + net/netfilter/nfnetlink_log.c | 23 +++++++++-- + net/netfilter/nfnetlink_queue.c | 64 +++++++++++++++++++++++++---- + 4 files changed, 89 insertions(+), 18 deletions(-) + +diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c +index 3fda71a8579d13..73f185cccd63df 100644 +--- a/net/bridge/netfilter/ebt_dnat.c ++++ b/net/bridge/netfilter/ebt_dnat.c +@@ -39,7 +39,9 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par) + dev = xt_in(par); + break; + case NF_BR_PRE_ROUTING: +- dev = br_port_get_rcu(xt_in(par))->br->dev; ++ dev = netdev_master_upper_dev_get_rcu(xt_in(par)); ++ if (!dev) /* bridge port removed? */ ++ return EBT_DROP; + break; + default: + dev = NULL; +diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c +index 307790562b4929..83486cd4d564b1 100644 +--- a/net/bridge/netfilter/ebt_redirect.c ++++ b/net/bridge/netfilter/ebt_redirect.c +@@ -24,12 +24,18 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) + if (skb_ensure_writable(skb, 0)) + return EBT_DROP; + +- if (xt_hooknum(par) != NF_BR_BROUTING) +- /* rcu_read_lock()ed by nf_hook_thresh */ +- ether_addr_copy(eth_hdr(skb)->h_dest, +- br_port_get_rcu(xt_in(par))->br->dev->dev_addr); +- else ++ if (xt_hooknum(par) != NF_BR_BROUTING) { ++ const struct net_device *dev; ++ ++ dev = netdev_master_upper_dev_get_rcu(xt_in(par)); ++ if (!dev) ++ return EBT_DROP; ++ ++ ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); ++ } else { + ether_addr_copy(eth_hdr(skb)->h_dest, xt_in(par)->dev_addr); ++ } ++ + skb->pkt_type = PACKET_HOST; + return info->target; + } +diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c +index 3da32d2f68e092..cfd68bc005d26b 100644 +--- a/net/netfilter/nfnetlink_log.c ++++ b/net/netfilter/nfnetlink_log.c +@@ -450,6 +450,23 @@ static int nfulnl_put_bridge(struct nfulnl_instance *inst, const struct sk_buff + return -1; + } + ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++static int nflog_put_master_ifindex(struct sk_buff *nlskb, int attr, ++ const struct net_device *dev) ++{ ++ const struct net_device *upper; ++ ++ if (dev && !netif_is_bridge_port(dev)) ++ return 0; ++ ++ upper = netdev_master_upper_dev_get_rcu((struct net_device *)dev); ++ if (upper && nla_put_be32(nlskb, attr, htonl(upper->ifindex))) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++#endif ++ + /* This is an inline function, we don't really care about a long + * list of arguments */ + static inline int +@@ -504,8 +521,7 @@ __build_packet_message(struct nfnl_log_net *log, + /* rcu_read_lock()ed by nf_hook_thresh or + * nf_log_packet. + */ +- nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, +- htonl(br_port_get_rcu(indev)->br->dev->ifindex))) ++ nflog_put_master_ifindex(inst->skb, NFULA_IFINDEX_INDEV, indev)) + goto nla_put_failure; + } else { + int physinif; +@@ -541,8 +557,7 @@ __build_packet_message(struct nfnl_log_net *log, + /* rcu_read_lock()ed by nf_hook_thresh or + * nf_log_packet. + */ +- nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, +- htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) ++ nflog_put_master_ifindex(inst->skb, NFULA_IFINDEX_OUTDEV, outdev)) + goto nla_put_failure; + } else { + struct net_device *physoutdev; +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 8518b620ae50ed..1b517cd2bb58cc 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -426,10 +426,47 @@ static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_ + return false; + } + ++static bool nf_bridge_port_valid(const struct net_device *dev) ++{ ++ if (!dev) ++ return true; ++ ++ return netif_is_bridge_port(dev); ++} ++ ++/* queued skbs leave rcu protection. We bump device refcount so that ++ * the device cannot go away. However, while packet was out the port ++ * could have been removed from the bridge. ++ * ++ * Ensure in+outdev are still part of a bridge at reinject time. ++ * ++ * The device rx_handler_data could even be pointing at data that is ++ * not a net_bridge_port structure. ++ */ ++static bool nf_bridge_ports_valid(const struct nf_queue_entry *entry) ++{ ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++ if (!nf_bridge_port_valid(entry->physin) || ++ !nf_bridge_port_valid(entry->physout)) ++ return false; ++#endif ++ if (entry->state.pf != PF_BRIDGE) ++ return true; ++ ++ if (!nf_bridge_port_valid(entry->state.in) || ++ !nf_bridge_port_valid(entry->state.out)) ++ return false; ++ ++ return true; ++} ++ + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + { + const struct nf_ct_hook *ct_hook; + ++ if (!nf_bridge_ports_valid(entry)) ++ verdict = NF_DROP; ++ + if (verdict == NF_ACCEPT || + verdict == NF_REPEAT || + verdict == NF_STOP) { +@@ -622,6 +659,23 @@ static int nf_queue_checksum_help(struct sk_buff *entskb) + return skb_checksum_help(entskb); + } + ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++static int nfqnl_put_master_ifindex(struct sk_buff *nlskb, int attr, ++ const struct net_device *dev) ++{ ++ const struct net_device *upper; ++ ++ if (dev && !netif_is_bridge_port(dev)) ++ return 0; ++ ++ upper = netdev_master_upper_dev_get_rcu((struct net_device *)dev); ++ if (upper && nla_put_be32(nlskb, attr, htonl(upper->ifindex))) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++#endif ++ + static struct sk_buff * + nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + struct nf_queue_entry *entry, +@@ -755,10 +809,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + * netfilter_bridge) */ + if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV, + htonl(indev->ifindex)) || +- /* this is the bridge group "brX" */ +- /* rcu_read_lock()ed by __nf_queue */ +- nla_put_be32(skb, NFQA_IFINDEX_INDEV, +- htonl(br_port_get_rcu(indev)->br->dev->ifindex))) ++ nfqnl_put_master_ifindex(skb, NFQA_IFINDEX_INDEV, indev)) + goto nla_put_failure; + } else { + int physinif; +@@ -789,10 +840,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + * netfilter_bridge) */ + if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV, + htonl(outdev->ifindex)) || +- /* this is the bridge group "brX" */ +- /* rcu_read_lock()ed by __nf_queue */ +- nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, +- htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) ++ nfqnl_put_master_ifindex(skb, NFQA_IFINDEX_OUTDEV, outdev)) + goto nla_put_failure; + } else { + int physoutif; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-6.12/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..bf550310bc --- /dev/null +++ b/queue-6.12/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From 1a90c8ebd96e729c8e3cd49690ed5480017eb673 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 97ead883e4a13b..b752c9eac998e4 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -702,14 +702,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1327,9 +1325,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 3d101613f27fa5..0ba456c4c63416 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -832,14 +832,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1228,9 +1226,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 7d5602950ae72a..6c5022242cf0b0 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -848,14 +848,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1244,9 +1242,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-6.12/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-6.12/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..875ef6aabf --- /dev/null +++ b/queue-6.12/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From b522c72995b51f192c71b7ec6d1b8fd1ebc8a2e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index 9996883bf2b78d..6007cb000da678 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -764,24 +764,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-6.12/r8152-handle-the-return-value-of-usb_reset_device.patch b/queue-6.12/r8152-handle-the-return-value-of-usb_reset_device.patch new file mode 100644 index 0000000000..5c7e2e4d34 --- /dev/null +++ b/queue-6.12/r8152-handle-the-return-value-of-usb_reset_device.patch @@ -0,0 +1,44 @@ +From bf80a69c4781a569a0005e092471d3e970d5b0f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 17:22:47 +0800 +Subject: r8152: handle the return value of usb_reset_device() + +From: Chih Kai Hsu + +[ Upstream commit 19440600e729d4f74a42591a872099cf25c7d28a ] + +If usb_reset_device() returns a negative error code, stop the +process of probing. + +Fixes: 10c3271712f5 ("r8152: disable the ECM mode") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260604092247.27158-450-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 1c36816405f13b..f3a4a40d534631 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -9811,7 +9811,12 @@ static int rtl8152_probe_once(struct usb_interface *intf, + struct net_device *netdev; + int ret; + +- usb_reset_device(udev); ++ ret = usb_reset_device(udev); ++ if (ret < 0) { ++ dev_err(&intf->dev, "USB reset failed, errno=%d\n", ret); ++ return ret; ++ } ++ + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { + dev_err(&intf->dev, "Out of memory\n"); +-- +2.53.0 + diff --git a/queue-6.12/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-6.12/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..3c32ca03f1 --- /dev/null +++ b/queue-6.12/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From 96b7ae42b632136e4b7a494b8c911cac2fd9995c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index b6b46a8214a0a5..b3ee5f8238c44d 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-6.12/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-6.12/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..19c9004d92 --- /dev/null +++ b/queue-6.12/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From 524009126b15617308336481b694358d752748eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 032a10d82302c3..df5b2187b8fada 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1204,6 +1204,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index fe63823fa8..b73b762168 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -68,3 +68,39 @@ tools-rv-fix-cleanup-after-failed-trace-setup.patch tap-free-page-on-error-paths-in-tap_get_user_xdp.patch arm64-tlb-allow-xzr-argument-to-tlbi-ops.patch arm64-tlb-optimize-arm64_workaround_repeat_tlbi.patch +iomap-don-t-revert-iov_iter-on-partially-completed-b.patch +dma-debug-fix-physical-address-retrieval-in-debug_dm.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch +asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch +tcp-restrict-so_attach_filter-to-priv-users.patch +net-add-pskb_may_pull-to-skb_gro_receive_list.patch +net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch +net-ibm-emac-fix-use-after-free-during-device-remova.patch +netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch +net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch +net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch +net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +r8152-handle-the-return-value-of-usb_reset_device.patch +gpio-zynq-fix-runtime-pm-leak-on-remove.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +netfilter-revalidate-bridge-ports.patch +netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nf_log-validate-mac-header-was-set-before-.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch +net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch +net-mvpp2-add-metadata-support-for-xdp-mode.patch +net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch +net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch +ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch diff --git a/queue-6.12/tcp-restrict-so_attach_filter-to-priv-users.patch b/queue-6.12/tcp-restrict-so_attach_filter-to-priv-users.patch new file mode 100644 index 0000000000..16008294f3 --- /dev/null +++ b/queue-6.12/tcp-restrict-so_attach_filter-to-priv-users.patch @@ -0,0 +1,58 @@ +From 05d65973cac229286fc634130caa58eab1c8aed0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:21:34 +0000 +Subject: tcp: restrict SO_ATTACH_FILTER to priv users + +From: Eric Dumazet + +[ Upstream commit 5d39580f68e6ddeedd15e587282207489dfb3da2 ] + +This patch restricts the use of SO_ATTACH_FILTER (cBPF) on TCP sockets +to users with CAP_NET_ADMIN capability. + +This blocks potential side-channel attack where an unprivileged application +attaches a filter to leak TCP sequence/acknowledgment numbers. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Eric Dumazet +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Cc: Willem de Bruijn +Cc: Alexei Starovoitov +Cc: Daniel Borkmann +Cc: Andrii Nakryiko +Cc: Martin KaFai Lau +Cc: Eduard Zingerman +Cc: Kumar Kartikeya Dwivedi +Cc: Song Liu +Cc: Yonghong Song +Cc: Jiri Olsa +Cc: John Fastabend +Cc: Stanislav Fomichev +Acked-by: Daniel Borkmann +Reviewed-by: Willem de Bruijn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 7b6ed7c85a58cc..4a09e780406fe8 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1455,6 +1455,11 @@ int sk_setsockopt(struct sock *sk, int level, int optname, + case SO_ATTACH_FILTER: { + struct sock_fprog fprog; + ++ if (sk_is_tcp(sk) && ++ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ break; ++ } + ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); + if (!ret) + ret = sk_attach_filter(&fprog, sk); +-- +2.53.0 + diff --git a/queue-6.12/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-6.12/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..e425387ebb --- /dev/null +++ b/queue-6.12/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From a8242415ac4f31c3bea5956433dfa52741c16fa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index dab782dcc829de..5a7ec72e17b0e5 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1156,15 +1156,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1707,12 +1698,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 + diff --git a/queue-6.18/asoc-sof-amd-fix-for-ipc-flags-check.patch b/queue-6.18/asoc-sof-amd-fix-for-ipc-flags-check.patch new file mode 100644 index 0000000000..9d1ae91d87 --- /dev/null +++ b/queue-6.18/asoc-sof-amd-fix-for-ipc-flags-check.patch @@ -0,0 +1,68 @@ +From 8c4a3db8b59af6f5503e397109dbeee8589354dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:38:44 +0530 +Subject: ASoC: SOF: amd: fix for ipc flags check + +From: Vijendar Mukunda + +[ Upstream commit 6042c91df60e825625bc7d5c5c3b5a87b91d5805 ] + +Firmware will set dsp_ack to 1 when firmware sends response for the IPC +command issued by host. Similarly dsp_msg flag will be updated to 1. + +During ACP D0 entry, the value read from the sof_dsp_ack_write scratch +flag can be uninitialized. A non-zero garbage value is treated as a +pending DSP IPC ack before SOF_FW_BOOT_COMPLETE, causing a spurious +"IPC reply before FW_BOOT_COMPLETE" log. + +Fix the condition checks for ipc flags. + +Fixes: 738a2b5e2cc9 ("ASoC: SOF: amd: Add IPC support for ACP IP block") +Link: https://github.com/thesofproject/linux/pull/5642 +Signed-off-by: Vijendar Mukunda +Tested-by: Umang Jain +Link: https://patch.msgid.link/20260609160938.3717513-1-Vijendar.Mukunda@amd.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/amd/acp-ipc.c | 4 ++-- + sound/soc/sof/amd/acp.h | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c +index 22d4b807e1bb75..1c3f7601a8c4ce 100644 +--- a/sound/soc/sof/amd/acp-ipc.c ++++ b/sound/soc/sof/amd/acp-ipc.c +@@ -181,14 +181,14 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) + } + + dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); +- if (dsp_msg) { ++ if (dsp_msg == ACP_DSP_MSG_SET) { + snd_sof_ipc_msgs_rx(sdev); + acp_dsp_ipc_host_done(sdev); + ipc_irq = true; + } + + dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); +- if (dsp_ack) { ++ if (dsp_ack == ACP_DSP_ACK_SET) { + if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { + spin_lock_irq(&sdev->ipc_lock); + +diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h +index 2b7ea8c6410602..7bcb76676a984a 100644 +--- a/sound/soc/sof/amd/acp.h ++++ b/sound/soc/sof/amd/acp.h +@@ -116,6 +116,8 @@ + #define ACP_SRAM_PAGE_COUNT 128 + #define ACP6X_SDW_MAX_MANAGER_COUNT 2 + #define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT ++#define ACP_DSP_MSG_SET 1 ++#define ACP_DSP_ACK_SET 1 + + enum clock_source { + ACP_CLOCK_96M = 0, +-- +2.53.0 + diff --git a/queue-6.18/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch b/queue-6.18/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch new file mode 100644 index 0000000000..d801809084 --- /dev/null +++ b/queue-6.18/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch @@ -0,0 +1,52 @@ +From 0e78363d86abed255e370db5edfdaf4a0f157674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:12:44 +0100 +Subject: ASoC: wm_adsp: Fix NULL dereference when removing firmware controls + +From: Richard Fitzgerald + +[ Upstream commit 7d3fb78b550301e43fdc60312aed733069694426 ] + +In wm_adsp_control_remove() check that the priv pointer is not NULL +before attempting to cleanup what it points to. + +When cs_dsp creates a control it calls wm_adsp_control_add_cb() so that +wm_adsp can create its own private control data. There are two cases +where private data is not created: + +1. The control is a SYSTEM control, so an ALSA control is not created. + +2. The codec driver has registered a control_add() callback that + hides the control, so wm_adsp_control_add() is not called. + +When cs_dsp_remove destroys its control list it calls +wm_adsp_control_remove() for each control. But wm_adsp_control_remove() +was attempting to cleanup the private data pointed to by cs_ctl->priv +without checking the pointer for NULL. + +Signed-off-by: Richard Fitzgerald +Fixes: 0700bc2fb94c ("ASoC: wm_adsp: Separate generic cs_dsp_coeff_ctl handling") +Link: https://patch.msgid.link/20260604101244.1402862-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wm_adsp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c +index 8782c331e92529..751a3c25e4f0b1 100644 +--- a/sound/soc/codecs/wm_adsp.c ++++ b/sound/soc/codecs/wm_adsp.c +@@ -666,6 +666,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) + { + struct wm_coeff_ctl *ctl = cs_ctl->priv; + ++ if (!ctl) ++ return; ++ + cancel_work_sync(&ctl->work); + + kfree(ctl->name); +-- +2.53.0 + diff --git a/queue-6.18/bnge-fix-context-mem-iteration.patch b/queue-6.18/bnge-fix-context-mem-iteration.patch new file mode 100644 index 0000000000..5a7432ab0c --- /dev/null +++ b/queue-6.18/bnge-fix-context-mem-iteration.patch @@ -0,0 +1,75 @@ +From 2e0c7b62d85f19964a0c424617588a59c0218e0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 22:07:09 +0530 +Subject: bnge: fix context mem iteration + +From: Vikas Gupta + +[ Upstream commit 3847d94783c0b893c27ff0b26a3325796d9444c6 ] + +The firmware advertises context memory (backing store) types +through a linked list, with BNGE_CTX_INV serving as the +end-of-list sentinel. +However, the driver incorrectly assumes that the list is strictly +ordered and prematurely terminates traversal when it encounters +an unrecognized type (>=BNGE_CTX_V2_MAX). As a result, any valid +context types that appear later in the chain are silently skipped, +leading to incomplete memory configuration and eventual driver load +failure. + +Fix this by traversing the entire list until the BNGE_CTX_INV sentinel +is reached, while safely ignoring only those context types that fall +outside the supported range. + +Fixes: 29c5b358f385 ("bng_en: Add backing store support") +Signed-off-by: Vikas Gupta +Reviewed-by: Dharmender Garg +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +index 2994f10446a63c..0042d7d6ff9bc2 100644 +--- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c ++++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +@@ -259,7 +259,7 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd) + struct hwrm_func_backing_store_qcaps_v2_output *resp; + struct hwrm_func_backing_store_qcaps_v2_input *req; + struct bnge_ctx_mem_info *ctx; +- u16 type; ++ u16 type, next_type; + int rc; + + if (bd->ctx) +@@ -276,8 +276,8 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd) + + resp = bnge_hwrm_req_hold(bd, req); + +- for (type = 0; type < BNGE_CTX_V2_MAX; ) { +- struct bnge_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; ++ for (type = 0; type < BNGE_CTX_INV; type = next_type) { ++ struct bnge_ctx_mem_type *ctxm; + u8 init_val, init_off, i; + __le32 *p; + u32 flags; +@@ -286,8 +286,14 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd) + rc = bnge_hwrm_req_send(bd, req); + if (rc) + goto ctx_done; ++ ++ next_type = le16_to_cpu(resp->next_valid_type); ++ if (type >= BNGE_CTX_V2_MAX) ++ continue; ++ ++ ctxm = &ctx->ctx_arr[type]; + flags = le32_to_cpu(resp->flags); +- type = le16_to_cpu(resp->next_valid_type); ++ + if (!(flags & + FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID)) + continue; +-- +2.53.0 + diff --git a/queue-6.18/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch b/queue-6.18/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch new file mode 100644 index 0000000000..76d3f292f9 --- /dev/null +++ b/queue-6.18/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch @@ -0,0 +1,45 @@ +From d327d997176ac629827569af7dc105849d6135fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 20:37:08 +0800 +Subject: dma-debug: fix physical address retrieval in + debug_dma_sync_sg_for_device + +From: Li RongQing + +[ Upstream commit 9bfaa86b405381326c971984fd6da184c289713f ] + +In debug_dma_sync_sg_for_device(), when iterating over a scatterlist, +the debug entry population mistakenly uses the head of the scatterlist +'sg' to fetch the physical address via sg_phys(), instead of using the +current iterator variable 's'. + +This causes dma-debug to track the physical address of the very first +scatterlist entry for all subsequent entries in the list. + +Fix this by passing the correct loop iterator 's' to sg_phys() + +Fixes: 9d4f645a1fd49ee ("dma-debug: store a phys_addr_t in struct dma_debug_entry") +Signed-off-by: Li RongQing +Signed-off-by: Marek Szyprowski +Link: https://lore.kernel.org/r/20260603123708.1665-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + kernel/dma/debug.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c +index fa4aac33391723..03780f39613cca 100644 +--- a/kernel/dma/debug.c ++++ b/kernel/dma/debug.c +@@ -1555,7 +1555,7 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + struct dma_debug_entry ref = { + .type = dma_debug_sg, + .dev = dev, +- .paddr = sg_phys(sg), ++ .paddr = sg_phys(s), + .dev_addr = sg_dma_address(s), + .size = sg_dma_len(s), + .direction = direction, +-- +2.53.0 + diff --git a/queue-6.18/dma-mapping-direct-fix-missing-mapping-for-thru_host.patch b/queue-6.18/dma-mapping-direct-fix-missing-mapping-for-thru_host.patch new file mode 100644 index 0000000000..1599621a45 --- /dev/null +++ b/queue-6.18/dma-mapping-direct-fix-missing-mapping-for-thru_host.patch @@ -0,0 +1,43 @@ +From bc5a32e3fa194e68226719ed2b9339b19c44cb60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:37:23 +0800 +Subject: dma-mapping: direct: fix missing mapping for THRU_HOST_BRIDGE + segments + +From: Li RongQing + +[ Upstream commit 560000d619ef162568746ce287f0c725e24ea967 ] + +In dma_direct_map_sg(), the case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE +incorrectly used 'break' instead of falling through to MAP_NONE. +As a result, segments traversing the host bridge skipped the required +dma_direct_map_phys() call entirely, leaving sg->dma_address +uninitialized and leading to DMA failures. Fix this by using +'fallthrough;'. + +Fixes: a25e7962db0d79 ("PCI/P2PDMA: Refactor the p2pdma mapping helpers") +Reviewed-by: Logan Gunthorpe +Signed-off-by: Li RongQing +Signed-off-by: Marek Szyprowski +Link: https://lore.kernel.org/r/20260603013723.2439-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + kernel/dma/direct.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c +index f973e7e73c90bb..fd483b558b504c 100644 +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -469,7 +469,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents, + * must be mapped with CPU physical address and not PCI + * bus addresses. + */ +- break; ++ fallthrough; + case PCI_P2PDMA_MAP_NONE: + sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg), + sg->length, dir, attrs); +-- +2.53.0 + diff --git a/queue-6.18/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch b/queue-6.18/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch new file mode 100644 index 0000000000..878887a198 --- /dev/null +++ b/queue-6.18/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch @@ -0,0 +1,85 @@ +From e187f982337d7823c46dc75a63c650f35d298b2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:43:34 +0800 +Subject: gpio: mvebu: fix NULL pointer dereference in suspend/resume + +From: Yun Zhou + +[ Upstream commit b9ad50d7505ebd48282ec3630258dc820fc85c81 ] + +mvebu_pwm_suspend() and mvebu_pwm_resume() are called for all GPIO +banks during suspend/resume, but not all banks have PWM functionality. +GPIO banks without PWM have mvchip->mvpwm set to NULL. + +Calling mvebu_pwm_suspend() with mvpwm == NULL causes a NULL pointer +dereference when it tries to access mvpwm->blink_select. + + Unable to handle kernel NULL pointer dereference at virtual address 00000020 when write + [00000020] *pgd=00000000 + Internal error: Oops: 815 [#1] PREEMPT ARM + Modules linked in: + CPU: 0 UID: 0 PID: 406 Comm: sh Not tainted 6.12.74-rt12-yocto-standard-g4e96f98fb7db-dirty #353 + Hardware name: Marvell Armada 370/XP (Device Tree) + PC is at regmap_mmio_read+0x38/0x54 + LR is at regmap_mmio_read+0x38/0x54 + pc : [] lr : [] psr: 200f0013 + sp : f0c11d10 ip : 00000000 fp : c100d2f0 + r10: c14fb854 r9 : 00000000 r8 : 00000000 + r7 : c1799c00 r6 : 00000020 r5 : 00000020 r4 : c179c7c0 + r3 : f0a231a0 r2 : 00000020 r1 : 00000020 r0 : 00000000 + Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none + Control: 10c5387d Table: 135ec059 DAC: 00000051 + Call trace: + regmap_mmio_read from _regmap_bus_reg_read+0x78/0xac + _regmap_bus_reg_read from _regmap_read+0x60/0x154 + _regmap_read from regmap_read+0x3c/0x60 + regmap_read from mvebu_gpio_suspend+0xa4/0x14c + mvebu_gpio_suspend from dpm_run_callback+0x54/0x180 + dpm_run_callback from device_suspend+0x124/0x630 + device_suspend from dpm_suspend+0x124/0x270 + dpm_suspend from dpm_suspend_start+0x64/0x6c + dpm_suspend_start from suspend_devices_and_enter+0x140/0x8e8 + suspend_devices_and_enter from pm_suspend+0x2fc/0x308 + pm_suspend from state_store+0x6c/0xc8 + state_store from kernfs_fop_write_iter+0x10c/0x1f8 + kernfs_fop_write_iter from vfs_write+0x270/0x468 + vfs_write from ksys_write+0x70/0xf0 + ksys_write from ret_fast_syscall+0x0/0x54 + +Add a NULL check for mvchip->mvpwm before calling the PWM +suspend/resume functions. + +Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support") +Signed-off-by: Yun Zhou +Link: https://patch.msgid.link/20260608084334.2960803-1-yun.zhou@windriver.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mvebu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c +index ac799fced950e3..a7018e8ed88b10 100644 +--- a/drivers/gpio/gpio-mvebu.c ++++ b/drivers/gpio/gpio-mvebu.c +@@ -997,7 +997,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_suspend(mvchip); + + return 0; +@@ -1049,7 +1049,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_resume(mvchip); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch b/queue-6.18/gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch new file mode 100644 index 0000000000..331a08ef78 --- /dev/null +++ b/queue-6.18/gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch @@ -0,0 +1,54 @@ +From 99fab45149831505bf0250fa54f418f8aaebc5c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 01:05:02 +0200 +Subject: gpio: rockchip: fix generic IRQ chip leak on remove + +From: Marco Scardovi + +[ Upstream commit 1c1e0fc88d6ef65bf15d517853251f75ab9d18c3 ] + +The driver allocates domain generic chips using +irq_alloc_domain_generic_chips() during probe. However, on driver +remove/teardown, the generic chips are not automatically freed when the +IRQ domain is removed because the domain flags do not include +IRQ_DOMAIN_FLAG_DESTROY_GC. + +This causes both the domain generic chips structure and the associated +generic chips to be leaked. Additionally, the generic chips remain on +the global gc_list and may later be visited by generic IRQ chip suspend, +resume, or shutdown callbacks after the GPIO bank has been removed, +potentially resulting in a use-after-free and kernel crash. + +Fix the resource leak by explicitly calling +irq_domain_remove_generic_chips() before removing the IRQ domain in +rockchip_gpio_remove(). + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260607230504.35392-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index 1ef0ba956cfd8c..46dd9085d9c8cd 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -802,8 +802,10 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + + irq_set_chained_handler_and_data(bank->irq, NULL, NULL); +- if (bank->domain) ++ if (bank->domain) { ++ irq_domain_remove_generic_chips(bank->domain); + irq_domain_remove(bank->domain); ++ } + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-6.18/gpio-zynq-fix-runtime-pm-leak-on-remove.patch b/queue-6.18/gpio-zynq-fix-runtime-pm-leak-on-remove.patch new file mode 100644 index 0000000000..c0c88f848b --- /dev/null +++ b/queue-6.18/gpio-zynq-fix-runtime-pm-leak-on-remove.patch @@ -0,0 +1,39 @@ +From f6716c72fe40889a127e42b82f9e2a383fb50a86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:33:13 +0800 +Subject: gpio: zynq: fix runtime PM leak on remove + +From: Ruoyu Wang + +[ Upstream commit 6edb934de9bda3b7abcec856eaee6fc8b4278dd1 ] + +pm_runtime_get_sync() increments the runtime PM usage counter even when it +returns an error. zynq_gpio_remove() uses it to keep the controller active +while removing the GPIO chip, but never drops the usage counter again. + +Balance the get with pm_runtime_put_noidle() after disabling runtime PM. + +Fixes: 3242ba117e9b ("gpio: Add driver for Zynq GPIO controller") +Signed-off-by: Ruoyu Wang +Link: https://patch.msgid.link/20260609073313.5-1-ruoyuw560@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-zynq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c +index 0ffd76e8951fc0..c2e4a79cd6d8ce 100644 +--- a/drivers/gpio/gpio-zynq.c ++++ b/drivers/gpio/gpio-zynq.c +@@ -1017,6 +1017,7 @@ static void zynq_gpio_remove(struct platform_device *pdev) + gpiochip_remove(&gpio->chip); + device_set_wakeup_capable(&pdev->dev, 0); + pm_runtime_disable(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); + } + + static struct platform_driver zynq_gpio_driver = { +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch b/queue-6.18/ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch new file mode 100644 index 0000000000..f930873f18 --- /dev/null +++ b/queue-6.18/ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch @@ -0,0 +1,74 @@ +From d31f2e63f9f8e9438a10054eab36bea40b4eaef5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:55:10 -0700 +Subject: ice: fix missing priority callbacks for U.FL DPLL pins + +From: Petr Oros + +[ Upstream commit f1fa677e428e8873486938086bd934dc18169b47 ] + +The U.FL2 input pin advertises DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE +in its capability mask, but ice_dpll_pin_ufl_ops does not provide +.prio_get and .prio_set callbacks. As a result the DPLL subsystem +cannot report or accept priority for U.FL pins: pin-get omits the prio +field on U.FL2 and pin-set with prio is rejected as invalid, even +though the capability is present. This prevents user space from using +priority to select or disable U.FL2 as a DPLL input source. + +Reproducer with iproute2 (dpll command): + + # dpll pin show board-label U.FL2 + pin id 16: + module-name ice + board-label U.FL2 + type ext + capabilities priority-can-change|state-can-change + parent-device: + id 0 direction input state selectable phase-offset 0 + /* note: no "prio" between "direction" and "state", + even though priority-can-change is advertised */ + + # dpll pin set id 16 parent-device 0 prio 5 + RTNETLINK answers: Operation not supported + +After the fix the prio field is reported by pin show and pin set with +prio is accepted on U.FL2. + +Add the missing .prio_get and .prio_set callbacks to +ice_dpll_pin_ufl_ops, reusing ice_dpll_sw_input_prio_{get,set}. The +same ops struct is shared by U.FL1 and U.FL2: U.FL2 (input) delegates +to the backing hardware input pin, while U.FL1 (output) does not +advertise DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE so the dpll core +capability gate never invokes prio_set for it, and prio_get reports +the OUTPUT sentinel (ICE_DPLL_PIN_PRIO_OUTPUT) on the output side +exactly like the SMA path does today. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Paul Menzel +Signed-off-by: Petr Oros +Tested-by: Rinitha S (A Contingent worker at Intel) +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260602225513.393338-3-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 14048ac5eff56f..81267bae0e5cb5 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -2481,6 +2481,8 @@ static const struct dpll_pin_ops ice_dpll_pin_ufl_ops = { + .state_on_dpll_set = ice_dpll_ufl_pin_state_set, + .state_on_dpll_get = ice_dpll_sw_pin_state_get, + .direction_get = ice_dpll_pin_sw_direction_get, ++ .prio_get = ice_dpll_sw_input_prio_get, ++ .prio_set = ice_dpll_sw_input_prio_set, + .frequency_get = ice_dpll_sw_pin_frequency_get, + .frequency_set = ice_dpll_sw_pin_frequency_set, + .esync_set = ice_dpll_sw_esync_set, +-- +2.53.0 + diff --git a/queue-6.18/idpf-fix-mailbox-capability-for-set-device-clock-tim.patch b/queue-6.18/idpf-fix-mailbox-capability-for-set-device-clock-tim.patch new file mode 100644 index 0000000000..7e0e764ac3 --- /dev/null +++ b/queue-6.18/idpf-fix-mailbox-capability-for-set-device-clock-tim.patch @@ -0,0 +1,41 @@ +From 7a8feaeb35f0a82bfb6c0f8dba3885751e8abfeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:55:11 -0700 +Subject: idpf: fix mailbox capability for set device clock time + +From: Alok Tiwari + +[ Upstream commit 85b0cbc1f38bc1e38956a9e6d7b04d309b435697 ] + +The current code incorrectly uses VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME +for both direct and mailbox capabilities, causing mailbox-only support +to be ignored and potentially reporting IDPF_PTP_NONE. + +Fixes: d5dba8f7206da ("idpf: add PTP clock configuration") +Signed-off-by: Alok Tiwari +Tested-by: Samuel Salin +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260602225513.393338-4-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/idpf/idpf_ptp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +index 31c5593550e1af..1063c1a96ee5c1 100644 +--- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c ++++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +@@ -51,7 +51,7 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter) + + /* Set the device clock time */ + direct = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; +- mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; ++ mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB; + ptp->set_dev_clk_time_access = idpf_ptp_get_access(adapter, + direct, + mailbox); +-- +2.53.0 + diff --git a/queue-6.18/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-6.18/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..b18c3a9bba --- /dev/null +++ b/queue-6.18/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From c66bd9717ef227118bdb317afc8fcd2b9531cc57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index d2b74a6f2cf62d..d871cab6938d36 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -106,6 +106,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -113,6 +114,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-6.18/ip6_vti-set-netns_immutable-on-the-fallback-device.patch b/queue-6.18/ip6_vti-set-netns_immutable-on-the-fallback-device.patch new file mode 100644 index 0000000000..fe6228de30 --- /dev/null +++ b/queue-6.18/ip6_vti-set-netns_immutable-on-the-fallback-device.patch @@ -0,0 +1,43 @@ +From ef76e998461a9a89687e3354715ddf3f81809656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:59:18 +0000 +Subject: ip6_vti: set netns_immutable on the fallback device. + +From: Eric Dumazet + +[ Upstream commit d289d5307762d1838aaece22c6b6fcad9e8865f9 ] + +john1988 and Noam Rathaus reported that vti6_init_net() does not set the +netns_immutable flag on the per-netns fallback tunnel device (ip6_vti0). + +Other similar tunnel drivers (like ip6_tunnel, sit, ip6_gre, and ip_tunnel) +correctly set this flag during their fallback device initialization to +prevent them from being moved to another network namespace. + +Fixes: 61220ab34948 ("vti6: Enable namespace changing") +Reported-by: Noam Rathaus +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608155918.787644-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index df793c8bfffb0a..d2b74a6f2cf62d 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -1159,6 +1159,7 @@ static int __net_init vti6_init_net(struct net *net) + goto err_alloc_dev; + dev_net_set(ip6n->fb_tnl_dev, net); + ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops; ++ ip6n->fb_tnl_dev->netns_immutable = true; + + err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev); + if (err < 0) +-- +2.53.0 + diff --git a/queue-6.18/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch b/queue-6.18/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch new file mode 100644 index 0000000000..7cc164d103 --- /dev/null +++ b/queue-6.18/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch @@ -0,0 +1,89 @@ +From 04d48bd2630d218d63b61f8eaba76313257e9ce2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 17:54:48 +0300 +Subject: ipv6: Fix a potential NPD in cleanup_prefix_route() + +From: Ido Schimmel + +[ Upstream commit b70c687b7cf267fb08586667a3946c8851cad672 ] + +addrconf_get_prefix_route() can return the fib6_null_entry sentinel +entry which has a NULL fib6_table pointer. Therefore, before setting the +route's expiration time, check that we are not working with this entry, +as otherwise a NPD will be triggered [1]. + +Note that the other callers of addrconf_get_prefix_route() are not +susceptible to this bug: + +1. addrconf_prefix_rcv(): Requests a route with the 'RTF_ADDRCONF | + RTF_PREFIX_RT' flags which are not set on fib6_null_entry. + +2. modify_prefix_route(): Fixed by commit a747e02430df ("ipv6: avoid + possible NULL deref in modify_prefix_route()"). + +3. __ipv6_ifa_notify(): Calls ip6_del_rt() which specifically checks for + fib6_null_entry and returns an error. + +[1] +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] SMP KASAN +KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037] +[...] +Call Trace: + +__kasan_check_byte (mm/kasan/common.c:573) +lock_acquire.part.0 (kernel/locking/lockdep.c:5842 (discriminator 1)) +_raw_spin_lock_bh (kernel/locking/spinlock.c:182 (discriminator 1)) +cleanup_prefix_route (net/ipv6/addrconf.c:1280) +ipv6_del_addr (net/ipv6/addrconf.c:1342) +inet6_addr_del.isra.0 (net/ipv6/addrconf.c:3119) +inet6_rtm_deladdr (net/ipv6/addrconf.c:4812) +rtnetlink_rcv_msg (net/core/rtnetlink.c:6997) +netlink_rcv_skb (net/netlink/af_netlink.c:2555) +netlink_unicast (net/netlink/af_netlink.c:1344) +netlink_sendmsg (net/netlink/af_netlink.c:1899) +__sock_sendmsg (net/socket.c:802 (discriminator 4)) +____sys_sendmsg (net/socket.c:2698) +___sys_sendmsg (net/socket.c:2752) +__sys_sendmsg (net/socket.c:2784) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 5eb902b8e719 ("net/ipv6: Remove expired routes with a separated list of routes.") +Reported-by: Ji'an Zhou +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260609145448.768318-1-idosch@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 2d4c3d9c1a2a51..b2e1328371d3f6 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1265,6 +1265,7 @@ static void + cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + bool del_rt, bool del_peer) + { ++ struct net *net = dev_net(ifp->idev->dev); + struct fib6_table *table; + struct fib6_info *f6i; + +@@ -1273,9 +1274,10 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + ifp->idev->dev, 0, RTF_DEFAULT, true); + if (f6i) { + if (del_rt) +- ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); ++ ip6_del_rt(net, f6i, false); + else { +- if (!(f6i->fib6_flags & RTF_EXPIRES)) { ++ if (f6i != net->ipv6.fib6_null_entry && ++ !(f6i->fib6_flags & RTF_EXPIRES)) { + table = f6i->fib6_table; + spin_lock_bh(&table->tb6_lock); + +-- +2.53.0 + diff --git a/queue-6.18/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-6.18/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..63a166434d --- /dev/null +++ b/queue-6.18/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From 34475980a8afb2f7e3884e55348d935c02534c61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index cf37ad9686e698..6a833ee665e9b4 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -960,6 +960,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-6.18/net-add-pskb_may_pull-to-skb_gro_receive_list.patch b/queue-6.18/net-add-pskb_may_pull-to-skb_gro_receive_list.patch new file mode 100644 index 0000000000..d2dbefb92a --- /dev/null +++ b/queue-6.18/net-add-pskb_may_pull-to-skb_gro_receive_list.patch @@ -0,0 +1,57 @@ +From 1b1d95d28702273c9f70650511ab2a98a9702e7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:46:25 +0000 +Subject: net: add pskb_may_pull() to skb_gro_receive_list() + +From: HanQuan + +[ Upstream commit f2bb3434544454099a5b6dec213567267b05d79d ] + +skb_gro_receive_list() calls skb_pull(skb, skb_gro_offset(skb)) without +first ensuring the data is in the linear area via pskb_may_pull(). When +the skb arrives via napi_gro_frags(), skb_headlen can be 0 (all data in +page fragments) while skb_gro_offset is non-zero (after IP+TCP header +parsing). The skb_pull() then decrements skb->len by skb_gro_offset +but skb->data_len stays unchanged, hitting BUG_ON(skb->len < skb->data_len) +in __skb_pull(). + +The UDP fraglist GRO path already contains this guard at +udp_offload.c:749. Adding it to skb_gro_receive_list() itself provides +centralized protection for all callers (TCP, UDP, and any future +protocols), and ensures the precondition of skb_pull() is satisfied +before it is called. + +On pskb_may_pull() failure, set NAPI_GRO_CB(skb)->flush = 1 so the +skb is not held as a new GRO head and is instead delivered through the +normal receive path, matching the UDP handling. + +Fixes: 8d95dc474f85 ("net: add code for TCP fraglist GRO") +Reported-by: HanQuan +Reported-by: MingXuan +Signed-off-by: HanQuan +Reviewed-by: Eric Dumazet +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/gro.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/gro.c b/net/core/gro.c +index b5f790a643d497..9ec8a46b30bb97 100644 +--- a/net/core/gro.c ++++ b/net/core/gro.c +@@ -234,6 +234,11 @@ int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) + if (unlikely(p->len + skb->len >= 65536)) + return -E2BIG; + ++ if (!pskb_may_pull(skb, skb_gro_offset(skb))) { ++ NAPI_GRO_CB(skb)->flush = 1; ++ return -ENOMEM; ++ } ++ + if (NAPI_GRO_CB(p)->last == p) + skb_shinfo(p)->frag_list = skb; + else +-- +2.53.0 + diff --git a/queue-6.18/net-ena-phc-add-missing-barrier.patch b/queue-6.18/net-ena-phc-add-missing-barrier.patch new file mode 100644 index 0000000000..2309f50686 --- /dev/null +++ b/queue-6.18/net-ena-phc-add-missing-barrier.patch @@ -0,0 +1,41 @@ +From a4eeb31d7ade52e6e3bbe92b25762fca67ab0afe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 08:07:04 +0000 +Subject: net: ena: PHC: Add missing barrier + +From: Arthur Kiyanovski + +[ Upstream commit 954981dbbfbd78f21d2fbac1ac0742dbf38b4e69 ] + +Add dma_rmb() barrier after req_id completion check in +ena_com_phc_get_timestamp(). On weakly-ordered architectures, +payload fields may be read before req_id is observed as updated. + +Fixes: e0ea34158ee8 ("net: ena: Add PHC support in the ENA driver") +Closes: https://sashiko.dev/#/patchset/20260430032507.11586-1-akiyano%40amazon.com +Signed-off-by: Arthur Kiyanovski +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amazon/ena/ena_com.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c +index 8c86789d867a5f..297fb36ab8c16f 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_com.c ++++ b/drivers/net/ethernet/amazon/ena/ena_com.c +@@ -1880,6 +1880,11 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp) + continue; + } + ++ /* Ensure PHC payload (timestamp, error_flags) is read ++ * after req_id update is observed ++ */ ++ dma_rmb(); ++ + /* req_id was updated by the device which indicates that + * PHC timestamp and error_flags are updated too, + * checking errors before retrieving timestamp +-- +2.53.0 + diff --git a/queue-6.18/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-6.18/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..897eccb1b7 --- /dev/null +++ b/queue-6.18/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From 7293fb4a339175d1df5f4189357d30a544e1b765 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 9540dcc5a0c012..5a26a3834ac68f 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1818,6 +1818,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 745bb0a67c6a4c..43dca2c045766f 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -5399,7 +5399,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -5408,8 +5408,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index 2b6e11b085ebd7..4ce6ddd768fb46 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -792,12 +792,13 @@ EXPORT_SYMBOL(kernel_sendmsg); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-6.18/net-ibm-emac-fix-use-after-free-during-device-remova.patch b/queue-6.18/net-ibm-emac-fix-use-after-free-during-device-remova.patch new file mode 100644 index 0000000000..991332a124 --- /dev/null +++ b/queue-6.18/net-ibm-emac-fix-use-after-free-during-device-remova.patch @@ -0,0 +1,73 @@ +From cb3a84a3ba0a470dad778a7e12ebd7413c6a6fb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 15:12:17 -0700 +Subject: net: ibm: emac: Fix use-after-free during device removal + +From: Rosen Penev + +[ Upstream commit a0130d682222ae21afc395aead7cd2d87e1a8358 ] + +The driver was using devm_register_netdev() which causes unregister_netdev() +to be deferred until the devres cleanup phase, which runs after emac_remove() +returns. This creates a use-after-free window where: + +1. emac_remove() is called, which tears down hardware (cancels work, detaches + modules, unregisters from MAL) +2. emac_remove() returns +3. devres cleanup runs and finally calls unregister_netdev() + +During step 3, the network stack might still process packets, triggering +emac_irq(), emac_poll(), or other handlers that access now-freed hardware +resources (dev->emacp, dev->mal, etc.). + +Fix this by replacing devm_register_netdev() with manual register_netdev() +and calling unregister_netdev() at the beginning of emac_remove(), before +any hardware teardown. This ensures the network device is fully stopped and +unregistered before hardware resources are released. + +The change is safe because: +- dev->ndev is assigned very early in probe (before any error paths that + could bypass emac_remove) +- platform_set_drvdata() is only called after successful registration, so + emac_remove() only runs for fully registered devices +- unregister_netdev() is idempotent and safe to call on any registered device + +Fixes: a4dd8535a527 ("net: ibm: emac: use devm for register_netdev") +Signed-off-by: Rosen Penev +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ibm/emac/core.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c +index 417dfa18daae3a..4e503b3d0d2d34 100644 +--- a/drivers/net/ethernet/ibm/emac/core.c ++++ b/drivers/net/ethernet/ibm/emac/core.c +@@ -3144,7 +3144,7 @@ static int emac_probe(struct platform_device *ofdev) + + netif_carrier_off(ndev); + +- err = devm_register_netdev(&ofdev->dev, ndev); ++ err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "%pOF: failed to register net device (%d)!\n", + np, err); +@@ -3197,6 +3197,13 @@ static void emac_remove(struct platform_device *ofdev) + + DBG(dev, "remove" NL); + ++ /* Unregister network device before tearing down hardware ++ * to prevent use-after-free during deferred cleanup. This ensures ++ * the network stack stops all operations before hardware resources ++ * are released. ++ */ ++ unregister_netdev(dev->ndev); ++ + cancel_work_sync(&dev->reset_work); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) +-- +2.53.0 + diff --git a/queue-6.18/net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch b/queue-6.18/net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch new file mode 100644 index 0000000000..03408bf12f --- /dev/null +++ b/queue-6.18/net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch @@ -0,0 +1,42 @@ +From 317ec0104495a390f4c771f6a2e81ee5b822ac8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 09:25:41 +0800 +Subject: net: mctp: usb: don't fail mctp_usb_rx_queue on a deferred submission + +From: Jeremy Kerr + +[ Upstream commit 881a3113b74964918cdd72747e3bc119c02b0c0c ] + +In the ndo_open path, a deferred queue open will report a failure, and +so the netdev will not be ndo_stop()ed, leaving us with the rx_retry +work potentially pending. + +Don't report a deferred queue as an error, as we are still operational. +This means we use the ndo_stop() path for future cleanup, which handles +rx_retry_work cancellation. + +Fixes: 0791c0327a6e ("net: mctp: Add MCTP USB transport driver") +Signed-off-by: Jeremy Kerr +Link: https://patch.msgid.link/20260608-dev-mctp-usb-rx-requeue-v2-2-29a3aa507609@codeconstruct.com.au +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c +index cf6f6a93a45112..fade65f2f26995 100644 +--- a/drivers/net/mctp/mctp-usb.c ++++ b/drivers/net/mctp/mctp-usb.c +@@ -154,7 +154,7 @@ static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp) + if (!mctp_usb->rx_stopped) + schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY); + spin_unlock_irqrestore(&mctp_usb->rx_lock, flags); +- return rc; ++ return 0; + } + + static void mctp_usb_in_complete(struct urb *urb) +-- +2.53.0 + diff --git a/queue-6.18/net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch b/queue-6.18/net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch new file mode 100644 index 0000000000..8440e64b50 --- /dev/null +++ b/queue-6.18/net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch @@ -0,0 +1,135 @@ +From 4cd9f5cb070786a9bab65a7933b92eae2e16b8a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 09:25:40 +0800 +Subject: net: mctp: usb: fix race between urb completion and rx_retry + cancellation + +From: Jeremy Kerr + +[ Upstream commit 54665dce982689e2fd99b32e9a0dcc204fda8a51 ] + +It's possible that sequencing between setting ->stopped and cancelling +the rx_retry work (in ndo_stop) could leave us with an urb queued: + + T1: ndo_stop T2: rx_retry_work + ------------ ---------------- + LD: ->stopped => false + ST: ->stopped <= true + usb_kill_urb() + mctp_usb_rx_queue() + usb_submit_urb() + cancel_delayed_work_sync() + +That urb completion can then re-schedule rx_retry_work. + +Strenghen the sequencing between the stop (preventing another requeue) +and the cancel by updating both atomically under a new rx lock. After +setting ->rx_stopped, and cancelling pending work, we know that the +requeue cannot occur, so all that's left is killing any pending urb. + +Fixes: 0791c0327a6e ("net: mctp: Add MCTP USB transport driver") +Signed-off-by: Jeremy Kerr +Link: https://patch.msgid.link/20260608-dev-mctp-usb-rx-requeue-v2-1-29a3aa507609@codeconstruct.com.au +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-usb.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c +index 3b5dff14417747..cf6f6a93a45112 100644 +--- a/drivers/net/mctp/mctp-usb.c ++++ b/drivers/net/mctp/mctp-usb.c +@@ -22,7 +22,6 @@ + struct mctp_usb { + struct usb_device *usbdev; + struct usb_interface *intf; +- bool stopped; + + struct net_device *netdev; + +@@ -32,6 +31,9 @@ struct mctp_usb { + struct urb *tx_urb; + struct urb *rx_urb; + ++ /* enforces atomic access to rx_stopped and requeuing the retry work */ ++ spinlock_t rx_lock; ++ bool rx_stopped; + struct delayed_work rx_retry_work; + }; + +@@ -122,6 +124,7 @@ static const unsigned long RX_RETRY_DELAY = HZ / 4; + + static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp) + { ++ unsigned long flags; + struct sk_buff *skb; + int rc; + +@@ -147,7 +150,10 @@ static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp) + return rc; + + err_retry: +- schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY); ++ spin_lock_irqsave(&mctp_usb->rx_lock, flags); ++ if (!mctp_usb->rx_stopped) ++ schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY); ++ spin_unlock_irqrestore(&mctp_usb->rx_lock, flags); + return rc; + } + +@@ -248,9 +254,6 @@ static void mctp_usb_rx_retry_work(struct work_struct *work) + struct mctp_usb *mctp_usb = container_of(work, struct mctp_usb, + rx_retry_work.work); + +- if (READ_ONCE(mctp_usb->stopped)) +- return; +- + mctp_usb_rx_queue(mctp_usb, GFP_KERNEL); + } + +@@ -258,7 +261,7 @@ static int mctp_usb_open(struct net_device *dev) + { + struct mctp_usb *mctp_usb = netdev_priv(dev); + +- WRITE_ONCE(mctp_usb->stopped, false); ++ WRITE_ONCE(mctp_usb->rx_stopped, false); + + netif_start_queue(dev); + +@@ -268,17 +271,21 @@ static int mctp_usb_open(struct net_device *dev) + static int mctp_usb_stop(struct net_device *dev) + { + struct mctp_usb *mctp_usb = netdev_priv(dev); ++ unsigned long flags; + + netif_stop_queue(dev); + + /* prevent RX submission retry */ +- WRITE_ONCE(mctp_usb->stopped, true); ++ spin_lock_irqsave(&mctp_usb->rx_lock, flags); ++ mctp_usb->rx_stopped = true; ++ cancel_delayed_work(&mctp_usb->rx_retry_work); ++ spin_unlock_irqrestore(&mctp_usb->rx_lock, flags); ++ ++ flush_delayed_work(&mctp_usb->rx_retry_work); + + usb_kill_urb(mctp_usb->rx_urb); + usb_kill_urb(mctp_usb->tx_urb); + +- cancel_delayed_work_sync(&mctp_usb->rx_retry_work); +- + return 0; + } + +@@ -331,6 +338,7 @@ static int mctp_usb_probe(struct usb_interface *intf, + dev->netdev = netdev; + dev->usbdev = interface_to_usbdev(intf); + dev->intf = intf; ++ spin_lock_init(&dev->rx_lock); + usb_set_intfdata(intf, dev); + + dev->ep_in = ep_in->bEndpointAddress; +-- +2.53.0 + diff --git a/queue-6.18/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch b/queue-6.18/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch new file mode 100644 index 0000000000..bd6bbc012d --- /dev/null +++ b/queue-6.18/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch @@ -0,0 +1,61 @@ +From 51ab2faf201f12f72a6dd6bc13ab73d9f7f3704f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:10:44 +0800 +Subject: net/mlx4: avoid GCC 10 __bad_copy_from() false positive + +From: Yao Sang + +[ Upstream commit 2365343f4aad3e1b1e7a2e87e98cf66d5e590589 ] + +mlx4_init_user_cqes() fills a scratch buffer with the CQE +initialization pattern and then copies from that buffer to userspace. + +In the single-copy path, the copy length is array_size(entries, +cqe_size), but the scratch buffer is allocated with PAGE_SIZE. GCC 10 +does not carry the branch invariant strongly enough through the object +size checks and falsely triggers __bad_copy_from(). + +Size the scratch buffer to the actual copy length for the active path, +keep array_size() for the single-copy case, and retain a WARN_ON_ONCE() +guard for the PAGE_SIZE invariant before allocating the buffer. + +Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()") +Signed-off-by: Yao Sang +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx4/cq.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c +index e130e7259275a3..5c55971abbf072 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/cq.c ++++ b/drivers/net/ethernet/mellanox/mlx4/cq.c +@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) + static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + { + int entries_per_copy = PAGE_SIZE / cqe_size; ++ size_t copy_bytes; + void *init_ents; + int err = 0; + int i; +@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + buf += PAGE_SIZE; + } + } else { ++ copy_bytes = array_size(entries, cqe_size); ++ if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE)) { ++ err = -EINVAL; ++ goto out; ++ } ++ + err = copy_to_user((void __user *)buf, init_ents, +- array_size(entries, cqe_size)) ? ++ copy_bytes) ? + -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch b/queue-6.18/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch new file mode 100644 index 0000000000..2f38f73f31 --- /dev/null +++ b/queue-6.18/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch @@ -0,0 +1,221 @@ +From 88debfe2a40232cb29e180e32dbb2a56a2b8489b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:58:49 +0300 +Subject: net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list + +From: Dragos Tatulea + +[ Upstream commit 894e036a24a26a6dd7b17d8d3fb5c53ab48a6074 ] + +mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using +the PF's log_max_current_uc/mc_list capabilities. When querying a VF +vport with a larger configured max (via devlink), the firmware response +can overflow this buffer: + + BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 + + CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) + Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] + Call Trace: + + dump_stack_lvl+0x69/0xa0 + print_report+0x176/0x4e4 + kasan_report+0xc8/0x100 + mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] + esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] + esw_vport_change_handler+0x6a/0x90 [mlx5_core] + process_one_work+0x87f/0x15e0 + worker_thread+0x62b/0x1020 + kthread+0x375/0x490 + ret_from_fork+0x4dc/0x810 + ret_from_fork_asm+0x11/0x20 + + +Fix by querying the vport's own HCA caps to size the buffer correctly. +Refactor the function to allocate and return the MAC list internally, +removing the caller's dependency on knowing the correct max. + +Fixes: e16aea2744ab ("net/mlx5: Introduce access functions to modify/query vport mac lists") +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135849.458060-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +--- + .../net/ethernet/mellanox/mlx5/core/vport.c | 72 ++++++++++++++----- + include/linux/mlx5/vport.h | 4 +- + 3 files changed, 59 insertions(+), 30 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +index 49bc409d7dbb00..c38deabcb7b966 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, int list_type) + { + bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC; +- u8 (*mac_list)[ETH_ALEN]; ++ u8 (*mac_list)[ETH_ALEN] = NULL; + struct l2addr_node *node; + struct vport_addr *addr; + struct hlist_head *hash; + struct hlist_node *tmp; +- int size; ++ int size = 0; + int err; + int hi; + int i; + +- size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) : +- MLX5_MAX_MC_PER_VPORT(esw->dev); +- +- mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL); +- if (!mac_list) +- return; +- + hash = is_uc ? vport->uc_list : vport->mc_list; + + for_each_l2hash_node(node, tmp, hash, hi) { +@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + goto out; + + err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type, +- mac_list, &size); ++ &mac_list, &size); + if (err) + goto out; + esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n", +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +index 2ed2e530b07d0f..a44214c660b03b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +@@ -251,35 +251,63 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu) + } + EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mtu); + ++static int mlx5_vport_max_mac_list_size(struct mlx5_core_dev *dev, u16 vport, ++ enum mlx5_list_type list_type) ++{ ++ void *query_ctx, *hca_caps; ++ int ret = 0; ++ ++ if (!vport && !mlx5_core_is_ecpf(dev)) ++ return list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : ++ 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ ++ query_ctx = kzalloc(MLX5_ST_SZ_BYTES(query_hca_cap_out), GFP_KERNEL); ++ if (!query_ctx) ++ return -ENOMEM; ++ ++ ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_ctx); ++ if (ret) ++ goto out; ++ ++ hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); ++ ret = list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_uc_list) : ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_mc_list); ++ ++out: ++ kfree(query_ctx); ++ ++ return ret; ++} ++ + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size) ++ u8 (**addr_list)[ETH_ALEN], ++ int *addr_list_size) + { + u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {0}; ++ int allowed_list_size; + void *nic_vport_ctx; + int max_list_size; +- int req_list_size; + int out_sz; + void *out; + int err; + int i; + +- req_list_size = *list_size; ++ if (!addr_list || !addr_list_size) ++ return -EINVAL; + +- max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ? +- 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : +- 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ *addr_list = NULL; ++ *addr_list_size = 0; + +- if (req_list_size > max_list_size) { +- mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n", +- req_list_size, max_list_size); +- req_list_size = max_list_size; +- } ++ max_list_size = mlx5_vport_max_mac_list_size(dev, vport, list_type); ++ if (max_list_size < 0) ++ return max_list_size; + + out_sz = MLX5_ST_SZ_BYTES(query_nic_vport_context_out) + +- req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); ++ max_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); + + out = kvzalloc(out_sz, GFP_KERNEL); + if (!out) +@@ -298,16 +326,24 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + + nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out, + nic_vport_context); +- req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, +- allowed_list_size); ++ allowed_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, ++ allowed_list_size); ++ if (!allowed_list_size) ++ goto out; ++ ++ *addr_list = kcalloc(allowed_list_size, ETH_ALEN, GFP_KERNEL); ++ if (!*addr_list) { ++ err = -ENOMEM; ++ goto out; ++ } + +- *list_size = req_list_size; +- for (i = 0; i < req_list_size; i++) { ++ for (i = 0; i < allowed_list_size; i++) { + u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context, + nic_vport_ctx, + current_uc_mac_address[i]) + 2; +- ether_addr_copy(addr_list[i], mac_addr); ++ ether_addr_copy((*addr_list)[i], mac_addr); + } ++ *addr_list_size = allowed_list_size; + out: + kvfree(out); + return err; +diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h +index c87b9507cfa180..b98aaa471ac228 100644 +--- a/include/linux/mlx5/vport.h ++++ b/include/linux/mlx5/vport.h +@@ -95,8 +95,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size); ++ u8 (**mac_list)[ETH_ALEN], ++ int *mac_list_size); + int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev, + enum mlx5_list_type list_type, + u8 addr_list[][ETH_ALEN], +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch b/queue-6.18/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch new file mode 100644 index 0000000000..2f62a47a54 --- /dev/null +++ b/queue-6.18/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch @@ -0,0 +1,71 @@ +From 964a9a69770f26c410422ed2373a330a7550241b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 18:21:12 +0800 +Subject: net/mlx5: Use effective affinity mask for IRQ selection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fushuai Wang + +[ Upstream commit a7767290e77ca2e926b49f8bfa29daa12262c612 ] + +When a sf is created after a CPU has been taken offline, the IRQ pool may +contain IRQs with affinity masks that include the offline CPU. Since only +online CPUs should be considered for IRQ placement, cpumask_subset() check +would fail because the iter_mask contains offline CPUs that are not present +in req_mask, causing sf creation to fail. + +This is an example: + 1. When mlx5 driver loads, it initializes the IRQ pools. + For sf_ctrl_pool with ≤64 sf: + - xa_num_irqs = {N, N} (There is only one slot) + 2. When the first SF is created: + - The ctrl IRQ is allocated with mask=cpu_online_mask={0-191} + 2. We take CPU 20 offline + 3. Existing ctl irq still have mask={0-191} + 4. Create a new SF: + - req_mask={0-19,21-191} + - iter_mask={0-191} + - {0-191} is NOT a subset of {0-19,21-191} + - least_loaded_irq=NULL + 5. Try to allocate a new irq via irq_pool_request_irq() + 6. xa_alloc() fails because the pool is full(There is only one slot) + 7. sf creation fails with error + +Use irq_get_effective_affinity_mask() instead, which returns the IRQ's +actual effective affinity that already excludes offline CPUs. + +Fixes: 061f5b23588a ("net/mlx5: SF, Use all available cpu for setting cpu affinity") +Suggested-by: Shay Drory +Signed-off-by: Fushuai Wang +Reviewed-by: Shay Drory +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260605102112.91772-1-fushuai.wang@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +index 14d339eceb92d5..cc63b091b70e8a 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +@@ -105,9 +105,12 @@ irq_pool_find_least_loaded(struct mlx5_irq_pool *pool, const struct cpumask *req + + lockdep_assert_held(&pool->lock); + xa_for_each_range(&pool->irqs, index, iter, start, end) { +- struct cpumask *iter_mask = mlx5_irq_get_affinity_mask(iter); + int iter_refcount = mlx5_irq_read_locked(iter); ++ const struct cpumask *iter_mask; + ++ iter_mask = irq_get_effective_affinity_mask(mlx5_irq_get_irq(iter)); ++ if (!iter_mask) ++ continue; + if (!cpumask_subset(iter_mask, req_mask)) + /* skip IRQs with a mask which is not subset of req_mask */ + continue; +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch b/queue-6.18/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch new file mode 100644 index 0000000000..4e1ec4159b --- /dev/null +++ b/queue-6.18/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch @@ -0,0 +1,69 @@ +From 5f1f371c5804d5f9057d3e3587a0b868c7f35896 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:54:46 +0300 +Subject: net/mlx5e: xsk: Fix DMA and xdp_frame leak on XDP_TX xmit failure + +From: Dragos Tatulea + +[ Upstream commit b69004f5a6ad32da84d8aa5b23b9c0caafe6252e ] + +In the XSK branch of mlx5e_xmit_xdp_buff(), when sq->xmit_xdp_frame() +returns false (e.g. XDPSQ is full), the function returns without +unmapping the DMA address or freeing the xdp_frame allocated by +xdp_convert_zc_to_xdp_frame(). The xdpi_fifo push only happens on +success, so the completion path cannot recover these entries. + +With CONFIG_DMA_API_DEBUG=y, the leak surfaces on driver unbind: + + DMA-API: pci 0000:08:00.0: device driver has pending DMA + allocations while released from device [count=1116] + One of leaked entries details: [device address=0x000000010ffd7028] + [size=1534 bytes] [mapped with DMA_TO_DEVICE] [mapped as phy] + WARNING: kernel/dma/debug.c:881 at dma_debug_device_change+0x127/0x180 + ... + DMA-API: Mapped at: + debug_dma_map_phys+0x4b/0xd0 + dma_map_phys+0xfd/0x2d0 + mlx5e_xdp_handle+0x5ae/0xac0 [mlx5_core] + mlx5e_xsk_skb_from_cqe_mpwrq_linear+0xc4/0x170 [mlx5_core] + mlx5e_handle_rx_cqe_mpwrq+0xc1/0x290 [mlx5_core] + +Add the missing unmap + xdp_return_frame, matching the cleanup already +done in mlx5e_xdp_xmit(). has_frags is rejected earlier in this branch, +so no per-frag unmap is needed. + +Fixes: 84a0a2310d6d ("net/mlx5e: XDP_TX from UMEM support") +Signed-off-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135446.456119-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +index 5d51600935a6f8..5322964214b22e 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +@@ -102,9 +102,15 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq, + + xdptxd->dma_addr = dma_addr; + +- if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, +- mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL))) ++ if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, ++ mlx5e_xmit_xdp_frame_mpwqe, ++ mlx5e_xmit_xdp_frame, ++ sq, xdptxd, 0, NULL))) { ++ dma_unmap_single(sq->pdev, dma_addr, xdptxd->len, ++ DMA_TO_DEVICE); ++ xdp_return_frame(xdpf); + return false; ++ } + + /* xmit_mode == MLX5E_XDP_XMIT_MODE_FRAME */ + mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, +-- +2.53.0 + diff --git a/queue-6.18/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch b/queue-6.18/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch new file mode 100644 index 0000000000..ea05d56b2d --- /dev/null +++ b/queue-6.18/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch @@ -0,0 +1,106 @@ +From 9282e7de4f6b6d34b35498e8f95c05aba5056893 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:43 +0200 +Subject: net: mvpp2: build skb from XDP-adjusted data on XDP_PASS + +From: Til Kaiser + +[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ] + +When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() +and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets +derived from the original RX descriptor. Packet geometry changes made by +the XDP program are therefore discarded before the skb reaches the stack. + +Update rx_offset and rx_bytes from xdp.data and xdp.data_end for +XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen +by XDP, and makes RX byte accounting for XDP_PASS follow the length of the +skb passed to the network stack. + +Keep a separate rx_sync_size for page-pool recycling on skb allocation +failure, which must stay tied to the received buffer range. + +Non-PASS verdicts continue to account the descriptor length because no skb +is passed up in those cases. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-5-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 7f748cd6605ae4..79f8e0abfdbfd1 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3919,10 +3919,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; +- unsigned int frag_size; ++ unsigned int frag_size, rx_sync_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- int pool, rx_bytes, err, ret; ++ int pool, rx_bytes, rx_offset, err, ret; + struct page *page; + void *data; + +@@ -3935,6 +3935,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + rx_status = mvpp2_rxdesc_status_get(port, rx_desc); + rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc); + rx_bytes -= MVPP2_MH_SIZE; ++ rx_sync_size = rx_bytes + MVPP2_MH_SIZE; ++ rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM; + dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc); + + pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> +@@ -3950,7 +3952,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, + MVPP2_SKB_HEADROOM, +- rx_bytes + MVPP2_MH_SIZE, ++ rx_sync_size, + dma_dir); + + /* Buffer header not supported */ +@@ -4001,6 +4003,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + } + ++ rx_sync_size = max_t(unsigned int, rx_sync_size, ++ xdp.data_end - xdp.data_hard_start - ++ MVPP2_SKB_HEADROOM); ++ ++ /* Update offset and length to reflect any XDP adjustments. */ ++ rx_offset = xdp.data - data; ++ rx_bytes = xdp.data_end - xdp.data; ++ + metasize = xdp.data - xdp.data_meta; + } + +@@ -4012,8 +4022,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + netdev_warn(port->dev, "skb build failed\n"); + if (pp) { + page_pool_put_page(pp, virt_to_head_page(data), +- rx_bytes + MVPP2_MH_SIZE, +- true); ++ rx_sync_size, true); + } else { + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, +@@ -4043,7 +4052,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + +- skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); ++ skb_reserve(skb, rx_offset); + skb_put(skb, rx_bytes); + if (metasize) + skb_metadata_set(skb, metasize); +-- +2.53.0 + diff --git a/queue-6.18/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch b/queue-6.18/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch new file mode 100644 index 0000000000..d4723cb179 --- /dev/null +++ b/queue-6.18/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch @@ -0,0 +1,46 @@ +From 0ed4da342532ab78937e6fadd236ebc46c8b5e1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:41 +0200 +Subject: net: mvpp2: limit XDP frame size to the RX buffer + +From: Til Kaiser + +[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ] + +mvpp2 has short and long BM pools, and short pool buffers can be smaller +than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with +PAGE_SIZE as frame size. + +XDP helpers use frame_sz to validate tail growth and to derive the hard +end of the data area. Advertising PAGE_SIZE for short buffers can let +bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting +memory or later tripping skb tailroom checks. + +Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches +the actual buffer backing the packet. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-3-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 5ef8637d408015..814b60b16a23dc 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3981,7 +3981,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + xdp_rxq = &rxq->xdp_rxq_long; + +- xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq); ++ xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, + rx_bytes, true); +-- +2.53.0 + diff --git a/queue-6.18/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch b/queue-6.18/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch new file mode 100644 index 0000000000..ea11323c91 --- /dev/null +++ b/queue-6.18/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch @@ -0,0 +1,126 @@ +From 2003aa4535fe1add359de82cfdd2c47abdfb6e8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:42 +0200 +Subject: net: mvpp2: refill RX buffers before XDP or skb use + +From: Til Kaiser + +[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ] + +The RX error path returns the current descriptor buffer to the hardware +BM pool. That is only valid while the driver still owns the buffer. + +mvpp2_rx_refill() can fail after the current buffer has been handed to +XDP or attached to an skb. In those cases mvpp2_run_xdp() may have +recycled, redirected, or queued the page for XDP_TX, and an skb free also +retires the data buffer. Returning such a buffer to BM lets hardware DMA +into memory that is no longer owned by the RX ring. + +Refill the BM pool before handing the current buffer to XDP or to the +skb. If the allocation fails there, drop the packet and return the +still-owned current buffer to BM, preserving the pool depth. Once the +refill succeeds, later local drops retire/free the current buffer instead +of returning it to BM. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-4-mail@tk154.de +Signed-off-by: Paolo Abeni +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- + 1 file changed, 24 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 814b60b16a23dc..7f748cd6605ae4 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3973,6 +3973,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + frag_size = bm_pool->frag_size; + ++ err = mvpp2_rx_refill(port, bm_pool, pp, pool); ++ if (err) { ++ netdev_err(port->dev, "failed to refill BM pools\n"); ++ goto err_drop_frame; ++ } ++ + if (xdp_prog) { + struct xdp_rxq_info *xdp_rxq; + +@@ -3990,12 +3996,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + if (ret) { + xdp_ret |= ret; +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- goto err_drop_frame; +- } +- + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + continue; +@@ -4010,8 +4010,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb = slab_build_skb(data); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); +- goto err_drop_frame; ++ if (pp) { ++ page_pool_put_page(pp, virt_to_head_page(data), ++ rx_bytes + MVPP2_MH_SIZE, ++ true); ++ } else { ++ dma_unmap_single_attrs(dev->dev.parent, dma_addr, ++ bm_pool->buf_size, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ mvpp2_frag_free(bm_pool, pp, data); ++ } ++ goto err_drop_frame_retired; + } ++ if (pp) ++ skb_mark_for_recycle(skb); + + /* If we have RX hardware timestamping enabled, grab the + * timestamp from the queue and convert. +@@ -4022,16 +4035,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb_hwtstamps(skb)); + } + +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- dev_kfree_skb_any(skb); +- goto err_drop_frame; +- } +- +- if (pp) +- skb_mark_for_recycle(skb); +- else ++ if (!pp) + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); +@@ -4050,13 +4054,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + + err_drop_frame: +- dev->stats.rx_errors++; +- mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + if (rx_status & MVPP2_RXD_BUF_HDR) + mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status); + else + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); ++err_drop_frame_retired: ++ dev->stats.rx_errors++; ++ mvpp2_rx_error(port, rx_desc); + } + + if (xdp_ret & MVPP2_XDP_REDIR) +-- +2.53.0 + diff --git a/queue-6.18/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-6.18/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..30b5bcd0a4 --- /dev/null +++ b/queue-6.18/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From 35fa984fa499b321fff83e89bc54ce5845b913bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 74d44510684bfb..5ef8637d408015 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3948,9 +3948,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-6.18/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-6.18/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..1779bba713 --- /dev/null +++ b/queue-6.18/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From 858ce1b2d60b04decca950e4a2dee0938228eebc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 2304c8e3be4f70..56c744e1e14c5f 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1316,6 +1316,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-6.18/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch b/queue-6.18/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch new file mode 100644 index 0000000000..f10a66aed0 --- /dev/null +++ b/queue-6.18/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch @@ -0,0 +1,53 @@ +From 45599696180a9061c503c086cc2468b31f10ce73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:15 +0200 +Subject: net: phy: clean the sfp upstream if phy probing fails + +From: Maxime Chevallier + +[ Upstream commit 48774e87bbaa0056819d4b52301e4692e50e3252 ] + +Sashiko reported that we don't call sfp_bus_del_upstream() in the probe +failure path, so let's add it, otherwise the sfp-bus is left with a +dangling 'upstream' field, that may be used later on during SFP events. + +This issue existed before the generic phylib sfp support, back when +drivers were calling phy_sfp_probe themselves. + +Reviewed-by: Nicolai Buchwitz +Fixes: 298e54fa810e ("net: phy: add core phylib sfp support") +Signed-off-by: Maxime Chevallier +Link: https://patch.msgid.link/20260604092819.723505-2-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 78cf05a17f8ff2..26b08e3dbd1dee 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1598,6 +1598,9 @@ int phy_sfp_probe(struct phy_device *phydev, + + ret = sfp_bus_add_upstream(bus, phydev, ops); + sfp_bus_put(bus); ++ ++ if (ret) ++ phydev->sfp_bus = NULL; + } + return ret; + } +@@ -3513,6 +3516,9 @@ static int phy_probe(struct device *dev) + return 0; + + out: ++ sfp_bus_del_upstream(phydev->sfp_bus); ++ phydev->sfp_bus = NULL; ++ + if (!phydev->is_on_sfp_module) + phy_led_triggers_unregister(phydev); + +-- +2.53.0 + diff --git a/queue-6.18/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-6.18/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..7e02aa3fe2 --- /dev/null +++ b/queue-6.18/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From 8f476d5c6de5b839c1cce9f33128477b67bdfdc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index b703e4c6458532..2c009793f1931d 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -707,13 +707,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-6.18/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-6.18/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..1f3dbef569 --- /dev/null +++ b/queue-6.18/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From d45c180590855c67796de510e5eed0e8d3c07961 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index 4190b90ff3b18a..1909cd440a4b66 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-6.18/net-txgbe-initialize-module-info-buffer.patch b/queue-6.18/net-txgbe-initialize-module-info-buffer.patch new file mode 100644 index 0000000000..c689f2b926 --- /dev/null +++ b/queue-6.18/net-txgbe-initialize-module-info-buffer.patch @@ -0,0 +1,38 @@ +From 528a48a00f75a06e9b5b849d6982fa028002a7da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:08:40 +0800 +Subject: net: txgbe: initialize module info buffer + +From: Jiawen Wu + +[ Upstream commit 0487cfca46517ff6699c72dc1a8872b0af3c31a9 ] + +The module info buffer should be initialized to 0 before the firmware +returns information. Otherwise, there is a risk that the buffer field +not filled by the firmware is random value. + +Fixes: 343929799ace ("net: txgbe: Support to handle GPIO IRQs for AML devices") +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20260608070842.36504-2-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index 0bc59431d43343..07ae491e3bc9b9 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -220,7 +220,7 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id) + + int txgbe_identify_module(struct wx *wx) + { +- struct txgbe_hic_get_module_info buffer; ++ struct txgbe_hic_get_module_info buffer = { 0 }; + struct txgbe_sff_id *id; + int err = 0; + u32 gpio; +-- +2.53.0 + diff --git a/queue-6.18/net-txgbe-optimize-the-flow-to-setup-phy-for-aml-dev.patch b/queue-6.18/net-txgbe-optimize-the-flow-to-setup-phy-for-aml-dev.patch new file mode 100644 index 0000000000..9f47422122 --- /dev/null +++ b/queue-6.18/net-txgbe-optimize-the-flow-to-setup-phy-for-aml-dev.patch @@ -0,0 +1,165 @@ +From 485a7e42021adae2ac1434eab27c550e9baa7f45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Oct 2025 14:17:25 +0800 +Subject: net: txgbe: optimize the flow to setup PHY for AML devices + +From: Jiawen Wu + +[ Upstream commit 1f863ce5c71276710a7689c88bf4003fa5173998 ] + +To adapt to new firmware for AML devices, the driver should send the +"SET_LINK_CMD" to the firmware only once when switching PHY interface +mode, and no longer needs to re-trigger PHY configuration based on the +RX signal interrupt (TXGBE_GPIOBIT_3). + +In previous firmware versions, the PHY was configured only after receiving +"SET_LINK_CMD", and might remain incomplete if the RX signal was lost. +To handle this case, the driver used TXGBE_GPIOBIT_3 interrupt to resend +the command. This workaround is no longer necessary with the new firmware. + +And the unknown link speed is permitted in the mailbox buffer. + +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20251014061726.36660-3-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 0487cfca4651 ("net: txgbe: initialize module info buffer") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/libwx/wx_type.h | 2 - + .../net/ethernet/wangxun/txgbe/txgbe_aml.c | 50 ++++++------------- + .../net/ethernet/wangxun/txgbe/txgbe_type.h | 1 + + 3 files changed, 15 insertions(+), 38 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h +index 2f8319e031820c..d367644debef36 100644 +--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h ++++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h +@@ -1271,8 +1271,6 @@ struct wx { + + /* PHY stuff */ + bool notify_down; +- int adv_speed; +- int adv_duplex; + unsigned int link; + int speed; + int duplex; +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index 08b9b426f64846..80413504e4bc86 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -19,8 +19,8 @@ void txgbe_gpio_init_aml(struct wx *wx) + { + u32 status; + +- wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_2 | TXGBE_GPIOBIT_3); +- wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_2 | TXGBE_GPIOBIT_3); ++ wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_2); ++ wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_2); + + status = rd32(wx, WX_GPIO_INTSTATUS); + for (int i = 0; i < 6; i++) { +@@ -42,11 +42,6 @@ irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data) + wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_2); + wx_service_event_schedule(wx); + } +- if (status & TXGBE_GPIOBIT_3) { +- set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags); +- wx_service_event_schedule(wx); +- wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_3); +- } + + wr32(wx, WX_GPIO_INTMASK, 0); + return IRQ_HANDLED; +@@ -96,6 +91,9 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int + case SPEED_10000: + buffer.speed = TXGBE_LINK_SPEED_10GB_FULL; + break; ++ default: ++ buffer.speed = TXGBE_LINK_SPEED_UNKNOWN; ++ break; + } + + buffer.fec_mode = TXGBE_PHY_FEC_AUTO; +@@ -106,19 +104,18 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int + WX_HI_COMMAND_TIMEOUT, false); + } + +-static void txgbe_get_link_capabilities(struct wx *wx) ++static void txgbe_get_link_capabilities(struct wx *wx, int *speed, int *duplex) + { + struct txgbe *txgbe = wx->priv; + + if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->sfp_interfaces)) +- wx->adv_speed = SPEED_25000; ++ *speed = SPEED_25000; + else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->sfp_interfaces)) +- wx->adv_speed = SPEED_10000; ++ *speed = SPEED_10000; + else +- wx->adv_speed = SPEED_UNKNOWN; ++ *speed = SPEED_UNKNOWN; + +- wx->adv_duplex = wx->adv_speed == SPEED_UNKNOWN ? +- DUPLEX_HALF : DUPLEX_FULL; ++ *duplex = *speed == SPEED_UNKNOWN ? DUPLEX_HALF : DUPLEX_FULL; + } + + static void txgbe_get_phy_link(struct wx *wx, int *speed) +@@ -138,23 +135,11 @@ static void txgbe_get_phy_link(struct wx *wx, int *speed) + + int txgbe_set_phy_link(struct wx *wx) + { +- int speed, err; +- u32 gpio; ++ int speed, duplex, err; + +- /* Check RX signal */ +- gpio = rd32(wx, WX_GPIO_EXT); +- if (gpio & TXGBE_GPIOBIT_3) +- return -ENODEV; ++ txgbe_get_link_capabilities(wx, &speed, &duplex); + +- txgbe_get_link_capabilities(wx); +- if (wx->adv_speed == SPEED_UNKNOWN) +- return -ENODEV; +- +- txgbe_get_phy_link(wx, &speed); +- if (speed == wx->adv_speed) +- return 0; +- +- err = txgbe_set_phy_link_hostif(wx, wx->adv_speed, 0, wx->adv_duplex); ++ err = txgbe_set_phy_link_hostif(wx, speed, 0, duplex); + if (err) { + wx_err(wx, "Failed to setup link\n"); + return err; +@@ -230,14 +215,7 @@ int txgbe_identify_sfp(struct wx *wx) + return -ENODEV; + } + +- err = txgbe_sfp_to_linkmodes(wx, id); +- if (err) +- return err; +- +- if (gpio & TXGBE_GPIOBIT_3) +- set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags); +- +- return 0; ++ return txgbe_sfp_to_linkmodes(wx, id); + } + + void txgbe_setup_link(struct wx *wx) +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +index be78f8f61a7950..34920b49d0c09b 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +@@ -314,6 +314,7 @@ void txgbe_up(struct wx *wx); + int txgbe_setup_tc(struct net_device *dev, u8 tc); + void txgbe_do_reset(struct net_device *netdev); + ++#define TXGBE_LINK_SPEED_UNKNOWN 0 + #define TXGBE_LINK_SPEED_10GB_FULL 4 + #define TXGBE_LINK_SPEED_25GB_FULL 0x10 + +-- +2.53.0 + diff --git a/queue-6.18/net-txgbe-rename-the-sfp-related.patch b/queue-6.18/net-txgbe-rename-the-sfp-related.patch new file mode 100644 index 0000000000..8d4cbd0967 --- /dev/null +++ b/queue-6.18/net-txgbe-rename-the-sfp-related.patch @@ -0,0 +1,259 @@ +From 030e2da3139e7d29c870bffe2bdd11b6200cec71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 16:02:56 +0800 +Subject: net: txgbe: rename the SFP related + +From: Jiawen Wu + +[ Upstream commit dbba6b7a47cba914d48890da7233a64c7b9f3ccc ] + +QSFP supported will be introduced for AML 40G devices, the code related +to identify various modules should be renamed to more appropriate names. + +And struct txgbe_hic_i2c_read used to get module information is renamed +as struct txgbe_hic_get_module_info, because another SW-FW command to +read I2C will be added later. + +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20251118080259.24676-3-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 0487cfca4651 ("net: txgbe: initialize module info buffer") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/libwx/wx_type.h | 2 +- + .../net/ethernet/wangxun/txgbe/txgbe_aml.c | 39 ++++++++++--------- + .../net/ethernet/wangxun/txgbe/txgbe_aml.h | 2 +- + .../ethernet/wangxun/txgbe/txgbe_ethtool.c | 2 +- + .../net/ethernet/wangxun/txgbe/txgbe_main.c | 12 +++--- + .../net/ethernet/wangxun/txgbe/txgbe_type.h | 12 +++--- + 6 files changed, 35 insertions(+), 34 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h +index d367644debef36..f040b014f2dd74 100644 +--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h ++++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h +@@ -1229,7 +1229,7 @@ enum wx_pf_flags { + WX_FLAG_RX_HWTSTAMP_IN_REGISTER, + WX_FLAG_PTP_PPS_ENABLED, + WX_FLAG_NEED_LINK_CONFIG, +- WX_FLAG_NEED_SFP_RESET, ++ WX_FLAG_NEED_MODULE_RESET, + WX_FLAG_NEED_UPDATE_LINK, + WX_FLAG_NEED_DO_RESET, + WX_PF_FLAGS_NBITS /* must be last */ +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index 05f852e31e6e52..0bc59431d43343 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -38,7 +38,7 @@ irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data) + wr32(wx, WX_GPIO_INTMASK, 0xFF); + status = rd32(wx, WX_GPIO_INTSTATUS); + if (status & TXGBE_GPIOBIT_2) { +- set_bit(WX_FLAG_NEED_SFP_RESET, wx->flags); ++ set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags); + wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_2); + wx_service_event_schedule(wx); + } +@@ -63,15 +63,16 @@ int txgbe_test_hostif(struct wx *wx) + WX_HI_COMMAND_TIMEOUT, false); + } + +-static int txgbe_identify_sfp_hostif(struct wx *wx, struct txgbe_hic_i2c_read *buffer) ++static int txgbe_identify_module_hostif(struct wx *wx, ++ struct txgbe_hic_get_module_info *buffer) + { +- buffer->hdr.cmd = FW_READ_SFP_INFO_CMD; +- buffer->hdr.buf_len = sizeof(struct txgbe_hic_i2c_read) - ++ buffer->hdr.cmd = FW_GET_MODULE_INFO_CMD; ++ buffer->hdr.buf_len = sizeof(struct txgbe_hic_get_module_info) - + sizeof(struct wx_hic_hdr); + buffer->hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; + + return wx_host_interface_command(wx, (u32 *)buffer, +- sizeof(struct txgbe_hic_i2c_read), ++ sizeof(struct txgbe_hic_get_module_info), + WX_HI_COMMAND_TIMEOUT, true); + } + +@@ -109,9 +110,9 @@ static void txgbe_get_link_capabilities(struct wx *wx, int *speed, + { + struct txgbe *txgbe = wx->priv; + +- if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->sfp_interfaces)) ++ if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->link_interfaces)) + *speed = SPEED_25000; +- else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->sfp_interfaces)) ++ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->link_interfaces)) + *speed = SPEED_10000; + else + *speed = SPEED_UNKNOWN; +@@ -150,7 +151,7 @@ int txgbe_set_phy_link(struct wx *wx) + return 0; + } + +-static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id) ++static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id) + { + __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; + DECLARE_PHY_INTERFACE_MASK(interfaces); +@@ -204,9 +205,9 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id) + phylink_set(modes, Asym_Pause); + phylink_set(modes, FIBRE); + +- if (!linkmode_equal(txgbe->sfp_support, modes)) { +- linkmode_copy(txgbe->sfp_support, modes); +- phy_interface_and(txgbe->sfp_interfaces, ++ if (!linkmode_equal(txgbe->link_support, modes)) { ++ linkmode_copy(txgbe->link_support, modes); ++ phy_interface_and(txgbe->link_interfaces, + wx->phylink_config.supported_interfaces, + interfaces); + linkmode_copy(txgbe->advertising, modes); +@@ -217,10 +218,10 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id) + return 0; + } + +-int txgbe_identify_sfp(struct wx *wx) ++int txgbe_identify_module(struct wx *wx) + { +- struct txgbe_hic_i2c_read buffer; +- struct txgbe_sfp_id *id; ++ struct txgbe_hic_get_module_info buffer; ++ struct txgbe_sff_id *id; + int err = 0; + u32 gpio; + +@@ -228,9 +229,9 @@ int txgbe_identify_sfp(struct wx *wx) + if (gpio & TXGBE_GPIOBIT_2) + return -ENODEV; + +- err = txgbe_identify_sfp_hostif(wx, &buffer); ++ err = txgbe_identify_module_hostif(wx, &buffer); + if (err) { +- wx_err(wx, "Failed to identify SFP module\n"); ++ wx_err(wx, "Failed to identify module\n"); + return err; + } + +@@ -247,10 +248,10 @@ void txgbe_setup_link(struct wx *wx) + { + struct txgbe *txgbe = wx->priv; + +- phy_interface_zero(txgbe->sfp_interfaces); +- linkmode_zero(txgbe->sfp_support); ++ phy_interface_zero(txgbe->link_interfaces); ++ linkmode_zero(txgbe->link_support); + +- txgbe_identify_sfp(wx); ++ txgbe_identify_module(wx); + } + + static void txgbe_get_link_state(struct phylink_config *config, +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h +index 25d4971ca0d911..7c8fa48e68d378 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h +@@ -8,7 +8,7 @@ void txgbe_gpio_init_aml(struct wx *wx); + irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data); + int txgbe_test_hostif(struct wx *wx); + int txgbe_set_phy_link(struct wx *wx); +-int txgbe_identify_sfp(struct wx *wx); ++int txgbe_identify_module(struct wx *wx); + void txgbe_setup_link(struct wx *wx); + int txgbe_phylink_init_aml(struct txgbe *txgbe); + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c +index e8dd277a35c7a4..d7f9053594588d 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c +@@ -32,7 +32,7 @@ int txgbe_get_link_ksettings(struct net_device *netdev, + cmd->base.port = txgbe->link_port; + cmd->base.autoneg = phylink_test(txgbe->advertising, Autoneg) ? + AUTONEG_ENABLE : AUTONEG_DISABLE; +- linkmode_copy(cmd->link_modes.supported, txgbe->sfp_support); ++ linkmode_copy(cmd->link_modes.supported, txgbe->link_support); + linkmode_copy(cmd->link_modes.advertising, txgbe->advertising); + + return 0; +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +index 1377ea90a8c284..4d20b178af236b 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +@@ -89,21 +89,21 @@ static int txgbe_enumerate_functions(struct wx *wx) + return physfns; + } + +-static void txgbe_sfp_detection_subtask(struct wx *wx) ++static void txgbe_module_detection_subtask(struct wx *wx) + { + int err; + +- if (!test_bit(WX_FLAG_NEED_SFP_RESET, wx->flags)) ++ if (!test_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags)) + return; + +- /* wait for SFP module ready */ ++ /* wait for SFF module ready */ + msleep(200); + +- err = txgbe_identify_sfp(wx); ++ err = txgbe_identify_module(wx); + if (err) + return; + +- clear_bit(WX_FLAG_NEED_SFP_RESET, wx->flags); ++ clear_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags); + } + + static void txgbe_link_config_subtask(struct wx *wx) +@@ -128,7 +128,7 @@ static void txgbe_service_task(struct work_struct *work) + { + struct wx *wx = container_of(work, struct wx, service_task); + +- txgbe_sfp_detection_subtask(wx); ++ txgbe_module_detection_subtask(wx); + txgbe_link_config_subtask(wx); + + wx_service_event_complete(wx); +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +index 34920b49d0c09b..4d77da720eba16 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +@@ -341,9 +341,9 @@ void txgbe_do_reset(struct net_device *netdev); + + #define FW_PHY_GET_LINK_CMD 0xC0 + #define FW_PHY_SET_LINK_CMD 0xC1 +-#define FW_READ_SFP_INFO_CMD 0xC5 ++#define FW_GET_MODULE_INFO_CMD 0xC5 + +-struct txgbe_sfp_id { ++struct txgbe_sff_id { + u8 identifier; /* A0H 0x00 */ + u8 com_1g_code; /* A0H 0x06 */ + u8 com_10g_code; /* A0H 0x03 */ +@@ -356,9 +356,9 @@ struct txgbe_sfp_id { + u8 reserved[3]; + }; + +-struct txgbe_hic_i2c_read { ++struct txgbe_hic_get_module_info { + struct wx_hic_hdr hdr; +- struct txgbe_sfp_id id; ++ struct txgbe_sff_id id; + }; + + struct txgbe_hic_ephy_setlink { +@@ -449,8 +449,8 @@ struct txgbe { + int fdir_filter_count; + spinlock_t fdir_perfect_lock; /* spinlock for FDIR */ + +- DECLARE_PHY_INTERFACE_MASK(sfp_interfaces); +- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); ++ DECLARE_PHY_INTERFACE_MASK(link_interfaces); ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(link_support); + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); + u8 link_port; + }; +-- +2.53.0 + diff --git a/queue-6.18/net-txgbe-support-cr-modules-for-aml-devices.patch b/queue-6.18/net-txgbe-support-cr-modules-for-aml-devices.patch new file mode 100644 index 0000000000..c782b034f3 --- /dev/null +++ b/queue-6.18/net-txgbe-support-cr-modules-for-aml-devices.patch @@ -0,0 +1,140 @@ +From 77d691a059518c90f60bb5e5b8b52d548ed49591 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 16:02:55 +0800 +Subject: net: txgbe: support CR modules for AML devices + +From: Jiawen Wu + +[ Upstream commit 354d128aa7212c53ffc7127877953264a445f5af ] + +Support to identify 25G/10G CR modules for AML devices. Autoneg is +enbaled by default in CR mode. + +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20251118080259.24676-2-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 0487cfca4651 ("net: txgbe: initialize module info buffer") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/wangxun/txgbe/txgbe_aml.c | 59 +++++++++++++------ + .../ethernet/wangxun/txgbe/txgbe_ethtool.c | 3 +- + 2 files changed, 44 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index 80413504e4bc86..05f852e31e6e52 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -104,7 +104,8 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int + WX_HI_COMMAND_TIMEOUT, false); + } + +-static void txgbe_get_link_capabilities(struct wx *wx, int *speed, int *duplex) ++static void txgbe_get_link_capabilities(struct wx *wx, int *speed, ++ int *autoneg, int *duplex) + { + struct txgbe *txgbe = wx->priv; + +@@ -115,6 +116,7 @@ static void txgbe_get_link_capabilities(struct wx *wx, int *speed, int *duplex) + else + *speed = SPEED_UNKNOWN; + ++ *autoneg = phylink_test(txgbe->advertising, Autoneg); + *duplex = *speed == SPEED_UNKNOWN ? DUPLEX_HALF : DUPLEX_FULL; + } + +@@ -135,11 +137,11 @@ static void txgbe_get_phy_link(struct wx *wx, int *speed) + + int txgbe_set_phy_link(struct wx *wx) + { +- int speed, duplex, err; ++ int speed, autoneg, duplex, err; + +- txgbe_get_link_capabilities(wx, &speed, &duplex); ++ txgbe_get_link_capabilities(wx, &speed, &autoneg, &duplex); + +- err = txgbe_set_phy_link_hostif(wx, speed, 0, duplex); ++ err = txgbe_set_phy_link_hostif(wx, speed, autoneg, duplex); + if (err) { + wx_err(wx, "Failed to setup link\n"); + return err; +@@ -154,19 +156,43 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id) + DECLARE_PHY_INTERFACE_MASK(interfaces); + struct txgbe *txgbe = wx->priv; + +- if (id->com_25g_code & (TXGBE_SFF_25GBASESR_CAPABLE | +- TXGBE_SFF_25GBASEER_CAPABLE | +- TXGBE_SFF_25GBASELR_CAPABLE)) { +- phylink_set(modes, 25000baseSR_Full); ++ if (id->cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) { ++ txgbe->link_port = PORT_DA; ++ phylink_set(modes, Autoneg); ++ if (id->com_25g_code == TXGBE_SFF_25GBASECR_91FEC || ++ id->com_25g_code == TXGBE_SFF_25GBASECR_74FEC || ++ id->com_25g_code == TXGBE_SFF_25GBASECR_NOFEC) { ++ phylink_set(modes, 25000baseCR_Full); ++ phylink_set(modes, 10000baseCR_Full); ++ __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces); ++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ } else { ++ phylink_set(modes, 10000baseCR_Full); ++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ } ++ } else if (id->cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE) { ++ txgbe->link_port = PORT_DA; ++ phylink_set(modes, Autoneg); ++ phylink_set(modes, 25000baseCR_Full); + __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces); +- } +- if (id->com_10g_code & TXGBE_SFF_10GBASESR_CAPABLE) { +- phylink_set(modes, 10000baseSR_Full); +- __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); +- } +- if (id->com_10g_code & TXGBE_SFF_10GBASELR_CAPABLE) { +- phylink_set(modes, 10000baseLR_Full); +- __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ } else { ++ if (id->com_25g_code == TXGBE_SFF_25GBASESR_CAPABLE || ++ id->com_25g_code == TXGBE_SFF_25GBASEER_CAPABLE || ++ id->com_25g_code == TXGBE_SFF_25GBASELR_CAPABLE) { ++ txgbe->link_port = PORT_FIBRE; ++ phylink_set(modes, 25000baseSR_Full); ++ __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces); ++ } ++ if (id->com_10g_code & TXGBE_SFF_10GBASESR_CAPABLE) { ++ txgbe->link_port = PORT_FIBRE; ++ phylink_set(modes, 10000baseSR_Full); ++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ } ++ if (id->com_10g_code & TXGBE_SFF_10GBASELR_CAPABLE) { ++ txgbe->link_port = PORT_FIBRE; ++ phylink_set(modes, 10000baseLR_Full); ++ __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); ++ } + } + + if (phy_interface_empty(interfaces)) { +@@ -177,7 +203,6 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sfp_id *id) + phylink_set(modes, Pause); + phylink_set(modes, Asym_Pause); + phylink_set(modes, FIBRE); +- txgbe->link_port = PORT_FIBRE; + + if (!linkmode_equal(txgbe->sfp_support, modes)) { + linkmode_copy(txgbe->sfp_support, modes); +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c +index e285b088c7b267..e8dd277a35c7a4 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c +@@ -30,7 +30,8 @@ int txgbe_get_link_ksettings(struct net_device *netdev, + return 0; + + cmd->base.port = txgbe->link_port; +- cmd->base.autoneg = AUTONEG_DISABLE; ++ cmd->base.autoneg = phylink_test(txgbe->advertising, Autoneg) ? ++ AUTONEG_ENABLE : AUTONEG_DISABLE; + linkmode_copy(cmd->link_modes.supported, txgbe->sfp_support); + linkmode_copy(cmd->link_modes.advertising, txgbe->advertising); + +-- +2.53.0 + diff --git a/queue-6.18/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch b/queue-6.18/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch new file mode 100644 index 0000000000..63c748ee0e --- /dev/null +++ b/queue-6.18/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch @@ -0,0 +1,52 @@ +From ca35b33b0756d4cb21bb0e40869fed1070933691 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 18:21:24 -0700 +Subject: netdev: fix double-free in netdev_nl_bind_rx_doit() + +From: Jakub Kicinski + +[ Upstream commit c849de7d8757a7af801fc4a4058f71d481d367f2 ] + +Sashiko flags that genlmsg_reply() always consumes the skb. +The error path calls nlmsg_free(rsp) so we can't jump directly +to it. Let's not unbind, just propagate the error to the user. +This is the typical way of handling genlmsg_reply() failures. +They shouldn't happen unless user does something silly like +calling the kernel with an already-full rcvbuf. + +Reported-by: Sashiko +Fixes: 170aafe35cb9 ("netdev: support binding dma-buf to netdevice") +Reviewed-by: Bobby Eshleman +Acked-by: Daniel Borkmann +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/netdev-genl.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c +index 470fabbeacd9bd..93ea09bd1e7bab 100644 +--- a/net/core/netdev-genl.c ++++ b/net/core/netdev-genl.c +@@ -1019,8 +1019,6 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) + genlmsg_end(rsp, hdr); + + err = genlmsg_reply(rsp, info); +- if (err) +- goto err_unbind; + + bitmap_free(rxq_bitmap); + +@@ -1028,7 +1026,7 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) + + mutex_unlock(&priv->lock); + +- return 0; ++ return err < 0 ? err : 0; + + err_unbind: + net_devmem_unbind_dmabuf(binding); +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch b/queue-6.18/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch new file mode 100644 index 0000000000..7a2a7ae499 --- /dev/null +++ b/queue-6.18/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch @@ -0,0 +1,150 @@ +From f8b099609c291c073deb42c5b96ce8b5325fef43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 00:38:17 -0700 +Subject: netfilter: nf_conntrack: destroy stale expectfn expectations on + unregister + +From: Weiming Shi + +[ Upstream commit c3009418f9fa1dcb3eb86f4d8c92583537b5faa3 ] + +NAT helpers such as nf_nat_h323 store a raw pointer to module text in +exp->expectfn (e.g. ip_nat_q931_expect). nf_ct_helper_expectfn_unregister() +only unlinks the callback descriptor and never walks the expectation table, +so an expectation pending at module removal survives with a dangling +exp->expectfn into freed module text. + +When the expected connection arrives, init_conntrack() invokes +exp->expectfn(), now a stale pointer into the unloaded module. Reproduced +on a KASAN build by loading the H.323 helpers, creating a Q.931 +expectation, unloading nf_nat_h323, then connecting to the expected port: + + Oops: int3: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:0xffffffffa06102d1 + init_conntrack.isra.0 (net/netfilter/nf_conntrack_core.c:1862) + nf_conntrack_in (net/netfilter/nf_conntrack_core.c:2049) + ipv4_conntrack_local (net/netfilter/nf_conntrack_proto.c:223) + nf_hook_slow (net/netfilter/core.c:619) + __ip_local_out (net/ipv4/ip_output.c:120) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1715) + tcp_connect (net/ipv4/tcp_output.c:4374) + tcp_v4_connect (net/ipv4/tcp_ipv4.c:345) + __sys_connect (net/socket.c:2167) + Modules linked in: nf_conntrack_h323 [last unloaded: nf_nat_h323] + +Reaching the dangling state requires CAP_SYS_MODULE in the initial user +namespace to remove a NAT helper that still has live expectations, so this +is a robustness fix; leaving an expectation pointing at freed text is wrong +regardless. + +Add nf_ct_helper_expectfn_destroy(), which walks the expectation table and +drops every expectation whose ->expectfn matches the descriptor being torn +down. Call it from each NAT helper's exit path after the existing RCU grace +period, so no expectation outlives the code it points at and no extra +synchronize_rcu() is introduced. With the fix, the same reproducer runs to +completion without the Oops. + +Fixes: f587de0e2feb ("[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Weiming Shi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_helper.h | 1 + + net/ipv4/netfilter/nf_nat_h323.c | 2 ++ + net/netfilter/nf_conntrack_helper.c | 19 +++++++++++++++++++ + net/netfilter/nf_nat_core.c | 2 ++ + net/netfilter/nf_nat_sip.c | 1 + + 5 files changed, 25 insertions(+) + +diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h +index de2f956abf3480..24cf3d2d97450f 100644 +--- a/include/net/netfilter/nf_conntrack_helper.h ++++ b/include/net/netfilter/nf_conntrack_helper.h +@@ -155,6 +155,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct, + + void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); + void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n); + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name); + struct nf_ct_helper_expectfn * +diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c +index faee20af485613..10e1b0837731b7 100644 +--- a/net/ipv4/netfilter/nf_nat_h323.c ++++ b/net/ipv4/netfilter/nf_nat_h323.c +@@ -555,6 +555,8 @@ static void __exit nf_nat_h323_fini(void) + nf_ct_helper_expectfn_unregister(&q931_nat); + nf_ct_helper_expectfn_unregister(&callforwarding_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&q931_nat); ++ nf_ct_helper_expectfn_destroy(&callforwarding_nat); + } + + /****************************************************************************/ +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index a715304a53d8c2..9150bcfd7ca83b 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -283,6 +283,25 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) + } + EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); + ++static bool expect_iter_expectfn(struct nf_conntrack_expect *exp, void *data) ++{ ++ const struct nf_ct_helper_expectfn *n = data; ++ ++ /* Relies on registered expectfn descriptors having unique ->expectfn ++ * pointers, which holds for the in-tree NAT helpers. ++ */ ++ return exp->expectfn == n->expectfn; ++} ++ ++/* Destroy expectations still pointing at @n->expectfn; call after the ++ * caller's RCU grace period so none outlives the (often modular) callback. ++ */ ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n) ++{ ++ nf_ct_expect_iterate_destroy(expect_iter_expectfn, (void *)n); ++} ++EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_destroy); ++ + /* Caller should hold the rcu lock */ + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 8e36b4e3e5c478..d3e158ecf729a3 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1347,6 +1347,7 @@ static int __init nf_nat_init(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + nf_ct_helper_expectfn_unregister(&follow_master_nat); + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + unregister_pernet_subsys(&nat_net_ops); + kvfree(nf_nat_bysource); + } +@@ -1364,6 +1365,7 @@ static void __exit nf_nat_cleanup(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + kvfree(nf_nat_bysource); + unregister_pernet_subsys(&nat_net_ops); + } +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 9fbfc6bff0c221..00838c0cc5bb28 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -655,6 +655,7 @@ static void __exit nf_nat_sip_fini(void) + RCU_INIT_POINTER(nf_nat_sip_hooks, NULL); + nf_ct_helper_expectfn_unregister(&sip_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&sip_nat); + } + + static const struct nf_nat_sip_hooks sip_hooks = { +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nf_log-validate-mac-header-was-set-before-.patch b/queue-6.18/netfilter-nf_log-validate-mac-header-was-set-before-.patch new file mode 100644 index 0000000000..56dd28e3c6 --- /dev/null +++ b/queue-6.18/netfilter-nf_log-validate-mac-header-was-set-before-.patch @@ -0,0 +1,70 @@ +From 9456bdb324265e01d8e883f84b36db8c16d39afd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:55:02 -0700 +Subject: netfilter: nf_log: validate MAC header was set before dumping it + +From: Xiang Mei + +[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ] + +The fallback path of dump_mac_header() guards the MAC header access +only with "skb->mac_header != skb->network_header", without checking +skb_mac_header_was_set(). When the MAC header is unset, mac_header is +0xffff, so the test passes and skb_mac_header(skb) returns +skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads +dev->hard_header_len bytes out of bounds into the kernel log. + +This is reachable via the netdev logger: nf_log_unknown_packet() calls +dump_mac_header() unconditionally, and an skb sent through AF_PACKET +with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still +unset (__dev_queue_xmit(), which would reset it, is bypassed). + +Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already +uses, and replace the open-coded MAC header length test with +skb_mac_header_len(). Only skbs with an unset MAC header are affected; +valid ones are dumped as before. + + BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) + Read of size 1 at addr ffff88800ea49d3f by task exploit/148 + Call Trace: + kasan_report (mm/kasan/report.c:595) + dump_mac_header (net/netfilter/nf_log_syslog.c:831) + nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) + nf_log_packet (net/netfilter/nf_log.c:260) + nft_log_eval (net/netfilter/nft_log.c:60) + nft_do_chain (net/netfilter/nf_tables_core.c:285) + nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) + nf_hook_slow (net/netfilter/core.c:619) + nf_hook_direct_egress (net/packet/af_packet.c:257) + packet_xmit (net/packet/af_packet.c:280) + packet_sendmsg (net/packet/af_packet.c:3114) + __sys_sendto (net/socket.c:2265) + +Fixes: 7eb9282cd0ef ("netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_log_syslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 86d5fc5d28e3b6..613f37b300a560 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -801,8 +801,8 @@ static void dump_mac_header(struct nf_log_buf *m, + + fallback: + nf_log_buf_add(m, "MAC="); +- if (dev->hard_header_len && +- skb->mac_header != skb->network_header) { ++ if (dev->hard_header_len && skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) != 0) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-6.18/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..9940affa8f --- /dev/null +++ b/queue-6.18/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From 47fc7cd464150296cfb5acacbf52cb1de1ade4d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index 7eedf4e3ae9c75..9471328802d3b7 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -532,6 +532,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-revalidate-bridge-ports.patch b/queue-6.18/netfilter-revalidate-bridge-ports.patch new file mode 100644 index 0000000000..4b81bdad08 --- /dev/null +++ b/queue-6.18/netfilter-revalidate-bridge-ports.patch @@ -0,0 +1,239 @@ +From 41794cbb9ea9f8eab0682b430cb4ff49cb87a521 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 17:04:25 +0200 +Subject: netfilter: revalidate bridge ports + +From: Florian Westphal + +[ Upstream commit ccb9fd4b87538ccf19ccff78ee26700526d94867 ] + +ebt_redirect_tg() dereferences br_port_get_rcu() return without a +NULL check, causing a kernel panic when the bridge port has been +removed between the original hook invocation and an NFQUEUE +reinject. + +A mere NULL check isn't sufficient, however. As sashiko review +points out userspace can not only remove the port from the bridge, +it could also place the device in a different virtual device, e.g. +macvlan. + +If this happens, we must drop the packet, there is no way for us to +reinject it into the bridge path. + +Switch to _upper API, we don't need the bridge port structure. +Also, this fix keeps another bug intact: + +Both nfnetlink_log and nfnetlink_queue use CONFIG_BRIDGE_NETFILTER +too aggressive, which prevents certain logging features when queueing +in bridge family: NETFILTER_FAMILY_BRIDGE can be enabled while the old +CONFIG_BRIDGE_NETFILTER cruft is off. + +Fixes tag is a common ancestor, this was always broken. + +Fixes: f350a0a87374 ("bridge: use rx_handler_data pointer to store net_bridge_port pointer") +Reported-by: Ji'an Zhou +Assisted-by: Claude:claude-sonnet-4-6 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_dnat.c | 4 +- + net/bridge/netfilter/ebt_redirect.c | 16 +++++--- + net/netfilter/nfnetlink_log.c | 23 +++++++++-- + net/netfilter/nfnetlink_queue.c | 64 +++++++++++++++++++++++++---- + 4 files changed, 89 insertions(+), 18 deletions(-) + +diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c +index 3fda71a8579d13..73f185cccd63df 100644 +--- a/net/bridge/netfilter/ebt_dnat.c ++++ b/net/bridge/netfilter/ebt_dnat.c +@@ -39,7 +39,9 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par) + dev = xt_in(par); + break; + case NF_BR_PRE_ROUTING: +- dev = br_port_get_rcu(xt_in(par))->br->dev; ++ dev = netdev_master_upper_dev_get_rcu(xt_in(par)); ++ if (!dev) /* bridge port removed? */ ++ return EBT_DROP; + break; + default: + dev = NULL; +diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c +index 307790562b4929..83486cd4d564b1 100644 +--- a/net/bridge/netfilter/ebt_redirect.c ++++ b/net/bridge/netfilter/ebt_redirect.c +@@ -24,12 +24,18 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) + if (skb_ensure_writable(skb, 0)) + return EBT_DROP; + +- if (xt_hooknum(par) != NF_BR_BROUTING) +- /* rcu_read_lock()ed by nf_hook_thresh */ +- ether_addr_copy(eth_hdr(skb)->h_dest, +- br_port_get_rcu(xt_in(par))->br->dev->dev_addr); +- else ++ if (xt_hooknum(par) != NF_BR_BROUTING) { ++ const struct net_device *dev; ++ ++ dev = netdev_master_upper_dev_get_rcu(xt_in(par)); ++ if (!dev) ++ return EBT_DROP; ++ ++ ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); ++ } else { + ether_addr_copy(eth_hdr(skb)->h_dest, xt_in(par)->dev_addr); ++ } ++ + skb->pkt_type = PACKET_HOST; + return info->target; + } +diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c +index b1f3eda85989cd..25a30bf722c69a 100644 +--- a/net/netfilter/nfnetlink_log.c ++++ b/net/netfilter/nfnetlink_log.c +@@ -450,6 +450,23 @@ static int nfulnl_put_bridge(struct nfulnl_instance *inst, const struct sk_buff + return -1; + } + ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++static int nflog_put_master_ifindex(struct sk_buff *nlskb, int attr, ++ const struct net_device *dev) ++{ ++ const struct net_device *upper; ++ ++ if (dev && !netif_is_bridge_port(dev)) ++ return 0; ++ ++ upper = netdev_master_upper_dev_get_rcu((struct net_device *)dev); ++ if (upper && nla_put_be32(nlskb, attr, htonl(upper->ifindex))) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++#endif ++ + /* This is an inline function, we don't really care about a long + * list of arguments */ + static inline int +@@ -504,8 +521,7 @@ __build_packet_message(struct nfnl_log_net *log, + /* rcu_read_lock()ed by nf_hook_thresh or + * nf_log_packet. + */ +- nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, +- htonl(br_port_get_rcu(indev)->br->dev->ifindex))) ++ nflog_put_master_ifindex(inst->skb, NFULA_IFINDEX_INDEV, indev)) + goto nla_put_failure; + } else { + int physinif; +@@ -541,8 +557,7 @@ __build_packet_message(struct nfnl_log_net *log, + /* rcu_read_lock()ed by nf_hook_thresh or + * nf_log_packet. + */ +- nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, +- htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) ++ nflog_put_master_ifindex(inst->skb, NFULA_IFINDEX_OUTDEV, outdev)) + goto nla_put_failure; + } else { + struct net_device *physoutdev; +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index d42e8ac3062fb1..0a5aa6b90fc271 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -426,10 +426,47 @@ static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_ + return false; + } + ++static bool nf_bridge_port_valid(const struct net_device *dev) ++{ ++ if (!dev) ++ return true; ++ ++ return netif_is_bridge_port(dev); ++} ++ ++/* queued skbs leave rcu protection. We bump device refcount so that ++ * the device cannot go away. However, while packet was out the port ++ * could have been removed from the bridge. ++ * ++ * Ensure in+outdev are still part of a bridge at reinject time. ++ * ++ * The device rx_handler_data could even be pointing at data that is ++ * not a net_bridge_port structure. ++ */ ++static bool nf_bridge_ports_valid(const struct nf_queue_entry *entry) ++{ ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++ if (!nf_bridge_port_valid(entry->physin) || ++ !nf_bridge_port_valid(entry->physout)) ++ return false; ++#endif ++ if (entry->state.pf != PF_BRIDGE) ++ return true; ++ ++ if (!nf_bridge_port_valid(entry->state.in) || ++ !nf_bridge_port_valid(entry->state.out)) ++ return false; ++ ++ return true; ++} ++ + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + { + const struct nf_ct_hook *ct_hook; + ++ if (!nf_bridge_ports_valid(entry)) ++ verdict = NF_DROP; ++ + if (verdict == NF_ACCEPT || + verdict == NF_REPEAT || + verdict == NF_STOP) { +@@ -622,6 +659,23 @@ static int nf_queue_checksum_help(struct sk_buff *entskb) + return skb_checksum_help(entskb); + } + ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++static int nfqnl_put_master_ifindex(struct sk_buff *nlskb, int attr, ++ const struct net_device *dev) ++{ ++ const struct net_device *upper; ++ ++ if (dev && !netif_is_bridge_port(dev)) ++ return 0; ++ ++ upper = netdev_master_upper_dev_get_rcu((struct net_device *)dev); ++ if (upper && nla_put_be32(nlskb, attr, htonl(upper->ifindex))) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++#endif ++ + static struct sk_buff * + nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + struct nf_queue_entry *entry, +@@ -757,10 +811,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + * netfilter_bridge) */ + if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV, + htonl(indev->ifindex)) || +- /* this is the bridge group "brX" */ +- /* rcu_read_lock()ed by __nf_queue */ +- nla_put_be32(skb, NFQA_IFINDEX_INDEV, +- htonl(br_port_get_rcu(indev)->br->dev->ifindex))) ++ nfqnl_put_master_ifindex(skb, NFQA_IFINDEX_INDEV, indev)) + goto nla_put_failure; + } else { + int physinif; +@@ -791,10 +842,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + * netfilter_bridge) */ + if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV, + htonl(outdev->ifindex)) || +- /* this is the bridge group "brX" */ +- /* rcu_read_lock()ed by __nf_queue */ +- nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, +- htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) ++ nfqnl_put_master_ifindex(skb, NFQA_IFINDEX_OUTDEV, outdev)) + goto nla_put_failure; + } else { + int physoutif; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-6.18/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..a2381d8d2f --- /dev/null +++ b/queue-6.18/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From 98b6dba8ca22e5c490e203a707134c48d9edf6d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index f3dadbc416a3a5..1490466b146e4b 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -702,14 +702,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1327,9 +1325,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index f4079f0718deae..0549fad53c0364 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -832,14 +832,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1228,9 +1226,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index dfaea4f6727ed9..3586e636c66bdc 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -848,14 +848,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1244,9 +1242,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-6.18/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-6.18/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..60570622f7 --- /dev/null +++ b/queue-6.18/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From a7d66930e176b427507cb8709bb1c9086403b015 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index dfda9ea61971b3..2237a5261dd2a2 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -757,24 +757,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-6.18/r8152-handle-the-return-value-of-usb_reset_device.patch b/queue-6.18/r8152-handle-the-return-value-of-usb_reset_device.patch new file mode 100644 index 0000000000..171bc745ac --- /dev/null +++ b/queue-6.18/r8152-handle-the-return-value-of-usb_reset_device.patch @@ -0,0 +1,44 @@ +From ec4836a306d5bab97a9d6d95ab58c38718b53853 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 17:22:47 +0800 +Subject: r8152: handle the return value of usb_reset_device() + +From: Chih Kai Hsu + +[ Upstream commit 19440600e729d4f74a42591a872099cf25c7d28a ] + +If usb_reset_device() returns a negative error code, stop the +process of probing. + +Fixes: 10c3271712f5 ("r8152: disable the ECM mode") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260604092247.27158-450-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index d610741782794b..8cf4e81f8f882b 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -9781,7 +9781,12 @@ static int rtl8152_probe_once(struct usb_interface *intf, + struct net_device *netdev; + int ret; + +- usb_reset_device(udev); ++ ret = usb_reset_device(udev); ++ if (ret < 0) { ++ dev_err(&intf->dev, "USB reset failed, errno=%d\n", ret); ++ return ret; ++ } ++ + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { + dev_err(&intf->dev, "Out of memory\n"); +-- +2.53.0 + diff --git a/queue-6.18/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-6.18/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..3490a3ebcc --- /dev/null +++ b/queue-6.18/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From e0241c1b061ec6b232de394a932f7782e5f4229c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index b6b46a8214a0a5..b3ee5f8238c44d 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-6.18/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-6.18/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..83195ba495 --- /dev/null +++ b/queue-6.18/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From 5dfa75c2b1eb714ab5825984aa25091ca2d733e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index e119e460ccde0b..864741fae4187e 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1204,6 +1204,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-6.18/sctp-validate-embedded-init-chunk-and-address-list-l.patch b/queue-6.18/sctp-validate-embedded-init-chunk-and-address-list-l.patch new file mode 100644 index 0000000000..20440a8541 --- /dev/null +++ b/queue-6.18/sctp-validate-embedded-init-chunk-and-address-list-l.patch @@ -0,0 +1,110 @@ +From d1fbe9ae50d19619b7a766173267c4780198b479 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 19:03:47 -0400 +Subject: sctp: validate embedded INIT chunk and address list lengths in cookie + +From: Xin Long + +[ Upstream commit 6f4c80a2a7e6d06753b89a578b710a2499a5e62b ] + +sctp_unpack_cookie() only checked that the embedded INIT chunk length +did not exceed the remaining cookie payload, but did not ensure that the +INIT chunk is large enough to contain a complete INIT header. + +A malformed COOKIE_ECHO can therefore carry a truncated INIT chunk whose +length field is smaller than sizeof(struct sctp_init_chunk). Later, +sctp_process_init() accesses INIT parameters unconditionally, which may +lead to out-of-bounds reads. + +In addition, raw_addr_list_len is not fully validated against the +remaining cookie payload. When cookie authentication is disabled, an +attacker can supply an oversized raw_addr_list_len and cause +sctp_raw_to_bind_addrs() to read beyond the end of the cookie. The +address parser also lacks sufficient bounds checks for parameter headers +and lengths, allowing malformed address parameters to trigger +out-of-bounds reads. + +Fix this by: + +- requiring the embedded INIT chunk length to be at least sizeof(struct + sctp_init_chunk); +- validating that the INIT chunk and raw address list together fit + within the cookie payload; +- verifying sufficient data exists for each address parameter header and + payload before parsing it. + +Note that sctp_verify_init() must be called after sctp_unpack_cookie() +and before sctp_process_init() when cookie authentication is disabled. +This will be addressed in a separate patch. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Sashiko +Signed-off-by: Xin Long +Link: https://patch.msgid.link/75af23a89adf881a0895d511775e4770da367cbf.1780873427.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/bind_addr.c | 11 ++++++++++- + net/sctp/sm_make_chunk.c | 9 +++++++-- + 2 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c +index 6b95d3ba8fe1ce..0947b276d1e085 100644 +--- a/net/sctp/bind_addr.c ++++ b/net/sctp/bind_addr.c +@@ -275,6 +275,16 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, + param = (struct sctp_paramhdr *)raw_addr_list; + rawaddr = (union sctp_addr_param *)raw_addr_list; + ++ if (addrs_len < sizeof(*param)) { ++ retval = -EINVAL; ++ goto out_err; ++ } ++ len = ntohs(param->length); ++ if (addrs_len < len) { ++ retval = -EINVAL; ++ goto out_err; ++ } ++ + af = sctp_get_af_specific(param_type2af(param->type)); + if (unlikely(!af) || + !af->from_addr_param(&addr, rawaddr, htons(port), 0)) { +@@ -291,7 +301,6 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, + goto out_err; + + next: +- len = ntohs(param->length); + addrs_len -= len; + raw_addr_list += len; + } +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index 9014b095f52ddb..51affa4fd396b7 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -1731,8 +1731,8 @@ struct sctp_association *sctp_unpack_cookie( + struct sk_buff *skb = chunk->skb; + struct sctp_cookie *bear_cookie; + struct sctp_chunkhdr *ch; ++ unsigned int len, chlen; + enum sctp_scope scope; +- unsigned int len; + ktime_t kt; + + /* Header size is static data prior to the actual cookie, including +@@ -1761,7 +1761,12 @@ struct sctp_association *sctp_unpack_cookie( + bear_cookie = &cookie->c; + + ch = (struct sctp_chunkhdr *)(bear_cookie + 1); +- if (ntohs(ch->length) > len - fixed_size) ++ chlen = ntohs(ch->length); ++ if (chlen < sizeof(struct sctp_init_chunk)) ++ goto malformed; ++ if (chlen > len - fixed_size) ++ goto malformed; ++ if (bear_cookie->raw_addr_list_len > len - fixed_size - chlen) + goto malformed; + + /* Verify the cookie's MAC, if cookie authentication is enabled. */ +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index 6178051f58..8646c259cb 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -82,3 +82,55 @@ tools-rv-fix-cleanup-after-failed-trace-setup.patch verification-rvgen-fix-options-shared-among-commands.patch verification-rvgen-fix-ltl2k-writing-true-as-a-liter.patch tap-free-page-on-error-paths-in-tap_get_user_xdp.patch +xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch +dma-mapping-direct-fix-missing-mapping-for-thru_host.patch +dma-debug-fix-physical-address-retrieval-in-debug_dm.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch +idpf-fix-mailbox-capability-for-set-device-clock-tim.patch +net-ena-phc-add-missing-barrier.patch +bnge-fix-context-mem-iteration.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch +asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch +tcp-restrict-so_attach_filter-to-priv-users.patch +net-add-pskb_may_pull-to-skb_gro_receive_list.patch +net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch +net-ibm-emac-fix-use-after-free-during-device-remova.patch +netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch +net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch +net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch +net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +r8152-handle-the-return-value-of-usb_reset_device.patch +gpio-zynq-fix-runtime-pm-leak-on-remove.patch +gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch +net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch +net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch +asoc-sof-amd-fix-for-ipc-flags-check.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +ip6_vti-set-netns_immutable-on-the-fallback-device.patch +sctp-validate-embedded-init-chunk-and-address-list-l.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +tun-zero-the-whole-vnet-header-in-tun_put_user.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch +netfilter-revalidate-bridge-ports.patch +netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nf_log-validate-mac-header-was-set-before-.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch +net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch +net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch +net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch +net-txgbe-optimize-the-flow-to-setup-phy-for-aml-dev.patch +net-txgbe-support-cr-modules-for-aml-devices.patch +net-txgbe-rename-the-sfp-related.patch +net-txgbe-initialize-module-info-buffer.patch +ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch diff --git a/queue-6.18/spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch b/queue-6.18/spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch new file mode 100644 index 0000000000..71729d5985 --- /dev/null +++ b/queue-6.18/spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch @@ -0,0 +1,47 @@ +From 8cb0c8a7caee99ff1d508318654d9f9ea306d86e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jun 2026 20:08:17 +0800 +Subject: spi: rzv2h-rspi: Fix SPDR read access width for 16-bit RX + +From: Felix Gu + +[ Upstream commit 310628484ef06f95c5589374fade917a5689787b ] + +The RZ/V2H hardware manual (section 7.5.2.2.1) specifies that read access +size for the SPI Data Register (SPDR) are fixed at 32 bits. The +RZV2H_RSPI_RX macro for the 16-bit data path used readw(), violating +this requirement. + +Switch to readl() for the 16-bit RX path to conform to the hardware +specification. + +Fixes: 8b61c8919dff ("spi: Add driver for the RZ/V2H(P) RSPI IP") +Suggested-by: Geert Uytterhoeven +Signed-off-by: Felix Gu +Reviewed-by: Geert Uytterhoeven +Reviewed-by: Fabrizio Castro +Link: https://patch.msgid.link/20260610-rzv2h-rspi-v2-1-40c80b4a2c90@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rzv2h-rspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c +index dcc431ba60a9e5..c981dd3c0dbab6 100644 +--- a/drivers/spi/spi-rzv2h-rspi.c ++++ b/drivers/spi/spi-rzv2h-rspi.c +@@ -105,8 +105,9 @@ static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \ + RZV2H_RSPI_TX(writel, u32) + RZV2H_RSPI_TX(writew, u16) + RZV2H_RSPI_TX(writeb, u8) ++/* The read access size for RSPI_SPDR is fixed at 32 bits */ + RZV2H_RSPI_RX(readl, u32) +-RZV2H_RSPI_RX(readw, u16) ++RZV2H_RSPI_RX(readl, u16) + RZV2H_RSPI_RX(readl, u8) + + static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi, +-- +2.53.0 + diff --git a/queue-6.18/tcp-restrict-so_attach_filter-to-priv-users.patch b/queue-6.18/tcp-restrict-so_attach_filter-to-priv-users.patch new file mode 100644 index 0000000000..b5b1f416af --- /dev/null +++ b/queue-6.18/tcp-restrict-so_attach_filter-to-priv-users.patch @@ -0,0 +1,58 @@ +From 3cc30c8e8de96e425da1ae0b120bda5c7d3a6ae7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:21:34 +0000 +Subject: tcp: restrict SO_ATTACH_FILTER to priv users + +From: Eric Dumazet + +[ Upstream commit 5d39580f68e6ddeedd15e587282207489dfb3da2 ] + +This patch restricts the use of SO_ATTACH_FILTER (cBPF) on TCP sockets +to users with CAP_NET_ADMIN capability. + +This blocks potential side-channel attack where an unprivileged application +attaches a filter to leak TCP sequence/acknowledgment numbers. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Eric Dumazet +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Cc: Willem de Bruijn +Cc: Alexei Starovoitov +Cc: Daniel Borkmann +Cc: Andrii Nakryiko +Cc: Martin KaFai Lau +Cc: Eduard Zingerman +Cc: Kumar Kartikeya Dwivedi +Cc: Song Liu +Cc: Yonghong Song +Cc: Jiri Olsa +Cc: John Fastabend +Cc: Stanislav Fomichev +Acked-by: Daniel Borkmann +Reviewed-by: Willem de Bruijn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 82470f59fa5c50..04fa0c18adc3e4 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1457,6 +1457,11 @@ int sk_setsockopt(struct sock *sk, int level, int optname, + case SO_ATTACH_FILTER: { + struct sock_fprog fprog; + ++ if (sk_is_tcp(sk) && ++ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ break; ++ } + ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); + if (!ret) + ret = sk_attach_filter(&fprog, sk); +-- +2.53.0 + diff --git a/queue-6.18/tun-zero-the-whole-vnet-header-in-tun_put_user.patch b/queue-6.18/tun-zero-the-whole-vnet-header-in-tun_put_user.patch new file mode 100644 index 0000000000..6aa110d2e4 --- /dev/null +++ b/queue-6.18/tun-zero-the-whole-vnet-header-in-tun_put_user.patch @@ -0,0 +1,49 @@ +From d6c6067c234efba5f76be25f4d38187369b52581 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 22:44:28 -0700 +Subject: tun: zero the whole vnet header in tun_put_user() + +From: Xiang Mei + +[ Upstream commit 7f2fcff15e99bb852f6967396ed12b38376e2c8d ] + +tun_put_user() declares an on-stack struct virtio_net_hdr_v1_hash_tunnel +without zeroing it. For a non-tunnel skb, virtio_net_hdr_tnl_from_skb() +only initializes the first 10 bytes (sizeof(struct virtio_net_hdr)), +leaving bytes 10..23 (num_buffers and the hash/tunnel fields) as stack +garbage. + +An unprivileged user can set the vnet header size to 24 with +TUNSETVNETHDRSZ, so __tun_vnet_hdr_put() copies all 24 bytes of the +partially-initialized struct to userspace, leaking 14 bytes of kernel +stack on every read of a non-tunnel packet. + +Fix it the same way tun_get_user() already does by zeroing the whole +header right after declaration. + +Fixes: 288f30435132 ("tun: enable gso over UDP tunnel support.") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607054428.3050243-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 9a767da38c71e7..d27c3229465ad9 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2068,6 +2068,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, + struct virtio_net_hdr_v1_hash_tunnel hdr; + struct virtio_net_hdr *gso; + ++ memset(&hdr, 0, sizeof(hdr)); + ret = tun_vnet_hdr_tnl_from_skb(tun->flags, tun->dev, skb, + &hdr); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch b/queue-6.18/xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch new file mode 100644 index 0000000000..5fbe946866 --- /dev/null +++ b/queue-6.18/xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch @@ -0,0 +1,72 @@ +From f6b78540048be4a550437216fdc5ceeb82b02b1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:53:28 +0800 +Subject: xfrm: iptfs: fix use-after-free on first_skb in + __input_process_payload +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit eb48730bb827d1550401a5d391903f9d90b493c8 ] + +__input_process_payload() stores first_skb into xtfs->ra_newskb under +drop_lock when starting partial reassembly, then unlocks and breaks out +of the processing loop. The post-loop check reads xtfs->ra_newskb +without the lock to decide whether first_skb is still owned: + + if (first_skb && first_iplen && !defer && first_skb != xtfs->ra_newskb) + +Between spin_unlock and this read, a concurrent CPU running +iptfs_reassem_cont() (or the drop_timer hrtimer) can complete +reassembly, NULL xtfs->ra_newskb, and free the skb. The check then +evaluates first_skb != NULL as true, and pskb_trim/ip_summed/consume_skb +operate on the freed skb — a use-after-free in skbuff_head_cache. + +Replace the unlocked read with a local bool that records whether +first_skb was handed to the reassembly state in the current call. The +flag is set after the existing spin_unlock, before the break, using the +pointer equality that is stable at that point (first_skb == skb iff +first_skb was stored in ra_newskb). + +Fixes: 3f3339885fb3 ("xfrm: iptfs: add reusing received skb for the tunnel egress packet") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_iptfs.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c +index e11e4f7411fd25..3dbb9c2cf4d5f6 100644 +--- a/net/xfrm/xfrm_iptfs.c ++++ b/net/xfrm/xfrm_iptfs.c +@@ -954,6 +954,7 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data, + u32 first_iplen, iphlen, iplen, remaining, tail; + u32 capturelen; + u64 seq; ++ bool first_skb_partial = false; + + xtfs = x->mode_data; + net = xs_net(x); +@@ -1161,6 +1162,7 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data, + + spin_unlock(&xtfs->drop_lock); + ++ first_skb_partial = (first_skb == skb); + break; + } + +@@ -1172,7 +1174,7 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data, + /* this should not happen from the above code */ + XFRM_INC_STATS(net, LINUX_MIB_XFRMINIPTFSERROR); + +- if (first_skb && first_iplen && !defer && first_skb != xtfs->ra_newskb) { ++ if (first_skb && first_iplen && !defer && !first_skb_partial) { + /* first_skb is queued b/c !defer and not partial */ + if (pskb_trim(first_skb, first_iplen)) { + /* error trimming */ +-- +2.53.0 + diff --git a/queue-6.18/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-6.18/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..b6bf52eb94 --- /dev/null +++ b/queue-6.18/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From d45c07932e60a1e66b7a73f220549fc5e0d3f9b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index ee1f6d5c391de8..c76625d511ec34 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1156,15 +1156,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1707,12 +1698,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 + diff --git a/queue-6.6/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch b/queue-6.6/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch new file mode 100644 index 0000000000..e48257e2ae --- /dev/null +++ b/queue-6.6/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch @@ -0,0 +1,52 @@ +From 5f715649ced3b8552b79e96bfe684b4d18ecf551 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:12:44 +0100 +Subject: ASoC: wm_adsp: Fix NULL dereference when removing firmware controls + +From: Richard Fitzgerald + +[ Upstream commit 7d3fb78b550301e43fdc60312aed733069694426 ] + +In wm_adsp_control_remove() check that the priv pointer is not NULL +before attempting to cleanup what it points to. + +When cs_dsp creates a control it calls wm_adsp_control_add_cb() so that +wm_adsp can create its own private control data. There are two cases +where private data is not created: + +1. The control is a SYSTEM control, so an ALSA control is not created. + +2. The codec driver has registered a control_add() callback that + hides the control, so wm_adsp_control_add() is not called. + +When cs_dsp_remove destroys its control list it calls +wm_adsp_control_remove() for each control. But wm_adsp_control_remove() +was attempting to cleanup the private data pointed to by cs_ctl->priv +without checking the pointer for NULL. + +Signed-off-by: Richard Fitzgerald +Fixes: 0700bc2fb94c ("ASoC: wm_adsp: Separate generic cs_dsp_coeff_ctl handling") +Link: https://patch.msgid.link/20260604101244.1402862-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wm_adsp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c +index b9c20e29fe63ef..2da19de4800e2f 100644 +--- a/sound/soc/codecs/wm_adsp.c ++++ b/sound/soc/codecs/wm_adsp.c +@@ -674,6 +674,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) + { + struct wm_coeff_ctl *ctl = cs_ctl->priv; + ++ if (!ctl) ++ return; ++ + cancel_work_sync(&ctl->work); + + kfree(ctl->name); +-- +2.53.0 + diff --git a/queue-6.6/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch b/queue-6.6/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch new file mode 100644 index 0000000000..f5b461ffe8 --- /dev/null +++ b/queue-6.6/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch @@ -0,0 +1,85 @@ +From 3acb0100e369067d5c9fe2c63720d5763486b5f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:43:34 +0800 +Subject: gpio: mvebu: fix NULL pointer dereference in suspend/resume + +From: Yun Zhou + +[ Upstream commit b9ad50d7505ebd48282ec3630258dc820fc85c81 ] + +mvebu_pwm_suspend() and mvebu_pwm_resume() are called for all GPIO +banks during suspend/resume, but not all banks have PWM functionality. +GPIO banks without PWM have mvchip->mvpwm set to NULL. + +Calling mvebu_pwm_suspend() with mvpwm == NULL causes a NULL pointer +dereference when it tries to access mvpwm->blink_select. + + Unable to handle kernel NULL pointer dereference at virtual address 00000020 when write + [00000020] *pgd=00000000 + Internal error: Oops: 815 [#1] PREEMPT ARM + Modules linked in: + CPU: 0 UID: 0 PID: 406 Comm: sh Not tainted 6.12.74-rt12-yocto-standard-g4e96f98fb7db-dirty #353 + Hardware name: Marvell Armada 370/XP (Device Tree) + PC is at regmap_mmio_read+0x38/0x54 + LR is at regmap_mmio_read+0x38/0x54 + pc : [] lr : [] psr: 200f0013 + sp : f0c11d10 ip : 00000000 fp : c100d2f0 + r10: c14fb854 r9 : 00000000 r8 : 00000000 + r7 : c1799c00 r6 : 00000020 r5 : 00000020 r4 : c179c7c0 + r3 : f0a231a0 r2 : 00000020 r1 : 00000020 r0 : 00000000 + Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none + Control: 10c5387d Table: 135ec059 DAC: 00000051 + Call trace: + regmap_mmio_read from _regmap_bus_reg_read+0x78/0xac + _regmap_bus_reg_read from _regmap_read+0x60/0x154 + _regmap_read from regmap_read+0x3c/0x60 + regmap_read from mvebu_gpio_suspend+0xa4/0x14c + mvebu_gpio_suspend from dpm_run_callback+0x54/0x180 + dpm_run_callback from device_suspend+0x124/0x630 + device_suspend from dpm_suspend+0x124/0x270 + dpm_suspend from dpm_suspend_start+0x64/0x6c + dpm_suspend_start from suspend_devices_and_enter+0x140/0x8e8 + suspend_devices_and_enter from pm_suspend+0x2fc/0x308 + pm_suspend from state_store+0x6c/0xc8 + state_store from kernfs_fop_write_iter+0x10c/0x1f8 + kernfs_fop_write_iter from vfs_write+0x270/0x468 + vfs_write from ksys_write+0x70/0xf0 + ksys_write from ret_fast_syscall+0x0/0x54 + +Add a NULL check for mvchip->mvpwm before calling the PWM +suspend/resume functions. + +Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support") +Signed-off-by: Yun Zhou +Link: https://patch.msgid.link/20260608084334.2960803-1-yun.zhou@windriver.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mvebu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c +index 67497116ce27d4..ee184720de57c2 100644 +--- a/drivers/gpio/gpio-mvebu.c ++++ b/drivers/gpio/gpio-mvebu.c +@@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_suspend(mvchip); + + return 0; +@@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_resume(mvchip); + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch b/queue-6.6/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch new file mode 100644 index 0000000000..12e08011bb --- /dev/null +++ b/queue-6.6/iomap-don-t-revert-iov_iter-on-partially-completed-b.patch @@ -0,0 +1,61 @@ +From 5453c1653edadf19761b340c5cd6bbc86905324d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jun 2026 08:10:47 -0400 +Subject: iomap: don't revert iov_iter on partially completed buffered writes + +From: Brian Foster + +Gregg reports that the iomap retry behavior for nonblocking (nowait) +append writes is broken. The problem occurs when an append write is +first submitted in non-blocking mode (i.e. via io_uring), partially +completes before hitting -EAGAIN, and then is resubmitted from +blocking context. + +The specific problem is that at least one iteration of the loop in +iomap_write_iter() completes in non-blocking context and thus has +bumped i_size. The next iteration hits -EAGAIN, reverts the iov_iter +and returns. io_uring retries the entire append write from blocking +context, but since i_size has already been increased, the data that +was partially written on the first attempt is rewritten at the new +i_size. This is essentially an intra-write data corruption since the +data written to the file does not reflect the write from userspace. + +This problem is already fixed on master as of commit 1a1a3b574b97 +("iomap: advance the iter directly on buffered writes"). That commit +was primarily intended to clean up iomap iter state tracking, but it +also happened to remove the iov_iter revert and thus accidentally +fix this problem as well. Without the revert, iomap will commit +partial progress internally and loop once more before it more than +likely hits -EAGAIN and returns partial progress consistent with the +inode updates. This means the blocking retry from io_uring will pick +up where the first attempt left off at the current i_size and +perform the remainder of the write correctly. + +Cc: +Fixes: 18e419f6e80a ("iomap: Return -EAGAIN from iomap_write_iter()") +Reported-by: Gregg Leventhal +Reported-by: Eric Hagberg +Signed-off-by: Brian Foster +Signed-off-by: Sasha Levin +--- + fs/iomap/buffered-io.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index c5d439f8e2254e..4bc57934aa52df 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -974,10 +974,6 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) + } + } while (iov_iter_count(i) && length); + +- if (status == -EAGAIN) { +- iov_iter_revert(i, written); +- return -EAGAIN; +- } + return written ? written : status; + } + +-- +2.53.0 + diff --git a/queue-6.6/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-6.6/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..3964f0738b --- /dev/null +++ b/queue-6.6/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From b916f51035e075aae8458a807b51c8349873d814 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index 5e71dbd9401694..67cf616c1499a4 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -105,6 +105,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -112,6 +113,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-6.6/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch b/queue-6.6/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch new file mode 100644 index 0000000000..8ab30ebed8 --- /dev/null +++ b/queue-6.6/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch @@ -0,0 +1,89 @@ +From 093acb55d94e92e710ee6b10d37d195e8fb9e538 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 17:54:48 +0300 +Subject: ipv6: Fix a potential NPD in cleanup_prefix_route() + +From: Ido Schimmel + +[ Upstream commit b70c687b7cf267fb08586667a3946c8851cad672 ] + +addrconf_get_prefix_route() can return the fib6_null_entry sentinel +entry which has a NULL fib6_table pointer. Therefore, before setting the +route's expiration time, check that we are not working with this entry, +as otherwise a NPD will be triggered [1]. + +Note that the other callers of addrconf_get_prefix_route() are not +susceptible to this bug: + +1. addrconf_prefix_rcv(): Requests a route with the 'RTF_ADDRCONF | + RTF_PREFIX_RT' flags which are not set on fib6_null_entry. + +2. modify_prefix_route(): Fixed by commit a747e02430df ("ipv6: avoid + possible NULL deref in modify_prefix_route()"). + +3. __ipv6_ifa_notify(): Calls ip6_del_rt() which specifically checks for + fib6_null_entry and returns an error. + +[1] +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] SMP KASAN +KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037] +[...] +Call Trace: + +__kasan_check_byte (mm/kasan/common.c:573) +lock_acquire.part.0 (kernel/locking/lockdep.c:5842 (discriminator 1)) +_raw_spin_lock_bh (kernel/locking/spinlock.c:182 (discriminator 1)) +cleanup_prefix_route (net/ipv6/addrconf.c:1280) +ipv6_del_addr (net/ipv6/addrconf.c:1342) +inet6_addr_del.isra.0 (net/ipv6/addrconf.c:3119) +inet6_rtm_deladdr (net/ipv6/addrconf.c:4812) +rtnetlink_rcv_msg (net/core/rtnetlink.c:6997) +netlink_rcv_skb (net/netlink/af_netlink.c:2555) +netlink_unicast (net/netlink/af_netlink.c:1344) +netlink_sendmsg (net/netlink/af_netlink.c:1899) +__sock_sendmsg (net/socket.c:802 (discriminator 4)) +____sys_sendmsg (net/socket.c:2698) +___sys_sendmsg (net/socket.c:2752) +__sys_sendmsg (net/socket.c:2784) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 5eb902b8e719 ("net/ipv6: Remove expired routes with a separated list of routes.") +Reported-by: Ji'an Zhou +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260609145448.768318-1-idosch@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 32fa6236dacdd9..ba5de8b924b80c 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1268,6 +1268,7 @@ static void + cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + bool del_rt, bool del_peer) + { ++ struct net *net = dev_net(ifp->idev->dev); + struct fib6_table *table; + struct fib6_info *f6i; + +@@ -1276,9 +1277,10 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + ifp->idev->dev, 0, RTF_DEFAULT, true); + if (f6i) { + if (del_rt) +- ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); ++ ip6_del_rt(net, f6i, false); + else { +- if (!(f6i->fib6_flags & RTF_EXPIRES)) { ++ if (f6i != net->ipv6.fib6_null_entry && ++ !(f6i->fib6_flags & RTF_EXPIRES)) { + table = f6i->fib6_table; + spin_lock_bh(&table->tb6_lock); + +-- +2.53.0 + diff --git a/queue-6.6/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-6.6/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..b803c92bb5 --- /dev/null +++ b/queue-6.6/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From b3e3ff5fab76731a09e1707bfb2821f901c23e7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index eb4c8e2a2b12e0..aa88a41034d920 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -965,6 +965,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-6.6/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-6.6/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..8ce6773e2e --- /dev/null +++ b/queue-6.6/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From 3db34b86ca87b3889a5fb1c7560d6d1c293b1740 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index d516ed80500844..a6944844553afe 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1921,6 +1921,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 5f45a52cc8ca66..c5e2ae6d0406bd 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -5120,7 +5120,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -5129,8 +5129,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index 94c38c73fc6982..fa242d7e51c791 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -823,12 +823,13 @@ EXPORT_SYMBOL(kernel_sendmsg_locked); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-6.6/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch b/queue-6.6/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch new file mode 100644 index 0000000000..b6a2de38e5 --- /dev/null +++ b/queue-6.6/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch @@ -0,0 +1,61 @@ +From 362b11f0bc6fc2178fc615d8b3efc6d9346a2912 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:10:44 +0800 +Subject: net/mlx4: avoid GCC 10 __bad_copy_from() false positive + +From: Yao Sang + +[ Upstream commit 2365343f4aad3e1b1e7a2e87e98cf66d5e590589 ] + +mlx4_init_user_cqes() fills a scratch buffer with the CQE +initialization pattern and then copies from that buffer to userspace. + +In the single-copy path, the copy length is array_size(entries, +cqe_size), but the scratch buffer is allocated with PAGE_SIZE. GCC 10 +does not carry the branch invariant strongly enough through the object +size checks and falsely triggers __bad_copy_from(). + +Size the scratch buffer to the actual copy length for the active path, +keep array_size() for the single-copy case, and retain a WARN_ON_ONCE() +guard for the PAGE_SIZE invariant before allocating the buffer. + +Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()") +Signed-off-by: Yao Sang +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx4/cq.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c +index 4d4f9cf9facb87..fb83d8af8dcb9c 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/cq.c ++++ b/drivers/net/ethernet/mellanox/mlx4/cq.c +@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) + static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + { + int entries_per_copy = PAGE_SIZE / cqe_size; ++ size_t copy_bytes; + void *init_ents; + int err = 0; + int i; +@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + buf += PAGE_SIZE; + } + } else { ++ copy_bytes = array_size(entries, cqe_size); ++ if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE)) { ++ err = -EINVAL; ++ goto out; ++ } ++ + err = copy_to_user((void __user *)buf, init_ents, +- array_size(entries, cqe_size)) ? ++ copy_bytes) ? + -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch b/queue-6.6/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch new file mode 100644 index 0000000000..52afb74b8b --- /dev/null +++ b/queue-6.6/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch @@ -0,0 +1,221 @@ +From a6bdf5057817a40c67566ddeab1c313586f05f9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:58:49 +0300 +Subject: net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list + +From: Dragos Tatulea + +[ Upstream commit 894e036a24a26a6dd7b17d8d3fb5c53ab48a6074 ] + +mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using +the PF's log_max_current_uc/mc_list capabilities. When querying a VF +vport with a larger configured max (via devlink), the firmware response +can overflow this buffer: + + BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 + + CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) + Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] + Call Trace: + + dump_stack_lvl+0x69/0xa0 + print_report+0x176/0x4e4 + kasan_report+0xc8/0x100 + mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] + esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] + esw_vport_change_handler+0x6a/0x90 [mlx5_core] + process_one_work+0x87f/0x15e0 + worker_thread+0x62b/0x1020 + kthread+0x375/0x490 + ret_from_fork+0x4dc/0x810 + ret_from_fork_asm+0x11/0x20 + + +Fix by querying the vport's own HCA caps to size the buffer correctly. +Refactor the function to allocate and return the MAC list internally, +removing the caller's dependency on knowing the correct max. + +Fixes: e16aea2744ab ("net/mlx5: Introduce access functions to modify/query vport mac lists") +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135849.458060-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +--- + .../net/ethernet/mellanox/mlx5/core/vport.c | 72 ++++++++++++++----- + include/linux/mlx5/vport.h | 4 +- + 3 files changed, 59 insertions(+), 30 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +index 2559237da49c52..3593e2770baf7e 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, int list_type) + { + bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC; +- u8 (*mac_list)[ETH_ALEN]; ++ u8 (*mac_list)[ETH_ALEN] = NULL; + struct l2addr_node *node; + struct vport_addr *addr; + struct hlist_head *hash; + struct hlist_node *tmp; +- int size; ++ int size = 0; + int err; + int hi; + int i; + +- size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) : +- MLX5_MAX_MC_PER_VPORT(esw->dev); +- +- mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL); +- if (!mac_list) +- return; +- + hash = is_uc ? vport->uc_list : vport->mc_list; + + for_each_l2hash_node(node, tmp, hash, hi) { +@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + goto out; + + err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type, +- mac_list, &size); ++ &mac_list, &size); + if (err) + goto out; + esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n", +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +index 06b5265b6e6db2..23a22caa955f31 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +@@ -250,35 +250,63 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu) + } + EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mtu); + ++static int mlx5_vport_max_mac_list_size(struct mlx5_core_dev *dev, u16 vport, ++ enum mlx5_list_type list_type) ++{ ++ void *query_ctx, *hca_caps; ++ int ret = 0; ++ ++ if (!vport && !mlx5_core_is_ecpf(dev)) ++ return list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : ++ 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ ++ query_ctx = kzalloc(MLX5_ST_SZ_BYTES(query_hca_cap_out), GFP_KERNEL); ++ if (!query_ctx) ++ return -ENOMEM; ++ ++ ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_ctx); ++ if (ret) ++ goto out; ++ ++ hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); ++ ret = list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_uc_list) : ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_mc_list); ++ ++out: ++ kfree(query_ctx); ++ ++ return ret; ++} ++ + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size) ++ u8 (**addr_list)[ETH_ALEN], ++ int *addr_list_size) + { + u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {0}; ++ int allowed_list_size; + void *nic_vport_ctx; + int max_list_size; +- int req_list_size; + int out_sz; + void *out; + int err; + int i; + +- req_list_size = *list_size; ++ if (!addr_list || !addr_list_size) ++ return -EINVAL; + +- max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ? +- 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : +- 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ *addr_list = NULL; ++ *addr_list_size = 0; + +- if (req_list_size > max_list_size) { +- mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n", +- req_list_size, max_list_size); +- req_list_size = max_list_size; +- } ++ max_list_size = mlx5_vport_max_mac_list_size(dev, vport, list_type); ++ if (max_list_size < 0) ++ return max_list_size; + + out_sz = MLX5_ST_SZ_BYTES(query_nic_vport_context_out) + +- req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); ++ max_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); + + out = kvzalloc(out_sz, GFP_KERNEL); + if (!out) +@@ -297,16 +325,24 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + + nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out, + nic_vport_context); +- req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, +- allowed_list_size); ++ allowed_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, ++ allowed_list_size); ++ if (!allowed_list_size) ++ goto out; ++ ++ *addr_list = kcalloc(allowed_list_size, ETH_ALEN, GFP_KERNEL); ++ if (!*addr_list) { ++ err = -ENOMEM; ++ goto out; ++ } + +- *list_size = req_list_size; +- for (i = 0; i < req_list_size; i++) { ++ for (i = 0; i < allowed_list_size; i++) { + u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context, + nic_vport_ctx, + current_uc_mac_address[i]) + 2; +- ether_addr_copy(addr_list[i], mac_addr); ++ ether_addr_copy((*addr_list)[i], mac_addr); + } ++ *addr_list_size = allowed_list_size; + out: + kvfree(out); + return err; +diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h +index fbb9bf4478894c..598e58cceeec50 100644 +--- a/include/linux/mlx5/vport.h ++++ b/include/linux/mlx5/vport.h +@@ -94,8 +94,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size); ++ u8 (**mac_list)[ETH_ALEN], ++ int *mac_list_size); + int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev, + enum mlx5_list_type list_type, + u8 addr_list[][ETH_ALEN], +-- +2.53.0 + diff --git a/queue-6.6/net-mvpp2-add-metadata-support-for-xdp-mode.patch b/queue-6.6/net-mvpp2-add-metadata-support-for-xdp-mode.patch new file mode 100644 index 0000000000..3de7c5b68b --- /dev/null +++ b/queue-6.6/net-mvpp2-add-metadata-support-for-xdp-mode.patch @@ -0,0 +1,81 @@ +From 43329ae1211443c1cbc9e396600f430e13915928 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Mar 2025 12:46:06 +0100 +Subject: net: mvpp2: Add metadata support for xdp mode + +From: Lorenzo Bianconi + +[ Upstream commit 9a45e193c88a55a536d7fd0ebfa29823d588c2cf ] + +Set metadata size building the skb from xdp_buff in mvpp2 driver +mvpp2 driver sets xdp headroom to: + +MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM + +where + +MVPP2_MH_SIZE 2 +MVPP2_SKB_HEADROOM min(max(XDP_PACKET_HEADROOM, NET_SKB_PAD), 224) + +so the headroom is large enough to contain xdp_frame and xdp metadata. +Please note this patch is just compiled tested. + +Reviewed-by: Michal Kubiak +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20250318-mvneta-xdp-meta-v2-2-b6075778f61f@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 9221ee209a309b..812c80d45859d5 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3915,13 +3915,13 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + while (rx_done < rx_todo) { + struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); ++ u32 rx_status, timestamp, metasize = 0; + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; + unsigned int frag_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- u32 rx_status, timestamp; + int pool, rx_bytes, err, ret; + struct page *page; + void *data; +@@ -3984,7 +3984,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, +- rx_bytes, false); ++ rx_bytes, true); + + ret = mvpp2_run_xdp(port, xdp_prog, &xdp, pp, &ps); + +@@ -4000,6 +4000,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_bytes += rx_bytes; + continue; + } ++ ++ metasize = xdp.data - xdp.data_meta; + } + + if (frag_size) +@@ -4039,6 +4041,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); + skb_put(skb, rx_bytes); ++ if (metasize) ++ skb_metadata_set(skb, metasize); + skb->ip_summed = mvpp2_rx_csum(port, rx_status); + skb->protocol = eth_type_trans(skb, dev); + +-- +2.53.0 + diff --git a/queue-6.6/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch b/queue-6.6/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch new file mode 100644 index 0000000000..c59a0ce88d --- /dev/null +++ b/queue-6.6/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch @@ -0,0 +1,106 @@ +From 555ef7a681c8725bf16b0f333deb841c2a12c041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:43 +0200 +Subject: net: mvpp2: build skb from XDP-adjusted data on XDP_PASS + +From: Til Kaiser + +[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ] + +When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() +and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets +derived from the original RX descriptor. Packet geometry changes made by +the XDP program are therefore discarded before the skb reaches the stack. + +Update rx_offset and rx_bytes from xdp.data and xdp.data_end for +XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen +by XDP, and makes RX byte accounting for XDP_PASS follow the length of the +skb passed to the network stack. + +Keep a separate rx_sync_size for page-pool recycling on skb allocation +failure, which must stay tied to the received buffer range. + +Non-PASS verdicts continue to account the descriptor length because no skb +is passed up in those cases. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-5-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 5bdc26bebe4488..ab608cd497a936 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3919,10 +3919,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; +- unsigned int frag_size; ++ unsigned int frag_size, rx_sync_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- int pool, rx_bytes, err, ret; ++ int pool, rx_bytes, rx_offset, err, ret; + struct page *page; + void *data; + +@@ -3935,6 +3935,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + rx_status = mvpp2_rxdesc_status_get(port, rx_desc); + rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc); + rx_bytes -= MVPP2_MH_SIZE; ++ rx_sync_size = rx_bytes + MVPP2_MH_SIZE; ++ rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM; + dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc); + + pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> +@@ -3950,7 +3952,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, + MVPP2_SKB_HEADROOM, +- rx_bytes + MVPP2_MH_SIZE, ++ rx_sync_size, + dma_dir); + + /* Buffer header not supported */ +@@ -4001,6 +4003,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + } + ++ rx_sync_size = max_t(unsigned int, rx_sync_size, ++ xdp.data_end - xdp.data_hard_start - ++ MVPP2_SKB_HEADROOM); ++ ++ /* Update offset and length to reflect any XDP adjustments. */ ++ rx_offset = xdp.data - data; ++ rx_bytes = xdp.data_end - xdp.data; ++ + metasize = xdp.data - xdp.data_meta; + } + +@@ -4012,8 +4022,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + netdev_warn(port->dev, "skb build failed\n"); + if (pp) { + page_pool_put_page(pp, virt_to_head_page(data), +- rx_bytes + MVPP2_MH_SIZE, +- true); ++ rx_sync_size, true); + } else { + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, +@@ -4043,7 +4052,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + +- skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); ++ skb_reserve(skb, rx_offset); + skb_put(skb, rx_bytes); + if (metasize) + skb_metadata_set(skb, metasize); +-- +2.53.0 + diff --git a/queue-6.6/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch b/queue-6.6/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch new file mode 100644 index 0000000000..6f6d9ba68b --- /dev/null +++ b/queue-6.6/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch @@ -0,0 +1,46 @@ +From 5322e56f0c0faa53504aa0d0b37b1c6a72459be3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:41 +0200 +Subject: net: mvpp2: limit XDP frame size to the RX buffer + +From: Til Kaiser + +[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ] + +mvpp2 has short and long BM pools, and short pool buffers can be smaller +than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with +PAGE_SIZE as frame size. + +XDP helpers use frame_sz to validate tail growth and to derive the hard +end of the data area. Advertising PAGE_SIZE for short buffers can let +bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting +memory or later tripping skb tailroom checks. + +Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches +the actual buffer backing the packet. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-3-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index af10654f655674..9221ee209a309b 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3981,7 +3981,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + xdp_rxq = &rxq->xdp_rxq_long; + +- xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq); ++ xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, + rx_bytes, false); +-- +2.53.0 + diff --git a/queue-6.6/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch b/queue-6.6/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch new file mode 100644 index 0000000000..6a047c67b7 --- /dev/null +++ b/queue-6.6/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch @@ -0,0 +1,126 @@ +From fc4599dde5a49623e6d885950a04649a48947682 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:42 +0200 +Subject: net: mvpp2: refill RX buffers before XDP or skb use + +From: Til Kaiser + +[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ] + +The RX error path returns the current descriptor buffer to the hardware +BM pool. That is only valid while the driver still owns the buffer. + +mvpp2_rx_refill() can fail after the current buffer has been handed to +XDP or attached to an skb. In those cases mvpp2_run_xdp() may have +recycled, redirected, or queued the page for XDP_TX, and an skb free also +retires the data buffer. Returning such a buffer to BM lets hardware DMA +into memory that is no longer owned by the RX ring. + +Refill the BM pool before handing the current buffer to XDP or to the +skb. If the allocation fails there, drop the packet and return the +still-owned current buffer to BM, preserving the pool depth. Once the +refill succeeds, later local drops retire/free the current buffer instead +of returning it to BM. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-4-mail@tk154.de +Signed-off-by: Paolo Abeni +Stable-dep-of: 77a6b90ce56b ("net: mvpp2: build skb from XDP-adjusted data on XDP_PASS") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- + 1 file changed, 24 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 812c80d45859d5..5bdc26bebe4488 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3973,6 +3973,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + frag_size = bm_pool->frag_size; + ++ err = mvpp2_rx_refill(port, bm_pool, pp, pool); ++ if (err) { ++ netdev_err(port->dev, "failed to refill BM pools\n"); ++ goto err_drop_frame; ++ } ++ + if (xdp_prog) { + struct xdp_rxq_info *xdp_rxq; + +@@ -3990,12 +3996,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + if (ret) { + xdp_ret |= ret; +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- goto err_drop_frame; +- } +- + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + continue; +@@ -4010,8 +4010,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb = slab_build_skb(data); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); +- goto err_drop_frame; ++ if (pp) { ++ page_pool_put_page(pp, virt_to_head_page(data), ++ rx_bytes + MVPP2_MH_SIZE, ++ true); ++ } else { ++ dma_unmap_single_attrs(dev->dev.parent, dma_addr, ++ bm_pool->buf_size, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ mvpp2_frag_free(bm_pool, pp, data); ++ } ++ goto err_drop_frame_retired; + } ++ if (pp) ++ skb_mark_for_recycle(skb); + + /* If we have RX hardware timestamping enabled, grab the + * timestamp from the queue and convert. +@@ -4022,16 +4035,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb_hwtstamps(skb)); + } + +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- dev_kfree_skb_any(skb); +- goto err_drop_frame; +- } +- +- if (pp) +- skb_mark_for_recycle(skb); +- else ++ if (!pp) + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); +@@ -4050,13 +4054,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + + err_drop_frame: +- dev->stats.rx_errors++; +- mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + if (rx_status & MVPP2_RXD_BUF_HDR) + mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status); + else + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); ++err_drop_frame_retired: ++ dev->stats.rx_errors++; ++ mvpp2_rx_error(port, rx_desc); + } + + if (xdp_ret & MVPP2_XDP_REDIR) +-- +2.53.0 + diff --git a/queue-6.6/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-6.6/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..00e2438f52 --- /dev/null +++ b/queue-6.6/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From cc59f1b01d6f164d5f317d31f0829316520171c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 410c9dea4fa2ef..af10654f655674 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3948,9 +3948,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-6.6/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-6.6/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..8f29f91759 --- /dev/null +++ b/queue-6.6/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From 45691aaabdbc2b84541655b5fcd48dc3591ec765 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 7803e7548d9203..857edc53739332 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1287,6 +1287,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-6.6/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch b/queue-6.6/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch new file mode 100644 index 0000000000..df5d4a7881 --- /dev/null +++ b/queue-6.6/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch @@ -0,0 +1,53 @@ +From 16dc2809eae6663bdd0fe7c026088e4108e239a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:15 +0200 +Subject: net: phy: clean the sfp upstream if phy probing fails + +From: Maxime Chevallier + +[ Upstream commit 48774e87bbaa0056819d4b52301e4692e50e3252 ] + +Sashiko reported that we don't call sfp_bus_del_upstream() in the probe +failure path, so let's add it, otherwise the sfp-bus is left with a +dangling 'upstream' field, that may be used later on during SFP events. + +This issue existed before the generic phylib sfp support, back when +drivers were calling phy_sfp_probe themselves. + +Reviewed-by: Nicolai Buchwitz +Fixes: 298e54fa810e ("net: phy: add core phylib sfp support") +Signed-off-by: Maxime Chevallier +Link: https://patch.msgid.link/20260604092819.723505-2-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 1d073947dd4c26..c8aa322f59918c 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1432,6 +1432,9 @@ int phy_sfp_probe(struct phy_device *phydev, + + ret = sfp_bus_add_upstream(bus, phydev, ops); + sfp_bus_put(bus); ++ ++ if (ret) ++ phydev->sfp_bus = NULL; + } + return ret; + } +@@ -3414,6 +3417,9 @@ static int phy_probe(struct device *dev) + return 0; + + out: ++ sfp_bus_del_upstream(phydev->sfp_bus); ++ phydev->sfp_bus = NULL; ++ + if (!phydev->is_on_sfp_module) + phy_led_triggers_unregister(phydev); + +-- +2.53.0 + diff --git a/queue-6.6/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-6.6/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..67df911617 --- /dev/null +++ b/queue-6.6/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From 40d14bd58923c11ecc30879ad706446598024c6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index b703e4c6458532..2c009793f1931d 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -707,13 +707,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-6.6/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-6.6/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..53028dd445 --- /dev/null +++ b/queue-6.6/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From 16c2e1b90f0c17ca8b8c22d73343929d57f508e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index 4190b90ff3b18a..1909cd440a4b66 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch b/queue-6.6/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch new file mode 100644 index 0000000000..ef9eeee19d --- /dev/null +++ b/queue-6.6/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch @@ -0,0 +1,150 @@ +From 6cefa86add604fbcaea0114bc7ab7a37b4b24a06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 00:38:17 -0700 +Subject: netfilter: nf_conntrack: destroy stale expectfn expectations on + unregister + +From: Weiming Shi + +[ Upstream commit c3009418f9fa1dcb3eb86f4d8c92583537b5faa3 ] + +NAT helpers such as nf_nat_h323 store a raw pointer to module text in +exp->expectfn (e.g. ip_nat_q931_expect). nf_ct_helper_expectfn_unregister() +only unlinks the callback descriptor and never walks the expectation table, +so an expectation pending at module removal survives with a dangling +exp->expectfn into freed module text. + +When the expected connection arrives, init_conntrack() invokes +exp->expectfn(), now a stale pointer into the unloaded module. Reproduced +on a KASAN build by loading the H.323 helpers, creating a Q.931 +expectation, unloading nf_nat_h323, then connecting to the expected port: + + Oops: int3: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:0xffffffffa06102d1 + init_conntrack.isra.0 (net/netfilter/nf_conntrack_core.c:1862) + nf_conntrack_in (net/netfilter/nf_conntrack_core.c:2049) + ipv4_conntrack_local (net/netfilter/nf_conntrack_proto.c:223) + nf_hook_slow (net/netfilter/core.c:619) + __ip_local_out (net/ipv4/ip_output.c:120) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1715) + tcp_connect (net/ipv4/tcp_output.c:4374) + tcp_v4_connect (net/ipv4/tcp_ipv4.c:345) + __sys_connect (net/socket.c:2167) + Modules linked in: nf_conntrack_h323 [last unloaded: nf_nat_h323] + +Reaching the dangling state requires CAP_SYS_MODULE in the initial user +namespace to remove a NAT helper that still has live expectations, so this +is a robustness fix; leaving an expectation pointing at freed text is wrong +regardless. + +Add nf_ct_helper_expectfn_destroy(), which walks the expectation table and +drops every expectation whose ->expectfn matches the descriptor being torn +down. Call it from each NAT helper's exit path after the existing RCU grace +period, so no expectation outlives the code it points at and no extra +synchronize_rcu() is introduced. With the fix, the same reproducer runs to +completion without the Oops. + +Fixes: f587de0e2feb ("[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Weiming Shi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_helper.h | 1 + + net/ipv4/netfilter/nf_nat_h323.c | 2 ++ + net/netfilter/nf_conntrack_helper.c | 19 +++++++++++++++++++ + net/netfilter/nf_nat_core.c | 2 ++ + net/netfilter/nf_nat_sip.c | 1 + + 5 files changed, 25 insertions(+) + +diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h +index de2f956abf3480..24cf3d2d97450f 100644 +--- a/include/net/netfilter/nf_conntrack_helper.h ++++ b/include/net/netfilter/nf_conntrack_helper.h +@@ -155,6 +155,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct, + + void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); + void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n); + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name); + struct nf_ct_helper_expectfn * +diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c +index faee20af485613..10e1b0837731b7 100644 +--- a/net/ipv4/netfilter/nf_nat_h323.c ++++ b/net/ipv4/netfilter/nf_nat_h323.c +@@ -555,6 +555,8 @@ static void __exit nf_nat_h323_fini(void) + nf_ct_helper_expectfn_unregister(&q931_nat); + nf_ct_helper_expectfn_unregister(&callforwarding_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&q931_nat); ++ nf_ct_helper_expectfn_destroy(&callforwarding_nat); + } + + /****************************************************************************/ +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 7d5e4f67f268c6..1d449e825dc63e 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -288,6 +288,25 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) + } + EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); + ++static bool expect_iter_expectfn(struct nf_conntrack_expect *exp, void *data) ++{ ++ const struct nf_ct_helper_expectfn *n = data; ++ ++ /* Relies on registered expectfn descriptors having unique ->expectfn ++ * pointers, which holds for the in-tree NAT helpers. ++ */ ++ return exp->expectfn == n->expectfn; ++} ++ ++/* Destroy expectations still pointing at @n->expectfn; call after the ++ * caller's RCU grace period so none outlives the (often modular) callback. ++ */ ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n) ++{ ++ nf_ct_expect_iterate_destroy(expect_iter_expectfn, (void *)n); ++} ++EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_destroy); ++ + /* Caller should hold the rcu lock */ + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 9df883d79acc92..2500e409757d0d 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1363,6 +1363,7 @@ static int __init nf_nat_init(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + nf_ct_helper_expectfn_unregister(&follow_master_nat); + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + unregister_pernet_subsys(&nat_net_ops); + kvfree(nf_nat_bysource); + } +@@ -1380,6 +1381,7 @@ static void __exit nf_nat_cleanup(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + kvfree(nf_nat_bysource); + unregister_pernet_subsys(&nat_net_ops); + } +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 9fbfc6bff0c221..00838c0cc5bb28 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -655,6 +655,7 @@ static void __exit nf_nat_sip_fini(void) + RCU_INIT_POINTER(nf_nat_sip_hooks, NULL); + nf_ct_helper_expectfn_unregister(&sip_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&sip_nat); + } + + static const struct nf_nat_sip_hooks sip_hooks = { +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nf_log-validate-mac-header-was-set-before-.patch b/queue-6.6/netfilter-nf_log-validate-mac-header-was-set-before-.patch new file mode 100644 index 0000000000..76ea9c40a3 --- /dev/null +++ b/queue-6.6/netfilter-nf_log-validate-mac-header-was-set-before-.patch @@ -0,0 +1,70 @@ +From a5e964995cd7e85d2317e53b2ec6ea002271e112 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:55:02 -0700 +Subject: netfilter: nf_log: validate MAC header was set before dumping it + +From: Xiang Mei + +[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ] + +The fallback path of dump_mac_header() guards the MAC header access +only with "skb->mac_header != skb->network_header", without checking +skb_mac_header_was_set(). When the MAC header is unset, mac_header is +0xffff, so the test passes and skb_mac_header(skb) returns +skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads +dev->hard_header_len bytes out of bounds into the kernel log. + +This is reachable via the netdev logger: nf_log_unknown_packet() calls +dump_mac_header() unconditionally, and an skb sent through AF_PACKET +with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still +unset (__dev_queue_xmit(), which would reset it, is bypassed). + +Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already +uses, and replace the open-coded MAC header length test with +skb_mac_header_len(). Only skbs with an unset MAC header are affected; +valid ones are dumped as before. + + BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) + Read of size 1 at addr ffff88800ea49d3f by task exploit/148 + Call Trace: + kasan_report (mm/kasan/report.c:595) + dump_mac_header (net/netfilter/nf_log_syslog.c:831) + nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) + nf_log_packet (net/netfilter/nf_log.c:260) + nft_log_eval (net/netfilter/nft_log.c:60) + nft_do_chain (net/netfilter/nf_tables_core.c:285) + nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) + nf_hook_slow (net/netfilter/core.c:619) + nf_hook_direct_egress (net/packet/af_packet.c:257) + packet_xmit (net/packet/af_packet.c:280) + packet_sendmsg (net/packet/af_packet.c:3114) + __sys_sendto (net/socket.c:2265) + +Fixes: 7eb9282cd0ef ("netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_log_syslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 58402226045e84..09b9152e9e5492 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -799,8 +799,8 @@ static void dump_mac_header(struct nf_log_buf *m, + + fallback: + nf_log_buf_add(m, "MAC="); +- if (dev->hard_header_len && +- skb->mac_header != skb->network_header) { ++ if (dev->hard_header_len && skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) != 0) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-6.6/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..7b6e83d72d --- /dev/null +++ b/queue-6.6/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From c9620b864707711b603a16d8d5d37af4dd4c0e77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index 1d4c9632072c8d..cac46accf566b5 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -530,6 +530,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-6.6/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..1a65f3e66c --- /dev/null +++ b/queue-6.6/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From eca7f1f5d85bdbe0fd5a72b1f1502b9a5cf0b0b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 564054123772a1..eeb48265208a2b 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -702,14 +702,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1327,9 +1325,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index fe89a056eb06c4..74840604e8d963 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -832,14 +832,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1228,9 +1226,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 131f7bb2110d3a..858cea15e322f1 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -848,14 +848,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1244,9 +1242,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-6.6/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-6.6/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..2856e75d06 --- /dev/null +++ b/queue-6.6/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From 17af861d96cca3dbcc899a57cc0d98252f4bf4f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index 9996883bf2b78d..6007cb000da678 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -764,24 +764,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-6.6/r8152-handle-the-return-value-of-usb_reset_device.patch b/queue-6.6/r8152-handle-the-return-value-of-usb_reset_device.patch new file mode 100644 index 0000000000..a483294bb1 --- /dev/null +++ b/queue-6.6/r8152-handle-the-return-value-of-usb_reset_device.patch @@ -0,0 +1,44 @@ +From 98b5ab47039461dc43fa9bfb5496e2cd4b02ea1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 17:22:47 +0800 +Subject: r8152: handle the return value of usb_reset_device() + +From: Chih Kai Hsu + +[ Upstream commit 19440600e729d4f74a42591a872099cf25c7d28a ] + +If usb_reset_device() returns a negative error code, stop the +process of probing. + +Fixes: 10c3271712f5 ("r8152: disable the ECM mode") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260604092247.27158-450-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index d39d66e25b01b9..cf8119924bb72e 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -9757,7 +9757,12 @@ static int rtl8152_probe_once(struct usb_interface *intf, + struct net_device *netdev; + int ret; + +- usb_reset_device(udev); ++ ret = usb_reset_device(udev); ++ if (ret < 0) { ++ dev_err(&intf->dev, "USB reset failed, errno=%d\n", ret); ++ return ret; ++ } ++ + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { + dev_err(&intf->dev, "Out of memory\n"); +-- +2.53.0 + diff --git a/queue-6.6/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-6.6/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..32ce694e3c --- /dev/null +++ b/queue-6.6/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From 159b9697255d0fb732b37e6fe60e1b5e165cd0af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index b6b46a8214a0a5..b3ee5f8238c44d 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-6.6/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-6.6/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..1520d8c07a --- /dev/null +++ b/queue-6.6/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From 3a7184814e8681fda92eee25d39cfcd8efca7472 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 032a10d82302c3..df5b2187b8fada 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1204,6 +1204,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index ca3de67c27..ce46b5c3fb 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -255,3 +255,31 @@ tap-free-page-on-error-paths-in-tap_get_user_xdp.patch kvm-arm64-remove-vpipt-i-cache-handling.patch arm64-tlb-allow-xzr-argument-to-tlbi-ops.patch arm64-tlb-optimize-arm64_workaround_repeat_tlbi.patch +iomap-don-t-revert-iov_iter-on-partially-completed-b.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch +asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch +tcp-restrict-so_attach_filter-to-priv-users.patch +net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch +net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +r8152-handle-the-return-value-of-usb_reset_device.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nf_log-validate-mac-header-was-set-before-.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch +net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch +net-mvpp2-add-metadata-support-for-xdp-mode.patch +net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch +net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch +ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch diff --git a/queue-6.6/tcp-restrict-so_attach_filter-to-priv-users.patch b/queue-6.6/tcp-restrict-so_attach_filter-to-priv-users.patch new file mode 100644 index 0000000000..aa6acc9277 --- /dev/null +++ b/queue-6.6/tcp-restrict-so_attach_filter-to-priv-users.patch @@ -0,0 +1,58 @@ +From de3bd484deab85623a6d1d05aba82cbcb53cd876 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:21:34 +0000 +Subject: tcp: restrict SO_ATTACH_FILTER to priv users + +From: Eric Dumazet + +[ Upstream commit 5d39580f68e6ddeedd15e587282207489dfb3da2 ] + +This patch restricts the use of SO_ATTACH_FILTER (cBPF) on TCP sockets +to users with CAP_NET_ADMIN capability. + +This blocks potential side-channel attack where an unprivileged application +attaches a filter to leak TCP sequence/acknowledgment numbers. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Eric Dumazet +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Cc: Willem de Bruijn +Cc: Alexei Starovoitov +Cc: Daniel Borkmann +Cc: Andrii Nakryiko +Cc: Martin KaFai Lau +Cc: Eduard Zingerman +Cc: Kumar Kartikeya Dwivedi +Cc: Song Liu +Cc: Yonghong Song +Cc: Jiri Olsa +Cc: John Fastabend +Cc: Stanislav Fomichev +Acked-by: Daniel Borkmann +Reviewed-by: Willem de Bruijn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 267f771dda1cc2..87e6060c8bca7f 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1311,6 +1311,11 @@ int sk_setsockopt(struct sock *sk, int level, int optname, + case SO_ATTACH_FILTER: { + struct sock_fprog fprog; + ++ if (sk_is_tcp(sk) && ++ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ break; ++ } + ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); + if (!ret) + ret = sk_attach_filter(&fprog, sk); +-- +2.53.0 + diff --git a/queue-6.6/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-6.6/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..3d68d91dea --- /dev/null +++ b/queue-6.6/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From 7bc0dcb90f1e2d268ceec6e8b5e435271ddbd9f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 2dffccf370626d..2110941c8e9a75 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1127,15 +1127,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1729,12 +1720,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 + diff --git a/queue-7.0/asoc-sdca-fix-null-pointer-dereference-in-sdca_dev_u.patch b/queue-7.0/asoc-sdca-fix-null-pointer-dereference-in-sdca_dev_u.patch new file mode 100644 index 0000000000..0df3b11cc2 --- /dev/null +++ b/queue-7.0/asoc-sdca-fix-null-pointer-dereference-in-sdca_dev_u.patch @@ -0,0 +1,118 @@ +From 25ca78c6c08ae78287c6bb0306e272b3ba667943 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Jun 2026 10:37:57 +0800 +Subject: ASoC: SDCA: fix NULL pointer dereference in + sdca_dev_unregister_functions + +From: Kean Ren + +[ Upstream commit e4c60a1d4b6ccc66aefb3789cd908d4f9482eefd ] + +sdca_dev_unregister_functions() iterates over all SDCA function +descriptors and calls sdca_dev_unregister() on each func_dev without +checking for NULL. When a function registration has failed partway +through, or the device cleanup races with probe deferral, func_dev +entries may be NULL, leading to a kernel oops: + + BUG: kernel NULL pointer dereference, address: 0000000000000040 + RIP: 0010:device_del+0x1e/0x3e0 + Call Trace: + sdca_dev_unregister_functions+0x37/0x60 [snd_soc_sdca] + release_nodes+0x35/0xb0 + devres_release_all+0x90/0x100 + device_unbind_cleanup+0xe/0x80 + device_release_driver_internal+0x1c1/0x200 + bus_remove_device+0xc6/0x130 + device_del+0x161/0x3e0 + device_unregister+0x17/0x60 + sdw_delete_slave+0xb6/0xd0 [soundwire_bus] + sdw_bus_master_delete+0x1e/0x50 [soundwire_bus] + ... + sof_probe_work+0x19/0x30 [snd_sof] + +This was observed on a Lenovo ThinkPad X1 Carbon G14 (Panther Lake) +with the SOF audio driver probe failing due to missing Panther Lake +firmware, causing the subsequent cleanup of SoundWire devices to +trigger the crash. + +Fix this with three changes: + +1) Add a NULL guard in sdca_dev_unregister() so that callers do not + need to pre-validate the pointer (defense in depth). + +2) In sdca_dev_unregister_functions(), skip NULL func_dev entries + and clear func_dev to NULL after unregistration, making the + function idempotent and safe against double-invocation. + +3) In sdca_dev_register_functions(), roll back all previously + registered functions when a later one fails, so the function + array is never left in a partially-populated state. + +Fixes: 4496d1c65bad ("ASoC: SDCA: add function devices") +Signed-off-by: Kean Ren +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20260611023757.1553960-1-rh_king@163.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_function_device.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c +index feacfbc6a51880..b5ca98283a8895 100644 +--- a/sound/soc/sdca/sdca_function_device.c ++++ b/sound/soc/sdca/sdca_function_device.c +@@ -82,6 +82,9 @@ static struct sdca_dev *sdca_dev_register(struct device *parent, + + static void sdca_dev_unregister(struct sdca_dev *sdev) + { ++ if (!sdev) ++ return; ++ + auxiliary_device_delete(&sdev->auxdev); + auxiliary_device_uninit(&sdev->auxdev); + } +@@ -90,14 +93,24 @@ int sdca_dev_register_functions(struct sdw_slave *slave) + { + struct sdca_device_data *sdca_data = &slave->sdca_data; + int i; ++ int ret; + + for (i = 0; i < sdca_data->num_functions; i++) { + struct sdca_dev *func_dev; + + func_dev = sdca_dev_register(&slave->dev, + &sdca_data->function[i]); +- if (IS_ERR(func_dev)) +- return PTR_ERR(func_dev); ++ if (IS_ERR(func_dev)) { ++ ret = PTR_ERR(func_dev); ++ /* ++ * Unregister functions that were successfully ++ * registered before this failure. This also ++ * sets func_dev to NULL so the caller will not ++ * try to unregister them again. ++ */ ++ sdca_dev_unregister_functions(slave); ++ return ret; ++ } + + sdca_data->function[i].func_dev = func_dev; + } +@@ -111,7 +124,12 @@ void sdca_dev_unregister_functions(struct sdw_slave *slave) + struct sdca_device_data *sdca_data = &slave->sdca_data; + int i; + +- for (i = 0; i < sdca_data->num_functions; i++) ++ for (i = 0; i < sdca_data->num_functions; i++) { ++ if (!sdca_data->function[i].func_dev) ++ continue; ++ + sdca_dev_unregister(sdca_data->function[i].func_dev); ++ sdca_data->function[i].func_dev = NULL; ++ } + } + EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA"); +-- +2.53.0 + diff --git a/queue-7.0/asoc-sof-amd-fix-for-ipc-flags-check.patch b/queue-7.0/asoc-sof-amd-fix-for-ipc-flags-check.patch new file mode 100644 index 0000000000..195355a702 --- /dev/null +++ b/queue-7.0/asoc-sof-amd-fix-for-ipc-flags-check.patch @@ -0,0 +1,68 @@ +From f566d8e5fbf506618a85422b7b73b45795dcc72d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:38:44 +0530 +Subject: ASoC: SOF: amd: fix for ipc flags check + +From: Vijendar Mukunda + +[ Upstream commit 6042c91df60e825625bc7d5c5c3b5a87b91d5805 ] + +Firmware will set dsp_ack to 1 when firmware sends response for the IPC +command issued by host. Similarly dsp_msg flag will be updated to 1. + +During ACP D0 entry, the value read from the sof_dsp_ack_write scratch +flag can be uninitialized. A non-zero garbage value is treated as a +pending DSP IPC ack before SOF_FW_BOOT_COMPLETE, causing a spurious +"IPC reply before FW_BOOT_COMPLETE" log. + +Fix the condition checks for ipc flags. + +Fixes: 738a2b5e2cc9 ("ASoC: SOF: amd: Add IPC support for ACP IP block") +Link: https://github.com/thesofproject/linux/pull/5642 +Signed-off-by: Vijendar Mukunda +Tested-by: Umang Jain +Link: https://patch.msgid.link/20260609160938.3717513-1-Vijendar.Mukunda@amd.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/amd/acp-ipc.c | 4 ++-- + sound/soc/sof/amd/acp.h | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c +index 3cd4674dd80075..94025bc799ea40 100644 +--- a/sound/soc/sof/amd/acp-ipc.c ++++ b/sound/soc/sof/amd/acp-ipc.c +@@ -181,14 +181,14 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) + } + + dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); +- if (dsp_msg) { ++ if (dsp_msg == ACP_DSP_MSG_SET) { + snd_sof_ipc_msgs_rx(sdev); + acp_dsp_ipc_host_done(sdev); + ipc_irq = true; + } + + dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); +- if (dsp_ack) { ++ if (dsp_ack == ACP_DSP_ACK_SET) { + if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { + guard(spinlock_irq)(&sdev->ipc_lock); + +diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h +index 2b7ea8c6410602..7bcb76676a984a 100644 +--- a/sound/soc/sof/amd/acp.h ++++ b/sound/soc/sof/amd/acp.h +@@ -116,6 +116,8 @@ + #define ACP_SRAM_PAGE_COUNT 128 + #define ACP6X_SDW_MAX_MANAGER_COUNT 2 + #define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT ++#define ACP_DSP_MSG_SET 1 ++#define ACP_DSP_ACK_SET 1 + + enum clock_source { + ACP_CLOCK_96M = 0, +-- +2.53.0 + diff --git a/queue-7.0/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch b/queue-7.0/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch new file mode 100644 index 0000000000..bb9e774792 --- /dev/null +++ b/queue-7.0/asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch @@ -0,0 +1,52 @@ +From aa9d774931b4a12931516beb2e1225855c4ed4c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:12:44 +0100 +Subject: ASoC: wm_adsp: Fix NULL dereference when removing firmware controls + +From: Richard Fitzgerald + +[ Upstream commit 7d3fb78b550301e43fdc60312aed733069694426 ] + +In wm_adsp_control_remove() check that the priv pointer is not NULL +before attempting to cleanup what it points to. + +When cs_dsp creates a control it calls wm_adsp_control_add_cb() so that +wm_adsp can create its own private control data. There are two cases +where private data is not created: + +1. The control is a SYSTEM control, so an ALSA control is not created. + +2. The codec driver has registered a control_add() callback that + hides the control, so wm_adsp_control_add() is not called. + +When cs_dsp_remove destroys its control list it calls +wm_adsp_control_remove() for each control. But wm_adsp_control_remove() +was attempting to cleanup the private data pointed to by cs_ctl->priv +without checking the pointer for NULL. + +Signed-off-by: Richard Fitzgerald +Fixes: 0700bc2fb94c ("ASoC: wm_adsp: Separate generic cs_dsp_coeff_ctl handling") +Link: https://patch.msgid.link/20260604101244.1402862-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wm_adsp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c +index 2e23848e1dce94..d7ba14ce613b74 100644 +--- a/sound/soc/codecs/wm_adsp.c ++++ b/sound/soc/codecs/wm_adsp.c +@@ -666,6 +666,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) + { + struct wm_coeff_ctl *ctl = cs_ctl->priv; + ++ if (!ctl) ++ return; ++ + cancel_work_sync(&ctl->work); + + kfree(ctl->name); +-- +2.53.0 + diff --git a/queue-7.0/bnge-fix-context-mem-iteration.patch b/queue-7.0/bnge-fix-context-mem-iteration.patch new file mode 100644 index 0000000000..0c207e0dc5 --- /dev/null +++ b/queue-7.0/bnge-fix-context-mem-iteration.patch @@ -0,0 +1,75 @@ +From 8fd69150b979dbe2ec16f60f7107243e241824c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 22:07:09 +0530 +Subject: bnge: fix context mem iteration + +From: Vikas Gupta + +[ Upstream commit 3847d94783c0b893c27ff0b26a3325796d9444c6 ] + +The firmware advertises context memory (backing store) types +through a linked list, with BNGE_CTX_INV serving as the +end-of-list sentinel. +However, the driver incorrectly assumes that the list is strictly +ordered and prematurely terminates traversal when it encounters +an unrecognized type (>=BNGE_CTX_V2_MAX). As a result, any valid +context types that appear later in the chain are silently skipped, +leading to incomplete memory configuration and eventual driver load +failure. + +Fix this by traversing the entire list until the BNGE_CTX_INV sentinel +is reached, while safely ignoring only those context types that fall +outside the supported range. + +Fixes: 29c5b358f385 ("bng_en: Add backing store support") +Signed-off-by: Vikas Gupta +Reviewed-by: Dharmender Garg +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +index c46da34134179c..3f07311d065e24 100644 +--- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c ++++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +@@ -259,7 +259,7 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd) + struct hwrm_func_backing_store_qcaps_v2_output *resp; + struct hwrm_func_backing_store_qcaps_v2_input *req; + struct bnge_ctx_mem_info *ctx; +- u16 type; ++ u16 type, next_type; + int rc; + + if (bd->ctx) +@@ -276,8 +276,8 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd) + + resp = bnge_hwrm_req_hold(bd, req); + +- for (type = 0; type < BNGE_CTX_V2_MAX; ) { +- struct bnge_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; ++ for (type = 0; type < BNGE_CTX_INV; type = next_type) { ++ struct bnge_ctx_mem_type *ctxm; + u8 init_val, init_off, i; + __le32 *p; + u32 flags; +@@ -286,8 +286,14 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd) + rc = bnge_hwrm_req_send(bd, req); + if (rc) + goto ctx_done; ++ ++ next_type = le16_to_cpu(resp->next_valid_type); ++ if (type >= BNGE_CTX_V2_MAX) ++ continue; ++ ++ ctxm = &ctx->ctx_arr[type]; + flags = le32_to_cpu(resp->flags); +- type = le16_to_cpu(resp->next_valid_type); ++ + if (!(flags & + FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID)) + continue; +-- +2.53.0 + diff --git a/queue-7.0/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch b/queue-7.0/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch new file mode 100644 index 0000000000..23344861d2 --- /dev/null +++ b/queue-7.0/dma-debug-fix-physical-address-retrieval-in-debug_dm.patch @@ -0,0 +1,45 @@ +From aed42bd943c4e7f97b0ba49190414c0a60a3ba3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 20:37:08 +0800 +Subject: dma-debug: fix physical address retrieval in + debug_dma_sync_sg_for_device + +From: Li RongQing + +[ Upstream commit 9bfaa86b405381326c971984fd6da184c289713f ] + +In debug_dma_sync_sg_for_device(), when iterating over a scatterlist, +the debug entry population mistakenly uses the head of the scatterlist +'sg' to fetch the physical address via sg_phys(), instead of using the +current iterator variable 's'. + +This causes dma-debug to track the physical address of the very first +scatterlist entry for all subsequent entries in the list. + +Fix this by passing the correct loop iterator 's' to sg_phys() + +Fixes: 9d4f645a1fd49ee ("dma-debug: store a phys_addr_t in struct dma_debug_entry") +Signed-off-by: Li RongQing +Signed-off-by: Marek Szyprowski +Link: https://lore.kernel.org/r/20260603123708.1665-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + kernel/dma/debug.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c +index 3248f8b4d096de..2c0e2cd89b5ed7 100644 +--- a/kernel/dma/debug.c ++++ b/kernel/dma/debug.c +@@ -1556,7 +1556,7 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + struct dma_debug_entry ref = { + .type = dma_debug_sg, + .dev = dev, +- .paddr = sg_phys(sg), ++ .paddr = sg_phys(s), + .dev_addr = sg_dma_address(s), + .size = sg_dma_len(s), + .direction = direction, +-- +2.53.0 + diff --git a/queue-7.0/dma-mapping-direct-fix-missing-mapping-for-thru_host.patch b/queue-7.0/dma-mapping-direct-fix-missing-mapping-for-thru_host.patch new file mode 100644 index 0000000000..014680ad18 --- /dev/null +++ b/queue-7.0/dma-mapping-direct-fix-missing-mapping-for-thru_host.patch @@ -0,0 +1,43 @@ +From 45bb23a1cb92455d7449fe2fc69a9505197f850a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:37:23 +0800 +Subject: dma-mapping: direct: fix missing mapping for THRU_HOST_BRIDGE + segments + +From: Li RongQing + +[ Upstream commit 560000d619ef162568746ce287f0c725e24ea967 ] + +In dma_direct_map_sg(), the case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE +incorrectly used 'break' instead of falling through to MAP_NONE. +As a result, segments traversing the host bridge skipped the required +dma_direct_map_phys() call entirely, leaving sg->dma_address +uninitialized and leading to DMA failures. Fix this by using +'fallthrough;'. + +Fixes: a25e7962db0d79 ("PCI/P2PDMA: Refactor the p2pdma mapping helpers") +Reviewed-by: Logan Gunthorpe +Signed-off-by: Li RongQing +Signed-off-by: Marek Szyprowski +Link: https://lore.kernel.org/r/20260603013723.2439-1-lirongqing@baidu.com +Signed-off-by: Sasha Levin +--- + kernel/dma/direct.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c +index 8f43a930716d46..306afebf54ef06 100644 +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -466,7 +466,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents, + * must be mapped with CPU physical address and not PCI + * bus addresses. + */ +- break; ++ fallthrough; + case PCI_P2PDMA_MAP_NONE: + sg->dma_address = dma_direct_map_phys(dev, sg_phys(sg), + sg->length, dir, attrs); +-- +2.53.0 + diff --git a/queue-7.0/esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch b/queue-7.0/esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch new file mode 100644 index 0000000000..45a727625b --- /dev/null +++ b/queue-7.0/esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch @@ -0,0 +1,167 @@ +From 8ecadcac3eec210ffe0d3cc1551a6609fb0afc35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 14:22:15 +0200 +Subject: esp: fix page frag reference leak on skb_to_sgvec failure + +From: Alessandro Schino <7991aleschino@gmail.com> + +[ Upstream commit 2982e599fff6faa21c8df147d96fc7af6c1a2f24 ] + +In esp_output_tail(), when esp->inplace is false, the old skb page frags +are replaced with a new page from the xfrm page_frag cache. The source +scatterlist (sg) is built from the old frags before the replacement, and +esp_ssg_unref() is responsible for releasing the old page references +after the crypto operation completes. + +However, if the second skb_to_sgvec() call (which builds the destination +scatterlist from the new page) fails, the code jumps to error_free which +only calls kfree(tmp). The old page frag references captured in the +source scatterlist are never released: + + 1. sg[] is built from old frags via skb_to_sgvec() (no extra get_page) + 2. nr_frags is set to 1 and frag[0] is replaced with the new page + 3. Second skb_to_sgvec() fails -> goto error_free + 4. kfree(tmp) frees the sg[] memory but old frags are not unref'd + 5. kfree_skb() only releases frag[0] (the new page), not the old ones + +Fix this by adding a bool parameter to esp_ssg_unref() that, when true, +unconditionally unrefs the source scatterlist frags without checking +req->src and req->dst, since those fields are not yet initialized by +aead_request_set_crypt() at the point of the error. Existing callers +pass false to preserve the original behavior. + +The same issue exists in both esp4 and esp6 as the code is identical. + +Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") +Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") + +Signed-off-by: Alessandro Schino <7991aleschino@gmail.com> +Signed-off-by: Steffen Klassert +Stable-dep-of: 26aad08a9289 ("esp: fix page frag reference leak on skb_to_sgvec failure") +Signed-off-by: Sasha Levin +--- + net/ipv4/esp4.c | 17 +++++++++++------ + net/ipv6/esp6.c | 17 +++++++++++------ + 2 files changed, 22 insertions(+), 12 deletions(-) + +diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c +index 513c8215c947f1..dfc81ee969ae03 100644 +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -96,7 +96,7 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, + __alignof__(struct scatterlist)); + } + +-static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) ++static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb, bool already_unref) + { + struct crypto_aead *aead = x->data; + int extralen = 0; +@@ -113,10 +113,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + /* Unref skb_frag_pages in the src scatterlist if necessary. + * Skip the first sg which comes from skb->data. + */ +- if (req->src != req->dst) +- for (sg = sg_next(req->src); sg; sg = sg_next(sg)) ++ if (already_unref || req->src != req->dst) { ++ struct scatterlist *src = already_unref ? esp_req_sg(aead, req) : req->src; ++ ++ for (sg = sg_next(src); sg; sg = sg_next(sg)) + skb_page_unref(page_to_netmem(sg_page(sg)), + skb->pp_recycle); ++ } + } + + #ifdef CONFIG_INET_ESPINTCP +@@ -220,7 +223,7 @@ static void esp_output_done(void *data, int err) + } + + tmp = ESP_SKB_CB(skb)->tmp; +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + kfree(tmp); + + if (xo && (xo->flags & XFRM_DEV_RESUME)) { +@@ -569,8 +572,10 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * + err = skb_to_sgvec(skb, dsg, + (unsigned char *)esph - skb->data, + assoclen + ivlen + esp->clen + alen); +- if (unlikely(err < 0)) ++ if (unlikely(err < 0)) { ++ esp_ssg_unref(x, tmp, skb, true); + goto error_free; ++ } + } + + if ((x->props.flags & XFRM_STATE_ESN)) +@@ -602,7 +607,7 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * + } + + if (sg != dsg) +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + + if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) + err = esp_output_tail_tcp(x, skb); +diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c +index 57481e423e59e6..296b57926abb98 100644 +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -113,7 +113,7 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, + __alignof__(struct scatterlist)); + } + +-static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) ++static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb, bool already_unref) + { + struct crypto_aead *aead = x->data; + int extralen = 0; +@@ -130,10 +130,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb) + /* Unref skb_frag_pages in the src scatterlist if necessary. + * Skip the first sg which comes from skb->data. + */ +- if (req->src != req->dst) +- for (sg = sg_next(req->src); sg; sg = sg_next(sg)) ++ if (already_unref || req->src != req->dst) { ++ struct scatterlist *src = already_unref ? esp_req_sg(aead, req) : req->src; ++ ++ for (sg = sg_next(src); sg; sg = sg_next(sg)) + skb_page_unref(page_to_netmem(sg_page(sg)), + skb->pp_recycle); ++ } + } + + #ifdef CONFIG_INET6_ESPINTCP +@@ -254,7 +257,7 @@ static void esp_output_done(void *data, int err) + } + + tmp = ESP_SKB_CB(skb)->tmp; +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + kfree(tmp); + + esp_output_encap_csum(skb); +@@ -600,8 +603,10 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info + err = skb_to_sgvec(skb, dsg, + (unsigned char *)esph - skb->data, + assoclen + ivlen + esp->clen + alen); +- if (unlikely(err < 0)) ++ if (unlikely(err < 0)) { ++ esp_ssg_unref(x, tmp, skb, true); + goto error_free; ++ } + } + + if ((x->props.flags & XFRM_STATE_ESN)) +@@ -634,7 +639,7 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info + } + + if (sg != dsg) +- esp_ssg_unref(x, tmp, skb); ++ esp_ssg_unref(x, tmp, skb, false); + + if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) + err = esp_output_tail_tcp(x, skb); +-- +2.53.0 + diff --git a/queue-7.0/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch b/queue-7.0/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch new file mode 100644 index 0000000000..e52fbb1dda --- /dev/null +++ b/queue-7.0/gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch @@ -0,0 +1,85 @@ +From 2a156afc582e3b984f00d23468ee10268458cbac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:43:34 +0800 +Subject: gpio: mvebu: fix NULL pointer dereference in suspend/resume + +From: Yun Zhou + +[ Upstream commit b9ad50d7505ebd48282ec3630258dc820fc85c81 ] + +mvebu_pwm_suspend() and mvebu_pwm_resume() are called for all GPIO +banks during suspend/resume, but not all banks have PWM functionality. +GPIO banks without PWM have mvchip->mvpwm set to NULL. + +Calling mvebu_pwm_suspend() with mvpwm == NULL causes a NULL pointer +dereference when it tries to access mvpwm->blink_select. + + Unable to handle kernel NULL pointer dereference at virtual address 00000020 when write + [00000020] *pgd=00000000 + Internal error: Oops: 815 [#1] PREEMPT ARM + Modules linked in: + CPU: 0 UID: 0 PID: 406 Comm: sh Not tainted 6.12.74-rt12-yocto-standard-g4e96f98fb7db-dirty #353 + Hardware name: Marvell Armada 370/XP (Device Tree) + PC is at regmap_mmio_read+0x38/0x54 + LR is at regmap_mmio_read+0x38/0x54 + pc : [] lr : [] psr: 200f0013 + sp : f0c11d10 ip : 00000000 fp : c100d2f0 + r10: c14fb854 r9 : 00000000 r8 : 00000000 + r7 : c1799c00 r6 : 00000020 r5 : 00000020 r4 : c179c7c0 + r3 : f0a231a0 r2 : 00000020 r1 : 00000020 r0 : 00000000 + Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none + Control: 10c5387d Table: 135ec059 DAC: 00000051 + Call trace: + regmap_mmio_read from _regmap_bus_reg_read+0x78/0xac + _regmap_bus_reg_read from _regmap_read+0x60/0x154 + _regmap_read from regmap_read+0x3c/0x60 + regmap_read from mvebu_gpio_suspend+0xa4/0x14c + mvebu_gpio_suspend from dpm_run_callback+0x54/0x180 + dpm_run_callback from device_suspend+0x124/0x630 + device_suspend from dpm_suspend+0x124/0x270 + dpm_suspend from dpm_suspend_start+0x64/0x6c + dpm_suspend_start from suspend_devices_and_enter+0x140/0x8e8 + suspend_devices_and_enter from pm_suspend+0x2fc/0x308 + pm_suspend from state_store+0x6c/0xc8 + state_store from kernfs_fop_write_iter+0x10c/0x1f8 + kernfs_fop_write_iter from vfs_write+0x270/0x468 + vfs_write from ksys_write+0x70/0xf0 + ksys_write from ret_fast_syscall+0x0/0x54 + +Add a NULL check for mvchip->mvpwm before calling the PWM +suspend/resume functions. + +Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support") +Signed-off-by: Yun Zhou +Link: https://patch.msgid.link/20260608084334.2960803-1-yun.zhou@windriver.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-mvebu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c +index 22c36b79e249ff..c030d1f00abcae 100644 +--- a/drivers/gpio/gpio-mvebu.c ++++ b/drivers/gpio/gpio-mvebu.c +@@ -996,7 +996,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_suspend(mvchip); + + return 0; +@@ -1048,7 +1048,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev) + BUG(); + } + +- if (IS_REACHABLE(CONFIG_PWM)) ++ if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm) + mvebu_pwm_resume(mvchip); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch b/queue-7.0/gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch new file mode 100644 index 0000000000..470a25247a --- /dev/null +++ b/queue-7.0/gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch @@ -0,0 +1,54 @@ +From 4e081bf14408ae9448bc39f31bb61795f0ff32bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 01:05:02 +0200 +Subject: gpio: rockchip: fix generic IRQ chip leak on remove + +From: Marco Scardovi + +[ Upstream commit 1c1e0fc88d6ef65bf15d517853251f75ab9d18c3 ] + +The driver allocates domain generic chips using +irq_alloc_domain_generic_chips() during probe. However, on driver +remove/teardown, the generic chips are not automatically freed when the +IRQ domain is removed because the domain flags do not include +IRQ_DOMAIN_FLAG_DESTROY_GC. + +This causes both the domain generic chips structure and the associated +generic chips to be leaked. Additionally, the generic chips remain on +the global gc_list and may later be visited by generic IRQ chip suspend, +resume, or shutdown callbacks after the GPIO bank has been removed, +potentially resulting in a use-after-free and kernel crash. + +Fix the resource leak by explicitly calling +irq_domain_remove_generic_chips() before removing the IRQ domain in +rockchip_gpio_remove(). + +Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") +Assisted-by: Antigravity:gemini-3.5-flash +Signed-off-by: Marco Scardovi +Link: https://patch.msgid.link/20260607230504.35392-2-scardracs@disroot.org +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-rockchip.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index 1ef0ba956cfd8c..46dd9085d9c8cd 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -802,8 +802,10 @@ static void rockchip_gpio_remove(struct platform_device *pdev) + struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); + + irq_set_chained_handler_and_data(bank->irq, NULL, NULL); +- if (bank->domain) ++ if (bank->domain) { ++ irq_domain_remove_generic_chips(bank->domain); + irq_domain_remove(bank->domain); ++ } + gpiochip_remove(&bank->gpio_chip); + } + +-- +2.53.0 + diff --git a/queue-7.0/gpio-zynq-fix-runtime-pm-leak-on-remove.patch b/queue-7.0/gpio-zynq-fix-runtime-pm-leak-on-remove.patch new file mode 100644 index 0000000000..e6be6793ce --- /dev/null +++ b/queue-7.0/gpio-zynq-fix-runtime-pm-leak-on-remove.patch @@ -0,0 +1,39 @@ +From bdeab3eabdbca4132323f4cf81bc7d59df0793a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:33:13 +0800 +Subject: gpio: zynq: fix runtime PM leak on remove + +From: Ruoyu Wang + +[ Upstream commit 6edb934de9bda3b7abcec856eaee6fc8b4278dd1 ] + +pm_runtime_get_sync() increments the runtime PM usage counter even when it +returns an error. zynq_gpio_remove() uses it to keep the controller active +while removing the GPIO chip, but never drops the usage counter again. + +Balance the get with pm_runtime_put_noidle() after disabling runtime PM. + +Fixes: 3242ba117e9b ("gpio: Add driver for Zynq GPIO controller") +Signed-off-by: Ruoyu Wang +Link: https://patch.msgid.link/20260609073313.5-1-ruoyuw560@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-zynq.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c +index 571e366624d2af..fafca91128b2e6 100644 +--- a/drivers/gpio/gpio-zynq.c ++++ b/drivers/gpio/gpio-zynq.c +@@ -1014,6 +1014,7 @@ static void zynq_gpio_remove(struct platform_device *pdev) + gpiochip_remove(&gpio->chip); + device_set_wakeup_capable(&pdev->dev, 0); + pm_runtime_disable(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); + } + + static struct platform_driver zynq_gpio_driver = { +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch b/queue-7.0/ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch new file mode 100644 index 0000000000..2ab173dc56 --- /dev/null +++ b/queue-7.0/ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch @@ -0,0 +1,74 @@ +From 1e8bb78c4d40b90ed7fb211fd20366c9d8625b3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:55:10 -0700 +Subject: ice: fix missing priority callbacks for U.FL DPLL pins + +From: Petr Oros + +[ Upstream commit f1fa677e428e8873486938086bd934dc18169b47 ] + +The U.FL2 input pin advertises DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE +in its capability mask, but ice_dpll_pin_ufl_ops does not provide +.prio_get and .prio_set callbacks. As a result the DPLL subsystem +cannot report or accept priority for U.FL pins: pin-get omits the prio +field on U.FL2 and pin-set with prio is rejected as invalid, even +though the capability is present. This prevents user space from using +priority to select or disable U.FL2 as a DPLL input source. + +Reproducer with iproute2 (dpll command): + + # dpll pin show board-label U.FL2 + pin id 16: + module-name ice + board-label U.FL2 + type ext + capabilities priority-can-change|state-can-change + parent-device: + id 0 direction input state selectable phase-offset 0 + /* note: no "prio" between "direction" and "state", + even though priority-can-change is advertised */ + + # dpll pin set id 16 parent-device 0 prio 5 + RTNETLINK answers: Operation not supported + +After the fix the prio field is reported by pin show and pin set with +prio is accepted on U.FL2. + +Add the missing .prio_get and .prio_set callbacks to +ice_dpll_pin_ufl_ops, reusing ice_dpll_sw_input_prio_{get,set}. The +same ops struct is shared by U.FL1 and U.FL2: U.FL2 (input) delegates +to the backing hardware input pin, while U.FL1 (output) does not +advertise DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE so the dpll core +capability gate never invokes prio_set for it, and prio_get reports +the OUTPUT sentinel (ICE_DPLL_PIN_PRIO_OUTPUT) on the output side +exactly like the SMA path does today. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Paul Menzel +Signed-off-by: Petr Oros +Tested-by: Rinitha S (A Contingent worker at Intel) +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260602225513.393338-3-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 892bc7c2e28b46..0704e92ab04305 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -2633,6 +2633,8 @@ static const struct dpll_pin_ops ice_dpll_pin_ufl_ops = { + .state_on_dpll_set = ice_dpll_ufl_pin_state_set, + .state_on_dpll_get = ice_dpll_sw_pin_state_get, + .direction_get = ice_dpll_pin_sw_direction_get, ++ .prio_get = ice_dpll_sw_input_prio_get, ++ .prio_set = ice_dpll_sw_input_prio_set, + .frequency_get = ice_dpll_sw_pin_frequency_get, + .frequency_set = ice_dpll_sw_pin_frequency_set, + .esync_set = ice_dpll_sw_esync_set, +-- +2.53.0 + diff --git a/queue-7.0/idpf-fix-mailbox-capability-for-set-device-clock-tim.patch b/queue-7.0/idpf-fix-mailbox-capability-for-set-device-clock-tim.patch new file mode 100644 index 0000000000..b2208ebc48 --- /dev/null +++ b/queue-7.0/idpf-fix-mailbox-capability-for-set-device-clock-tim.patch @@ -0,0 +1,41 @@ +From f1a8a74339a10d71327b25f986d160133a199d59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 15:55:11 -0700 +Subject: idpf: fix mailbox capability for set device clock time + +From: Alok Tiwari + +[ Upstream commit 85b0cbc1f38bc1e38956a9e6d7b04d309b435697 ] + +The current code incorrectly uses VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME +for both direct and mailbox capabilities, causing mailbox-only support +to be ignored and potentially reporting IDPF_PTP_NONE. + +Fixes: d5dba8f7206da ("idpf: add PTP clock configuration") +Signed-off-by: Alok Tiwari +Tested-by: Samuel Salin +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260602225513.393338-4-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/idpf/idpf_ptp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +index 4a51d2727547d9..71fe8b2a8b4e42 100644 +--- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c ++++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c +@@ -51,7 +51,7 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter) + + /* Set the device clock time */ + direct = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; +- mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; ++ mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB; + ptp->set_dev_clk_time_access = idpf_ptp_get_access(adapter, + direct, + mailbox); +-- +2.53.0 + diff --git a/queue-7.0/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch b/queue-7.0/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch new file mode 100644 index 0000000000..ac3c42ee27 --- /dev/null +++ b/queue-7.0/ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch @@ -0,0 +1,59 @@ +From eb383192b8aa69f4c6af88879c3b729ba8eb1be9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 16:46:13 +0000 +Subject: ip6_vti: fix incorrect tunnel matching in vti6_tnl_lookup() + +From: Eric Dumazet + +[ Upstream commit a5c0359f5cbc51a2e2b114d6041e0f3c73f903e9 ] + +In vti6_tnl_lookup(), when an exact match for a tunnel fails, +the code falls back to searching for wildcard tunnels: + +- Tunnels matching the packet's local address, with any remote address + wildcard remote). + +- Tunnels matching the packet's remote address, with any local address + (wildcard local). + +However, vti6 stores all these different types of tunnels in the same +hash table (ip6n->tnls_r_l) prone to hash collisions. + +The bug is that the fallback search loops in vti6_tnl_lookup() were +missing checks to ensure that the candidate tunnel actually has +a wildcard address. + +Fixes: fbe68ee87522 ("vti6: Add a lookup method for tunnels with wildcard endpoints.") +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608164613.933023-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index d2b74a6f2cf62d..d871cab6938d36 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -106,6 +106,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(&any, local); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && ++ ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } +@@ -113,6 +114,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, + hash = HASH(remote, &any); + for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && ++ ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } +-- +2.53.0 + diff --git a/queue-7.0/ip6_vti-set-netns_immutable-on-the-fallback-device.patch b/queue-7.0/ip6_vti-set-netns_immutable-on-the-fallback-device.patch new file mode 100644 index 0000000000..4000aaad0d --- /dev/null +++ b/queue-7.0/ip6_vti-set-netns_immutable-on-the-fallback-device.patch @@ -0,0 +1,43 @@ +From 14a20bf2464090e96138c7b210b7c6b5a5e931b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:59:18 +0000 +Subject: ip6_vti: set netns_immutable on the fallback device. + +From: Eric Dumazet + +[ Upstream commit d289d5307762d1838aaece22c6b6fcad9e8865f9 ] + +john1988 and Noam Rathaus reported that vti6_init_net() does not set the +netns_immutable flag on the per-netns fallback tunnel device (ip6_vti0). + +Other similar tunnel drivers (like ip6_tunnel, sit, ip6_gre, and ip_tunnel) +correctly set this flag during their fallback device initialization to +prevent them from being moved to another network namespace. + +Fixes: 61220ab34948 ("vti6: Enable namespace changing") +Reported-by: Noam Rathaus +Signed-off-by: Eric Dumazet +Cc: Steffen Klassert +Reviewed-by: Nicolas Dichtel +Link: https://patch.msgid.link/20260608155918.787644-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_vti.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c +index df793c8bfffb0a..d2b74a6f2cf62d 100644 +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -1159,6 +1159,7 @@ static int __net_init vti6_init_net(struct net *net) + goto err_alloc_dev; + dev_net_set(ip6n->fb_tnl_dev, net); + ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops; ++ ip6n->fb_tnl_dev->netns_immutable = true; + + err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev); + if (err < 0) +-- +2.53.0 + diff --git a/queue-7.0/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch b/queue-7.0/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch new file mode 100644 index 0000000000..8723fe06ea --- /dev/null +++ b/queue-7.0/ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch @@ -0,0 +1,89 @@ +From 59cada4b6a56df47896b295316cba8acf30a1680 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 17:54:48 +0300 +Subject: ipv6: Fix a potential NPD in cleanup_prefix_route() + +From: Ido Schimmel + +[ Upstream commit b70c687b7cf267fb08586667a3946c8851cad672 ] + +addrconf_get_prefix_route() can return the fib6_null_entry sentinel +entry which has a NULL fib6_table pointer. Therefore, before setting the +route's expiration time, check that we are not working with this entry, +as otherwise a NPD will be triggered [1]. + +Note that the other callers of addrconf_get_prefix_route() are not +susceptible to this bug: + +1. addrconf_prefix_rcv(): Requests a route with the 'RTF_ADDRCONF | + RTF_PREFIX_RT' flags which are not set on fib6_null_entry. + +2. modify_prefix_route(): Fixed by commit a747e02430df ("ipv6: avoid + possible NULL deref in modify_prefix_route()"). + +3. __ipv6_ifa_notify(): Calls ip6_del_rt() which specifically checks for + fib6_null_entry and returns an error. + +[1] +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] SMP KASAN +KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037] +[...] +Call Trace: + +__kasan_check_byte (mm/kasan/common.c:573) +lock_acquire.part.0 (kernel/locking/lockdep.c:5842 (discriminator 1)) +_raw_spin_lock_bh (kernel/locking/spinlock.c:182 (discriminator 1)) +cleanup_prefix_route (net/ipv6/addrconf.c:1280) +ipv6_del_addr (net/ipv6/addrconf.c:1342) +inet6_addr_del.isra.0 (net/ipv6/addrconf.c:3119) +inet6_rtm_deladdr (net/ipv6/addrconf.c:4812) +rtnetlink_rcv_msg (net/core/rtnetlink.c:6997) +netlink_rcv_skb (net/netlink/af_netlink.c:2555) +netlink_unicast (net/netlink/af_netlink.c:1344) +netlink_sendmsg (net/netlink/af_netlink.c:1899) +__sock_sendmsg (net/socket.c:802 (discriminator 4)) +____sys_sendmsg (net/socket.c:2698) +___sys_sendmsg (net/socket.c:2752) +__sys_sendmsg (net/socket.c:2784) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) + +Fixes: 5eb902b8e719 ("net/ipv6: Remove expired routes with a separated list of routes.") +Reported-by: Ji'an Zhou +Reviewed-by: David Ahern +Signed-off-by: Ido Schimmel +Link: https://patch.msgid.link/20260609145448.768318-1-idosch@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv6/addrconf.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index e5276be71062a3..8f8fdc9cfce224 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1264,6 +1264,7 @@ static void + cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + bool del_rt, bool del_peer) + { ++ struct net *net = dev_net(ifp->idev->dev); + struct fib6_table *table; + struct fib6_info *f6i; + +@@ -1272,9 +1273,10 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, + ifp->idev->dev, 0, RTF_DEFAULT, true); + if (f6i) { + if (del_rt) +- ip6_del_rt(dev_net(ifp->idev->dev), f6i, false); ++ ip6_del_rt(net, f6i, false); + else { +- if (!(f6i->fib6_flags & RTF_EXPIRES)) { ++ if (f6i != net->ipv6.fib6_null_entry && ++ !(f6i->fib6_flags & RTF_EXPIRES)) { + table = f6i->fib6_table; + spin_lock_bh(&table->tb6_lock); + +-- +2.53.0 + diff --git a/queue-7.0/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch b/queue-7.0/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch new file mode 100644 index 0000000000..e28b9a8aff --- /dev/null +++ b/queue-7.0/ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch @@ -0,0 +1,53 @@ +From ce6f178ffc48afac053971430712436298d1d270 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 00:34:48 -0700 +Subject: ipv6: sit: reload inner IPv6 header after GSO offloads + +From: Kyle Zeng + +[ Upstream commit f0e42f0c4337b1f220de1ddd63f47197c7dee4de ] + +ipip6_tunnel_xmit() caches the inner IPv6 header pointer at function +entry and continues using it after iptunnel_handle_offloads(). + +For GSO skbs, iptunnel_handle_offloads() calls skb_header_unclone(). +When the skb header is cloned, skb_header_unclone() can call +pskb_expand_head(), which may move the skb head. The pskb_expand_head() +contract requires pointers into the skb header to be reloaded after the +call. + +If the later skb_realloc_headroom() branch is not taken, SIT uses the +stale iph6 pointer to read the inner hop limit and DS field. That can +read from a freed skb head after the old head's remaining clone is +released. + +Reload iph6 after the offload helper succeeds and before subsequent +reads from the inner IPv6 header. Keep the existing reload after +skb_realloc_headroom(), since that branch can also replace the skb. + +Fixes: 14909664e4e1 ("sit: Setup and TX path for sit/UDP foo-over-udp encapsulation") +Signed-off-by: Kyle Zeng +Reviewed-by: Eric Dumazet +Reported-by: syzbot+6eb9ca986d80f6f88cf9@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260605073448.6524-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/sit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 6a7b8abb047727..7c317c105bdcbe 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -960,6 +960,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + ip_rt_put(rt); + goto tx_error; + } ++ iph6 = ipv6_hdr(skb); + + if (df) { + mtu = dst4_mtu(&rt->dst) - t_hlen; +-- +2.53.0 + diff --git a/queue-7.0/net-add-pskb_may_pull-to-skb_gro_receive_list.patch b/queue-7.0/net-add-pskb_may_pull-to-skb_gro_receive_list.patch new file mode 100644 index 0000000000..66f0e812df --- /dev/null +++ b/queue-7.0/net-add-pskb_may_pull-to-skb_gro_receive_list.patch @@ -0,0 +1,57 @@ +From 2940c2b651745a89bb3799c1ca2567d64bf9fe27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:46:25 +0000 +Subject: net: add pskb_may_pull() to skb_gro_receive_list() + +From: HanQuan + +[ Upstream commit f2bb3434544454099a5b6dec213567267b05d79d ] + +skb_gro_receive_list() calls skb_pull(skb, skb_gro_offset(skb)) without +first ensuring the data is in the linear area via pskb_may_pull(). When +the skb arrives via napi_gro_frags(), skb_headlen can be 0 (all data in +page fragments) while skb_gro_offset is non-zero (after IP+TCP header +parsing). The skb_pull() then decrements skb->len by skb_gro_offset +but skb->data_len stays unchanged, hitting BUG_ON(skb->len < skb->data_len) +in __skb_pull(). + +The UDP fraglist GRO path already contains this guard at +udp_offload.c:749. Adding it to skb_gro_receive_list() itself provides +centralized protection for all callers (TCP, UDP, and any future +protocols), and ensures the precondition of skb_pull() is satisfied +before it is called. + +On pskb_may_pull() failure, set NAPI_GRO_CB(skb)->flush = 1 so the +skb is not held as a new GRO head and is instead delivered through the +normal receive path, matching the UDP handling. + +Fixes: 8d95dc474f85 ("net: add code for TCP fraglist GRO") +Reported-by: HanQuan +Reported-by: MingXuan +Signed-off-by: HanQuan +Reviewed-by: Eric Dumazet +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/gro.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/gro.c b/net/core/gro.c +index a847539834679c..35f2f708f01052 100644 +--- a/net/core/gro.c ++++ b/net/core/gro.c +@@ -232,6 +232,11 @@ int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) + if (unlikely(p->len + skb->len >= 65536)) + return -E2BIG; + ++ if (!pskb_may_pull(skb, skb_gro_offset(skb))) { ++ NAPI_GRO_CB(skb)->flush = 1; ++ return -ENOMEM; ++ } ++ + if (NAPI_GRO_CB(p)->last == p) + skb_shinfo(p)->frag_list = skb; + else +-- +2.53.0 + diff --git a/queue-7.0/net-ena-phc-add-missing-barrier.patch b/queue-7.0/net-ena-phc-add-missing-barrier.patch new file mode 100644 index 0000000000..1e7ad44aca --- /dev/null +++ b/queue-7.0/net-ena-phc-add-missing-barrier.patch @@ -0,0 +1,41 @@ +From ff50811358e8e8e1b3b305c9cc10e83aa3d62269 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 08:07:04 +0000 +Subject: net: ena: PHC: Add missing barrier + +From: Arthur Kiyanovski + +[ Upstream commit 954981dbbfbd78f21d2fbac1ac0742dbf38b4e69 ] + +Add dma_rmb() barrier after req_id completion check in +ena_com_phc_get_timestamp(). On weakly-ordered architectures, +payload fields may be read before req_id is observed as updated. + +Fixes: e0ea34158ee8 ("net: ena: Add PHC support in the ENA driver") +Closes: https://sashiko.dev/#/patchset/20260430032507.11586-1-akiyano%40amazon.com +Signed-off-by: Arthur Kiyanovski +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amazon/ena/ena_com.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c +index 8c86789d867a5f..297fb36ab8c16f 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_com.c ++++ b/drivers/net/ethernet/amazon/ena/ena_com.c +@@ -1880,6 +1880,11 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp) + continue; + } + ++ /* Ensure PHC payload (timestamp, error_flags) is read ++ * after req_id update is observed ++ */ ++ dma_rmb(); ++ + /* req_id was updated by the device which indicates that + * PHC timestamp and error_flags are updated too, + * checking errors before retrieving timestamp +-- +2.53.0 + diff --git a/queue-7.0/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch b/queue-7.0/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch new file mode 100644 index 0000000000..ec07a69e8c --- /dev/null +++ b/queue-7.0/net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch @@ -0,0 +1,105 @@ +From 0fd56f6fad761355130a5b9eda5a0b4343132491 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 19:18:19 -0700 +Subject: net: guard timestamp cmsgs to real error queue skbs + +From: Kyle Zeng + +[ Upstream commit 1ee90b77b727df903033db873c75caac5c27ec98 ] + +skb_is_err_queue() treats PACKET_OUTGOING as the sole marker for an skb +from sk_error_queue. That assumption is not true for AF_PACKET sockets: +outgoing packet taps are also delivered to packet sockets with +skb->pkt_type == PACKET_OUTGOING, but their skb->cb is owned by AF_PACKET +instead of struct sock_exterr_skb. + +If such an skb is received with timestamping enabled, the generic +timestamp cmsg path can read AF_PACKET control-buffer state as +sock_exterr_skb::opt_stats. With SO_RXQ_OVFL enabled, the packet drop +counter overlaps opt_stats. An odd drop count makes the path emit +SCM_TIMESTAMPING_OPT_STATS with skb->len and skb->data. For non-linear +skbs this copies past the linear head and can trigger hardened usercopy or +disclose adjacent heap contents. + +Keep skb_is_err_queue() local to net/socket.c, but make it verify that +the PACKET_OUTGOING marker is paired with the sock_rmem_free destructor +installed by sock_queue_err_skb(). AF_PACKET receive skbs use normal +receive ownership and no longer pass as error-queue skbs, while legitimate +sk_error_queue entries keep the PACKET_OUTGOING marker and sock_rmem_free +ownership. + +Fixes: 8605330aac5a ("tcp: fix SCM_TIMESTAMPING_OPT_STATS for normal skbs") +Signed-off-by: Kyle Zeng +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607021819.49698-1-kylebot@openai.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sock.h | 1 + + net/core/skbuff.c | 6 +++--- + net/socket.c | 11 ++++++----- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 6c9a83016e9551..24aab97f1bcae7 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1853,6 +1853,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, + gfp_t priority); + void skb_orphan_partial(struct sk_buff *skb); + void sock_rfree(struct sk_buff *skb); ++void sock_rmem_free(struct sk_buff *skb); + void sock_efree(struct sk_buff *skb); + #ifdef CONFIG_INET + void sock_edemux(struct sk_buff *skb); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 9edad9b88433bb..6bee1a9d128bf2 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -5474,7 +5474,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) + } + EXPORT_SYMBOL_GPL(skb_cow_data); + +-static void sock_rmem_free(struct sk_buff *skb) ++void sock_rmem_free(struct sk_buff *skb) + { + struct sock *sk = skb->sk; + +@@ -5483,8 +5483,8 @@ static void sock_rmem_free(struct sk_buff *skb) + + static void skb_set_err_queue(struct sk_buff *skb) + { +- /* pkt_type of skbs received on local sockets is never PACKET_OUTGOING. +- * So, it is safe to (mis)use it to mark skbs on the error queue. ++ /* The error-queue test in skb_is_err_queue() matches this marker ++ * with the sock_rmem_free destructor installed by sock_queue_err_skb(). + */ + skb->pkt_type = PACKET_OUTGOING; + BUILD_BUG_ON(PACKET_OUTGOING == 0); +diff --git a/net/socket.c b/net/socket.c +index 05952188127f5b..86dc88f5b76983 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -792,12 +792,13 @@ EXPORT_SYMBOL(kernel_sendmsg); + + static bool skb_is_err_queue(const struct sk_buff *skb) + { +- /* pkt_type of skbs enqueued on the error queue are set to +- * PACKET_OUTGOING in skb_set_err_queue(). This is only safe to do +- * in recvmsg, since skbs received on a local socket will never +- * have a pkt_type of PACKET_OUTGOING. ++ /* Error-queue skbs are marked as PACKET_OUTGOING in ++ * skb_set_err_queue() and use the destructor installed by ++ * sock_queue_err_skb(). PACKET_OUTGOING alone is not unique: ++ * AF_PACKET outgoing taps use the same pkt_type. + */ +- return skb->pkt_type == PACKET_OUTGOING; ++ return skb->pkt_type == PACKET_OUTGOING && ++ skb->destructor == sock_rmem_free; + } + + /* On transmit, software and hardware timestamps are returned independently. +-- +2.53.0 + diff --git a/queue-7.0/net-ibm-emac-fix-use-after-free-during-device-remova.patch b/queue-7.0/net-ibm-emac-fix-use-after-free-during-device-remova.patch new file mode 100644 index 0000000000..2940bbd86d --- /dev/null +++ b/queue-7.0/net-ibm-emac-fix-use-after-free-during-device-remova.patch @@ -0,0 +1,73 @@ +From 13b4960deaec9b552514fe42574be007416d6237 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 15:12:17 -0700 +Subject: net: ibm: emac: Fix use-after-free during device removal + +From: Rosen Penev + +[ Upstream commit a0130d682222ae21afc395aead7cd2d87e1a8358 ] + +The driver was using devm_register_netdev() which causes unregister_netdev() +to be deferred until the devres cleanup phase, which runs after emac_remove() +returns. This creates a use-after-free window where: + +1. emac_remove() is called, which tears down hardware (cancels work, detaches + modules, unregisters from MAL) +2. emac_remove() returns +3. devres cleanup runs and finally calls unregister_netdev() + +During step 3, the network stack might still process packets, triggering +emac_irq(), emac_poll(), or other handlers that access now-freed hardware +resources (dev->emacp, dev->mal, etc.). + +Fix this by replacing devm_register_netdev() with manual register_netdev() +and calling unregister_netdev() at the beginning of emac_remove(), before +any hardware teardown. This ensures the network device is fully stopped and +unregistered before hardware resources are released. + +The change is safe because: +- dev->ndev is assigned very early in probe (before any error paths that + could bypass emac_remove) +- platform_set_drvdata() is only called after successful registration, so + emac_remove() only runs for fully registered devices +- unregister_netdev() is idempotent and safe to call on any registered device + +Fixes: a4dd8535a527 ("net: ibm: emac: use devm for register_netdev") +Signed-off-by: Rosen Penev +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ibm/emac/core.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c +index 417dfa18daae3a..4e503b3d0d2d34 100644 +--- a/drivers/net/ethernet/ibm/emac/core.c ++++ b/drivers/net/ethernet/ibm/emac/core.c +@@ -3144,7 +3144,7 @@ static int emac_probe(struct platform_device *ofdev) + + netif_carrier_off(ndev); + +- err = devm_register_netdev(&ofdev->dev, ndev); ++ err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "%pOF: failed to register net device (%d)!\n", + np, err); +@@ -3197,6 +3197,13 @@ static void emac_remove(struct platform_device *ofdev) + + DBG(dev, "remove" NL); + ++ /* Unregister network device before tearing down hardware ++ * to prevent use-after-free during deferred cleanup. This ensures ++ * the network stack stops all operations before hardware resources ++ * are released. ++ */ ++ unregister_netdev(dev->ndev); ++ + cancel_work_sync(&dev->reset_work); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) +-- +2.53.0 + diff --git a/queue-7.0/net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch b/queue-7.0/net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch new file mode 100644 index 0000000000..0ec56b3d3b --- /dev/null +++ b/queue-7.0/net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch @@ -0,0 +1,42 @@ +From 9ac7093dbb537750052c8ab0afffa26262ddba49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 09:25:41 +0800 +Subject: net: mctp: usb: don't fail mctp_usb_rx_queue on a deferred submission + +From: Jeremy Kerr + +[ Upstream commit 881a3113b74964918cdd72747e3bc119c02b0c0c ] + +In the ndo_open path, a deferred queue open will report a failure, and +so the netdev will not be ndo_stop()ed, leaving us with the rx_retry +work potentially pending. + +Don't report a deferred queue as an error, as we are still operational. +This means we use the ndo_stop() path for future cleanup, which handles +rx_retry_work cancellation. + +Fixes: 0791c0327a6e ("net: mctp: Add MCTP USB transport driver") +Signed-off-by: Jeremy Kerr +Link: https://patch.msgid.link/20260608-dev-mctp-usb-rx-requeue-v2-2-29a3aa507609@codeconstruct.com.au +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c +index cf6f6a93a45112..fade65f2f26995 100644 +--- a/drivers/net/mctp/mctp-usb.c ++++ b/drivers/net/mctp/mctp-usb.c +@@ -154,7 +154,7 @@ static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp) + if (!mctp_usb->rx_stopped) + schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY); + spin_unlock_irqrestore(&mctp_usb->rx_lock, flags); +- return rc; ++ return 0; + } + + static void mctp_usb_in_complete(struct urb *urb) +-- +2.53.0 + diff --git a/queue-7.0/net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch b/queue-7.0/net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch new file mode 100644 index 0000000000..c3b57bbfea --- /dev/null +++ b/queue-7.0/net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch @@ -0,0 +1,135 @@ +From c85c7bc5a3959ec1cea870cfd378a89a53700ac4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 09:25:40 +0800 +Subject: net: mctp: usb: fix race between urb completion and rx_retry + cancellation + +From: Jeremy Kerr + +[ Upstream commit 54665dce982689e2fd99b32e9a0dcc204fda8a51 ] + +It's possible that sequencing between setting ->stopped and cancelling +the rx_retry work (in ndo_stop) could leave us with an urb queued: + + T1: ndo_stop T2: rx_retry_work + ------------ ---------------- + LD: ->stopped => false + ST: ->stopped <= true + usb_kill_urb() + mctp_usb_rx_queue() + usb_submit_urb() + cancel_delayed_work_sync() + +That urb completion can then re-schedule rx_retry_work. + +Strenghen the sequencing between the stop (preventing another requeue) +and the cancel by updating both atomically under a new rx lock. After +setting ->rx_stopped, and cancelling pending work, we know that the +requeue cannot occur, so all that's left is killing any pending urb. + +Fixes: 0791c0327a6e ("net: mctp: Add MCTP USB transport driver") +Signed-off-by: Jeremy Kerr +Link: https://patch.msgid.link/20260608-dev-mctp-usb-rx-requeue-v2-1-29a3aa507609@codeconstruct.com.au +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-usb.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c +index 3b5dff14417747..cf6f6a93a45112 100644 +--- a/drivers/net/mctp/mctp-usb.c ++++ b/drivers/net/mctp/mctp-usb.c +@@ -22,7 +22,6 @@ + struct mctp_usb { + struct usb_device *usbdev; + struct usb_interface *intf; +- bool stopped; + + struct net_device *netdev; + +@@ -32,6 +31,9 @@ struct mctp_usb { + struct urb *tx_urb; + struct urb *rx_urb; + ++ /* enforces atomic access to rx_stopped and requeuing the retry work */ ++ spinlock_t rx_lock; ++ bool rx_stopped; + struct delayed_work rx_retry_work; + }; + +@@ -122,6 +124,7 @@ static const unsigned long RX_RETRY_DELAY = HZ / 4; + + static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp) + { ++ unsigned long flags; + struct sk_buff *skb; + int rc; + +@@ -147,7 +150,10 @@ static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp) + return rc; + + err_retry: +- schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY); ++ spin_lock_irqsave(&mctp_usb->rx_lock, flags); ++ if (!mctp_usb->rx_stopped) ++ schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY); ++ spin_unlock_irqrestore(&mctp_usb->rx_lock, flags); + return rc; + } + +@@ -248,9 +254,6 @@ static void mctp_usb_rx_retry_work(struct work_struct *work) + struct mctp_usb *mctp_usb = container_of(work, struct mctp_usb, + rx_retry_work.work); + +- if (READ_ONCE(mctp_usb->stopped)) +- return; +- + mctp_usb_rx_queue(mctp_usb, GFP_KERNEL); + } + +@@ -258,7 +261,7 @@ static int mctp_usb_open(struct net_device *dev) + { + struct mctp_usb *mctp_usb = netdev_priv(dev); + +- WRITE_ONCE(mctp_usb->stopped, false); ++ WRITE_ONCE(mctp_usb->rx_stopped, false); + + netif_start_queue(dev); + +@@ -268,17 +271,21 @@ static int mctp_usb_open(struct net_device *dev) + static int mctp_usb_stop(struct net_device *dev) + { + struct mctp_usb *mctp_usb = netdev_priv(dev); ++ unsigned long flags; + + netif_stop_queue(dev); + + /* prevent RX submission retry */ +- WRITE_ONCE(mctp_usb->stopped, true); ++ spin_lock_irqsave(&mctp_usb->rx_lock, flags); ++ mctp_usb->rx_stopped = true; ++ cancel_delayed_work(&mctp_usb->rx_retry_work); ++ spin_unlock_irqrestore(&mctp_usb->rx_lock, flags); ++ ++ flush_delayed_work(&mctp_usb->rx_retry_work); + + usb_kill_urb(mctp_usb->rx_urb); + usb_kill_urb(mctp_usb->tx_urb); + +- cancel_delayed_work_sync(&mctp_usb->rx_retry_work); +- + return 0; + } + +@@ -331,6 +338,7 @@ static int mctp_usb_probe(struct usb_interface *intf, + dev->netdev = netdev; + dev->usbdev = interface_to_usbdev(intf); + dev->intf = intf; ++ spin_lock_init(&dev->rx_lock); + usb_set_intfdata(intf, dev); + + dev->ep_in = ep_in->bEndpointAddress; +-- +2.53.0 + diff --git a/queue-7.0/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch b/queue-7.0/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch new file mode 100644 index 0000000000..6c721f5aea --- /dev/null +++ b/queue-7.0/net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch @@ -0,0 +1,61 @@ +From b0f46b5881a472f70a2cd870f254c19fda9527bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 14:10:44 +0800 +Subject: net/mlx4: avoid GCC 10 __bad_copy_from() false positive + +From: Yao Sang + +[ Upstream commit 2365343f4aad3e1b1e7a2e87e98cf66d5e590589 ] + +mlx4_init_user_cqes() fills a scratch buffer with the CQE +initialization pattern and then copies from that buffer to userspace. + +In the single-copy path, the copy length is array_size(entries, +cqe_size), but the scratch buffer is allocated with PAGE_SIZE. GCC 10 +does not carry the branch invariant strongly enough through the object +size checks and falsely triggers __bad_copy_from(). + +Size the scratch buffer to the actual copy length for the active path, +keep array_size() for the single-copy case, and retain a WARN_ON_ONCE() +guard for the PAGE_SIZE invariant before allocating the buffer. + +Fixes: f69bf5dee7ef ("net/mlx4: Use array_size() helper in copy_to_user()") +Signed-off-by: Yao Sang +Reviewed-by: Jacob Keller +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx4/cq.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c +index e130e7259275a3..5c55971abbf072 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/cq.c ++++ b/drivers/net/ethernet/mellanox/mlx4/cq.c +@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn) + static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + { + int entries_per_copy = PAGE_SIZE / cqe_size; ++ size_t copy_bytes; + void *init_ents; + int err = 0; + int i; +@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) + buf += PAGE_SIZE; + } + } else { ++ copy_bytes = array_size(entries, cqe_size); ++ if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE)) { ++ err = -EINVAL; ++ goto out; ++ } ++ + err = copy_to_user((void __user *)buf, init_ents, +- array_size(entries, cqe_size)) ? ++ copy_bytes) ? + -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch b/queue-7.0/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch new file mode 100644 index 0000000000..894b6ccd2a --- /dev/null +++ b/queue-7.0/net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch @@ -0,0 +1,221 @@ +From a50f4f622c6da0a064d186023bf269695caee49a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:58:49 +0300 +Subject: net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list + +From: Dragos Tatulea + +[ Upstream commit 894e036a24a26a6dd7b17d8d3fb5c53ab48a6074 ] + +mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using +the PF's log_max_current_uc/mc_list capabilities. When querying a VF +vport with a larger configured max (via devlink), the firmware response +can overflow this buffer: + + BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 + + CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) + Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] + Call Trace: + + dump_stack_lvl+0x69/0xa0 + print_report+0x176/0x4e4 + kasan_report+0xc8/0x100 + mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] + esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] + esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] + esw_vport_change_handler+0x6a/0x90 [mlx5_core] + process_one_work+0x87f/0x15e0 + worker_thread+0x62b/0x1020 + kthread+0x375/0x490 + ret_from_fork+0x4dc/0x810 + ret_from_fork_asm+0x11/0x20 + + +Fix by querying the vport's own HCA caps to size the buffer correctly. +Refactor the function to allocate and return the MAC list internally, +removing the caller's dependency on knowing the correct max. + +Fixes: e16aea2744ab ("net/mlx5: Introduce access functions to modify/query vport mac lists") +Signed-off-by: Dragos Tatulea +Reviewed-by: Carolina Jubran +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135849.458060-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +--- + .../net/ethernet/mellanox/mlx5/core/vport.c | 72 ++++++++++++++----- + include/linux/mlx5/vport.h | 4 +- + 3 files changed, 59 insertions(+), 30 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +index 7c8311f4123237..236f89a6483af1 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, int list_type) + { + bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC; +- u8 (*mac_list)[ETH_ALEN]; ++ u8 (*mac_list)[ETH_ALEN] = NULL; + struct l2addr_node *node; + struct vport_addr *addr; + struct hlist_head *hash; + struct hlist_node *tmp; +- int size; ++ int size = 0; + int err; + int hi; + int i; + +- size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) : +- MLX5_MAX_MC_PER_VPORT(esw->dev); +- +- mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL); +- if (!mac_list) +- return; +- + hash = is_uc ? vport->uc_list : vport->mc_list; + + for_each_l2hash_node(node, tmp, hash, hi) { +@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, + goto out; + + err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type, +- mac_list, &size); ++ &mac_list, &size); + if (err) + goto out; + esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n", +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +index 4effe37fd4552e..d63b0e8806b544 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c +@@ -324,35 +324,63 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu) + } + EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mtu); + ++static int mlx5_vport_max_mac_list_size(struct mlx5_core_dev *dev, u16 vport, ++ enum mlx5_list_type list_type) ++{ ++ void *query_ctx, *hca_caps; ++ int ret = 0; ++ ++ if (!vport && !mlx5_core_is_ecpf(dev)) ++ return list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : ++ 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ ++ query_ctx = kzalloc(MLX5_ST_SZ_BYTES(query_hca_cap_out), GFP_KERNEL); ++ if (!query_ctx) ++ return -ENOMEM; ++ ++ ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_ctx); ++ if (ret) ++ goto out; ++ ++ hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability); ++ ret = list_type == MLX5_NVPRT_LIST_TYPE_UC ? ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_uc_list) : ++ 1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_mc_list); ++ ++out: ++ kfree(query_ctx); ++ ++ return ret; ++} ++ + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size) ++ u8 (**addr_list)[ETH_ALEN], ++ int *addr_list_size) + { + u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {0}; ++ int allowed_list_size; + void *nic_vport_ctx; + int max_list_size; +- int req_list_size; + int out_sz; + void *out; + int err; + int i; + +- req_list_size = *list_size; ++ if (!addr_list || !addr_list_size) ++ return -EINVAL; + +- max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ? +- 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) : +- 1 << MLX5_CAP_GEN(dev, log_max_current_mc_list); ++ *addr_list = NULL; ++ *addr_list_size = 0; + +- if (req_list_size > max_list_size) { +- mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n", +- req_list_size, max_list_size); +- req_list_size = max_list_size; +- } ++ max_list_size = mlx5_vport_max_mac_list_size(dev, vport, list_type); ++ if (max_list_size < 0) ++ return max_list_size; + + out_sz = MLX5_ST_SZ_BYTES(query_nic_vport_context_out) + +- req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); ++ max_list_size * MLX5_ST_SZ_BYTES(mac_address_layout); + + out = kvzalloc(out_sz, GFP_KERNEL); + if (!out) +@@ -371,16 +399,24 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + + nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out, + nic_vport_context); +- req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, +- allowed_list_size); ++ allowed_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx, ++ allowed_list_size); ++ if (!allowed_list_size) ++ goto out; ++ ++ *addr_list = kcalloc(allowed_list_size, ETH_ALEN, GFP_KERNEL); ++ if (!*addr_list) { ++ err = -ENOMEM; ++ goto out; ++ } + +- *list_size = req_list_size; +- for (i = 0; i < req_list_size; i++) { ++ for (i = 0; i < allowed_list_size; i++) { + u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context, + nic_vport_ctx, + current_uc_mac_address[i]) + 2; +- ether_addr_copy(addr_list[i], mac_addr); ++ ether_addr_copy((*addr_list)[i], mac_addr); + } ++ *addr_list_size = allowed_list_size; + out: + kvfree(out); + return err; +diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h +index dfa2fe32217af0..282ed54422826d 100644 +--- a/include/linux/mlx5/vport.h ++++ b/include/linux/mlx5/vport.h +@@ -102,8 +102,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, + int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, + u16 vport, + enum mlx5_list_type list_type, +- u8 addr_list[][ETH_ALEN], +- int *list_size); ++ u8 (**mac_list)[ETH_ALEN], ++ int *mac_list_size); + int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev, + enum mlx5_list_type list_type, + u8 addr_list[][ETH_ALEN], +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch b/queue-7.0/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch new file mode 100644 index 0000000000..5a27e1499d --- /dev/null +++ b/queue-7.0/net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch @@ -0,0 +1,71 @@ +From b2cb61630edda856a2103585919881859434ae4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 18:21:12 +0800 +Subject: net/mlx5: Use effective affinity mask for IRQ selection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fushuai Wang + +[ Upstream commit a7767290e77ca2e926b49f8bfa29daa12262c612 ] + +When a sf is created after a CPU has been taken offline, the IRQ pool may +contain IRQs with affinity masks that include the offline CPU. Since only +online CPUs should be considered for IRQ placement, cpumask_subset() check +would fail because the iter_mask contains offline CPUs that are not present +in req_mask, causing sf creation to fail. + +This is an example: + 1. When mlx5 driver loads, it initializes the IRQ pools. + For sf_ctrl_pool with ≤64 sf: + - xa_num_irqs = {N, N} (There is only one slot) + 2. When the first SF is created: + - The ctrl IRQ is allocated with mask=cpu_online_mask={0-191} + 2. We take CPU 20 offline + 3. Existing ctl irq still have mask={0-191} + 4. Create a new SF: + - req_mask={0-19,21-191} + - iter_mask={0-191} + - {0-191} is NOT a subset of {0-19,21-191} + - least_loaded_irq=NULL + 5. Try to allocate a new irq via irq_pool_request_irq() + 6. xa_alloc() fails because the pool is full(There is only one slot) + 7. sf creation fails with error + +Use irq_get_effective_affinity_mask() instead, which returns the IRQ's +actual effective affinity that already excludes offline CPUs. + +Fixes: 061f5b23588a ("net/mlx5: SF, Use all available cpu for setting cpu affinity") +Suggested-by: Shay Drory +Signed-off-by: Fushuai Wang +Reviewed-by: Shay Drory +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260605102112.91772-1-fushuai.wang@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +index 994fe83da4bed8..a0bb8ee44e3550 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +@@ -105,9 +105,12 @@ irq_pool_find_least_loaded(struct mlx5_irq_pool *pool, const struct cpumask *req + + lockdep_assert_held(&pool->lock); + xa_for_each_range(&pool->irqs, index, iter, start, end) { +- struct cpumask *iter_mask = mlx5_irq_get_affinity_mask(iter); + int iter_refcount = mlx5_irq_read_locked(iter); ++ const struct cpumask *iter_mask; + ++ iter_mask = irq_get_effective_affinity_mask(mlx5_irq_get_irq(iter)); ++ if (!iter_mask) ++ continue; + if (!cpumask_subset(iter_mask, req_mask)) + /* skip IRQs with a mask which is not subset of req_mask */ + continue; +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch b/queue-7.0/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch new file mode 100644 index 0000000000..01494f97ad --- /dev/null +++ b/queue-7.0/net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch @@ -0,0 +1,69 @@ +From b1452b361dcc5a15cc0de478d648f6f95b953067 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 16:54:46 +0300 +Subject: net/mlx5e: xsk: Fix DMA and xdp_frame leak on XDP_TX xmit failure + +From: Dragos Tatulea + +[ Upstream commit b69004f5a6ad32da84d8aa5b23b9c0caafe6252e ] + +In the XSK branch of mlx5e_xmit_xdp_buff(), when sq->xmit_xdp_frame() +returns false (e.g. XDPSQ is full), the function returns without +unmapping the DMA address or freeing the xdp_frame allocated by +xdp_convert_zc_to_xdp_frame(). The xdpi_fifo push only happens on +success, so the completion path cannot recover these entries. + +With CONFIG_DMA_API_DEBUG=y, the leak surfaces on driver unbind: + + DMA-API: pci 0000:08:00.0: device driver has pending DMA + allocations while released from device [count=1116] + One of leaked entries details: [device address=0x000000010ffd7028] + [size=1534 bytes] [mapped with DMA_TO_DEVICE] [mapped as phy] + WARNING: kernel/dma/debug.c:881 at dma_debug_device_change+0x127/0x180 + ... + DMA-API: Mapped at: + debug_dma_map_phys+0x4b/0xd0 + dma_map_phys+0xfd/0x2d0 + mlx5e_xdp_handle+0x5ae/0xac0 [mlx5_core] + mlx5e_xsk_skb_from_cqe_mpwrq_linear+0xc4/0x170 [mlx5_core] + mlx5e_handle_rx_cqe_mpwrq+0xc1/0x290 [mlx5_core] + +Add the missing unmap + xdp_return_frame, matching the cleanup already +done in mlx5e_xdp_xmit(). has_frags is rejected earlier in this branch, +so no per-frag unmap is needed. + +Fixes: 84a0a2310d6d ("net/mlx5e: XDP_TX from UMEM support") +Signed-off-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260604135446.456119-1-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +index 80f9fc10877ad9..7b335da1d0cd22 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +@@ -102,9 +102,15 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq, + + xdptxd->dma_addr = dma_addr; + +- if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, +- mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL))) ++ if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, ++ mlx5e_xmit_xdp_frame_mpwqe, ++ mlx5e_xmit_xdp_frame, ++ sq, xdptxd, 0, NULL))) { ++ dma_unmap_single(sq->pdev, dma_addr, xdptxd->len, ++ DMA_TO_DEVICE); ++ xdp_return_frame(xdpf); + return false; ++ } + + /* xmit_mode == MLX5E_XDP_XMIT_MODE_FRAME */ + mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, +-- +2.53.0 + diff --git a/queue-7.0/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch b/queue-7.0/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch new file mode 100644 index 0000000000..ec7d5a4700 --- /dev/null +++ b/queue-7.0/net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch @@ -0,0 +1,106 @@ +From 5615c6fe2fbad464d9710785da99848ee3f5994e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:43 +0200 +Subject: net: mvpp2: build skb from XDP-adjusted data on XDP_PASS + +From: Til Kaiser + +[ Upstream commit 77a6b90ce56bc982dcfa94229b8e28e6abb16e95 ] + +When an XDP program uses bpf_xdp_adjust_head() or bpf_xdp_adjust_tail() +and then returns XDP_PASS, mvpp2 still builds the skb from fixed offsets +derived from the original RX descriptor. Packet geometry changes made by +the XDP program are therefore discarded before the skb reaches the stack. + +Update rx_offset and rx_bytes from xdp.data and xdp.data_end for +XDP_PASS. This makes skb_reserve() and skb_put() reflect the packet seen +by XDP, and makes RX byte accounting for XDP_PASS follow the length of the +skb passed to the network stack. + +Keep a separate rx_sync_size for page-pool recycling on skb allocation +failure, which must stay tied to the received buffer range. + +Non-PASS verdicts continue to account the descriptor length because no skb +is passed up in those cases. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-5-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 481daafdc1cbc7..ccc24a1301f22d 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3917,10 +3917,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + struct mvpp2_bm_pool *bm_pool; + struct page_pool *pp = NULL; + struct sk_buff *skb; +- unsigned int frag_size; ++ unsigned int frag_size, rx_sync_size; + dma_addr_t dma_addr; + phys_addr_t phys_addr; +- int pool, rx_bytes, err, ret; ++ int pool, rx_bytes, rx_offset, err, ret; + struct page *page; + void *data; + +@@ -3933,6 +3933,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + rx_status = mvpp2_rxdesc_status_get(port, rx_desc); + rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc); + rx_bytes -= MVPP2_MH_SIZE; ++ rx_sync_size = rx_bytes + MVPP2_MH_SIZE; ++ rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM; + dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc); + + pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> +@@ -3948,7 +3950,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, + MVPP2_SKB_HEADROOM, +- rx_bytes + MVPP2_MH_SIZE, ++ rx_sync_size, + dma_dir); + + /* Buffer header not supported */ +@@ -3999,6 +4001,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + } + ++ rx_sync_size = max_t(unsigned int, rx_sync_size, ++ xdp.data_end - xdp.data_hard_start - ++ MVPP2_SKB_HEADROOM); ++ ++ /* Update offset and length to reflect any XDP adjustments. */ ++ rx_offset = xdp.data - data; ++ rx_bytes = xdp.data_end - xdp.data; ++ + metasize = xdp.data - xdp.data_meta; + } + +@@ -4010,8 +4020,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + netdev_warn(port->dev, "skb build failed\n"); + if (pp) { + page_pool_put_page(pp, virt_to_head_page(data), +- rx_bytes + MVPP2_MH_SIZE, +- true); ++ rx_sync_size, true); + } else { + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, +@@ -4041,7 +4050,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + +- skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM); ++ skb_reserve(skb, rx_offset); + skb_put(skb, rx_bytes); + if (metasize) + skb_metadata_set(skb, metasize); +-- +2.53.0 + diff --git a/queue-7.0/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch b/queue-7.0/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch new file mode 100644 index 0000000000..06fae40837 --- /dev/null +++ b/queue-7.0/net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch @@ -0,0 +1,46 @@ +From 614f1b384b5f87656cff2dae69d78105cb0efa1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:41 +0200 +Subject: net: mvpp2: limit XDP frame size to the RX buffer + +From: Til Kaiser + +[ Upstream commit f3c6aa078927e6fe8121c9c591ddee8716c5305a ] + +mvpp2 has short and long BM pools, and short pool buffers can be smaller +than PAGE_SIZE. The XDP path nevertheless initializes every xdp_buff with +PAGE_SIZE as frame size. + +XDP helpers use frame_sz to validate tail growth and to derive the hard +end of the data area. Advertising PAGE_SIZE for short buffers can let +bpf_xdp_adjust_tail() grow a packet past the real allocation, corrupting +memory or later tripping skb tailroom checks. + +Initialize the XDP buffer with bm_pool->frag_size so XDP tailroom matches +the actual buffer backing the packet. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-3-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 92a701f4fe3f57..3372ed27cc8d67 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3979,7 +3979,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + xdp_rxq = &rxq->xdp_rxq_long; + +- xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq); ++ xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq); + xdp_prepare_buff(&xdp, data, + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM, + rx_bytes, true); +-- +2.53.0 + diff --git a/queue-7.0/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch b/queue-7.0/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch new file mode 100644 index 0000000000..06b4e8ea23 --- /dev/null +++ b/queue-7.0/net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch @@ -0,0 +1,125 @@ +From 559275ddbc5d21bdaf4cc0c25b3ec1840c00cc02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:42 +0200 +Subject: net: mvpp2: refill RX buffers before XDP or skb use + +From: Til Kaiser + +[ Upstream commit 5e8e2a9624df72fca7c736b2966b2cbf6c9c3ff6 ] + +The RX error path returns the current descriptor buffer to the hardware +BM pool. That is only valid while the driver still owns the buffer. + +mvpp2_rx_refill() can fail after the current buffer has been handed to +XDP or attached to an skb. In those cases mvpp2_run_xdp() may have +recycled, redirected, or queued the page for XDP_TX, and an skb free also +retires the data buffer. Returning such a buffer to BM lets hardware DMA +into memory that is no longer owned by the RX ring. + +Refill the BM pool before handing the current buffer to XDP or to the +skb. If the allocation fails there, drop the packet and return the +still-owned current buffer to BM, preserving the pool depth. Once the +refill succeeds, later local drops retire/free the current buffer instead +of returning it to BM. + +Fixes: 07dd0a7aae7f ("mvpp2: add basic XDP support") +Fixes: d6526926de73 ("net: mvpp2: fix memory leak in mvpp2_rx") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-4-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 43 +++++++++++-------- + 1 file changed, 24 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 3372ed27cc8d67..481daafdc1cbc7 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3971,6 +3971,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + else + frag_size = bm_pool->frag_size; + ++ err = mvpp2_rx_refill(port, bm_pool, pp, pool); ++ if (err) { ++ netdev_err(port->dev, "failed to refill BM pools\n"); ++ goto err_drop_frame; ++ } ++ + if (xdp_prog) { + struct xdp_rxq_info *xdp_rxq; + +@@ -3988,12 +3994,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + + if (ret) { + xdp_ret |= ret; +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- goto err_drop_frame; +- } +- + ps.rx_packets++; + ps.rx_bytes += rx_bytes; + continue; +@@ -4008,8 +4008,21 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb = slab_build_skb(data); + if (!skb) { + netdev_warn(port->dev, "skb build failed\n"); +- goto err_drop_frame; ++ if (pp) { ++ page_pool_put_page(pp, virt_to_head_page(data), ++ rx_bytes + MVPP2_MH_SIZE, ++ true); ++ } else { ++ dma_unmap_single_attrs(dev->dev.parent, dma_addr, ++ bm_pool->buf_size, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ mvpp2_frag_free(bm_pool, pp, data); ++ } ++ goto err_drop_frame_retired; + } ++ if (pp) ++ skb_mark_for_recycle(skb); + + /* If we have RX hardware timestamping enabled, grab the + * timestamp from the queue and convert. +@@ -4020,16 +4033,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + skb_hwtstamps(skb)); + } + +- err = mvpp2_rx_refill(port, bm_pool, pp, pool); +- if (err) { +- netdev_err(port->dev, "failed to refill BM pools\n"); +- dev_kfree_skb_any(skb); +- goto err_drop_frame; +- } +- +- if (pp) +- skb_mark_for_recycle(skb); +- else ++ if (!pp) + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); +@@ -4048,13 +4052,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + continue; + + err_drop_frame: +- dev->stats.rx_errors++; +- mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + if (rx_status & MVPP2_RXD_BUF_HDR) + mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status); + else + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); ++err_drop_frame_retired: ++ dev->stats.rx_errors++; ++ mvpp2_rx_error(port, rx_desc); + } + + if (xdp_ret & MVPP2_XDP_REDIR) +-- +2.53.0 + diff --git a/queue-7.0/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch b/queue-7.0/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch new file mode 100644 index 0000000000..ef23523a19 --- /dev/null +++ b/queue-7.0/net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch @@ -0,0 +1,51 @@ +From b0962a4c4512de840d5615e7a35df7f05890fda6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 15:49:40 +0200 +Subject: net: mvpp2: sync RX data at the hardware packet offset + +From: Til Kaiser + +[ Upstream commit 180235600934bef6add3be637c296d6cf3272e67 ] + +mvpp2 programs the RX queue packet offset, so hardware writes received +data at dma_addr + MVPP2_SKB_HEADROOM. The current CPU sync starts at +dma_addr and only covers rx_bytes + MVPP2_MH_SIZE bytes, which syncs the +unused headroom and misses the same number of bytes at the packet tail. + +On non-coherent DMA systems this can leave the CPU reading stale cache +contents for the end of the received frame. + +Use dma_sync_single_range_for_cpu() with MVPP2_SKB_HEADROOM as the range +offset so the sync covers the Marvell header and packet data actually +written by hardware. + +Fixes: e1921168bbd4 ("mvpp2: sync only the received frame") +Signed-off-by: Til Kaiser +Link: https://patch.msgid.link/20260607134943.21996-2-mail@tk154.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index f442b874bb5933..92a701f4fe3f57 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -3946,9 +3946,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, + dma_dir = DMA_FROM_DEVICE; + } + +- dma_sync_single_for_cpu(dev->dev.parent, dma_addr, +- rx_bytes + MVPP2_MH_SIZE, +- dma_dir); ++ dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr, ++ MVPP2_SKB_HEADROOM, ++ rx_bytes + MVPP2_MH_SIZE, ++ dma_dir); + + /* Buffer header not supported */ + if (rx_status & MVPP2_RXD_BUF_HDR) +-- +2.53.0 + diff --git a/queue-7.0/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch b/queue-7.0/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch new file mode 100644 index 0000000000..891a430810 --- /dev/null +++ b/queue-7.0/net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch @@ -0,0 +1,48 @@ +From 1b070ebb6b604159173156dc76e94f783122eda7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:19:46 +0200 +Subject: net: openvswitch: fix possible kfree_skb of ERR_PTR + +From: Adrian Moreno + +[ Upstream commit ee30dd2909d8b98619f4341c70ec8dc8e155ab02 ] + +After the patch in the "Fixes" tag, the allocation of the "reply" skb +can happen either before or after locking the ovs_mutex. + +However, error cleanups still follow the classical reversed order, +assuming "reply" is allocated before locking: it is freed after unlocking. + +If "reply" allocation happens after locking the mutex and it fails, +"reply" is left with an ERR_PTR, and execution jumps to the correspondent +cleanup stage which will try to free an invalid pointer. + +Fix this by setting the pointer to NULL after having saved its error +value. + +Fixes: 893f139b9a6c ("openvswitch: Minimize ovs_flow_cmd_new|set critical sections.") +Signed-off-by: Adrian Moreno +Reviewed-by: Aaron Conole +Acked-by: Eelco Chaudron +Link: https://patch.msgid.link/20260604121946.942164-1-amorenoz@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index bbbde50fc6498f..f0164817d9b723 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -1316,6 +1316,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) + + if (IS_ERR(reply)) { + error = PTR_ERR(reply); ++ reply = NULL; + goto err_unlock_ovs; + } + } +-- +2.53.0 + diff --git a/queue-7.0/net-phy-clean-the-phy_ports-after-unregistering-the-.patch b/queue-7.0/net-phy-clean-the-phy_ports-after-unregistering-the-.patch new file mode 100644 index 0000000000..d667e1f056 --- /dev/null +++ b/queue-7.0/net-phy-clean-the-phy_ports-after-unregistering-the-.patch @@ -0,0 +1,46 @@ +From 6afd28acc1d6b6f29918404aa0ed64c8c209551c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:17 +0200 +Subject: net: phy: Clean the phy_ports after unregistering the downstream SFP + bus + +From: Maxime Chevallier + +[ Upstream commit 4497f5028675b7e51c4aa59c3f4df01f29424277 ] + +As reported by sashiko when looking a other patches, we need to ensure +that the downstream SFP bus gets unregistered prior to destroying the +phy_ports attached to a phy_device, as the SFP code may reference these +ports. Let's make sure we follow that ordering in phy_remove(). + +Fixes: 589e934d2735 ("net: phy: Introduce PHY ports representation") +Signed-off-by: Maxime Chevallier +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260604092819.723505-4-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 111e3f3deb96f4..8b7e2789047694 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -3822,11 +3822,11 @@ static int phy_remove(struct device *dev) + + phydev->state = PHY_DOWN; + +- phy_cleanup_ports(phydev); +- + sfp_bus_del_upstream(phydev->sfp_bus); + phydev->sfp_bus = NULL; + ++ phy_cleanup_ports(phydev); ++ + if (phydev->drv && phydev->drv->remove) + phydev->drv->remove(phydev); + +-- +2.53.0 + diff --git a/queue-7.0/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch b/queue-7.0/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch new file mode 100644 index 0000000000..f9b601d1a1 --- /dev/null +++ b/queue-7.0/net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch @@ -0,0 +1,53 @@ +From bc47612d50e91f840059a96d3c83160fb26c7517 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:15 +0200 +Subject: net: phy: clean the sfp upstream if phy probing fails + +From: Maxime Chevallier + +[ Upstream commit 48774e87bbaa0056819d4b52301e4692e50e3252 ] + +Sashiko reported that we don't call sfp_bus_del_upstream() in the probe +failure path, so let's add it, otherwise the sfp-bus is left with a +dangling 'upstream' field, that may be used later on during SFP events. + +This issue existed before the generic phylib sfp support, back when +drivers were calling phy_sfp_probe themselves. + +Reviewed-by: Nicolai Buchwitz +Fixes: 298e54fa810e ("net: phy: add core phylib sfp support") +Signed-off-by: Maxime Chevallier +Link: https://patch.msgid.link/20260604092819.723505-2-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index cfb505ed9a3a09..c6722592f8672a 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1710,6 +1710,9 @@ static int phy_sfp_probe(struct phy_device *phydev) + + ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops); + sfp_bus_put(bus); ++ ++ if (ret) ++ phydev->sfp_bus = NULL; + } + + if (!ret && phydev->sfp_bus) +@@ -3791,6 +3794,9 @@ static int phy_probe(struct device *dev) + return 0; + + out: ++ sfp_bus_del_upstream(phydev->sfp_bus); ++ phydev->sfp_bus = NULL; ++ + if (!phydev->is_on_sfp_module) + phy_led_triggers_unregister(phydev); + +-- +2.53.0 + diff --git a/queue-7.0/net-phy-don-t-try-to-setup-phy-driven-sfp-cages-when.patch b/queue-7.0/net-phy-don-t-try-to-setup-phy-driven-sfp-cages-when.patch new file mode 100644 index 0000000000..5d48999f13 --- /dev/null +++ b/queue-7.0/net-phy-don-t-try-to-setup-phy-driven-sfp-cages-when.patch @@ -0,0 +1,59 @@ +From 97d8c58c01eae5fc002c5a43dc1631a553c087c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:18 +0200 +Subject: net: phy: don't try to setup PHY-driven SFP cages when using genphy + +From: Maxime Chevallier + +[ Upstream commit 5a0082ec20a05ef2378410323a5089a8f1786f4a ] + +We don't have support for PHY-driver SFP cages with the genphy code. + +On top of that, it was found by sashiko that running +sfp_bus_add_upstream() for genphy deadlocks, as for genphy the PHY +probing runs under RTNL, which isn't the case for non-genphy drivers. + +This problem was reproduced, and does lead to a deadlock on RTNL. + +Before the blamed commit, the phy_sfp_probe() call was made by +individual PHY drivers, so there was no way to get to the SFP probing +path when using genphy. + +Let's therefore only run phy_sfp_probe when not using genphy. + +Reviewed-by: Nicolai Buchwitz +Fixes: bad869b5e41a ("net: phy: Only rely on phy_port for PHY-driven SFP") +Signed-off-by: Maxime Chevallier +Link: https://patch.msgid.link/20260604092819.723505-5-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 8b7e2789047694..830d6fb36c6409 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -3528,9 +3528,15 @@ static int phy_setup_ports(struct phy_device *phydev) + if (ret) + return ret; + +- ret = phy_sfp_probe(phydev); +- if (ret) +- goto out; ++ /* We don't support SFP with genphy drivers. Also, genphy driver ++ * binding occurs with RTNL help, which will deadlock the call to ++ * sfp_bus_add_upstream(). ++ */ ++ if (!phydev->is_genphy_driven) { ++ ret = phy_sfp_probe(phydev); ++ if (ret) ++ goto out; ++ } + + if (phydev->n_ports < phydev->max_n_ports) { + ret = phy_default_setup_single_port(phydev); +-- +2.53.0 + diff --git a/queue-7.0/net-phy-remove-phy-ports-upon-probe-failure.patch b/queue-7.0/net-phy-remove-phy-ports-upon-probe-failure.patch new file mode 100644 index 0000000000..cc12dad636 --- /dev/null +++ b/queue-7.0/net-phy-remove-phy-ports-upon-probe-failure.patch @@ -0,0 +1,39 @@ +From 5d92776cc8b479b32a6ac9d764f514b81be9ce14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 11:28:16 +0200 +Subject: net: phy: remove phy ports upon probe failure + +From: Maxime Chevallier + +[ Upstream commit b1e780bb37c641d8291c51d7b4bde33450d18fb4 ] + +When phy_probe fails, let's clean the phy_ports that were successfully +added already. + +Suggested-by: Nicolai Buchwitz +Reviewed-by: Nicolai Buchwitz +Fixes: 589e934d2735 ("net: phy: Introduce PHY ports representation") +Signed-off-by: Maxime Chevallier +Link: https://patch.msgid.link/20260604092819.723505-3-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index c6722592f8672a..111e3f3deb96f4 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -3797,6 +3797,8 @@ static int phy_probe(struct device *dev) + sfp_bus_del_upstream(phydev->sfp_bus); + phydev->sfp_bus = NULL; + ++ phy_cleanup_ports(phydev); ++ + if (!phydev->is_on_sfp_module) + phy_led_triggers_unregister(phydev); + +-- +2.53.0 + diff --git a/queue-7.0/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch b/queue-7.0/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch new file mode 100644 index 0000000000..9c145bd5c2 --- /dev/null +++ b/queue-7.0/net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch @@ -0,0 +1,80 @@ +From 452284d6b3a327c53b50eb86dfed367ee776d6b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:48:01 +0800 +Subject: net: qrtr: fix refcount saturation and potential UAF in + qrtr_port_remove + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +[ Upstream commit a2171131ecda1ed61a594a1eb715e75fdad0fef5 ] + +In qrtr_port_remove(), the socket reference count is decremented via +__sock_put() before the port is removed from the qrtr_ports XArray and +before the RCU grace period elapses. + +This breaks the fundamental RCU update paradigm. It exposes a race +window where a concurrent RCU reader (such as qrtr_reset_ports() or +qrtr_port_lookup()) can obtain a pointer to the socket from the XArray, +and attempt to call sock_hold() on a socket whose reference count has +already dropped to zero. + +This exact race condition was hit during syzkaller fuzzing, leading to +the following refcount saturation warning and a potential Use-After-Free: + + refcount_t: saturated; leaking memory. + WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0 + Modules linked in: qrtr(+) bochs drm_shmem_helper ... + Call Trace: + + qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr] + __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr] + qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr] + kernel_bind+0xe4/0x120 net/socket.c:3592 + qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr] + qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr] + do_one_initcall+0xf5/0x5e0 init/main.c:1283 + ... + + +Fix this by deferring the reference count decrement until after the +xa_erase() and the synchronize_rcu() complete. + +(Note: The v1 of this patch incorrectly replaced __sock_put() with +sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove() +still hold a reference to the socket, so freeing the socket memory here +would lead to a subsequent UAF in the caller. Thus, the __sock_put() is +kept, but only repositioned to close the RCU race.) + +Fixes: bdabad3e363d ("net: Add Qualcomm IPC router") +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/qrtr/af_qrtr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c +index d77e9c8212da51..7087bb57aeac18 100644 +--- a/net/qrtr/af_qrtr.c ++++ b/net/qrtr/af_qrtr.c +@@ -707,13 +707,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) + if (port == QRTR_PORT_CTRL) + port = 0; + +- __sock_put(&ipc->sk); +- + xa_erase(&qrtr_ports, port); + + /* Ensure that if qrtr_port_lookup() did enter the RCU read section we + * wait for it to up increment the refcount */ + synchronize_rcu(); ++ ++ __sock_put(&ipc->sk); + } + + /* Assign port number to socket. +-- +2.53.0 + diff --git a/queue-7.0/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch b/queue-7.0/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch new file mode 100644 index 0000000000..4c6989e29f --- /dev/null +++ b/queue-7.0/net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch @@ -0,0 +1,68 @@ +From 6b7b8f533ec34b37273a19bd70c62734ea45388f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 12:24:48 -0700 +Subject: net/rds: fix NULL deref in rds_ib_send_cqe_handler() on masked atomic + completion + +From: Weiming Shi + +[ Upstream commit 34080db3e70ddf94c38512ad2331e3c3afca6cc1 ] + +rds_ib_xmit_atomic() always programs a masked atomic opcode +(IB_WR_MASKED_ATOMIC_CMP_AND_SWP or IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) +for every RDS atomic cmsg. But the completion-side switch in +rds_ib_send_unmap_op() only handles the non-masked opcodes, so a masked +atomic completion falls through to default and returns rm == NULL while +send->s_op is left set. rds_ib_send_cqe_handler() then dereferences the +NULL rm via rm->m_final_op, oopsing in softirq context. An unprivileged +AF_RDS sendmsg() of an atomic cmsg over an active RDS/IB connection +triggers it; on hardware that natively accepts masked atomics (mlx4, +mlx5) no extra setup is needed. + + RDS/IB: rds_ib_send_unmap_op: unexpected opcode 0xd in WR! + Oops: general protection fault [#1] SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000190-0x0000000000000197] + RIP: rds_ib_send_cqe_handler+0x25c/0xb10 (net/rds/ib_send.c:282) + Call Trace: + + rds_ib_send_cqe_handler (net/rds/ib_send.c:282) + poll_scq (net/rds/ib_cm.c:274) + rds_ib_tasklet_fn_send (net/rds/ib_cm.c:294) + tasklet_action_common (kernel/softirq.c:943) + handle_softirqs (kernel/softirq.c:573) + run_ksoftirqd (kernel/softirq.c:479) + + Kernel panic - not syncing: Fatal exception in interrupt + +Handle the masked atomic opcodes in the same case as the non-masked +ones: they map to the same struct rds_message.atomic union member, so +the existing container_of()/rds_ib_send_unmap_atomic() body is correct +for them. + +Fixes: 20c72bd5f5f9 ("RDS: Implement masked atomic operations") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260606192447.1179255-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/ib_send.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c +index fcd04c29f543e6..d6be95542119f6 100644 +--- a/net/rds/ib_send.c ++++ b/net/rds/ib_send.c +@@ -170,6 +170,8 @@ static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic, + break; + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_ATOMIC_CMP_AND_SWP: ++ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: ++ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + if (send->s_op) { + rm = container_of(send->s_op, struct rds_message, atomic); + rds_ib_send_unmap_atomic(ic, send->s_op, wc_status); +-- +2.53.0 + diff --git a/queue-7.0/net-txgbe-distinguish-module-types-by-checking-ident.patch b/queue-7.0/net-txgbe-distinguish-module-types-by-checking-ident.patch new file mode 100644 index 0000000000..e2752ec81a --- /dev/null +++ b/queue-7.0/net-txgbe-distinguish-module-types-by-checking-ident.patch @@ -0,0 +1,57 @@ +From 7b234ebc79398ffceadc1a23bb744157de5c3b03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:08:41 +0800 +Subject: net: txgbe: distinguish module types by checking identifier + +From: Jiawen Wu + +[ Upstream commit f2df54ddbfb04a006ee326a5d8270434a414e0af ] + +Rework txgbe_identify_module() to validate module identifiers through +explicit type checks instead of relying on transceiver_type heuristics. +When using the SFP module, transceiver_type could be a random value, +because it was read from an invalid register. + +Fixes: 57d39faed4c9 ("net: txgbe: improve functions of AML 40G devices") +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20260608070842.36504-3-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index a7e81f9e1be148..bdac654a236465 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -357,18 +357,16 @@ int txgbe_identify_module(struct wx *wx) + } + + id = &buffer.id; +- if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP && +- id->identifier != TXGBE_SFF_IDENTIFIER_QSFP && +- id->identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS && +- id->identifier != TXGBE_SFF_IDENTIFIER_QSFP28) { +- wx_err(wx, "Invalid module\n"); +- return -ENODEV; +- } +- +- if (id->transceiver_type == 0xFF) ++ if (id->identifier == TXGBE_SFF_IDENTIFIER_SFP) + return txgbe_sfp_to_linkmodes(wx, id); + +- return txgbe_qsfp_to_linkmodes(wx, id); ++ if (id->identifier == TXGBE_SFF_IDENTIFIER_QSFP || ++ id->identifier == TXGBE_SFF_IDENTIFIER_QSFP_PLUS || ++ id->identifier == TXGBE_SFF_IDENTIFIER_QSFP28) ++ return txgbe_qsfp_to_linkmodes(wx, id); ++ ++ wx_err(wx, "Invalid module\n"); ++ return -EINVAL; + } + + void txgbe_setup_link(struct wx *wx) +-- +2.53.0 + diff --git a/queue-7.0/net-txgbe-initialize-module-info-buffer.patch b/queue-7.0/net-txgbe-initialize-module-info-buffer.patch new file mode 100644 index 0000000000..1b6e0fcec8 --- /dev/null +++ b/queue-7.0/net-txgbe-initialize-module-info-buffer.patch @@ -0,0 +1,38 @@ +From 500f8e5c79857c0b8905064ea29af70d2247f679 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:08:40 +0800 +Subject: net: txgbe: initialize module info buffer + +From: Jiawen Wu + +[ Upstream commit 0487cfca46517ff6699c72dc1a8872b0af3c31a9 ] + +The module info buffer should be initialized to 0 before the firmware +returns information. Otherwise, there is a risk that the buffer field +not filled by the firmware is random value. + +Fixes: 343929799ace ("net: txgbe: Support to handle GPIO IRQs for AML devices") +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20260608070842.36504-2-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index f0514251d4f342..a7e81f9e1be148 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -335,7 +335,7 @@ static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id) + + int txgbe_identify_module(struct wx *wx) + { +- struct txgbe_hic_get_module_info buffer; ++ struct txgbe_hic_get_module_info buffer = { 0 }; + struct txgbe_sff_id *id; + int err = 0; + u32 mod_abs; +-- +2.53.0 + diff --git a/queue-7.0/net-txgbe-initialize-phy-interface-to-0.patch b/queue-7.0/net-txgbe-initialize-phy-interface-to-0.patch new file mode 100644 index 0000000000..ab4b6c2949 --- /dev/null +++ b/queue-7.0/net-txgbe-initialize-phy-interface-to-0.patch @@ -0,0 +1,62 @@ +From 79ac67cdf18b10480e7931d76787dfe13fdaa7e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:08:42 +0800 +Subject: net: txgbe: initialize PHY interface to 0 + +From: Jiawen Wu + +[ Upstream commit 47f848aac4e79bdb197f849fa86e71fff1ad36ef ] + +DECLARE_PHY_INTERFACE_MASK() does not guarantee zeroed contents. Add a +new macro DECLARE_PHY_INTERFACE_MASK_ZERO(), make the stack variable to +be zeroed before setting supported interfaces. + +Fixes: 57d39faed4c9 ("net: txgbe: improve functions of AML 40G devices") +Signed-off-by: Jiawen Wu +Link: https://patch.msgid.link/20260608070842.36504-4-jiawenwu@trustnetic.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 4 ++-- + drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +index bdac654a236465..8fc32df8e49a44 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +@@ -204,7 +204,7 @@ int txgbe_set_phy_link(struct wx *wx) + static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id) + { + __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; +- DECLARE_PHY_INTERFACE_MASK(interfaces); ++ DECLARE_PHY_INTERFACE_MASK_ZERO(interfaces); + struct txgbe *txgbe = wx->priv; + + if (id->cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) { +@@ -271,7 +271,7 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id) + static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id) + { + __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; +- DECLARE_PHY_INTERFACE_MASK(interfaces); ++ DECLARE_PHY_INTERFACE_MASK_ZERO(interfaces); + struct txgbe *txgbe = wx->priv; + + if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_CR4) { +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +index 6b05f32b4a0109..877234e3fdc2b6 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +@@ -315,6 +315,9 @@ void txgbe_up(struct wx *wx); + int txgbe_setup_tc(struct net_device *dev, u8 tc); + void txgbe_do_reset(struct net_device *netdev); + ++#define DECLARE_PHY_INTERFACE_MASK_ZERO(name) \ ++ unsigned long name[PHY_INTERFACE_MODE_MAX] = { 0, } ++ + #define TXGBE_LINK_SPEED_UNKNOWN 0 + #define TXGBE_LINK_SPEED_10GB_FULL 4 + #define TXGBE_LINK_SPEED_25GB_FULL 0x10 +-- +2.53.0 + diff --git a/queue-7.0/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch b/queue-7.0/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch new file mode 100644 index 0000000000..b6487b1f6a --- /dev/null +++ b/queue-7.0/netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch @@ -0,0 +1,52 @@ +From 4795b0f93ab942c57186a9d3fbf6bf7b7bf5a54a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 18:21:24 -0700 +Subject: netdev: fix double-free in netdev_nl_bind_rx_doit() + +From: Jakub Kicinski + +[ Upstream commit c849de7d8757a7af801fc4a4058f71d481d367f2 ] + +Sashiko flags that genlmsg_reply() always consumes the skb. +The error path calls nlmsg_free(rsp) so we can't jump directly +to it. Let's not unbind, just propagate the error to the user. +This is the typical way of handling genlmsg_reply() failures. +They shouldn't happen unless user does something silly like +calling the kernel with an already-full rcvbuf. + +Reported-by: Sashiko +Fixes: 170aafe35cb9 ("netdev: support binding dma-buf to netdevice") +Reviewed-by: Bobby Eshleman +Acked-by: Daniel Borkmann +Reviewed-by: Nikolay Aleksandrov +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/netdev-genl.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c +index 470fabbeacd9bd..93ea09bd1e7bab 100644 +--- a/net/core/netdev-genl.c ++++ b/net/core/netdev-genl.c +@@ -1019,8 +1019,6 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) + genlmsg_end(rsp, hdr); + + err = genlmsg_reply(rsp, info); +- if (err) +- goto err_unbind; + + bitmap_free(rxq_bitmap); + +@@ -1028,7 +1026,7 @@ int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info) + + mutex_unlock(&priv->lock); + +- return 0; ++ return err < 0 ? err : 0; + + err_unbind: + net_devmem_unbind_dmabuf(binding); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch b/queue-7.0/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch new file mode 100644 index 0000000000..8990b84de0 --- /dev/null +++ b/queue-7.0/netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch @@ -0,0 +1,150 @@ +From f6fa29f0f6abf6a5b8fb8de0927c0aee20d7efca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 00:38:17 -0700 +Subject: netfilter: nf_conntrack: destroy stale expectfn expectations on + unregister + +From: Weiming Shi + +[ Upstream commit c3009418f9fa1dcb3eb86f4d8c92583537b5faa3 ] + +NAT helpers such as nf_nat_h323 store a raw pointer to module text in +exp->expectfn (e.g. ip_nat_q931_expect). nf_ct_helper_expectfn_unregister() +only unlinks the callback descriptor and never walks the expectation table, +so an expectation pending at module removal survives with a dangling +exp->expectfn into freed module text. + +When the expected connection arrives, init_conntrack() invokes +exp->expectfn(), now a stale pointer into the unloaded module. Reproduced +on a KASAN build by loading the H.323 helpers, creating a Q.931 +expectation, unloading nf_nat_h323, then connecting to the expected port: + + Oops: int3: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:0xffffffffa06102d1 + init_conntrack.isra.0 (net/netfilter/nf_conntrack_core.c:1862) + nf_conntrack_in (net/netfilter/nf_conntrack_core.c:2049) + ipv4_conntrack_local (net/netfilter/nf_conntrack_proto.c:223) + nf_hook_slow (net/netfilter/core.c:619) + __ip_local_out (net/ipv4/ip_output.c:120) + __tcp_transmit_skb (net/ipv4/tcp_output.c:1715) + tcp_connect (net/ipv4/tcp_output.c:4374) + tcp_v4_connect (net/ipv4/tcp_ipv4.c:345) + __sys_connect (net/socket.c:2167) + Modules linked in: nf_conntrack_h323 [last unloaded: nf_nat_h323] + +Reaching the dangling state requires CAP_SYS_MODULE in the initial user +namespace to remove a NAT helper that still has live expectations, so this +is a robustness fix; leaving an expectation pointing at freed text is wrong +regardless. + +Add nf_ct_helper_expectfn_destroy(), which walks the expectation table and +drops every expectation whose ->expectfn matches the descriptor being torn +down. Call it from each NAT helper's exit path after the existing RCU grace +period, so no expectation outlives the code it points at and no extra +synchronize_rcu() is introduced. With the fix, the same reproducer runs to +completion without the Oops. + +Fixes: f587de0e2feb ("[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Weiming Shi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_helper.h | 1 + + net/ipv4/netfilter/nf_nat_h323.c | 2 ++ + net/netfilter/nf_conntrack_helper.c | 19 +++++++++++++++++++ + net/netfilter/nf_nat_core.c | 2 ++ + net/netfilter/nf_nat_sip.c | 1 + + 5 files changed, 25 insertions(+) + +diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h +index de2f956abf3480..24cf3d2d97450f 100644 +--- a/include/net/netfilter/nf_conntrack_helper.h ++++ b/include/net/netfilter/nf_conntrack_helper.h +@@ -155,6 +155,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct, + + void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); + void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n); + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name); + struct nf_ct_helper_expectfn * +diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c +index faee20af485613..10e1b0837731b7 100644 +--- a/net/ipv4/netfilter/nf_nat_h323.c ++++ b/net/ipv4/netfilter/nf_nat_h323.c +@@ -555,6 +555,8 @@ static void __exit nf_nat_h323_fini(void) + nf_ct_helper_expectfn_unregister(&q931_nat); + nf_ct_helper_expectfn_unregister(&callforwarding_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&q931_nat); ++ nf_ct_helper_expectfn_destroy(&callforwarding_nat); + } + + /****************************************************************************/ +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index b594cd244fe1d4..ea0cdb7ec91512 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -283,6 +283,25 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) + } + EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); + ++static bool expect_iter_expectfn(struct nf_conntrack_expect *exp, void *data) ++{ ++ const struct nf_ct_helper_expectfn *n = data; ++ ++ /* Relies on registered expectfn descriptors having unique ->expectfn ++ * pointers, which holds for the in-tree NAT helpers. ++ */ ++ return exp->expectfn == n->expectfn; ++} ++ ++/* Destroy expectations still pointing at @n->expectfn; call after the ++ * caller's RCU grace period so none outlives the (often modular) callback. ++ */ ++void nf_ct_helper_expectfn_destroy(const struct nf_ct_helper_expectfn *n) ++{ ++ nf_ct_expect_iterate_destroy(expect_iter_expectfn, (void *)n); ++} ++EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_destroy); ++ + /* Caller should hold the rcu lock */ + struct nf_ct_helper_expectfn * + nf_ct_helper_expectfn_find_by_name(const char *name) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index b30ca94c2bb7ff..4f41311b868b47 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1347,6 +1347,7 @@ static int __init nf_nat_init(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + nf_ct_helper_expectfn_unregister(&follow_master_nat); + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + unregister_pernet_subsys(&nat_net_ops); + kvfree(nf_nat_bysource); + } +@@ -1364,6 +1365,7 @@ static void __exit nf_nat_cleanup(void) + RCU_INIT_POINTER(nf_nat_hook, NULL); + + synchronize_net(); ++ nf_ct_helper_expectfn_destroy(&follow_master_nat); + kvfree(nf_nat_bysource); + unregister_pernet_subsys(&nat_net_ops); + } +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 9fbfc6bff0c221..00838c0cc5bb28 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -655,6 +655,7 @@ static void __exit nf_nat_sip_fini(void) + RCU_INIT_POINTER(nf_nat_sip_hooks, NULL); + nf_ct_helper_expectfn_unregister(&sip_nat); + synchronize_rcu(); ++ nf_ct_helper_expectfn_destroy(&sip_nat); + } + + static const struct nf_nat_sip_hooks sip_hooks = { +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_log-validate-mac-header-was-set-before-.patch b/queue-7.0/netfilter-nf_log-validate-mac-header-was-set-before-.patch new file mode 100644 index 0000000000..a1097039e4 --- /dev/null +++ b/queue-7.0/netfilter-nf_log-validate-mac-header-was-set-before-.patch @@ -0,0 +1,70 @@ +From 4f4e7bf8118c08b08a35a414e5e6d79f0c48df81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 15:55:02 -0700 +Subject: netfilter: nf_log: validate MAC header was set before dumping it + +From: Xiang Mei + +[ Upstream commit a84b6fedbc97078788be78dbdd7517d143ad1a77 ] + +The fallback path of dump_mac_header() guards the MAC header access +only with "skb->mac_header != skb->network_header", without checking +skb_mac_header_was_set(). When the MAC header is unset, mac_header is +0xffff, so the test passes and skb_mac_header(skb) returns +skb->head + 0xffff, ~64 KiB past the buffer; the loop then reads +dev->hard_header_len bytes out of bounds into the kernel log. + +This is reachable via the netdev logger: nf_log_unknown_packet() calls +dump_mac_header() unconditionally, and an skb sent through AF_PACKET +with PACKET_QDISC_BYPASS reaches the egress hook with mac_header still +unset (__dev_queue_xmit(), which would reset it, is bypassed). + +Add the skb_mac_header_was_set() check the ARPHRD_ETHER path already +uses, and replace the open-coded MAC header length test with +skb_mac_header_len(). Only skbs with an unset MAC header are affected; +valid ones are dumped as before. + + BUG: KASAN: slab-out-of-bounds in dump_mac_header (net/netfilter/nf_log_syslog.c:831) + Read of size 1 at addr ffff88800ea49d3f by task exploit/148 + Call Trace: + kasan_report (mm/kasan/report.c:595) + dump_mac_header (net/netfilter/nf_log_syslog.c:831) + nf_log_netdev_packet (net/netfilter/nf_log_syslog.c:938 net/netfilter/nf_log_syslog.c:963) + nf_log_packet (net/netfilter/nf_log.c:260) + nft_log_eval (net/netfilter/nft_log.c:60) + nft_do_chain (net/netfilter/nf_tables_core.c:285) + nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307) + nf_hook_slow (net/netfilter/core.c:619) + nf_hook_direct_egress (net/packet/af_packet.c:257) + packet_xmit (net/packet/af_packet.c:280) + packet_sendmsg (net/packet/af_packet.c:3114) + __sys_sendto (net/socket.c:2265) + +Fixes: 7eb9282cd0ef ("netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header") +Reported-by: Weiming Shi +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_log_syslog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c +index 41503847d9d7fb..c0462d403157a9 100644 +--- a/net/netfilter/nf_log_syslog.c ++++ b/net/netfilter/nf_log_syslog.c +@@ -801,8 +801,8 @@ static void dump_mac_header(struct nf_log_buf *m, + + fallback: + nf_log_buf_add(m, "MAC="); +- if (dev->hard_header_len && +- skb->mac_header != skb->network_header) { ++ if (dev->hard_header_len && skb_mac_header_was_set(skb) && ++ skb_mac_header_len(skb) != 0) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch b/queue-7.0/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch new file mode 100644 index 0000000000..3ce391b86c --- /dev/null +++ b/queue-7.0/netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch @@ -0,0 +1,45 @@ +From bd5008db248ba89bc69acd20cfda26c2d1ac7531 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 21:28:09 +0200 +Subject: netfilter: nft_exthdr: fix register tracking for F_PRESENT flag + +From: Florian Westphal + +[ Upstream commit 772cecf198da732faebb5dcfc46d66a505be8495 ] + +nft_exthdr_init() passes user-controlled priv->len to +nft_parse_register_store(), which marks that many bytes in the +register bitmap as initialized. However, when NFT_EXTHDR_F_PRESENT +is set, the eval paths write only 1 byte (nft_reg_store8) or +4 bytes (*dest = 0 on TCP/DCCP error path). When len > 4, +registers beyond the first are never written, retaining +uninitialized stack data from nft_regs. + +Bail out if userspace requests too much data when F_PRESENT is set. + +Reported-by: Ji'an Zhou +Fixes: c078ca3b0c5b ("netfilter: nft_exthdr: Add support for existence check") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index 7eedf4e3ae9c75..9471328802d3b7 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -532,6 +532,9 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, + return err; + } + ++ if ((flags & NFT_EXTHDR_F_PRESENT) && len != 1) ++ return -EINVAL; ++ + priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); + priv->offset = offset; + priv->len = len; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-revalidate-bridge-ports.patch b/queue-7.0/netfilter-revalidate-bridge-ports.patch new file mode 100644 index 0000000000..0a12cb5e5a --- /dev/null +++ b/queue-7.0/netfilter-revalidate-bridge-ports.patch @@ -0,0 +1,239 @@ +From 2307548fa1ef4d384bcc0459bc20cd7252dd6946 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 17:04:25 +0200 +Subject: netfilter: revalidate bridge ports + +From: Florian Westphal + +[ Upstream commit ccb9fd4b87538ccf19ccff78ee26700526d94867 ] + +ebt_redirect_tg() dereferences br_port_get_rcu() return without a +NULL check, causing a kernel panic when the bridge port has been +removed between the original hook invocation and an NFQUEUE +reinject. + +A mere NULL check isn't sufficient, however. As sashiko review +points out userspace can not only remove the port from the bridge, +it could also place the device in a different virtual device, e.g. +macvlan. + +If this happens, we must drop the packet, there is no way for us to +reinject it into the bridge path. + +Switch to _upper API, we don't need the bridge port structure. +Also, this fix keeps another bug intact: + +Both nfnetlink_log and nfnetlink_queue use CONFIG_BRIDGE_NETFILTER +too aggressive, which prevents certain logging features when queueing +in bridge family: NETFILTER_FAMILY_BRIDGE can be enabled while the old +CONFIG_BRIDGE_NETFILTER cruft is off. + +Fixes tag is a common ancestor, this was always broken. + +Fixes: f350a0a87374 ("bridge: use rx_handler_data pointer to store net_bridge_port pointer") +Reported-by: Ji'an Zhou +Assisted-by: Claude:claude-sonnet-4-6 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/bridge/netfilter/ebt_dnat.c | 4 +- + net/bridge/netfilter/ebt_redirect.c | 16 +++++--- + net/netfilter/nfnetlink_log.c | 23 +++++++++-- + net/netfilter/nfnetlink_queue.c | 64 +++++++++++++++++++++++++---- + 4 files changed, 89 insertions(+), 18 deletions(-) + +diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c +index 3fda71a8579d13..73f185cccd63df 100644 +--- a/net/bridge/netfilter/ebt_dnat.c ++++ b/net/bridge/netfilter/ebt_dnat.c +@@ -39,7 +39,9 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par) + dev = xt_in(par); + break; + case NF_BR_PRE_ROUTING: +- dev = br_port_get_rcu(xt_in(par))->br->dev; ++ dev = netdev_master_upper_dev_get_rcu(xt_in(par)); ++ if (!dev) /* bridge port removed? */ ++ return EBT_DROP; + break; + default: + dev = NULL; +diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c +index 307790562b4929..83486cd4d564b1 100644 +--- a/net/bridge/netfilter/ebt_redirect.c ++++ b/net/bridge/netfilter/ebt_redirect.c +@@ -24,12 +24,18 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) + if (skb_ensure_writable(skb, 0)) + return EBT_DROP; + +- if (xt_hooknum(par) != NF_BR_BROUTING) +- /* rcu_read_lock()ed by nf_hook_thresh */ +- ether_addr_copy(eth_hdr(skb)->h_dest, +- br_port_get_rcu(xt_in(par))->br->dev->dev_addr); +- else ++ if (xt_hooknum(par) != NF_BR_BROUTING) { ++ const struct net_device *dev; ++ ++ dev = netdev_master_upper_dev_get_rcu(xt_in(par)); ++ if (!dev) ++ return EBT_DROP; ++ ++ ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr); ++ } else { + ether_addr_copy(eth_hdr(skb)->h_dest, xt_in(par)->dev_addr); ++ } ++ + skb->pkt_type = PACKET_HOST; + return info->target; + } +diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c +index 0db908518b2fa2..f9bfc34d9ad355 100644 +--- a/net/netfilter/nfnetlink_log.c ++++ b/net/netfilter/nfnetlink_log.c +@@ -450,6 +450,23 @@ static int nfulnl_put_bridge(struct nfulnl_instance *inst, const struct sk_buff + return -1; + } + ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++static int nflog_put_master_ifindex(struct sk_buff *nlskb, int attr, ++ const struct net_device *dev) ++{ ++ const struct net_device *upper; ++ ++ if (dev && !netif_is_bridge_port(dev)) ++ return 0; ++ ++ upper = netdev_master_upper_dev_get_rcu((struct net_device *)dev); ++ if (upper && nla_put_be32(nlskb, attr, htonl(upper->ifindex))) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++#endif ++ + /* This is an inline function, we don't really care about a long + * list of arguments */ + static inline int +@@ -504,8 +521,7 @@ __build_packet_message(struct nfnl_log_net *log, + /* rcu_read_lock()ed by nf_hook_thresh or + * nf_log_packet. + */ +- nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, +- htonl(br_port_get_rcu(indev)->br->dev->ifindex))) ++ nflog_put_master_ifindex(inst->skb, NFULA_IFINDEX_INDEV, indev)) + goto nla_put_failure; + } else { + int physinif; +@@ -541,8 +557,7 @@ __build_packet_message(struct nfnl_log_net *log, + /* rcu_read_lock()ed by nf_hook_thresh or + * nf_log_packet. + */ +- nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, +- htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) ++ nflog_put_master_ifindex(inst->skb, NFULA_IFINDEX_OUTDEV, outdev)) + goto nla_put_failure; + } else { + struct net_device *physoutdev; +diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c +index 0529a19ca9a838..69038d946fc243 100644 +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -426,10 +426,47 @@ static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_ + return false; + } + ++static bool nf_bridge_port_valid(const struct net_device *dev) ++{ ++ if (!dev) ++ return true; ++ ++ return netif_is_bridge_port(dev); ++} ++ ++/* queued skbs leave rcu protection. We bump device refcount so that ++ * the device cannot go away. However, while packet was out the port ++ * could have been removed from the bridge. ++ * ++ * Ensure in+outdev are still part of a bridge at reinject time. ++ * ++ * The device rx_handler_data could even be pointing at data that is ++ * not a net_bridge_port structure. ++ */ ++static bool nf_bridge_ports_valid(const struct nf_queue_entry *entry) ++{ ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++ if (!nf_bridge_port_valid(entry->physin) || ++ !nf_bridge_port_valid(entry->physout)) ++ return false; ++#endif ++ if (entry->state.pf != PF_BRIDGE) ++ return true; ++ ++ if (!nf_bridge_port_valid(entry->state.in) || ++ !nf_bridge_port_valid(entry->state.out)) ++ return false; ++ ++ return true; ++} ++ + static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) + { + const struct nf_ct_hook *ct_hook; + ++ if (!nf_bridge_ports_valid(entry)) ++ verdict = NF_DROP; ++ + if (verdict == NF_ACCEPT || + verdict == NF_REPEAT || + verdict == NF_STOP) { +@@ -622,6 +659,23 @@ static int nf_queue_checksum_help(struct sk_buff *entskb) + return skb_checksum_help(entskb); + } + ++#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) ++static int nfqnl_put_master_ifindex(struct sk_buff *nlskb, int attr, ++ const struct net_device *dev) ++{ ++ const struct net_device *upper; ++ ++ if (dev && !netif_is_bridge_port(dev)) ++ return 0; ++ ++ upper = netdev_master_upper_dev_get_rcu((struct net_device *)dev); ++ if (upper && nla_put_be32(nlskb, attr, htonl(upper->ifindex))) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++#endif ++ + static struct sk_buff * + nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + struct nf_queue_entry *entry, +@@ -757,10 +811,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + * netfilter_bridge) */ + if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV, + htonl(indev->ifindex)) || +- /* this is the bridge group "brX" */ +- /* rcu_read_lock()ed by __nf_queue */ +- nla_put_be32(skb, NFQA_IFINDEX_INDEV, +- htonl(br_port_get_rcu(indev)->br->dev->ifindex))) ++ nfqnl_put_master_ifindex(skb, NFQA_IFINDEX_INDEV, indev)) + goto nla_put_failure; + } else { + int physinif; +@@ -791,10 +842,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, + * netfilter_bridge) */ + if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV, + htonl(outdev->ifindex)) || +- /* this is the bridge group "brX" */ +- /* rcu_read_lock()ed by __nf_queue */ +- nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, +- htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) ++ nfqnl_put_master_ifindex(skb, NFQA_IFINDEX_OUTDEV, outdev)) + goto nla_put_failure; + } else { + int physoutif; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch b/queue-7.0/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch new file mode 100644 index 0000000000..4af9fd8258 --- /dev/null +++ b/queue-7.0/netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch @@ -0,0 +1,143 @@ +From 79929e522bc788c0b442aadf7361c5ce591ae6db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 01:10:31 -0700 +Subject: netfilter: x_tables: avoid leaking percpu counter pointers + +From: Kyle Zeng + +[ Upstream commit f7f2fbb0e893a0238dc464f8d8c0f5609bec584f ] + +The native and compat get-entries paths copy the fixed rule entry header +from the kernelized rule blob to userspace before overwriting the entry's +counter fields with a sanitized counter snapshot. + +On SMP kernels, entry->counters.pcnt contains the percpu allocation +address used by x_tables rule counters. A caller can provide a userspace +buffer that faults during the initial fixed-header copy after pcnt has +been copied but before the later sanitized counter copy runs. The syscall +then returns -EFAULT while leaving the raw percpu pointer in userspace. + +Copy only the fixed entry prefix before counters from the kernelized rule +blob, then copy the sanitized counter snapshot into the counter field. +Apply this ordering to the IPv4, IPv6, and ARP native and compat +get-entries implementations so a fault cannot expose the internal percpu +counter pointer. + +Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") +Signed-off-by: Kyle Zeng +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 15 ++++++--------- + net/ipv4/netfilter/ip_tables.c | 15 ++++++--------- + net/ipv6/netfilter/ip6_tables.c | 15 ++++++--------- + 3 files changed, 18 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index ad2259678c7854..0ea513bf77fb6a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -702,14 +702,12 @@ static int copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct arpt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct arpt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1327,9 +1325,8 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_arpt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_arpt_entry); +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 5cbdb0815857f4..ca8ff0ae6cdb9f 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -832,14 +832,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ipt_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ipt_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1228,9 +1226,8 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ipt_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 9d9c3763f2f5e9..e34d5ba1460ca7 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -848,14 +848,12 @@ copy_entries_to_user(unsigned int total_size, + const struct xt_entry_target *t; + + e = loc_cpu_entry + off; +- if (copy_to_user(userptr + off, e, sizeof(*e))) { +- ret = -EFAULT; +- goto free_counters; +- } +- if (copy_to_user(userptr + off ++ if (copy_to_user(userptr + off, e, ++ offsetof(struct ip6t_entry, counters)) || ++ copy_to_user(userptr + off + + offsetof(struct ip6t_entry, counters), + &counters[num], +- sizeof(counters[num])) != 0) { ++ sizeof(counters[num]))) { + ret = -EFAULT; + goto free_counters; + } +@@ -1244,9 +1242,8 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, + + origsize = *size; + ce = *dstptr; +- if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || +- copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ if (copy_to_user(ce, e, offsetof(struct compat_ip6t_entry, counters)) || ++ copy_to_user(&ce->counters, &counters[i], sizeof(counters[i]))) + return -EFAULT; + + *dstptr += sizeof(struct compat_ip6t_entry); +-- +2.53.0 + diff --git a/queue-7.0/netlabel-validate-unlabeled-address-and-mask-attribu.patch b/queue-7.0/netlabel-validate-unlabeled-address-and-mask-attribu.patch new file mode 100644 index 0000000000..c3176f8bc3 --- /dev/null +++ b/queue-7.0/netlabel-validate-unlabeled-address-and-mask-attribu.patch @@ -0,0 +1,87 @@ +From 55a549f38f046e65707b9b4df86b3949b8067724 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2026 09:13:53 +0800 +Subject: netlabel: validate unlabeled address and mask attribute lengths + +From: Chenguang Zhao + +[ Upstream commit 9772589b57e44aedc240211c5c3f7a684a034d3a ] + +netlbl_unlabel_addrinfo_get() used the address attribute length to +determine whether the attribute data could be read as an IPv4 or IPv6 +address, but did not independently validate the corresponding mask +attribute length. A crafted Generic Netlink request could therefore +provide a valid IPv4/IPv6 address attribute with a shorter mask +attribute, which would later be read as a full struct in_addr or +struct in6_addr. + +NLA_BINARY policy lengths are maximum lengths by default, so use +NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask +attributes. This rejects short attributes during policy validation and +also exposes the exact length requirements through policy introspection. + +Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections") +Signed-off-by: Chenguang Zhao +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netlabel/netlabel_unlabeled.c | 30 ++++++++++-------------------- + 1 file changed, 10 insertions(+), 20 deletions(-) + +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index ca7a9e2a3de781..870e7699326a4a 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; + /* NetLabel Netlink attribute policy */ + static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { + [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, +- [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in6_addr) }, +- [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, +- [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, +- .len = sizeof(struct in_addr) }, ++ [NLBL_UNLABEL_A_IPV6ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV6MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), ++ [NLBL_UNLABEL_A_IPV4ADDR] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), ++ [NLBL_UNLABEL_A_IPV4MASK] = ++ NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } +@@ -757,24 +757,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, + void **mask, + u32 *len) + { +- u32 addr_len; +- + if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && + info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); +- if (addr_len != sizeof(struct in_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); + return 0; + } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { +- addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); +- if (addr_len != sizeof(struct in6_addr) && +- addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) +- return -EINVAL; +- *len = addr_len; ++ *len = sizeof(struct in6_addr); + *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); + *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); + return 0; +-- +2.53.0 + diff --git a/queue-7.0/ptp-ocp-fix-resource-freeing-order.patch b/queue-7.0/ptp-ocp-fix-resource-freeing-order.patch new file mode 100644 index 0000000000..acf03628aa --- /dev/null +++ b/queue-7.0/ptp-ocp-fix-resource-freeing-order.patch @@ -0,0 +1,81 @@ +From 8aafacd7393e0bedb2121e487492529fc38ad785 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 15:59:52 +0000 +Subject: ptp: ocp: fix resource freeing order + +From: Vadim Fedorenko + +[ Upstream commit 627366c51145a07f675b1800fb5ea2ec960bd900 ] + +Commit a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable +events") added a call to ptp_disable_all_events() which changes the +configuration of pins if they support EXTTS events. In ptp_ocp_detach() +pins resources are freed before ptp_clock_unregister() and it leads to +use-after-free during driver removal. Fix it by changing the order of +free/unregister calls. To avoid irq handler running on the other core +while ptp device unregistering, call synchronize_irq() after HW is +configured to stop producing irqs and no irqs are in-flight. + +Fixes: a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable events") +Signed-off-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260608155952.240304-1-vadim.fedorenko@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_ocp.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c +index d88ab2f86b1bf6..fcfa671bd6897c 100644 +--- a/drivers/ptp/ptp_ocp.c ++++ b/drivers/ptp/ptp_ocp.c +@@ -2216,8 +2216,13 @@ ptp_ocp_ts_enable(void *priv, u32 req, bool enable) + iowrite32(1, ®->intr_mask); + iowrite32(1, ®->intr); + } else { ++ int irq_vec = pci_irq_vector(bp->pdev, ext->irq_vec); ++ + iowrite32(0, ®->intr_mask); + iowrite32(0, ®->enable); ++ ioread32(®->intr_mask); ++ if (irq_vec > 0) ++ synchronize_irq(irq_vec); + } + + return 0; +@@ -4558,6 +4563,22 @@ ptp_ocp_detach(struct ptp_ocp *bp) + ptp_ocp_detach_sysfs(bp); + ptp_ocp_attr_group_del(bp); + timer_delete_sync(&bp->watchdog); ++ /* Disable interrupts on all timestampers */ ++ if (bp->ts0) ++ ptp_ocp_ts_enable(bp->ts0, 0, false); ++ if (bp->ts1) ++ ptp_ocp_ts_enable(bp->ts1, 0, false); ++ if (bp->ts2) ++ ptp_ocp_ts_enable(bp->ts2, 0, false); ++ if (bp->ts3) ++ ptp_ocp_ts_enable(bp->ts3, 0, false); ++ if (bp->ts4) ++ ptp_ocp_ts_enable(bp->ts4, 0, false); ++ if (bp->pps) ++ ptp_ocp_ts_enable(bp->pps, ~0, false); ++ if (bp->ptp) ++ ptp_clock_unregister(bp->ptp); ++ kfree(bp->ptp_info.pin_config); + ptp_ocp_unregister_ext(bp->ts0); + ptp_ocp_unregister_ext(bp->ts1); + ptp_ocp_unregister_ext(bp->ts2); +@@ -4575,9 +4596,6 @@ ptp_ocp_detach(struct ptp_ocp *bp) + clk_hw_unregister_fixed_rate(bp->i2c_clk); + if (bp->n_irqs) + pci_free_irq_vectors(bp->pdev); +- if (bp->ptp) +- ptp_clock_unregister(bp->ptp); +- kfree(bp->ptp_info.pin_config); + device_unregister(&bp->dev); + } + +-- +2.53.0 + diff --git a/queue-7.0/r8152-handle-the-return-value-of-usb_reset_device.patch b/queue-7.0/r8152-handle-the-return-value-of-usb_reset_device.patch new file mode 100644 index 0000000000..fbcada7c3f --- /dev/null +++ b/queue-7.0/r8152-handle-the-return-value-of-usb_reset_device.patch @@ -0,0 +1,44 @@ +From 79eaa654df97c32f3452472a7aeb4be9e1d9e183 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 17:22:47 +0800 +Subject: r8152: handle the return value of usb_reset_device() + +From: Chih Kai Hsu + +[ Upstream commit 19440600e729d4f74a42591a872099cf25c7d28a ] + +If usb_reset_device() returns a negative error code, stop the +process of probing. + +Fixes: 10c3271712f5 ("r8152: disable the ECM mode") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260604092247.27158-450-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index f69e7e1ab7788d..240265746990ec 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -9775,7 +9775,12 @@ static int rtl8152_probe_once(struct usb_interface *intf, + struct net_device *netdev; + int ret; + +- usb_reset_device(udev); ++ ret = usb_reset_device(udev); ++ if (ret < 0) { ++ dev_err(&intf->dev, "USB reset failed, errno=%d\n", ret); ++ return ret; ++ } ++ + netdev = alloc_etherdev(sizeof(struct r8152)); + if (!netdev) { + dev_err(&intf->dev, "Out of memory\n"); +-- +2.53.0 + diff --git a/queue-7.0/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch b/queue-7.0/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch new file mode 100644 index 0000000000..10c59c6ffa --- /dev/null +++ b/queue-7.0/rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch @@ -0,0 +1,45 @@ +From d463ea6d6e82dc0adef5ff9191d2f1ccd8755f4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 02:32:05 -0700 +Subject: rds: mark snapshot pages dirty in rds_info_getsockopt() + +From: Breno Leitao + +[ Upstream commit 512db8267b73a220a64180d95ab5eebe7c4964a8 ] + +rds_info_getsockopt() pins the destination user pages with FOLL_WRITE and +the RDS_INFO_* producers memcpy the snapshot into them through +kmap_atomic(). Because that copy goes through the kernel direct map, the +dirty bit on the user PTE is never set, so unpin_user_pages() releases the +pages without marking them dirty. A file-backed destination page can then +be reclaimed without writeback, silently discarding the copied data. + +Use unpin_user_pages_dirty_lock() with make_dirty=true so the modified +pages are marked dirty before they are unpinned. + +Fixes: a8c879a7ee98 ("RDS: Info and stats") +Signed-off-by: Breno Leitao +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260608-rds_fix-v1-1-006c88543408@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/info.c b/net/rds/info.c +index f1b29994934a03..17061f6ff74e58 100644 +--- a/net/rds/info.c ++++ b/net/rds/info.c +@@ -235,7 +235,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, + + out: + if (pages) +- unpin_user_pages(pages, nr_pages); ++ unpin_user_pages_dirty_lock(pages, nr_pages, true); + kfree(pages); + + return ret; +-- +2.53.0 + diff --git a/queue-7.0/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch b/queue-7.0/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch new file mode 100644 index 0000000000..ff74f3c40e --- /dev/null +++ b/queue-7.0/sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch @@ -0,0 +1,60 @@ +From 8e14091ecf1262d7e1383f8b428175b5edcead3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Jun 2026 08:22:34 -0400 +Subject: sctp: fix uninit-value in __sctp_rcv_asconf_lookup() + +From: Michael Bommarito + +[ Upstream commit f8373d7090b745728de66308deeecc67e8d319ce ] + +__sctp_rcv_asconf_lookup() in net/sctp/input.c only checks that the ASCONF +chunk can hold the ADDIP header and a parameter header, then calls +af->from_addr_param(), which reads the full address (16 bytes for IPv6) +trusting the parameter's declared length. + +An unauthenticated peer can send a truncated trailing ASCONF chunk that +declares an IPv6 address parameter but stops after the 4-byte parameter +header; reached from the no-association lookup path, from_addr_param() then +reads uninitialized bytes past the parameter. + +Impact: an unauthenticated SCTP peer makes the receive path read up to 16 +bytes of uninitialized memory past a truncated ASCONF address parameter. + +The sibling __sctp_rcv_init_lookup() bounds parameters with +sctp_walk_params(); this path open-codes the fetch and omits the bound. +Verify the whole address parameter lies within the chunk before +from_addr_param() reads it, the same class of fix as commit 51e5ad549c43 +("net: sctp: fix KMSAN uninit-value in sctp_inq_pop"). + +Fixes: df2185771439 ("[SCTP]: Update association lookup to look at ASCONF chunks as well") +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260608122234.459098-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/input.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/net/sctp/input.c b/net/sctp/input.c +index e119e460ccde0b..864741fae4187e 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -1204,6 +1204,14 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( + /* Skip over the ADDIP header and find the Address parameter */ + param = (union sctp_addr_param *)(asconf + 1); + ++ /* The whole address parameter must lie within the chunk before ++ * af->from_addr_param() reads the variable-length address; otherwise a ++ * truncated trailing ASCONF chunk lets it read uninitialized bytes past ++ * the parameter. ++ */ ++ if (sizeof(*asconf) + ntohs(param->p.length) > ntohs(ch->length)) ++ return NULL; ++ + af = sctp_get_af_specific(param_type2af(param->p.type)); + if (unlikely(!af)) + return NULL; +-- +2.53.0 + diff --git a/queue-7.0/sctp-validate-embedded-init-chunk-and-address-list-l.patch b/queue-7.0/sctp-validate-embedded-init-chunk-and-address-list-l.patch new file mode 100644 index 0000000000..ae49693194 --- /dev/null +++ b/queue-7.0/sctp-validate-embedded-init-chunk-and-address-list-l.patch @@ -0,0 +1,110 @@ +From d7e0c478d50c3399925be74af3afcba8f2213867 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Jun 2026 19:03:47 -0400 +Subject: sctp: validate embedded INIT chunk and address list lengths in cookie + +From: Xin Long + +[ Upstream commit 6f4c80a2a7e6d06753b89a578b710a2499a5e62b ] + +sctp_unpack_cookie() only checked that the embedded INIT chunk length +did not exceed the remaining cookie payload, but did not ensure that the +INIT chunk is large enough to contain a complete INIT header. + +A malformed COOKIE_ECHO can therefore carry a truncated INIT chunk whose +length field is smaller than sizeof(struct sctp_init_chunk). Later, +sctp_process_init() accesses INIT parameters unconditionally, which may +lead to out-of-bounds reads. + +In addition, raw_addr_list_len is not fully validated against the +remaining cookie payload. When cookie authentication is disabled, an +attacker can supply an oversized raw_addr_list_len and cause +sctp_raw_to_bind_addrs() to read beyond the end of the cookie. The +address parser also lacks sufficient bounds checks for parameter headers +and lengths, allowing malformed address parameters to trigger +out-of-bounds reads. + +Fix this by: + +- requiring the embedded INIT chunk length to be at least sizeof(struct + sctp_init_chunk); +- validating that the INIT chunk and raw address list together fit + within the cookie payload; +- verifying sufficient data exists for each address parameter header and + payload before parsing it. + +Note that sctp_verify_init() must be called after sctp_unpack_cookie() +and before sctp_process_init() when cookie authentication is disabled. +This will be addressed in a separate patch. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Sashiko +Signed-off-by: Xin Long +Link: https://patch.msgid.link/75af23a89adf881a0895d511775e4770da367cbf.1780873427.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/bind_addr.c | 11 ++++++++++- + net/sctp/sm_make_chunk.c | 9 +++++++-- + 2 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c +index 75e3e61d494e0f..31737f144c7f03 100644 +--- a/net/sctp/bind_addr.c ++++ b/net/sctp/bind_addr.c +@@ -275,6 +275,16 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, + param = (struct sctp_paramhdr *)raw_addr_list; + rawaddr = (union sctp_addr_param *)raw_addr_list; + ++ if (addrs_len < sizeof(*param)) { ++ retval = -EINVAL; ++ goto out_err; ++ } ++ len = ntohs(param->length); ++ if (addrs_len < len) { ++ retval = -EINVAL; ++ goto out_err; ++ } ++ + af = sctp_get_af_specific(param_type2af(param->type)); + if (unlikely(!af) || + !af->from_addr_param(&addr, rawaddr, htons(port), 0)) { +@@ -291,7 +301,6 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, + goto out_err; + + next: +- len = ntohs(param->length); + addrs_len -= len; + raw_addr_list += len; + } +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index 9014b095f52ddb..51affa4fd396b7 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -1731,8 +1731,8 @@ struct sctp_association *sctp_unpack_cookie( + struct sk_buff *skb = chunk->skb; + struct sctp_cookie *bear_cookie; + struct sctp_chunkhdr *ch; ++ unsigned int len, chlen; + enum sctp_scope scope; +- unsigned int len; + ktime_t kt; + + /* Header size is static data prior to the actual cookie, including +@@ -1761,7 +1761,12 @@ struct sctp_association *sctp_unpack_cookie( + bear_cookie = &cookie->c; + + ch = (struct sctp_chunkhdr *)(bear_cookie + 1); +- if (ntohs(ch->length) > len - fixed_size) ++ chlen = ntohs(ch->length); ++ if (chlen < sizeof(struct sctp_init_chunk)) ++ goto malformed; ++ if (chlen > len - fixed_size) ++ goto malformed; ++ if (bear_cookie->raw_addr_list_len > len - fixed_size - chlen) + goto malformed; + + /* Verify the cookie's MAC, if cookie authentication is enabled. */ +-- +2.53.0 + diff --git a/queue-7.0/series b/queue-7.0/series index ff43e9f3c8..9ca0d8551a 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -94,3 +94,60 @@ verification-rvgen-fix-options-shared-among-commands.patch verification-rvgen-fix-ltl2k-writing-true-as-a-liter.patch riscv-ptrace-use-user_regset_note_type-for-regset_cf.patch riscv-cfi-reject-unknown-flags-in-pr_set_cfi.patch +xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch +dma-mapping-direct-fix-missing-mapping-for-thru_host.patch +dma-debug-fix-physical-address-retrieval-in-debug_dm.patch +xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch +ice-fix-missing-priority-callbacks-for-u.fl-dpll-pin.patch +idpf-fix-mailbox-capability-for-set-device-clock-tim.patch +net-ena-phc-add-missing-barrier.patch +bnge-fix-context-mem-iteration.patch +netlabel-validate-unlabeled-address-and-mask-attribu.patch +gpio-mvebu-fix-null-pointer-dereference-in-suspend-r.patch +asoc-wm_adsp-fix-null-dereference-when-removing-firm.patch +tcp-restrict-so_attach_filter-to-priv-users.patch +net-add-pskb_may_pull-to-skb_gro_receive_list.patch +net-mlx4-avoid-gcc-10-__bad_copy_from-false-positive.patch +net-ibm-emac-fix-use-after-free-during-device-remova.patch +netdev-fix-double-free-in-netdev_nl_bind_rx_doit.patch +net-phy-clean-the-sfp-upstream-if-phy-probing-fails.patch +net-phy-remove-phy-ports-upon-probe-failure.patch +net-phy-clean-the-phy_ports-after-unregistering-the-.patch +net-phy-don-t-try-to-setup-phy-driven-sfp-cages-when.patch +net-qrtr-fix-refcount-saturation-and-potential-uaf-i.patch +net-mlx5-fix-slab-out-of-bounds-in-mlx5_query_nic_vp.patch +net-mlx5e-xsk-fix-dma-and-xdp_frame-leak-on-xdp_tx-x.patch +net-mlx5-use-effective-affinity-mask-for-irq-selecti.patch +ipv6-sit-reload-inner-ipv6-header-after-gso-offloads.patch +net-openvswitch-fix-possible-kfree_skb-of-err_ptr.patch +r8152-handle-the-return-value-of-usb_reset_device.patch +gpio-zynq-fix-runtime-pm-leak-on-remove.patch +gpio-rockchip-fix-generic-irq-chip-leak-on-remove.patch +net-mctp-usb-fix-race-between-urb-completion-and-rx_.patch +net-mctp-usb-don-t-fail-mctp_usb_rx_queue-on-a-defer.patch +esp-fix-page-frag-reference-leak-on-skb_to_sgvec-fai.patch +asoc-sof-amd-fix-for-ipc-flags-check.patch +sctp-fix-uninit-value-in-__sctp_rcv_asconf_lookup.patch +ip6_vti-set-netns_immutable-on-the-fallback-device.patch +sctp-validate-embedded-init-chunk-and-address-list-l.patch +net-guard-timestamp-cmsgs-to-real-error-queue-skbs.patch +net-rds-fix-null-deref-in-rds_ib_send_cqe_handler-on.patch +tun-zero-the-whole-vnet-header-in-tun_put_user.patch +ptp-ocp-fix-resource-freeing-order.patch +ip6_vti-fix-incorrect-tunnel-matching-in-vti6_tnl_lo.patch +rds-mark-snapshot-pages-dirty-in-rds_info_getsockopt.patch +spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch +netfilter-revalidate-bridge-ports.patch +netfilter-nf_conntrack-destroy-stale-expectfn-expect.patch +netfilter-x_tables-avoid-leaking-percpu-counter-poin.patch +netfilter-nf_log-validate-mac-header-was-set-before-.patch +netfilter-nft_exthdr-fix-register-tracking-for-f_pre.patch +net-mvpp2-sync-rx-data-at-the-hardware-packet-offset.patch +net-mvpp2-limit-xdp-frame-size-to-the-rx-buffer.patch +net-mvpp2-refill-rx-buffers-before-xdp-or-skb-use.patch +net-mvpp2-build-skb-from-xdp-adjusted-data-on-xdp_pa.patch +net-txgbe-initialize-module-info-buffer.patch +net-txgbe-distinguish-module-types-by-checking-ident.patch +net-txgbe-initialize-phy-interface-to-0.patch +ipv6-fix-a-potential-npd-in-cleanup_prefix_route.patch +asoc-sdca-fix-null-pointer-dereference-in-sdca_dev_u.patch diff --git a/queue-7.0/spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch b/queue-7.0/spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch new file mode 100644 index 0000000000..c461857f90 --- /dev/null +++ b/queue-7.0/spi-rzv2h-rspi-fix-spdr-read-access-width-for-16-bit.patch @@ -0,0 +1,47 @@ +From 7b73751f13da4144f1db9ab4991ac02b93ae77b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jun 2026 20:08:17 +0800 +Subject: spi: rzv2h-rspi: Fix SPDR read access width for 16-bit RX + +From: Felix Gu + +[ Upstream commit 310628484ef06f95c5589374fade917a5689787b ] + +The RZ/V2H hardware manual (section 7.5.2.2.1) specifies that read access +size for the SPI Data Register (SPDR) are fixed at 32 bits. The +RZV2H_RSPI_RX macro for the 16-bit data path used readw(), violating +this requirement. + +Switch to readl() for the 16-bit RX path to conform to the hardware +specification. + +Fixes: 8b61c8919dff ("spi: Add driver for the RZ/V2H(P) RSPI IP") +Suggested-by: Geert Uytterhoeven +Signed-off-by: Felix Gu +Reviewed-by: Geert Uytterhoeven +Reviewed-by: Fabrizio Castro +Link: https://patch.msgid.link/20260610-rzv2h-rspi-v2-1-40c80b4a2c90@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rzv2h-rspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c +index 53c44799fab71d..6fc81ccbcad5a2 100644 +--- a/drivers/spi/spi-rzv2h-rspi.c ++++ b/drivers/spi/spi-rzv2h-rspi.c +@@ -133,8 +133,9 @@ static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \ + RZV2H_RSPI_TX(writel, u32) + RZV2H_RSPI_TX(writew, u16) + RZV2H_RSPI_TX(writeb, u8) ++/* The read access size for RSPI_SPDR is fixed at 32 bits */ + RZV2H_RSPI_RX(readl, u32) +-RZV2H_RSPI_RX(readw, u16) ++RZV2H_RSPI_RX(readl, u16) + RZV2H_RSPI_RX(readl, u8) + + static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi, +-- +2.53.0 + diff --git a/queue-7.0/tcp-restrict-so_attach_filter-to-priv-users.patch b/queue-7.0/tcp-restrict-so_attach_filter-to-priv-users.patch new file mode 100644 index 0000000000..47ffdb9331 --- /dev/null +++ b/queue-7.0/tcp-restrict-so_attach_filter-to-priv-users.patch @@ -0,0 +1,58 @@ +From 504888b2191dd25c0b63d5054c75ca8422efbc11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Jun 2026 11:21:34 +0000 +Subject: tcp: restrict SO_ATTACH_FILTER to priv users + +From: Eric Dumazet + +[ Upstream commit 5d39580f68e6ddeedd15e587282207489dfb3da2 ] + +This patch restricts the use of SO_ATTACH_FILTER (cBPF) on TCP sockets +to users with CAP_NET_ADMIN capability. + +This blocks potential side-channel attack where an unprivileged application +attaches a filter to leak TCP sequence/acknowledgment numbers. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Eric Dumazet +Reported-by: Tamir Shahar +Reported-by: Amit Klein +Cc: Willem de Bruijn +Cc: Alexei Starovoitov +Cc: Daniel Borkmann +Cc: Andrii Nakryiko +Cc: Martin KaFai Lau +Cc: Eduard Zingerman +Cc: Kumar Kartikeya Dwivedi +Cc: Song Liu +Cc: Yonghong Song +Cc: Jiri Olsa +Cc: John Fastabend +Cc: Stanislav Fomichev +Acked-by: Daniel Borkmann +Reviewed-by: Willem de Bruijn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/sock.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index b197a795306392..d317b4a8b85a25 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1463,6 +1463,11 @@ int sk_setsockopt(struct sock *sk, int level, int optname, + case SO_ATTACH_FILTER: { + struct sock_fprog fprog; + ++ if (sk_is_tcp(sk) && ++ !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ break; ++ } + ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); + if (!ret) + ret = sk_attach_filter(&fprog, sk); +-- +2.53.0 + diff --git a/queue-7.0/tun-zero-the-whole-vnet-header-in-tun_put_user.patch b/queue-7.0/tun-zero-the-whole-vnet-header-in-tun_put_user.patch new file mode 100644 index 0000000000..123967de93 --- /dev/null +++ b/queue-7.0/tun-zero-the-whole-vnet-header-in-tun_put_user.patch @@ -0,0 +1,49 @@ +From 88c468a539d7387564f56753d8e2c008b2b21447 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jun 2026 22:44:28 -0700 +Subject: tun: zero the whole vnet header in tun_put_user() + +From: Xiang Mei + +[ Upstream commit 7f2fcff15e99bb852f6967396ed12b38376e2c8d ] + +tun_put_user() declares an on-stack struct virtio_net_hdr_v1_hash_tunnel +without zeroing it. For a non-tunnel skb, virtio_net_hdr_tnl_from_skb() +only initializes the first 10 bytes (sizeof(struct virtio_net_hdr)), +leaving bytes 10..23 (num_buffers and the hash/tunnel fields) as stack +garbage. + +An unprivileged user can set the vnet header size to 24 with +TUNSETVNETHDRSZ, so __tun_vnet_hdr_put() copies all 24 bytes of the +partially-initialized struct to userspace, leaking 14 bytes of kernel +stack on every read of a non-tunnel packet. + +Fix it the same way tun_get_user() already does by zeroing the whole +header right after declaration. + +Fixes: 288f30435132 ("tun: enable gso over UDP tunnel support.") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260607054428.3050243-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/tun.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index ca0ae5df73af78..a0bd803e5fb4d5 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -2068,6 +2068,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, + struct virtio_net_hdr_v1_hash_tunnel hdr; + struct virtio_net_hdr *gso; + ++ memset(&hdr, 0, sizeof(hdr)); + ret = tun_vnet_hdr_tnl_from_skb(tun->flags, tun->dev, skb, + &hdr); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch b/queue-7.0/xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch new file mode 100644 index 0000000000..fa44496902 --- /dev/null +++ b/queue-7.0/xfrm-iptfs-fix-use-after-free-on-first_skb-in-__inpu.patch @@ -0,0 +1,72 @@ +From db3862c70913c6fda4f2071a715ef0b2ab18128c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 18:53:28 +0800 +Subject: xfrm: iptfs: fix use-after-free on first_skb in + __input_process_payload +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zhenghang Xiao + +[ Upstream commit eb48730bb827d1550401a5d391903f9d90b493c8 ] + +__input_process_payload() stores first_skb into xtfs->ra_newskb under +drop_lock when starting partial reassembly, then unlocks and breaks out +of the processing loop. The post-loop check reads xtfs->ra_newskb +without the lock to decide whether first_skb is still owned: + + if (first_skb && first_iplen && !defer && first_skb != xtfs->ra_newskb) + +Between spin_unlock and this read, a concurrent CPU running +iptfs_reassem_cont() (or the drop_timer hrtimer) can complete +reassembly, NULL xtfs->ra_newskb, and free the skb. The check then +evaluates first_skb != NULL as true, and pskb_trim/ip_summed/consume_skb +operate on the freed skb — a use-after-free in skbuff_head_cache. + +Replace the unlocked read with a local bool that records whether +first_skb was handed to the reassembly state in the current call. The +flag is set after the existing spin_unlock, before the break, using the +pointer equality that is stable at that point (first_skb == skb iff +first_skb was stored in ra_newskb). + +Fixes: 3f3339885fb3 ("xfrm: iptfs: add reusing received skb for the tunnel egress packet") +Signed-off-by: Zhenghang Xiao +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_iptfs.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c +index 6c6bbc0405170c..f25504610d8b23 100644 +--- a/net/xfrm/xfrm_iptfs.c ++++ b/net/xfrm/xfrm_iptfs.c +@@ -954,6 +954,7 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data, + u32 first_iplen, iphlen, iplen, remaining, tail; + u32 capturelen; + u64 seq; ++ bool first_skb_partial = false; + + xtfs = x->mode_data; + net = xs_net(x); +@@ -1161,6 +1162,7 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data, + + spin_unlock(&xtfs->drop_lock); + ++ first_skb_partial = (first_skb == skb); + break; + } + +@@ -1172,7 +1174,7 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data, + /* this should not happen from the above code */ + XFRM_INC_STATS(net, LINUX_MIB_XFRMINIPTFSERROR); + +- if (first_skb && first_iplen && !defer && first_skb != xtfs->ra_newskb) { ++ if (first_skb && first_iplen && !defer && !first_skb_partial) { + /* first_skb is queued b/c !defer and not partial */ + if (pskb_trim(first_skb, first_iplen)) { + /* error trimming */ +-- +2.53.0 + diff --git a/queue-7.0/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch b/queue-7.0/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch new file mode 100644 index 0000000000..cafff28085 --- /dev/null +++ b/queue-7.0/xfrm-policy-fix-use-after-free-on-inexact-bin-in-xfr.patch @@ -0,0 +1,80 @@ +From 9643d2d718b22bf55bfaed5306b895742c17facf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jun 2026 18:49:05 +0900 +Subject: xfrm: policy: fix use-after-free on inexact bin in + xfrm_policy_bysel_ctx() + +From: Sanghyun Park + +[ Upstream commit 7f2d76c9c03257c0782afef9d95321fa04096f60 ] + +Fix the race by pruning the bin while still holding xfrm_policy_lock, +before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since +the lock is already held. The wrapper xfrm_policy_inexact_prune_bin() +becomes unused and is removed. + +Race: + + CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO) + ========================== ========================== + xfrm_policy_bysel_ctx(): + spin_lock_bh(xfrm_policy_lock) + bin = xfrm_policy_inexact_lookup() + __xfrm_policy_unlink(pol) + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_kill(ret) + // wide window, lock not held + xfrm_hash_rebuild(): + spin_lock_bh(xfrm_policy_lock) + __xfrm_policy_inexact_flush(): + kfree_rcu(bin) // bin freed + spin_unlock_bh(xfrm_policy_lock) + xfrm_policy_inexact_prune_bin(bin) + // UAF: bin is freed + +Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure") +Signed-off-by: Sanghyun Park +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/xfrm/xfrm_policy.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index d904352fb24276..97b5ff9687a30c 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -1156,15 +1156,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool + } + } + +-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b) +-{ +- struct net *net = read_pnet(&b->k.net); +- +- spin_lock_bh(&net->xfrm.xfrm_policy_lock); +- __xfrm_policy_inexact_prune_bin(b, false); +- spin_unlock_bh(&net->xfrm.xfrm_policy_lock); +-} +- + static void __xfrm_policy_inexact_flush(struct net *net) + { + struct xfrm_pol_inexact_bin *bin, *t; +@@ -1707,12 +1698,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id, + } + ret = pol; + } ++ if (bin && delete) ++ __xfrm_policy_inexact_prune_bin(bin, false); + spin_unlock_bh(&net->xfrm.xfrm_policy_lock); + + if (ret && delete) + xfrm_policy_kill(ret); +- if (bin && delete) +- xfrm_policy_inexact_prune_bin(bin); + return ret; + } + EXPORT_SYMBOL(xfrm_policy_bysel_ctx); +-- +2.53.0 +