--- /dev/null
+From 209d6773af061614cbb6db7dfad59537fb76b96e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index 768df9d7cd676..a9d8ee2c68b6a 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -451,10 +460,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -470,23 +488,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -512,12 +523,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -534,18 +547,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -620,7 +642,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -755,12 +777,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From da816bf00f2c5306ad63cb36a6b0a080537e17ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index fda0bd990dcb7..b768abbf2b121 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -5948,6 +5948,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From fdeabe225a6f7c2818836b700f8b126818a3d320 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index a2ccbd97e8dd2..e6cf29b117e1a 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -9459,8 +9459,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From 568425250eed5841a954c5d34b35930b1aeaa0f5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index 3db1def4437b3..a44d14b94865e 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -248,12 +248,12 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -261,7 +261,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -278,6 +278,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -465,9 +467,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 18b72e664ddcdd25191d2e5175a9a8d5302c9a07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 3d622904f4c3d..5e0fe58f8bdd9 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -515,8 +515,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From da7c780b555d1d936d3770eb670640ebdf7394d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 227cf3f6ca227..948bd59ab5d21 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -442,12 +442,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 31d59b97739b0e8b6206b9fb12a3d82beb8ffa6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 2a7cd5be87444..12d70983ed407 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1251,10 +1251,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From 94a58b72ba4f9ad28fe9e564131f0e07d45c4685 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index e8c4e02e75d43..dda90c77f8984 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -634,11 +634,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From 0daf0dd2ae4fa22268ab0555793b755d26939b50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index a30ff5d6808aa..d8af31805133f 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -756,6 +756,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -917,9 +918,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -962,12 +967,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From 162a777ed64c0e51babe6048fe83da7b89d890df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index d01165bb6a32b..65846f4451894 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -673,6 +673,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From 4e5d6d83ce88929d6cba9f74abf1935b95f560f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index ced20abf4ef8e..758cea239e618 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3509,12 +3509,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 3ffc6b7a0e3bfff237e3e4b519b031b225c95a56 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index ceb85c67ce395..bb528d0ddb73a 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From 29176ae7a3668dc89dbdd4190ad20fdb584bc7bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 43ad4e5db5941..de389b519700d 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1155,6 +1155,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From 4a37da5626f59556aeb06ce5aab722f7fdb1ae6a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 3593b310c325d..9be050c5d83e0 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -110,10 +110,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 1956761739cc84c79017e9573694740d1408d984 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 9be050c5d83e0..e6c17e0af1ccf 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -97,10 +97,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -114,8 +114,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From d4317049df589e4dfa85f10b128ff4ad0b592869 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index 060561f633114..62ac22d82e1a9 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -60,9 +60,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index 02558ac2ace69..eb414452dbd0f 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -770,48 +770,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index b285f1515e4e8..d3279536c902c 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -209,8 +209,8 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ void mlx5e_init(void);
+ void mlx5e_cleanup(void);
+--
+2.53.0
+
--- /dev/null
+From 3b3b0162fb2c118af3ef6f9c76b91745f8d7e074 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Nov 2020 18:33:29 +0100
+Subject: net: qrtr: Add GFP flags parameter to qrtr_alloc_ctrl_packet
+
+From: Loic Poulain <loic.poulain@linaro.org>
+
+[ Upstream commit f7dec6cb914c8923808eefc034bba8227a5dfe3a ]
+
+This will be requested for allocating control packet in atomic context.
+
+Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 2428083101f6 ("net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory leak")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 8476a229bce0a..01d8cb93ad756 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -540,18 +540,20 @@ EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
+ /**
+ * qrtr_alloc_ctrl_packet() - allocate control packet skb
+ * @pkt: reference to qrtr_ctrl_pkt pointer
++ * @flags: the type of memory to allocate
+ *
+ * Returns newly allocated sk_buff, or NULL on failure
+ *
+ * This function allocates a sk_buff large enough to carry a qrtr_ctrl_pkt and
+ * on success returns a reference to the control packet in @pkt.
+ */
+-static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt)
++static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt,
++ gfp_t flags)
+ {
+ const int pkt_len = sizeof(struct qrtr_ctrl_pkt);
+ struct sk_buff *skb;
+
+- skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, GFP_KERNEL);
++ skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, flags);
+ if (!skb)
+ return NULL;
+
+@@ -620,7 +622,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ mutex_unlock(&node->ep_lock);
+
+ /* Notify the local controller about the event */
+- skb = qrtr_alloc_ctrl_packet(&pkt);
++ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
+ if (skb) {
+ pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
+ qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
+@@ -677,7 +679,7 @@ static void qrtr_port_remove(struct qrtr_sock *ipc)
+ to.sq_node = QRTR_NODE_BCAST;
+ to.sq_port = QRTR_PORT_CTRL;
+
+- skb = qrtr_alloc_ctrl_packet(&pkt);
++ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
+ if (skb) {
+ pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
+ pkt->client.node = cpu_to_le32(ipc->us.sq_node);
+@@ -992,7 +994,7 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
+ if (!node)
+ return -EINVAL;
+
+- skb = qrtr_alloc_ctrl_packet(&pkt);
++ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+--
+2.53.0
+
--- /dev/null
+From 4f40afd8bd45d690421e467296bc7f30e6a19cec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Nov 2020 18:33:30 +0100
+Subject: net: qrtr: Release distant nodes along the bridge node
+
+From: Loic Poulain <loic.poulain@linaro.org>
+
+[ Upstream commit 90829f07baea7efe4ca77f79820f3849081186a8 ]
+
+Distant QRTR nodes can be accessed via an other node that acts as
+a bridge. When the a QRTR endpoint associated to a bridge node is
+released, all the linked distant nodes should also be released.
+
+This patch fixes endpoint release by:
+- Submitting QRTR BYE message locally on behalf of all the nodes
+accessible through the endpoint.
+- Removing all the routable node IDs from radix tree pointing to
+the released node endpoint.
+
+Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 2428083101f6 ("net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory leak")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 01d8cb93ad756..68b6124fc8a10 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -172,8 +172,13 @@ static void __qrtr_node_release(struct kref *kref)
+ void __rcu **slot;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+- if (node->nid != QRTR_EP_NID_AUTO)
+- radix_tree_delete(&qrtr_nodes, node->nid);
++ /* If the node is a bridge for other nodes, there are possibly
++ * multiple entries pointing to our released node, delete them all.
++ */
++ radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
++ if (*slot == node)
++ radix_tree_iter_delete(&qrtr_nodes, &iter, slot);
++ }
+ spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
+
+ list_del(&node->item);
+@@ -615,6 +620,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_ctrl_pkt *pkt;
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
++ unsigned long flags;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -622,11 +628,18 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ mutex_unlock(&node->ep_lock);
+
+ /* Notify the local controller about the event */
+- skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
+- if (skb) {
+- pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
+- qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
++ spin_lock_irqsave(&qrtr_nodes_lock, flags);
++ radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
++ if (*slot != node)
++ continue;
++ src.sq_node = iter.index;
++ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_ATOMIC);
++ if (skb) {
++ pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
++ qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
++ }
+ }
++ spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+--
+2.53.0
+
--- /dev/null
+From 5156604c09f0687a285fdce7b9280bb0aebf1100 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 68b6124fc8a10..fdb7a5a12f035 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -116,7 +116,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -127,7 +127,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -170,6 +170,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -187,11 +188,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -226,9 +225,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -267,12 +264,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -324,9 +322,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -593,7 +589,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -621,6 +617,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -643,10 +640,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From ebf7ce3b795025352db25a26358b79fdc3dcf155 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index beedd0d2b5097..27847fae053d3 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2669,6 +2669,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From e6c2f2b0a138f4b3f4fd585a2bd54c1641e4bf30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 117c7b038591e..7918ecdcfe696 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -501,8 +501,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From a72d859eca8609cbad9bfd449e6ed0c41ec213fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index 08c41f1976c47..23cf4f7111174 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -246,8 +246,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From 900fb13ffc2f014ced61a72ab6eb0d9cfd2302a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index 25360061ad288..3a271ad16443b 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -556,7 +556,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -599,7 +599,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From 169bf69c5a79b027405c6f62d468c01922d2fcaf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 77ad186507f64..956e056803079 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 1d11677f92f320f10157bf8d85295ac5e60fced4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index e1c4197af468e..77ad186507f64 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (!more && x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From b9152c6df62b06acc6ccfc0fbddf4cdf75d2f42d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index 071822028ea5e..516f40e7560ac 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -103,7 +103,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -129,7 +129,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From 2dbc9afb1b5eb0845d6c4a3a18287fb6512a5537 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 8d35e17a0f7e7..befc9d2bc0b52 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3568,6 +3568,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From 63ca94754c3d0f9426afce54a52210c79dcb86f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index f27894e50ef19..4269b64252787 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -306,7 +306,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index a265efd31ba96..cf827d72581e1 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -823,7 +823,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -832,7 +832,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 5cc35b553a048..7d1ba6ad514f5 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From e930e2067a8235b76e39a1b80a91317d275ceb27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 89174c91053ed..24f3f8d5e6998 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -468,7 +468,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+
+ /* Maybe someone has gotten the helper already when unhelp above.
+--
+2.53.0
+
--- /dev/null
+From 06a7b19830f6c1330da2303419d4af0706164489 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 189997bcaeef5..15486d3051f6b 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -9362,8 +9362,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -9398,6 +9396,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 8c849ec772340d039446ca6799a2295fe8431458 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index 3a71ba47224c4..d41560d4812d0 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -711,7 +711,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From cbbc2d680cb536fd3b2aebba9974de702e018594 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c0f5e9a4f3c65..bfc98719684e2 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -53,6 +53,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -85,6 +88,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 158d9436d2e55d39bc6b8f816c9dfd3604cd3894 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index 92e9d4ebc5e8d..94778fae2d91d 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -481,6 +481,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -996,6 +1007,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From c872bc54ebbd8ca141bd8bc107c978d2767f0241 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index e92535ebb5287..7465b4b48c829 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static int pn532_receive_buf(struct serdev_device *serdev,
+
+ del_timer(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From 6f1c973008e7bd4e054012ae5c127f4df3bc3ea3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 20ccdd60353be..ac4bd2d4fdda6 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -1664,12 +1664,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From 5b07972c657651efd796f477a2da9cfda99af0de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 8f070ee7e7426..30fca2169aa7a 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -608,8 +608,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
dmaengine-xilinx_dma-program-interrupt-delay-timeout.patch
dmaengine-xilinx_dma-fix-reset-related-timeout-with-.patch
futex-clear-stale-exiting-pointer-in-futex_lock_pi-retry-path.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+net-qrtr-add-gfp-flags-parameter-to-qrtr_alloc_ctrl_.patch
+net-qrtr-release-distant-nodes-along-the-bridge-node.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
--- /dev/null
+From dd89bb9db624a0cd4c7e56aac6e466e7784c9d5d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index e8be9e5a244fd..954a51fe0cd70 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12232,7 +12232,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From 3ad4e46b4acc6891cfdaf3dc748d603f49b525ef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index 768df9d7cd676..a9d8ee2c68b6a 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -451,10 +460,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -470,23 +488,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -512,12 +523,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -534,18 +547,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -620,7 +642,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -755,12 +777,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From fd1aa338dcaff471ab3e6cbf79e13edcb63cc708 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index 1d04fb42f13f2..09232c424446b 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -6214,6 +6214,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From e078f7ef5f90db06c38ddaad062db337772d666d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 78daffc474899..13eede4c43d48 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -10599,8 +10599,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From ad7cfcbff32f0915894b2b411f201d21588f7b64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 17:29:22 +0800
+Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit b0db1accbc7395657c2b79db59fa9fae0d6656f3 ]
+
+check_mem_access() matches PTR_TO_BUF via base_type() which strips
+PTR_MAYBE_NULL, allowing direct dereference without a null check.
+
+Map iterator ctx->key and ctx->value are PTR_TO_BUF | PTR_MAYBE_NULL.
+On stop callbacks these are NULL, causing a kernel NULL dereference.
+
+Add a type_may_be_null() guard to the PTR_TO_BUF branch, matching the
+existing PTR_TO_BTF_ID pattern.
+
+Fixes: 20b2aff4bc15 ("bpf: Introduce MEM_RDONLY flag")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 13eede4c43d48..e2d49eab8c3d5 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -4572,7 +4572,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ } else if (reg->type == CONST_PTR_TO_MAP) {
+ err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+ value_regno);
+- } else if (base_type(reg->type) == PTR_TO_BUF) {
++ } else if (base_type(reg->type) == PTR_TO_BUF &&
++ !type_may_be_null(reg->type)) {
+ bool rdonly_mem = type_is_rdonly_mem(reg->type);
+ const char *buf_info;
+ u32 *max_access;
+--
+2.53.0
+
--- /dev/null
+From dfbb411134eb80dd3fce19c81f102359a5c13f16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index 3db1def4437b3..a44d14b94865e 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -248,12 +248,12 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -261,7 +261,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -278,6 +278,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -465,9 +467,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 25b412feb294ed2c4202a883c6e191c62e085869 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 11:53:46 +0100
+Subject: btrfs: don't take device_list_mutex when querying zone info
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 77603ab10429fe713a03345553ca8dbbfb1d91c6 ]
+
+Shin'ichiro reported sporadic hangs when running generic/013 in our CI
+system. When enabling lockdep, there is a lockdep splat when calling
+btrfs_get_dev_zone_info_all_devices() in the mount path that can be
+triggered by i.e. generic/013:
+
+ ======================================================
+ WARNING: possible circular locking dependency detected
+ 7.0.0-rc1+ #355 Not tainted
+ ------------------------------------------------------
+ mount/1043 is trying to acquire lock:
+ ffff8881020b5470 (&vblk->vdev_mutex){+.+.}-{4:4}, at: virtblk_report_zones+0xda/0x430
+
+ but task is already holding lock:
+ ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #4 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
+ __mutex_lock+0xa3/0x1360
+ btrfs_create_pending_block_groups+0x1f4/0x9d0
+ __btrfs_end_transaction+0x3e/0x2e0
+ btrfs_zoned_reserve_data_reloc_bg+0x2f8/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #3 (btrfs_trans_num_extwriters){++++}-{0:0}:
+ join_transaction+0xc2/0x5c0
+ start_transaction+0x17c/0xbc0
+ btrfs_zoned_reserve_data_reloc_bg+0x2b4/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #2 (btrfs_trans_num_writers){++++}-{0:0}:
+ lock_release+0x163/0x4b0
+ __btrfs_end_transaction+0x1c7/0x2e0
+ btrfs_dirty_inode+0x6f/0xd0
+ touch_atime+0xe5/0x2c0
+ btrfs_file_mmap_prepare+0x65/0x90
+ __mmap_region+0x4b9/0xf00
+ mmap_region+0xf7/0x120
+ do_mmap+0x43d/0x610
+ vm_mmap_pgoff+0xd6/0x190
+ ksys_mmap_pgoff+0x7e/0xc0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #1 (&mm->mmap_lock){++++}-{4:4}:
+ __might_fault+0x68/0xa0
+ _copy_to_user+0x22/0x70
+ blkdev_copy_zone_to_user+0x22/0x40
+ virtblk_report_zones+0x282/0x430
+ blkdev_report_zones_ioctl+0xfd/0x130
+ blkdev_ioctl+0x20f/0x2c0
+ __x64_sys_ioctl+0x86/0xd0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #0 (&vblk->vdev_mutex){+.+.}-{4:4}:
+ __lock_acquire+0x1522/0x2680
+ lock_acquire+0xd5/0x2f0
+ __mutex_lock+0xa3/0x1360
+ virtblk_report_zones+0xda/0x430
+ blkdev_report_zones_cached+0x162/0x190
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ other info that might help us debug this:
+
+ Chain exists of:
+ &vblk->vdev_mutex --> btrfs_trans_num_extwriters --> &fs_devs->device_list_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&fs_devs->device_list_mutex);
+ lock(btrfs_trans_num_extwriters);
+ lock(&fs_devs->device_list_mutex);
+ lock(&vblk->vdev_mutex);
+
+ *** DEADLOCK ***
+
+ 3 locks held by mount/1043:
+ #0: ffff88811063e878 (&fc->uapi_mutex){+.+.}-{4:4}, at: __do_sys_fsconfig+0x2ae/0x680
+ #1: ffff88810cb9f0e8 (&type->s_umount_key#31/1){+.+.}-{4:4}, at: alloc_super+0xc0/0x3e0
+ #2: ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 1043 Comm: mount Not tainted 7.0.0-rc1+ #355 PREEMPT(full)
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x80
+ print_circular_bug.cold+0x18d/0x1d8
+ check_noncircular+0x10d/0x130
+ __lock_acquire+0x1522/0x2680
+ ? vmap_small_pages_range_noflush+0x3ef/0x820
+ lock_acquire+0xd5/0x2f0
+ ? virtblk_report_zones+0xda/0x430
+ ? lock_is_held_type+0xcd/0x130
+ __mutex_lock+0xa3/0x1360
+ ? virtblk_report_zones+0xda/0x430
+ ? virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ ? virtblk_report_zones+0xda/0x430
+ virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ blkdev_report_zones_cached+0x162/0x190
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ ? rcu_is_watching+0x18/0x50
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ RIP: 0033:0x7f615e27a40e
+ RSP: 002b:00007fff11b18fb8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ RAX: ffffffffffffffda RBX: 000055572e92ab10 RCX: 00007f615e27a40e
+ RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ RBP: 00007fff11b19100 R08: 0000000000000000 R09: 0000000000000000
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055572e92bc40 R14: 00007f615e3faa60 R15: 000055572e92bd08
+ </TASK>
+
+Don't hold the device_list_mutex while calling into
+btrfs_get_dev_zone_info() in btrfs_get_dev_zone_info_all_devices() to
+mitigate the issue. This is safe, as no other thread can touch the device
+list at the moment of execution.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 8c858f31bdbc0..bff56f87b426a 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -313,7 +313,10 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (!btrfs_fs_incompat(fs_info, ZONED))
+ return 0;
+
+- mutex_lock(&fs_devices->device_list_mutex);
++ /*
++ * No need to take the device_list mutex here, we're still in the mount
++ * path and devices cannot be added to or removed from the list yet.
++ */
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ /* We can skip reading of zone info for missing devices */
+ if (!device->bdev)
+@@ -323,7 +326,6 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (ret)
+ break;
+ }
+- mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
+ }
+--
+2.53.0
+
--- /dev/null
+From 687de106fe9e0cfb92a3a4d0c895f2be2519ddfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Mar 2026 08:14:43 +0800
+Subject: btrfs: reject root items with drop_progress and zero drop_level
+
+From: ZhengYuan Huang <gality369@gmail.com>
+
+[ Upstream commit b17b79ff896305fd74980a5f72afec370ee88ca4 ]
+
+[BUG]
+When recovering relocation at mount time, merge_reloc_root() and
+btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
+an impossible state: a non-zero drop_progress combined with a zero
+drop_level in a root_item, which can be triggered:
+
+------------[ cut here ]------------
+kernel BUG at fs/btrfs/relocation.c:1545!
+Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
+CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
+Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
+RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
+Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
+Call Trace:
+ merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
+ btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
+ btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
+ open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
+ btrfs_fill_super fs/btrfs/super.c:987 [inline]
+ btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
+ btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
+ btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
+ vfs_get_tree+0x9a/0x370 fs/super.c:1758
+ fc_mount fs/namespace.c:1199 [inline]
+ do_new_mount_fc fs/namespace.c:3642 [inline]
+ do_new_mount fs/namespace.c:3718 [inline]
+ path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
+ do_mount fs/namespace.c:4041 [inline]
+ __do_sys_mount fs/namespace.c:4229 [inline]
+ __se_sys_mount fs/namespace.c:4206 [inline]
+ __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
+ ...
+RIP: 0033:0x7f969c9a8fde
+Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
+---[ end trace 0000000000000000 ]---
+
+The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
+metadata fuzzing tool that corrupts btrfs metadata at runtime.
+
+[CAUSE]
+A non-zero drop_progress.objectid means an interrupted
+btrfs_drop_snapshot() left a resume point on disk, and in that case
+drop_level must be greater than 0 because the checkpoint is only
+saved at internal node levels.
+
+Although this invariant is enforced when the kernel writes the root
+item, it is not validated when the root item is read back from disk.
+That allows on-disk corruption to provide an invalid state with
+drop_progress.objectid != 0 and drop_level == 0.
+
+When relocation recovery later processes such a root item,
+merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
+same invalid metadata can also trigger the corresponding BUG_ON() in
+btrfs_drop_snapshot().
+
+[FIX]
+Fix this by validating the root_item invariant in tree-checker when
+reading root items from disk: if drop_progress.objectid is non-zero,
+drop_level must also be non-zero. Reject such malformed metadata with
+-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
+and triggers the BUG_ON.
+
+After the fix, the same corruption is correctly rejected by tree-checker
+and the BUG_ON is no longer triggered.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index b0afa47032104..e370ad75072c7 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -1187,6 +1187,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
+ btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
+ return -EUCLEAN;
+ }
++ /*
++ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
++ * interrupted and the resume point was recorded in drop_progress and
++ * drop_level. In that case drop_level must be >= 1: level 0 is the
++ * leaf level and drop_snapshot never saves a checkpoint there (it
++ * only records checkpoints at internal node levels in DROP_REFERENCE
++ * stage). A zero drop_level combined with a non-zero drop_progress
++ * objectid indicates on-disk corruption and would cause a BUG_ON in
++ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
++ */
++ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
++ btrfs_root_drop_level(&ri) == 0)) {
++ generic_err(leaf, slot,
++ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
++ btrfs_disk_key_objectid(&ri.drop_progress));
++ return -EUCLEAN;
++ }
+
+ /* Flags check */
+ if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
+--
+2.53.0
+
--- /dev/null
+From e2a15e19d90861bd8e56492526e8e5acc4d56bb0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 658d5c3c88b7b..631ee6a220d5b 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -515,8 +515,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From 4672e3353be96d33df6248af28dd3ad0f7a2eeee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Mar 2026 16:59:55 -0500
+Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix
+ common property warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 398c0c8bbc8f5a9d2f43863275a427a9d3720b6f ]
+
+Change additionalProperties to unevaluatedProperties because it refs to
+/schemas/input/matrix-keymap.yaml.
+
+Fix below CHECK_DTBS warnings:
+arch/arm/boot/dts/nxp/imx/imx6dl-victgo.dtb: keypad@70 (holtek,ht16k33): 'keypad,num-columns', 'keypad,num-rows' do not match any of the regexes: '^pinctrl-[0-9]+$'
+ from schema $id: http://devicetree.org/schemas/auxdisplay/holtek,ht16k33.yaml#
+
+Fixes: f12b457c6b25c ("dt-bindings: auxdisplay: ht16k33: Convert to json-schema")
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../devicetree/bindings/auxdisplay/holtek,ht16k33.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+index 64ffff4600260..3ee00bcfcf827 100644
+--- a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++++ b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+@@ -46,7 +46,7 @@ required:
+ - reg
+ - refresh-rate-hz
+
+-additionalProperties: false
++unevaluatedProperties: false
+
+ examples:
+ - |
+--
+2.53.0
+
--- /dev/null
+From 5dc7bf5682b93f0c1df181959d740b0948c7d34c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 30769b37aabe7..7a092a2a1bf00 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -472,12 +472,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 0452aeac749403b783438aee1ce088142e9a7868 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 0ab473f372ad0..0cc979d99b3d8 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1258,10 +1258,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From 5a2f189c0cc64e4a42f6d291c61f5478783880b9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 7c1b5d01f8203..53930c28b6946 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -603,11 +603,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From 843d6604aa7d7551e68a23ad7487fa08d56233f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index a30ff5d6808aa..d8af31805133f 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -756,6 +756,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -917,9 +918,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -962,12 +967,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From 050488467d4eda4b4ba2dcc4dac9a9fb136f327c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index 8601c76f3cc93..6f053874de741 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -674,6 +674,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From d69e520ae1edea69cfdd2c8cd3b8b8742fe916c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 68038aa522db0..4b50898e45be9 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3547,12 +3547,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From c7ae95b865d06dd5c5fd89a423445c1f2d08f4f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 11:22:43 +0200
+Subject: net: hsr: fix VLAN add unwind on slave errors
+
+From: Luka Gejak <luka.gejak@linux.dev>
+
+[ Upstream commit 2e3514e63bfb0e972b1f19668547a455d0129e88 ]
+
+When vlan_vid_add() fails for a secondary slave, the error path calls
+vlan_vid_del() on the failing port instead of the peer slave that had
+already succeeded. This results in asymmetric VLAN state across the HSR
+pair.
+
+Fix this by switching to a centralized unwind path that removes the VID
+from any slave device that was already programmed.
+
+Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
+Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
+Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index 85537b245aaeb..0d7550f7498e1 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -476,8 +476,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+ {
+- bool is_slave_a_added = false;
+- bool is_slave_b_added = false;
++ struct net_device *slave_a_dev = NULL;
++ struct net_device *slave_b_dev = NULL;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+@@ -493,33 +493,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+- /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+- if (is_slave_b_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_a_added = true;
++ slave_a_dev = port->dev;
+ break;
+-
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+- /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+- if (is_slave_a_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_b_added = true;
++ slave_b_dev = port->dev;
+ break;
+ default:
++ if (ret)
++ goto unwind;
+ break;
+ }
+ }
+
+ return 0;
++
++unwind:
++ if (slave_a_dev)
++ vlan_vid_del(slave_a_dev, proto, vid);
++
++ if (slave_b_dev)
++ vlan_vid_del(slave_b_dev, proto, vid);
++
++ return ret;
+ }
+
+ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+--
+2.53.0
+
--- /dev/null
+From a47b5eb6afc1a29197435feda48f7d3a11c3d300 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index ceb85c67ce395..bb528d0ddb73a 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From 4dda93635ce6193bf6318ba899dad4a56c54ad6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 1821c1aa97ad4..74e82982ecd08 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1155,6 +1155,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From 3c63912b45574fb232b7166509bfe883e9a602b7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index f66d22de5168d..4dd0cec2e5423 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -110,10 +110,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 0092bc9309d7fb72c0323ef6bb756aef09b4cfce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 4dd0cec2e5423..34e249e0e5860 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -97,10 +97,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -114,8 +114,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 3e1f38aef0cde2026a84be00401a1a4204c61aba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index 7d56a927081d0..e8a676b08e4b1 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -54,9 +54,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index 016d26f809a59..31ef43f871308 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -776,48 +776,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index 3f3ea8d268ce4..1c047c5e5fb02 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -206,8 +206,8 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ #ifdef CONFIG_MLX5_CORE_EN
+ int mlx5e_init(void);
+--
+2.53.0
+
--- /dev/null
+From a4b281cbfde451db3c4c4412f59248c01d8bd802 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index c7a8260fa6ddb..431fd1f2b80c1 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -116,7 +116,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -127,7 +127,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -170,6 +170,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -187,11 +188,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -226,9 +225,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -267,12 +264,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -324,9 +322,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -594,7 +590,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -622,6 +618,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -644,10 +641,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From f0c67743a88f8a0528531ee2573405ed248dfefd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 3b12c3534b1b3..4c8ab5b05b663 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2672,6 +2672,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From f6a08c5320cd52524b7bf8399b09aa5aa0496c74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 22ed49748302f..74a6dbd234213 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -501,8 +501,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From bb6c57ed40cdbe5a174253793dd20cd8d42638d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index a2f53aee39097..a4ffee135c855 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -245,8 +245,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From bcc3e7f5e4fa67565facdecda10d695e919053bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index c398917652db8..f6c81c247418a 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -556,7 +556,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -599,7 +599,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From 642543e865ef198c4e77af165c1cef2acf8216b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 77ad186507f64..956e056803079 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 4ba757cf45a53a28736facbe732a06e94d72b06f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index e1c4197af468e..77ad186507f64 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (!more && x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From a2aeb822cfbf8270d270998adc18c319551fc0f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index 54087ce1c07cd..3b04867a1fcad 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -103,7 +103,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -129,7 +129,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From 0994b094b7d07614de98402b78c78fc816d56345 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 5087ab9b137f2..def356f828cd8 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3580,6 +3580,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From f7e91cef15079a8d6f7ff1c811efcd95fd860fc4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:17:09 +0100
+Subject: netfilter: flowtable: strictly check for maximum number of actions
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 76522fcdbc3a02b568f5d957f7e66fc194abb893 ]
+
+The maximum number of flowtable hardware offload actions in IPv6 is:
+
+* ethernet mangling (4 payload actions, 2 for each ethernet address)
+* SNAT (4 payload actions)
+* DNAT (4 payload actions)
+* Double VLAN (4 vlan actions, 2 for popping vlan, and 2 for pushing)
+ for QinQ.
+* Redirect (1 action)
+
+Which makes 17, while the maximum is 16. But act_ct supports for tunnels
+actions too. Note that payload action operates at 32-bit word level, so
+mangling an IPv6 address takes 4 payload actions.
+
+Update flow_action_entry_next() calls to check for the maximum number of
+supported actions.
+
+While at it, rise the maximum number of actions per flow from 16 to 24
+so this works fine with IPv6 setups.
+
+Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_offload.c | 196 +++++++++++++++++---------
+ 1 file changed, 130 insertions(+), 66 deletions(-)
+
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index d8cb304f809e5..dcbae058c59a3 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -13,6 +13,8 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
+
++#define NF_FLOW_RULE_ACTION_MAX 24
++
+ static struct workqueue_struct *nf_flow_offload_add_wq;
+ static struct workqueue_struct *nf_flow_offload_del_wq;
+ static struct workqueue_struct *nf_flow_offload_stats_wq;
+@@ -204,7 +206,12 @@ static void flow_offload_mangle(struct flow_action_entry *entry,
+ static inline struct flow_action_entry *
+ flow_action_entry_next(struct nf_flow_rule *flow_rule)
+ {
+- int i = flow_rule->rule->action.num_entries++;
++ int i;
++
++ if (unlikely(flow_rule->rule->action.num_entries >= NF_FLOW_RULE_ACTION_MAX))
++ return NULL;
++
++ i = flow_rule->rule->action.num_entries++;
+
+ return &flow_rule->rule->action.entries[i];
+ }
+@@ -222,6 +229,9 @@ static int flow_offload_eth_src(struct net *net,
+ u32 mask, val;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -272,6 +282,9 @@ static int flow_offload_eth_dst(struct net *net,
+ u8 nud_state;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -313,16 +326,19 @@ static int flow_offload_eth_dst(struct net *net,
+ return 0;
+ }
+
+-static void flow_offload_ipv4_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
+@@ -333,23 +349,27 @@ static void flow_offload_ipv4_snat(struct net *net,
+ offset = offsetof(struct iphdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
+@@ -360,14 +380,15 @@ static void flow_offload_ipv4_dnat(struct net *net,
+ offset = offsetof(struct iphdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
++static int flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+ unsigned int offset,
+ const __be32 *addr, const __be32 *mask)
+ {
+@@ -376,15 +397,20 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+
+ for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i++) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
++
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
+ offset + i * sizeof(u32), &addr[i], mask);
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_ipv6_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -400,16 +426,16 @@ static void flow_offload_ipv6_snat(struct net *net,
+ offset = offsetof(struct ipv6hdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+-static void flow_offload_ipv6_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -425,10 +451,10 @@ static void flow_offload_ipv6_dnat(struct net *net,
+ offset = offsetof(struct ipv6hdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+ static int flow_offload_l4proto(const struct flow_offload *flow)
+@@ -450,15 +476,18 @@ static int flow_offload_l4proto(const struct flow_offload *flow)
+ return type;
+ }
+
+-static void flow_offload_port_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
+@@ -473,22 +502,26 @@ static void flow_offload_port_snat(struct net *net,
+ mask = ~htonl(0xffff);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_port_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port);
+@@ -503,20 +536,24 @@ static void flow_offload_port_dnat(struct net *net,
+ mask = ~htonl(0xffff0000);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_checksum(struct net *net,
+- const struct flow_offload *flow,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_checksum(struct net *net,
++ const struct flow_offload *flow,
++ struct nf_flow_rule *flow_rule)
+ {
+ u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+
++ if (!entry)
++ return -E2BIG;
++
+ entry->id = FLOW_ACTION_CSUM;
+ entry->csum_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+@@ -528,12 +565,14 @@ static void flow_offload_ipv4_checksum(struct net *net,
+ entry->csum_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+ break;
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_redirect(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_redirect(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple, *other_tuple;
+ struct flow_action_entry *entry;
+@@ -551,21 +590,28 @@ static void flow_offload_redirect(struct net *net,
+ ifindex = other_tuple->iifidx;
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ dev = dev_get_by_index(net, ifindex);
+ if (!dev)
+- return;
++ return -ENODEV;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry) {
++ dev_put(dev);
++ return -E2BIG;
++ }
++
+ entry->id = FLOW_ACTION_REDIRECT;
+ entry->dev = dev;
++
++ return 0;
+ }
+
+-static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_encap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple;
+ struct flow_action_entry *entry;
+@@ -573,7 +619,7 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+
+ this_tuple = &flow->tuplehash[dir].tuple;
+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = this_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -582,15 +628,19 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+ entry->tunnel = tun_info;
+ }
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_decap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *other_tuple;
+ struct flow_action_entry *entry;
+@@ -598,7 +648,7 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+
+ other_tuple = &flow->tuplehash[!dir].tuple;
+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = other_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -607,9 +657,13 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_DECAP;
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -621,8 +675,9 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ const struct flow_offload_tuple *tuple;
+ int i;
+
+- flow_offload_decap_tunnel(flow, dir, flow_rule);
+- flow_offload_encap_tunnel(flow, dir, flow_rule);
++ if (flow_offload_decap_tunnel(flow, dir, flow_rule) < 0 ||
++ flow_offload_encap_tunnel(flow, dir, flow_rule) < 0)
++ return -1;
+
+ if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
+ flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
+@@ -638,6 +693,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+
+ if (tuple->encap[i].proto == htons(ETH_P_8021Q)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+ entry->id = FLOW_ACTION_VLAN_POP;
+ }
+ }
+@@ -651,6 +708,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ continue;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+
+ switch (other_tuple->encap[i].proto) {
+ case htons(ETH_P_PPP_SES):
+@@ -676,18 +735,22 @@ int nf_flow_rule_route_ipv4(struct net *net, const struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv4_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_SNAT, &flow->flags) ||
+ test_bit(NF_FLOW_DNAT, &flow->flags))
+- flow_offload_ipv4_checksum(net, flow, flow_rule);
++ if (flow_offload_ipv4_checksum(net, flow, flow_rule) < 0)
++ return -1;
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+@@ -701,22 +764,23 @@ int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv6_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
+
+-#define NF_FLOW_RULE_ACTION_MAX 16
+-
+ static struct nf_flow_rule *
+ nf_flow_offload_rule_alloc(struct net *net,
+ const struct flow_offload_work *offload,
+--
+2.53.0
+
--- /dev/null
+From 42dd568a0b9075b44ed7a987e8081f679c056907 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index 0b217d4ae2a48..d82413e6098a7 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -309,7 +309,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 72e5638206c0e..0e2c9e94a1c88 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -823,7 +823,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -832,7 +832,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 5cc35b553a048..7d1ba6ad514f5 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From 387adf2bfef33a3a32d321c901e754e0f841efd8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index de5ac9f431031..b5f4bfc60f897 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -469,7 +469,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+
+ /* Maybe someone has gotten the helper already when unhelp above.
+--
+2.53.0
+
--- /dev/null
+From fac33d670cf46d4e1cc4a6dcb8049344ca63c9f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 3c845d6a340fb..53d7dd39a95bc 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -10232,8 +10232,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -10268,6 +10266,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From eb426d853767417edd5c694c8cd992a3ef5cd1d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index 6484d08223dbc..37d10c3d19b60 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -715,7 +715,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From eb977a03ca700909db8f666cd3f4e639efe6f026 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c0f5e9a4f3c65..bfc98719684e2 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -53,6 +53,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -85,6 +88,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 50af1caa7ade2f3336d494d0e6818a7944948250 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index 6303ba7a62a2f..9c0ec0bbb5699 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -501,6 +501,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -1016,6 +1027,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From d72c2fb688a5c67f4827b943c3d48ac309a7a7ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index 7ad98973648cc..615ceff0adeee 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static int pn532_receive_buf(struct serdev_device *serdev,
+
+ del_timer(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From 7e7b43fa4229e1be92f71949b46f3a313cd77eb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index d2366ec61edc4..72a7e49dec276 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -1759,12 +1759,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From f9b5c7238ec1c3c6fc4ef57c2247d0644ecfde18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 8f070ee7e7426..30fca2169aa7a 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -608,8 +608,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
dmaengine-xilinx_dma-program-interrupt-delay-timeout.patch
dmaengine-xilinx_dma-fix-reset-related-timeout-with-.patch
futex-clear-stale-exiting-pointer-in-futex_lock_pi-retry-path.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+btrfs-don-t-take-device_list_mutex-when-querying-zon.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+btrfs-reject-root-items-with-drop_progress-and-zero-.patch
+dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+netfilter-flowtable-strictly-check-for-maximum-numbe.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+net-hsr-fix-vlan-add-unwind-on-slave-errors.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
+bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch
--- /dev/null
+From dd4e7f2d9819b10f99e114d9ee965f5d3db76638 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index bd3b56c7aab8d..e18e58f8258e6 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12223,7 +12223,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From 03a6ef544d77dc0bee5c19f3a63a2edcba6f8857 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:09:09 +0100
+Subject: ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on
+ failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+
+[ Upstream commit 622363757b2286dd2c2984b0d80255cbb35a0495 ]
+
+ep93xx_i2s_enable() calls clk_prepare_enable() on three clocks in
+sequence (mclk, sclk, lrclk) without checking the return value of any
+of them. If an intermediate enable fails, the clocks that were already
+enabled are never rolled back, leaking them until the next disable cycle
+— which may never come if the stream never started cleanly.
+
+Change ep93xx_i2s_enable() from void to int. Add error checking after
+each clk_prepare_enable() call and unwind already-enabled clocks on
+failure. Propagate the error through ep93xx_i2s_startup() and
+ep93xx_i2s_resume(), both of which already return int.
+
+Signed-off-by: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+Fixes: f4ff6b56bc8a ("ASoC: cirrus: i2s: Prepare clock before using it")
+Link: https://patch.msgid.link/20260324210909.45494-1-jihed.chaibi.dev@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/cirrus/ep93xx-i2s.c | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
+index 46160796af31a..f5034b03740f7 100644
+--- a/sound/soc/cirrus/ep93xx-i2s.c
++++ b/sound/soc/cirrus/ep93xx-i2s.c
+@@ -104,16 +104,28 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ return __raw_readl(info->regs + reg);
+ }
+
+-static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
++static int ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ {
+ unsigned base_reg;
++ int err;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+- clk_prepare_enable(info->mclk);
+- clk_prepare_enable(info->sclk);
+- clk_prepare_enable(info->lrclk);
++ err = clk_prepare_enable(info->mclk);
++ if (err)
++ return err;
++ err = clk_prepare_enable(info->sclk);
++ if (err) {
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
++ err = clk_prepare_enable(info->lrclk);
++ if (err) {
++ clk_disable_unprepare(info->sclk);
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+@@ -132,6 +144,8 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
+ EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
+ EP93XX_I2S_TXCTRL_TXUFIE);
++
++ return 0;
+ }
+
+ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+@@ -213,9 +227,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ {
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+- ep93xx_i2s_enable(info, substream->stream);
+-
+- return 0;
++ return ep93xx_i2s_enable(info, substream->stream);
+ }
+
+ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+@@ -389,14 +401,16 @@ static int ep93xx_i2s_suspend(struct snd_soc_component *component)
+ static int ep93xx_i2s_resume(struct snd_soc_component *component)
+ {
+ struct ep93xx_i2s_info *info = snd_soc_component_get_drvdata(component);
++ int err;
+
+ if (!snd_soc_component_active(component))
+ return 0;
+
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
++ err = ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
++ if (err)
++ return err;
+
+- return 0;
++ return ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ #else
+ #define ep93xx_i2s_suspend NULL
+--
+2.53.0
+
--- /dev/null
+From 90bd0d291f54fc040680b5cd5accd7ee87fa92a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Apr 2023 00:39:00 +0200
+Subject: ASoC: ep93xx: i2s: move enable call to startup callback
+
+From: Alexander Sverdlin <alexander.sverdlin@gmail.com>
+
+[ Upstream commit 80f47122538d40b1a6a2c1a3c2d37b6e51b74224 ]
+
+Make startup/shutdown callbacks symmetric to avoid clock subsystem warnings
+(reproduced with "aplay --dump-hw-params" + ctrl-c):
+
+WARNING: CPU: 0 PID: 102 at drivers/clk/clk.c:1048 clk_core_disable
+lrclk already disabled
+CPU: 0 PID: 102 Comm: aplay Not tainted 6.2.0-rc4 #1
+Hardware name: Generic DT based system
+ ...
+ clk_core_disable from clk_core_disable_lock
+ clk_core_disable_lock from ep93xx_i2s_shutdown
+ ep93xx_i2s_shutdown from snd_soc_dai_shutdown
+ snd_soc_dai_shutdown from soc_pcm_clean
+ soc_pcm_clean from soc_pcm_close
+ soc_pcm_close from snd_pcm_release_substream.part.0
+ snd_pcm_release_substream.part.0 from snd_pcm_release
+ snd_pcm_release from __fput
+ __fput from task_work_run
+ ...
+
+WARNING: CPU: 0 PID: 102 at drivers/clk/clk.c:907 clk_core_unprepare
+lrclk already unprepared
+CPU: 0 PID: 102 Comm: aplay Tainted: G W 6.2.0-rc4 #1
+Hardware name: Generic DT based system
+ ...
+ clk_core_unprepare from clk_unprepare
+ clk_unprepare from ep93xx_i2s_shutdown
+ ep93xx_i2s_shutdown from snd_soc_dai_shutdown
+ snd_soc_dai_shutdown from soc_pcm_clean
+ soc_pcm_clean from soc_pcm_close
+ soc_pcm_close from snd_pcm_release_substream.part.0
+ snd_pcm_release_substream.part.0 from snd_pcm_release
+ snd_pcm_release from __fput
+ __fput from task_work_run
+ ...
+
+Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
+Link: https://lore.kernel.org/r/20230410223902.2321834-2-alexander.sverdlin@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 622363757b22 ("ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/cirrus/ep93xx-i2s.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
+index 982151330c896..46160796af31a 100644
+--- a/sound/soc/cirrus/ep93xx-i2s.c
++++ b/sound/soc/cirrus/ep93xx-i2s.c
+@@ -208,6 +208,16 @@ static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
+ return 0;
+ }
+
++static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
++
++ ep93xx_i2s_enable(info, substream->stream);
++
++ return 0;
++}
++
+ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+ {
+@@ -348,7 +358,6 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
+ if (err)
+ return err;
+
+- ep93xx_i2s_enable(info, substream->stream);
+ return 0;
+ }
+
+@@ -395,6 +404,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component)
+ #endif
+
+ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
++ .startup = ep93xx_i2s_startup,
+ .shutdown = ep93xx_i2s_shutdown,
+ .hw_params = ep93xx_i2s_hw_params,
+ .set_sysclk = ep93xx_i2s_set_sysclk,
+--
+2.53.0
+
--- /dev/null
+From 72318dd696338010186f713e64b250d60da05e9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index 0d4b8e5936dcf..d8ab969625790 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From c3906212aa6ce12a00686db1eaf57d27ba4f616a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:02 +0300
+Subject: Bluetooth: hci_event: fix potential UAF in
+ hci_le_remote_conn_param_req_evt
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit b255531b27da336571411248c2a72a350662bd09 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_le_remote_conn_param_req_evt, otherwise it's possible it is freed
+concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage.
+
+Fixes: 95118dd4edfec ("Bluetooth: hci_event: Use of a function table to handle LE subevents")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 33 ++++++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index f713a9a27e934..1f05204ae1fe3 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -6629,25 +6629,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ latency = le16_to_cpu(ev->latency);
+ timeout = le16_to_cpu(ev->timeout);
+
++ hci_dev_lock(hdev);
++
+ hcon = hci_conn_hash_lookup_handle(hdev, handle);
+- if (!hcon || hcon->state != BT_CONNECTED)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_UNKNOWN_CONN_ID);
++ if (!hcon || hcon->state != BT_CONNECTED) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_UNKNOWN_CONN_ID);
++ goto unlock;
++ }
+
+- if (max > hcon->le_conn_max_interval)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (max > hcon->le_conn_max_interval) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+- if (hci_check_conn_params(min, max, latency, timeout))
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (hci_check_conn_params(min, max, latency, timeout)) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+ if (hcon->role == HCI_ROLE_MASTER) {
+ struct hci_conn_params *params;
+ u8 store_hint;
+
+- hci_dev_lock(hdev);
+-
+ params = hci_conn_params_lookup(hdev, &hcon->dst,
+ hcon->dst_type);
+ if (params) {
+@@ -6660,8 +6666,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ store_hint = 0x00;
+ }
+
+- hci_dev_unlock(hdev);
+-
+ mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
+ store_hint, min, max, latency, timeout);
+ }
+@@ -6675,6 +6679,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ cp.max_ce_len = 0;
+
+ hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
+--
+2.53.0
+
--- /dev/null
+From 6928569040cf96ade491c554da105e4596b9090a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index b89c3fc364b83..abbb17f1a025f 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -7224,6 +7224,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From f11d56f397bb380a4ebb14fad0f6935983b2349c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 22:25:26 +0800
+Subject: Bluetooth: MGMT: validate mesh send advertising payload length
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit bda93eec78cdbfe5cda00785cefebd443e56b88b ]
+
+mesh_send() currently bounds MGMT_OP_MESH_SEND by total command
+length, but it never verifies that the bytes supplied for the
+flexible adv_data[] array actually match the embedded adv_data_len
+field. MGMT_MESH_SEND_SIZE only covers the fixed header, so a
+truncated command can still pass the existing 20..50 byte range
+check and later drive the async mesh send path past the end of the
+queued command buffer.
+
+Keep rejecting zero-length and oversized advertising payloads, but
+validate adv_data_len explicitly and require the command length to
+exactly match the flexible array size before queueing the request.
+
+Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index abbb17f1a025f..c4f5268d5c507 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -2471,6 +2471,7 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ struct mgmt_mesh_tx *mesh_tx;
+ struct mgmt_cp_mesh_send *send = data;
+ struct mgmt_rp_mesh_read_features rp;
++ u16 expected_len;
+ bool sending;
+ int err = 0;
+
+@@ -2478,12 +2479,19 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ !hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_NOT_SUPPORTED);
+- if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
+- len <= MGMT_MESH_SEND_SIZE ||
+- len > (MGMT_MESH_SEND_SIZE + 31))
++ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_REJECTED);
++
++ if (!send->adv_data_len || send->adv_data_len > 31)
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_REJECTED);
+
++ expected_len = struct_size(send, adv_data, send->adv_data_len);
++ if (expected_len != len)
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_INVALID_PARAMS);
++
+ hci_dev_lock(hdev);
+
+ memset(&rp, 0, sizeof(rp));
+--
+2.53.0
+
--- /dev/null
+From 454c8b807f97ea86e701dc2b0c15df1fea68aa57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 23:16:45 +0800
+Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect()
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit 8a5b0135d4a5d9683203a3d9a12a711ccec5936b ]
+
+sco_sock_connect() checks sk_state and sk_type without holding
+the socket lock. Two concurrent connect() syscalls on the same
+socket can both pass the check and enter sco_connect(), leading
+to use-after-free.
+
+The buggy scenario involves three participants and was confirmed
+with additional logging instrumentation:
+
+ Thread A (connect): HCI disconnect: Thread B (connect):
+
+ sco_sock_connect(sk) sco_sock_connect(sk)
+ sk_state==BT_OPEN sk_state==BT_OPEN
+ (pass, no lock) (pass, no lock)
+ sco_connect(sk): sco_connect(sk):
+ hci_dev_lock hci_dev_lock
+ hci_connect_sco <- blocked
+ -> hcon1
+ sco_conn_add->conn1
+ lock_sock(sk)
+ sco_chan_add:
+ conn1->sk = sk
+ sk->conn = conn1
+ sk_state=BT_CONNECT
+ release_sock
+ hci_dev_unlock
+ hci_dev_lock
+ sco_conn_del:
+ lock_sock(sk)
+ sco_chan_del:
+ sk->conn=NULL
+ conn1->sk=NULL
+ sk_state=
+ BT_CLOSED
+ SOCK_ZAPPED
+ release_sock
+ hci_dev_unlock
+ (unblocked)
+ hci_connect_sco
+ -> hcon2
+ sco_conn_add
+ -> conn2
+ lock_sock(sk)
+ sco_chan_add:
+ sk->conn=conn2
+ sk_state=
+ BT_CONNECT
+ // zombie sk!
+ release_sock
+ hci_dev_unlock
+
+Thread B revives a BT_CLOSED + SOCK_ZAPPED socket back to
+BT_CONNECT. Subsequent cleanup triggers double sock_put() and
+use-after-free. Meanwhile conn1 is leaked as it was orphaned
+when sco_conn_del() cleared the association.
+
+Fix this by:
+- Moving lock_sock() before the sk_state/sk_type checks in
+ sco_sock_connect() to serialize concurrent connect attempts
+- Fixing the sk_type != SOCK_SEQPACKET check to actually
+ return the error instead of just assigning it
+- Adding a state re-check in sco_connect() after lock_sock()
+ to catch state changes during the window between the locks
+- Adding sco_pi(sk)->conn check in sco_chan_add() to prevent
+ double-attach of a socket to multiple connections
+- Adding hci_conn_drop() on sco_chan_add failure to prevent
+ HCI connection leaks
+
+Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm")
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/sco.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 94c90d472f317..eebbbe6deacdd 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -239,7 +239,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+ int err = 0;
+
+ sco_conn_lock(conn);
+- if (conn->sk)
++ if (conn->sk || sco_pi(sk)->conn)
+ err = -EBUSY;
+ else
+ __sco_chan_add(conn, sk, parent);
+@@ -293,9 +293,20 @@ static int sco_connect(struct sock *sk)
+
+ lock_sock(sk);
+
++ /* Recheck state after reacquiring the socket lock, as another
++ * thread may have changed it (e.g., closed the socket).
++ */
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
++ hci_conn_drop(hcon);
++ err = -EBADFD;
++ goto unlock;
++ }
++
+ err = sco_chan_add(conn, sk, NULL);
+ if (err) {
+ release_sock(sk);
++ hci_conn_drop(hcon);
+ goto unlock;
+ }
+
+@@ -613,13 +624,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
+ addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
+- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
++ lock_sock(sk);
++
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
+ return -EBADFD;
++ }
+
+- if (sk->sk_type != SOCK_SEQPACKET)
+- err = -EINVAL;
++ if (sk->sk_type != SOCK_SEQPACKET) {
++ release_sock(sk);
++ return -EINVAL;
++ }
+
+- lock_sock(sk);
+ /* Set destination address and psm */
+ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
+ release_sock(sk);
+--
+2.53.0
+
--- /dev/null
+From 27a7ebc26f9cf2ac337b63ad6e521eb8ffdde08f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 74c56ed5ddcbb..59f53fea9e3c6 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -11832,8 +11832,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From 5decedb24d276d397b09e4e0ae4fe295b18981d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 17:29:22 +0800
+Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit b0db1accbc7395657c2b79db59fa9fae0d6656f3 ]
+
+check_mem_access() matches PTR_TO_BUF via base_type() which strips
+PTR_MAYBE_NULL, allowing direct dereference without a null check.
+
+Map iterator ctx->key and ctx->value are PTR_TO_BUF | PTR_MAYBE_NULL.
+On stop callbacks these are NULL, causing a kernel NULL dereference.
+
+Add a type_may_be_null() guard to the PTR_TO_BUF branch, matching the
+existing PTR_TO_BTF_ID pattern.
+
+Fixes: 20b2aff4bc15 ("bpf: Introduce MEM_RDONLY flag")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 59f53fea9e3c6..d8d3616abceb6 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -5139,7 +5139,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ } else if (reg->type == CONST_PTR_TO_MAP) {
+ err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+ value_regno);
+- } else if (base_type(reg->type) == PTR_TO_BUF) {
++ } else if (base_type(reg->type) == PTR_TO_BUF &&
++ !type_may_be_null(reg->type)) {
+ bool rdonly_mem = type_is_rdonly_mem(reg->type);
+ u32 *max_access;
+
+--
+2.53.0
+
--- /dev/null
+From ff9576b115d71c5563463a11efdf87a779797927 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index b45c00c01dea1..2852ac69101c0 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -248,12 +248,12 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -261,7 +261,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -278,6 +278,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -465,9 +467,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 8cdee1a2fe6cedda04c4298efcda174b0e960f9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 11:53:46 +0100
+Subject: btrfs: don't take device_list_mutex when querying zone info
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 77603ab10429fe713a03345553ca8dbbfb1d91c6 ]
+
+Shin'ichiro reported sporadic hangs when running generic/013 in our CI
+system. When enabling lockdep, there is a lockdep splat when calling
+btrfs_get_dev_zone_info_all_devices() in the mount path that can be
+triggered by i.e. generic/013:
+
+ ======================================================
+ WARNING: possible circular locking dependency detected
+ 7.0.0-rc1+ #355 Not tainted
+ ------------------------------------------------------
+ mount/1043 is trying to acquire lock:
+ ffff8881020b5470 (&vblk->vdev_mutex){+.+.}-{4:4}, at: virtblk_report_zones+0xda/0x430
+
+ but task is already holding lock:
+ ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #4 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
+ __mutex_lock+0xa3/0x1360
+ btrfs_create_pending_block_groups+0x1f4/0x9d0
+ __btrfs_end_transaction+0x3e/0x2e0
+ btrfs_zoned_reserve_data_reloc_bg+0x2f8/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #3 (btrfs_trans_num_extwriters){++++}-{0:0}:
+ join_transaction+0xc2/0x5c0
+ start_transaction+0x17c/0xbc0
+ btrfs_zoned_reserve_data_reloc_bg+0x2b4/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #2 (btrfs_trans_num_writers){++++}-{0:0}:
+ lock_release+0x163/0x4b0
+ __btrfs_end_transaction+0x1c7/0x2e0
+ btrfs_dirty_inode+0x6f/0xd0
+ touch_atime+0xe5/0x2c0
+ btrfs_file_mmap_prepare+0x65/0x90
+ __mmap_region+0x4b9/0xf00
+ mmap_region+0xf7/0x120
+ do_mmap+0x43d/0x610
+ vm_mmap_pgoff+0xd6/0x190
+ ksys_mmap_pgoff+0x7e/0xc0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #1 (&mm->mmap_lock){++++}-{4:4}:
+ __might_fault+0x68/0xa0
+ _copy_to_user+0x22/0x70
+ blkdev_copy_zone_to_user+0x22/0x40
+ virtblk_report_zones+0x282/0x430
+ blkdev_report_zones_ioctl+0xfd/0x130
+ blkdev_ioctl+0x20f/0x2c0
+ __x64_sys_ioctl+0x86/0xd0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #0 (&vblk->vdev_mutex){+.+.}-{4:4}:
+ __lock_acquire+0x1522/0x2680
+ lock_acquire+0xd5/0x2f0
+ __mutex_lock+0xa3/0x1360
+ virtblk_report_zones+0xda/0x430
+ blkdev_report_zones_cached+0x162/0x190
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ other info that might help us debug this:
+
+ Chain exists of:
+ &vblk->vdev_mutex --> btrfs_trans_num_extwriters --> &fs_devs->device_list_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&fs_devs->device_list_mutex);
+ lock(btrfs_trans_num_extwriters);
+ lock(&fs_devs->device_list_mutex);
+ lock(&vblk->vdev_mutex);
+
+ *** DEADLOCK ***
+
+ 3 locks held by mount/1043:
+ #0: ffff88811063e878 (&fc->uapi_mutex){+.+.}-{4:4}, at: __do_sys_fsconfig+0x2ae/0x680
+ #1: ffff88810cb9f0e8 (&type->s_umount_key#31/1){+.+.}-{4:4}, at: alloc_super+0xc0/0x3e0
+ #2: ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 1043 Comm: mount Not tainted 7.0.0-rc1+ #355 PREEMPT(full)
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x80
+ print_circular_bug.cold+0x18d/0x1d8
+ check_noncircular+0x10d/0x130
+ __lock_acquire+0x1522/0x2680
+ ? vmap_small_pages_range_noflush+0x3ef/0x820
+ lock_acquire+0xd5/0x2f0
+ ? virtblk_report_zones+0xda/0x430
+ ? lock_is_held_type+0xcd/0x130
+ __mutex_lock+0xa3/0x1360
+ ? virtblk_report_zones+0xda/0x430
+ ? virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ ? virtblk_report_zones+0xda/0x430
+ virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ blkdev_report_zones_cached+0x162/0x190
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ ? rcu_is_watching+0x18/0x50
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ RIP: 0033:0x7f615e27a40e
+ RSP: 002b:00007fff11b18fb8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ RAX: ffffffffffffffda RBX: 000055572e92ab10 RCX: 00007f615e27a40e
+ RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ RBP: 00007fff11b19100 R08: 0000000000000000 R09: 0000000000000000
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055572e92bc40 R14: 00007f615e3faa60 R15: 000055572e92bd08
+ </TASK>
+
+Don't hold the device_list_mutex while calling into
+btrfs_get_dev_zone_info() in btrfs_get_dev_zone_info_all_devices() to
+mitigate the issue. This is safe, as no other thread can touch the device
+list at the moment of execution.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index ba03ea17a10f7..4e2ed51297ea1 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -332,7 +332,10 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (!btrfs_fs_incompat(fs_info, ZONED))
+ return 0;
+
+- mutex_lock(&fs_devices->device_list_mutex);
++ /*
++ * No need to take the device_list mutex here, we're still in the mount
++ * path and devices cannot be added to or removed from the list yet.
++ */
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ /* We can skip reading of zone info for missing devices */
+ if (!device->bdev)
+@@ -342,7 +345,6 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (ret)
+ break;
+ }
+- mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
+ }
+--
+2.53.0
+
--- /dev/null
+From 3cd9bede1e55fde8a6ec4273e2b6662c776b36c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Mar 2026 08:14:43 +0800
+Subject: btrfs: reject root items with drop_progress and zero drop_level
+
+From: ZhengYuan Huang <gality369@gmail.com>
+
+[ Upstream commit b17b79ff896305fd74980a5f72afec370ee88ca4 ]
+
+[BUG]
+When recovering relocation at mount time, merge_reloc_root() and
+btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
+an impossible state: a non-zero drop_progress combined with a zero
+drop_level in a root_item, which can be triggered:
+
+------------[ cut here ]------------
+kernel BUG at fs/btrfs/relocation.c:1545!
+Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
+CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
+Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
+RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
+Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
+Call Trace:
+ merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
+ btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
+ btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
+ open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
+ btrfs_fill_super fs/btrfs/super.c:987 [inline]
+ btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
+ btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
+ btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
+ vfs_get_tree+0x9a/0x370 fs/super.c:1758
+ fc_mount fs/namespace.c:1199 [inline]
+ do_new_mount_fc fs/namespace.c:3642 [inline]
+ do_new_mount fs/namespace.c:3718 [inline]
+ path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
+ do_mount fs/namespace.c:4041 [inline]
+ __do_sys_mount fs/namespace.c:4229 [inline]
+ __se_sys_mount fs/namespace.c:4206 [inline]
+ __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
+ ...
+RIP: 0033:0x7f969c9a8fde
+Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
+---[ end trace 0000000000000000 ]---
+
+The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
+metadata fuzzing tool that corrupts btrfs metadata at runtime.
+
+[CAUSE]
+A non-zero drop_progress.objectid means an interrupted
+btrfs_drop_snapshot() left a resume point on disk, and in that case
+drop_level must be greater than 0 because the checkpoint is only
+saved at internal node levels.
+
+Although this invariant is enforced when the kernel writes the root
+item, it is not validated when the root item is read back from disk.
+That allows on-disk corruption to provide an invalid state with
+drop_progress.objectid != 0 and drop_level == 0.
+
+When relocation recovery later processes such a root item,
+merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
+same invalid metadata can also trigger the corresponding BUG_ON() in
+btrfs_drop_snapshot().
+
+[FIX]
+Fix this by validating the root_item invariant in tree-checker when
+reading root items from disk: if drop_progress.objectid is non-zero,
+drop_level must also be non-zero. Reject such malformed metadata with
+-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
+and triggers the BUG_ON.
+
+After the fix, the same corruption is correctly rejected by tree-checker
+and the BUG_ON is no longer triggered.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index cafd7055ab090..0b1ab9b6b84b4 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -1204,6 +1204,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
+ btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
+ return -EUCLEAN;
+ }
++ /*
++ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
++ * interrupted and the resume point was recorded in drop_progress and
++ * drop_level. In that case drop_level must be >= 1: level 0 is the
++ * leaf level and drop_snapshot never saves a checkpoint there (it
++ * only records checkpoints at internal node levels in DROP_REFERENCE
++ * stage). A zero drop_level combined with a non-zero drop_progress
++ * objectid indicates on-disk corruption and would cause a BUG_ON in
++ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
++ */
++ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
++ btrfs_root_drop_level(&ri) == 0)) {
++ generic_err(leaf, slot,
++ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
++ btrfs_disk_key_objectid(&ri.drop_progress));
++ return -EUCLEAN;
++ }
+
+ /* Flags check */
+ if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
+--
+2.53.0
+
--- /dev/null
+From ed78013f42f94885fd2cb2412a4cce612d6d5464 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 4b7a7d9e198e1..1bb0ab702c98d 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -512,8 +512,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From 437c6f4e7e6db38559341da3b7ec2e1bafb3514a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Mar 2026 16:59:55 -0500
+Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix
+ common property warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 398c0c8bbc8f5a9d2f43863275a427a9d3720b6f ]
+
+Change additionalProperties to unevaluatedProperties because it refs to
+/schemas/input/matrix-keymap.yaml.
+
+Fix below CHECK_DTBS warnings:
+arch/arm/boot/dts/nxp/imx/imx6dl-victgo.dtb: keypad@70 (holtek,ht16k33): 'keypad,num-columns', 'keypad,num-rows' do not match any of the regexes: '^pinctrl-[0-9]+$'
+ from schema $id: http://devicetree.org/schemas/auxdisplay/holtek,ht16k33.yaml#
+
+Fixes: f12b457c6b25c ("dt-bindings: auxdisplay: ht16k33: Convert to json-schema")
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../devicetree/bindings/auxdisplay/holtek,ht16k33.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+index fc4873deb76f3..8f4759030a8ca 100644
+--- a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++++ b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+@@ -65,7 +65,7 @@ then:
+ required:
+ - refresh-rate-hz
+
+-additionalProperties: false
++unevaluatedProperties: false
+
+ examples:
+ - |
+--
+2.53.0
+
--- /dev/null
+From 374ed0982e5b8926217a46bf44ee5dafaf0733b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index b6c2cb7153fde..0039508943626 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -472,12 +472,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From bc8c571e94fea86cfc231b411c204503818e8ee3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 3837394f29a0b..614f2adab5635 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1253,10 +1253,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From 5b387b1eeabdbdc6c6db3d4a0bc43266690255a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:32:11 +0900
+Subject: i2c: tegra: Don't mark devices with pins as IRQ safe
+
+From: Mikko Perttunen <mperttunen@nvidia.com>
+
+[ Upstream commit ec69c9e88315c4be70c283f18c2ff130da6320b5 ]
+
+I2C devices with associated pinctrl states (DPAUX I2C controllers)
+will change pinctrl state during runtime PM. This requires taking
+a mutex, so these devices cannot be marked as IRQ safe.
+
+Add PINCTRL as dependency to avoid build errors.
+
+Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
+Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/Kconfig | 2 ++
+ drivers/i2c/busses/i2c-tegra.c | 5 ++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index e50f9603d189e..3dfdf91a5085b 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -1114,6 +1114,8 @@ config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
+ # COMPILE_TEST needs architectures with readsX()/writesX() primitives
++ depends on PINCTRL
++ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
+index 850d76d9114c4..7e25e6fb915a2 100644
+--- a/drivers/i2c/busses/i2c-tegra.c
++++ b/drivers/i2c/busses/i2c-tegra.c
+@@ -1816,8 +1816,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
+ *
+ * VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
+ * be used for atomic transfers. ACPI device is not IRQ safe also.
++ *
++ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
++ * state transitions during runtime PM require mutexes.
+ */
+- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
++ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
+ pm_runtime_irq_safe(i2c_dev->dev);
+
+ pm_runtime_enable(i2c_dev->dev);
+--
+2.53.0
+
--- /dev/null
+From 4a85cc38b0e31d3286e6cb6057de04ef4115f614 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 8ce36fcc3dd5b..a1a2e785063c3 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From ead7f65444831fb88b26e3a07514db91f29d8bb6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index e70ace403bbd0..4b8b9626428ca 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -761,6 +761,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -922,9 +923,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -967,12 +972,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From 85a93dc3b906b6800d2046b9b2560561bd4c97a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index ea1cdacbdcf1b..80eabb22d144f 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -677,6 +677,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From 928a302093f51fdd57c59fb8836d73165c728b5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index d6a33452dd369..801ecec3c15ba 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3566,12 +3566,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From d900e9e5ed8fdf2b90faa41936b9f8bf2de5c84f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 11:22:43 +0200
+Subject: net: hsr: fix VLAN add unwind on slave errors
+
+From: Luka Gejak <luka.gejak@linux.dev>
+
+[ Upstream commit 2e3514e63bfb0e972b1f19668547a455d0129e88 ]
+
+When vlan_vid_add() fails for a secondary slave, the error path calls
+vlan_vid_del() on the failing port instead of the peer slave that had
+already succeeded. This results in asymmetric VLAN state across the HSR
+pair.
+
+Fix this by switching to a centralized unwind path that removes the VID
+from any slave device that was already programmed.
+
+Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
+Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
+Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index 81eaae4c19da1..48f34ad9219fd 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -473,8 +473,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+ {
+- bool is_slave_a_added = false;
+- bool is_slave_b_added = false;
++ struct net_device *slave_a_dev = NULL;
++ struct net_device *slave_b_dev = NULL;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+@@ -490,33 +490,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+- /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+- if (is_slave_b_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_a_added = true;
++ slave_a_dev = port->dev;
+ break;
+-
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+- /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+- if (is_slave_a_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_b_added = true;
++ slave_b_dev = port->dev;
+ break;
+ default:
++ if (ret)
++ goto unwind;
+ break;
+ }
+ }
+
+ return 0;
++
++unwind:
++ if (slave_a_dev)
++ vlan_vid_del(slave_a_dev, proto, vid);
++
++ if (slave_b_dev)
++ vlan_vid_del(slave_b_dev, proto, vid);
++
++ return ret;
+ }
+
+ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+--
+2.53.0
+
--- /dev/null
+From b70c88d45d932382c1ce5d07dab68825583c30a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index 18481eb76a0a4..eb0d517aa6cb3 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From e8b1d08e3a81101fd20dd3ff9f16b200daae6fde Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 15:41:52 +0800
+Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 5e67ba9bb531e1ec6599a82a065dea9040b9ce50 ]
+
+ioam6_fill_trace_data() stores the schema contribution to the trace
+length in a u8. With bit 22 enabled and the largest schema payload,
+sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
+remaining-space check. __ioam6_fill_trace_data() then positions the
+write cursor without reserving the schema area but still copies the
+4-byte schema header and the full schema payload, overrunning the trace
+buffer.
+
+Keep sclen in an unsigned int so the remaining-space check and the write
+cursor calculation both see the full schema length.
+
+Fixes: 8c6f6fa67726 ("ipv6: ioam: IOAM Generic Netlink API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ioam6.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
+index a35b6fdbc93e9..a1953cf6131be 100644
+--- a/net/ipv6/ioam6.c
++++ b/net/ipv6/ioam6.c
+@@ -648,7 +648,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
+ struct ioam6_namespace *ns,
+ struct ioam6_trace_hdr *trace,
+ struct ioam6_schema *sc,
+- u8 sclen, bool is_input)
++ unsigned int sclen, bool is_input)
+ {
+ struct timespec64 ts;
+ ktime_t tstamp;
+@@ -878,7 +878,7 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
+ bool is_input)
+ {
+ struct ioam6_schema *sc;
+- u8 sclen = 0;
++ unsigned int sclen = 0;
+
+ /* Skip if Overflow flag is set
+ */
+--
+2.53.0
+
--- /dev/null
+From c3637b46ce6736b8c86495fbdb2c4e376d6d0a11 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index affbf12d44f57..f1c4c4dbefb0c 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1216,6 +1216,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From 851bfcf116d0a726a9f1be90186c4b5ec3b13351 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index f66d22de5168d..4dd0cec2e5423 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -110,10 +110,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From d61a14cfd2ba39ef3432618e21deeb68309a7efc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 4dd0cec2e5423..34e249e0e5860 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -97,10 +97,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -114,8 +114,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 28425c78523dbeb2c52a6c68d29c98ee88968ff1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index 64dcfac9ce724..fbeea3e539109 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -54,9 +54,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index 9e26dda93f8ee..d2e4546a1efd0 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -808,48 +808,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index 07b5c86fc26a4..67c1afc1df8f5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -262,8 +262,8 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ #ifdef CONFIG_MLX5_CORE_EN
+ int mlx5e_init(void);
+--
+2.53.0
+
--- /dev/null
+From eefc990784ed96e56e7f9646994a251e38e84c5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:13 +0300
+Subject: net/mlx5: lag: Check for LAG device before creating debugfs
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit bf16bca6653679d8a514d6c1c5a2c67065033f14 ]
+
+__mlx5_lag_dev_add_mdev() may return 0 (success) even when an error
+occurs that is handled gracefully. Consequently, the initialization
+flow proceeds to call mlx5_ldev_add_debugfs() even when there is no
+valid LAG context.
+
+mlx5_ldev_add_debugfs() blindly created the debugfs directory and
+attributes. This exposed interfaces (like the members file) that rely on
+a valid ldev pointer, leading to potential NULL pointer dereferences if
+accessed when ldev is NULL.
+
+Add a check to verify that mlx5_lag_dev(dev) returns a valid pointer
+before attempting to create the debugfs entries.
+
+Fixes: 7f46a0b7327a ("net/mlx5: Lag, add debugfs to query hardware lag state")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Mark Bloch <mbloch@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+index b8feaf0f5c4c8..a372cb13aa08b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+@@ -163,8 +163,11 @@ DEFINE_SHOW_ATTRIBUTE(members);
+
+ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
+ {
++ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+ struct dentry *dbg;
+
++ if (!ldev)
++ return;
+ dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
+ dev->priv.dbg.lag_debugfs = dbg;
+
+--
+2.53.0
+
--- /dev/null
+From 5bf959682b490d77f677b105039c4ac3e5ee6476 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index a59e1b2fea1c5..3831eb25e240a 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -116,7 +116,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -127,7 +127,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -170,6 +170,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -187,11 +188,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -226,9 +225,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -267,12 +264,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -324,9 +322,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -594,7 +590,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -622,6 +618,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -644,10 +641,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From cb2883be8751f8ee3961c6041606a1e5f288ecf0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index e5d4e64ce479c..0ccd8bf57a93b 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2726,6 +2726,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From f5d234bda3aac8c6482daca47e4a6c8cacca1a2b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 7657d86ad1427..64b281cca6ae7 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -501,8 +501,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From f712d8cae8b469ebbafd34606eee5aa39d66bd1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index 6160ef7d646ac..366bcc960e43e 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -245,8 +245,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From 35d7c95c014db5e3cf6004c63ba8e871d472719b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index 302413e0aceff..a01ff859cc03b 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -556,7 +556,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -599,7 +599,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From 275f6add54d0eecdfa24d15b3f88f1681b4dcded Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 0dbc73efab1cb..e47ebd8acd21b 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 475be12b055baa65d797bb8b2f89bd845741c297 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index b981a4828d08c..0dbc73efab1cb 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From 9e4ececca809a76ac6127676a38e2716ca15a373 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index deb94c26c605b..a27f10767867b 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -103,7 +103,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -129,7 +129,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From 63c1b8bf9c8b8172a70416cfd547dc69e8cee479 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 11:26:22 +0200
+Subject: netfilter: ctnetlink: ignore explicit helper on new expectations
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 917b61fa2042f11e2af4c428e43f08199586633a ]
+
+Use the existing master conntrack helper, anything else is not really
+supported and it just makes validation more complicated, so just ignore
+what helper userspace suggests for this expectation.
+
+This was uncovered when validating CTA_EXPECT_CLASS via different helper
+provided by userspace than the existing master conntrack helper:
+
+ BUG: KASAN: slab-out-of-bounds in nf_ct_expect_related_report+0x2479/0x27c0
+ Read of size 4 at addr ffff8880043fe408 by task poc/102
+ Call Trace:
+ nf_ct_expect_related_report+0x2479/0x27c0
+ ctnetlink_create_expect+0x22b/0x3b0
+ ctnetlink_new_expect+0x4bd/0x5c0
+ nfnetlink_rcv_msg+0x67a/0x950
+ netlink_rcv_skb+0x120/0x350
+
+Allowing to read kernel memory bytes off the expectation boundary.
+
+CTA_EXPECT_HELP_NAME is still used to offer the helper name to userspace
+via netlink dump.
+
+Fixes: bd0779370588 ("netfilter: nfnetlink_queue: allow to attach expectations to conntracks")
+Reported-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 54 +++++-----------------------
+ 1 file changed, 9 insertions(+), 45 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 2661441d91faa..89cec02de68ba 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2628,7 +2628,6 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask);
+
+@@ -2857,7 +2856,6 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ {
+ struct nlattr *cda[CTA_EXPECT_MAX+1];
+ struct nf_conntrack_tuple tuple, mask;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ int err;
+
+@@ -2871,17 +2869,8 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ if (err < 0)
+ return err;
+
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+- nf_ct_protonum(ct));
+- if (helper == NULL)
+- return -EOPNOTSUPP;
+- }
+-
+ exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
+- helper, &tuple, &mask);
++ &tuple, &mask);
+ if (IS_ERR(exp))
+ return PTR_ERR(exp);
+
+@@ -3510,11 +3499,11 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+ struct net *net = read_pnet(&ct->ct_net);
++ struct nf_conntrack_helper *helper;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3524,7 +3513,11 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ if (!help)
+ return ERR_PTR(-EOPNOTSUPP);
+
+- if (cda[CTA_EXPECT_CLASS] && helper) {
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return ERR_PTR(-EOPNOTSUPP);
++
++ if (cda[CTA_EXPECT_CLASS]) {
+ class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
+ if (class > helper->expect_class_max)
+ return ERR_PTR(-EINVAL);
+@@ -3558,8 +3551,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+ exp->zone = ct->zone;
+ #endif
+- if (!helper)
+- helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+@@ -3591,7 +3582,6 @@ ctnetlink_create_expect(struct net *net,
+ {
+ struct nf_conntrack_tuple tuple, mask, master_tuple;
+ struct nf_conntrack_tuple_hash *h = NULL;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn *ct;
+ int err;
+@@ -3617,33 +3607,7 @@ ctnetlink_create_expect(struct net *net,
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ rcu_read_lock();
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper == NULL) {
+- rcu_read_unlock();
+-#ifdef CONFIG_MODULES
+- if (request_module("nfct-helper-%s", helpname) < 0) {
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- rcu_read_lock();
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper) {
+- err = -EAGAIN;
+- goto err_rcu;
+- }
+- rcu_read_unlock();
+-#endif
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- }
+-
+- exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
++ exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask);
+ if (IS_ERR(exp)) {
+ err = PTR_ERR(exp);
+ goto err_rcu;
+@@ -3653,8 +3617,8 @@ ctnetlink_create_expect(struct net *net,
+ nf_ct_expect_put(exp);
+ err_rcu:
+ rcu_read_unlock();
+-err_ct:
+ nf_ct_put(ct);
++
+ return err;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From df6600d14225ccd6e4cf001adef9b2ab1f7886cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 6190a1d062402..c5480f952f157 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3569,6 +3569,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From 833eb354987976f55e85145d3a1a3b38cea8ad46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:17:09 +0100
+Subject: netfilter: flowtable: strictly check for maximum number of actions
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 76522fcdbc3a02b568f5d957f7e66fc194abb893 ]
+
+The maximum number of flowtable hardware offload actions in IPv6 is:
+
+* ethernet mangling (4 payload actions, 2 for each ethernet address)
+* SNAT (4 payload actions)
+* DNAT (4 payload actions)
+* Double VLAN (4 vlan actions, 2 for popping vlan, and 2 for pushing)
+ for QinQ.
+* Redirect (1 action)
+
+Which makes 17, while the maximum is 16. But act_ct supports for tunnels
+actions too. Note that payload action operates at 32-bit word level, so
+mangling an IPv6 address takes 4 payload actions.
+
+Update flow_action_entry_next() calls to check for the maximum number of
+supported actions.
+
+While at it, rise the maximum number of actions per flow from 16 to 24
+so this works fine with IPv6 setups.
+
+Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_offload.c | 196 +++++++++++++++++---------
+ 1 file changed, 130 insertions(+), 66 deletions(-)
+
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index 1904a4f295d4a..cd8bce176ae88 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -13,6 +13,8 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
+
++#define NF_FLOW_RULE_ACTION_MAX 24
++
+ static struct workqueue_struct *nf_flow_offload_add_wq;
+ static struct workqueue_struct *nf_flow_offload_del_wq;
+ static struct workqueue_struct *nf_flow_offload_stats_wq;
+@@ -215,7 +217,12 @@ static void flow_offload_mangle(struct flow_action_entry *entry,
+ static inline struct flow_action_entry *
+ flow_action_entry_next(struct nf_flow_rule *flow_rule)
+ {
+- int i = flow_rule->rule->action.num_entries++;
++ int i;
++
++ if (unlikely(flow_rule->rule->action.num_entries >= NF_FLOW_RULE_ACTION_MAX))
++ return NULL;
++
++ i = flow_rule->rule->action.num_entries++;
+
+ return &flow_rule->rule->action.entries[i];
+ }
+@@ -233,6 +240,9 @@ static int flow_offload_eth_src(struct net *net,
+ u32 mask, val;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -283,6 +293,9 @@ static int flow_offload_eth_dst(struct net *net,
+ u8 nud_state;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -324,16 +337,19 @@ static int flow_offload_eth_dst(struct net *net,
+ return 0;
+ }
+
+-static void flow_offload_ipv4_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
+@@ -344,23 +360,27 @@ static void flow_offload_ipv4_snat(struct net *net,
+ offset = offsetof(struct iphdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
+@@ -371,14 +391,15 @@ static void flow_offload_ipv4_dnat(struct net *net,
+ offset = offsetof(struct iphdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
++static int flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+ unsigned int offset,
+ const __be32 *addr, const __be32 *mask)
+ {
+@@ -387,15 +408,20 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+
+ for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i++) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
++
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
+ offset + i * sizeof(u32), &addr[i], mask);
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_ipv6_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -411,16 +437,16 @@ static void flow_offload_ipv6_snat(struct net *net,
+ offset = offsetof(struct ipv6hdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+-static void flow_offload_ipv6_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -436,10 +462,10 @@ static void flow_offload_ipv6_dnat(struct net *net,
+ offset = offsetof(struct ipv6hdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+ static int flow_offload_l4proto(const struct flow_offload *flow)
+@@ -461,15 +487,18 @@ static int flow_offload_l4proto(const struct flow_offload *flow)
+ return type;
+ }
+
+-static void flow_offload_port_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
+@@ -484,22 +513,26 @@ static void flow_offload_port_snat(struct net *net,
+ mask = ~htonl(0xffff);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_port_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port);
+@@ -514,20 +547,24 @@ static void flow_offload_port_dnat(struct net *net,
+ mask = ~htonl(0xffff0000);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_checksum(struct net *net,
+- const struct flow_offload *flow,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_checksum(struct net *net,
++ const struct flow_offload *flow,
++ struct nf_flow_rule *flow_rule)
+ {
+ u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+
++ if (!entry)
++ return -E2BIG;
++
+ entry->id = FLOW_ACTION_CSUM;
+ entry->csum_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+@@ -539,12 +576,14 @@ static void flow_offload_ipv4_checksum(struct net *net,
+ entry->csum_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+ break;
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_redirect(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_redirect(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple, *other_tuple;
+ struct flow_action_entry *entry;
+@@ -562,21 +601,28 @@ static void flow_offload_redirect(struct net *net,
+ ifindex = other_tuple->iifidx;
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ dev = dev_get_by_index(net, ifindex);
+ if (!dev)
+- return;
++ return -ENODEV;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry) {
++ dev_put(dev);
++ return -E2BIG;
++ }
++
+ entry->id = FLOW_ACTION_REDIRECT;
+ entry->dev = dev;
++
++ return 0;
+ }
+
+-static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_encap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple;
+ struct flow_action_entry *entry;
+@@ -584,7 +630,7 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+
+ this_tuple = &flow->tuplehash[dir].tuple;
+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = this_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -593,15 +639,19 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+ entry->tunnel = tun_info;
+ }
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_decap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *other_tuple;
+ struct flow_action_entry *entry;
+@@ -609,7 +659,7 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+
+ other_tuple = &flow->tuplehash[!dir].tuple;
+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = other_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -618,9 +668,13 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_DECAP;
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -632,8 +686,9 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ const struct flow_offload_tuple *tuple;
+ int i;
+
+- flow_offload_decap_tunnel(flow, dir, flow_rule);
+- flow_offload_encap_tunnel(flow, dir, flow_rule);
++ if (flow_offload_decap_tunnel(flow, dir, flow_rule) < 0 ||
++ flow_offload_encap_tunnel(flow, dir, flow_rule) < 0)
++ return -1;
+
+ if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
+ flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
+@@ -649,6 +704,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+
+ if (tuple->encap[i].proto == htons(ETH_P_8021Q)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+ entry->id = FLOW_ACTION_VLAN_POP;
+ }
+ }
+@@ -662,6 +719,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ continue;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+
+ switch (other_tuple->encap[i].proto) {
+ case htons(ETH_P_PPP_SES):
+@@ -687,18 +746,22 @@ int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv4_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_SNAT, &flow->flags) ||
+ test_bit(NF_FLOW_DNAT, &flow->flags))
+- flow_offload_ipv4_checksum(net, flow, flow_rule);
++ if (flow_offload_ipv4_checksum(net, flow, flow_rule) < 0)
++ return -1;
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+@@ -712,22 +775,23 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv6_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
+
+-#define NF_FLOW_RULE_ACTION_MAX 16
+-
+ static struct nf_flow_rule *
+ nf_flow_offload_rule_alloc(struct net *net,
+ const struct flow_offload_work *offload,
+--
+2.53.0
+
--- /dev/null
+From 3cce5bf4404cdcf36a1e4ef6f68fe70b5d30c822 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index 0b217d4ae2a48..d82413e6098a7 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -309,7 +309,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 56215fb63b645..f4f65fa948ff8 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -823,7 +823,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -832,7 +832,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 5cc35b553a048..7d1ba6ad514f5 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From ddd2b5d7e1fd378cb2ac0f7c92cc894e467e29b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:02 +0100
+Subject: netfilter: nf_conntrack_expect: honor expectation helper field
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 9c42bc9db90a154bc61ae337a070465f3393485a ]
+
+The expectation helper field is mostly unused. As a result, the
+netfilter codebase relies on accessing the helper through exp->master.
+
+Always set on the expectation helper field so it can be used to reach
+the helper.
+
+nf_ct_expect_init() is called from packet path where the skb owns
+the ct object, therefore accessing exp->master for the newly created
+expectation is safe. This saves a lot of updates in all callsites
+to pass the ct object as parameter to nf_ct_expect_init().
+
+This is a preparation patches for follow up fixes.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 2 +-
+ net/netfilter/nf_conntrack_broadcast.c | 2 +-
+ net/netfilter/nf_conntrack_expect.c | 14 +++++++++++++-
+ net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------
+ net/netfilter/nf_conntrack_helper.c | 7 ++++++-
+ net/netfilter/nf_conntrack_netlink.c | 2 +-
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 7 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 165e7a03b8e9d..1b01400b10bdb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -40,7 +40,7 @@ struct nf_conntrack_expect {
+ struct nf_conntrack_expect *this);
+
+ /* Helper to assign to new connection */
+- struct nf_conntrack_helper *helper;
++ struct nf_conntrack_helper __rcu *helper;
+
+ /* The conntrack of the master connection */
+ struct nf_conn *master;
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 9fb9b80312989..721b3e87416be 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -70,7 +70,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->expectfn = NULL;
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+- exp->helper = NULL;
++ rcu_assign_pointer(exp->helper, helper);
+
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 7bc64eb89bac4..43c6fc0576177 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -309,12 +309,19 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
+
++/* This function can only be used from packet path, where accessing
++ * master's helper is safe, because the packet holds a reference on
++ * the conntrack object. Never use it from control plane.
++ */
+ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ u_int8_t family,
+ const union nf_inet_addr *saddr,
+ const union nf_inet_addr *daddr,
+ u_int8_t proto, const __be16 *src, const __be16 *dst)
+ {
++ struct nf_conntrack_helper *helper = NULL;
++ struct nf_conn *ct = exp->master;
++ struct nf_conn_help *help;
+ int len;
+
+ if (family == AF_INET)
+@@ -325,7 +332,12 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ exp->flags = 0;
+ exp->class = class;
+ exp->expectfn = NULL;
+- exp->helper = NULL;
++
++ help = nfct_help(ct);
++ if (help)
++ helper = rcu_dereference(help->helper);
++
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
+index ed983421e2eb2..791aafe9f3960 100644
+--- a/net/netfilter/nf_conntrack_h323_main.c
++++ b/net/netfilter/nf_conntrack_h323_main.c
+@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = &nf_conntrack_helper_h245;
++ rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3 : NULL,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+ exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_UDP, NULL, &port);
+- exp->helper = nf_conntrack_helper_ras;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect RAS ");
+@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 2a15176731fe8..bc66589d2194b 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -402,7 +402,7 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (exp->helper == me)
++ if (rcu_access_pointer(exp->helper) == me)
+ return true;
+
+ this = rcu_dereference_protected(help->helper,
+@@ -424,6 +424,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
++
++ /* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
++ * last step, this ensures rcu readers of exp->helper are done.
++ * No need for another synchronize_rcu() here.
++ */
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index c5480f952f157..296386c7983f3 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3559,7 +3559,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+ exp->mask.src.u.all = mask->src.u.all;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 84334537c6067..6ae30a4cf3601 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -1303,7 +1303,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
+ nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
+ saddr, &daddr, proto, NULL, &port);
+ exp->timeout.expires = sip_timeout * HZ;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
+
+ hooks = rcu_dereference(nf_nat_sip_hooks);
+--
+2.53.0
+
--- /dev/null
+From 044f6016db39f6807593ef4d8302d5e40ee914db Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 22:39:55 +0100
+Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 02a3231b6d82efe750da6554ebf280e4a6f78756 ]
+
+__nf_ct_expect_find() and nf_ct_expect_find_get() are called under
+rcu_read_lock() but they dereference the master conntrack via
+exp->master.
+
+Since the expectation does not hold a reference on the master conntrack,
+this could be dying conntrack or different recycled conntrack than the
+real master due to SLAB_TYPESAFE_RCU.
+
+Store the netns, the master_tuple and the zone in struct
+nf_conntrack_expect as a safety measure.
+
+This patch is required by the follow up fix not to dump expectations
+that do not belong to this netns.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++++++++++-
+ net/netfilter/nf_conntrack_broadcast.c | 6 +++++-
+ net/netfilter/nf_conntrack_expect.c | 9 +++++++--
+ net/netfilter/nf_conntrack_netlink.c | 5 +++++
+ 4 files changed, 34 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 1b01400b10bdb..e9a8350e7ccfb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
+ /* Hash member */
+ struct hlist_node hnode;
+
++ /* Network namespace */
++ possible_net_t net;
++
+ /* We expect this tuple, with the following mask */
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
+
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ struct nf_conntrack_zone zone;
++#endif
+ /* Usage count. */
+ refcount_t use;
+
+@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
+
+ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
+ {
+- return nf_ct_net(exp->master);
++ return read_pnet(&exp->net);
++}
++
++static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
++ const struct nf_conntrack_zone *b)
++{
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ return a->zone.id == b->id;
++#else
++ return true;
++#endif
+ }
+
+ #define NF_CT_EXP_POLICY_NAME_LEN 16
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 721b3e87416be..d44d9379a8a08 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ unsigned int timeout)
+ {
+ const struct nf_conntrack_helper *helper;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = skb_rtable(skb);
+@@ -71,7 +72,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+ rcu_assign_pointer(exp->helper, helper);
+-
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index e0eb844c2cdcb..70bcddfc17ccc 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -112,8 +112,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
+ const struct net *net)
+ {
+ return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+- net_eq(net, nf_ct_net(i->master)) &&
+- nf_ct_zone_equal_any(i->master, zone);
++ net_eq(net, read_pnet(&i->net)) &&
++ nf_ct_exp_zone_equal_any(i, zone);
+ }
+
+ bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
+@@ -321,6 +321,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ {
+ struct nf_conntrack_helper *helper = NULL;
+ struct nf_conn *ct = exp->master;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conn_help *help;
+ int len;
+
+@@ -338,6 +339,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ helper = rcu_dereference(help->helper);
+
+ rcu_assign_pointer(exp->helper, helper);
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 21592a7fa57bd..2661441d91faa 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3514,6 +3514,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3553,6 +3554,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ if (!helper)
+ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+--
+2.53.0
+
--- /dev/null
+From 430196a72ec1653eaddcec74b741abe155d3bcd3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:03 +0100
+Subject: netfilter: nf_conntrack_expect: use expect->helper
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit f01794106042ee27e54af6fdf5b319a2fe3df94d ]
+
+Use expect->helper in ctnetlink and /proc to dump the helper name.
+Using nfct_help() without holding a reference to the master conntrack
+is unsafe.
+
+Use exp->master->helper in ctnetlink path if userspace does not provide
+an explicit helper when creating an expectation to retain the existing
+behaviour. The ctnetlink expectation path holds the reference on the
+master conntrack and nf_conntrack_expect lock and the nfnetlink glue
+path refers to the master ct that is attached to the skb.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_expect.c | 2 +-
+ net/netfilter/nf_conntrack_helper.c | 6 +-----
+ net/netfilter/nf_conntrack_netlink.c | 24 ++++++++++--------------
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 4 files changed, 13 insertions(+), 21 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 43c6fc0576177..e0eb844c2cdcb 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -670,7 +670,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
+ if (expect->flags & NF_CT_EXPECT_USERSPACE)
+ seq_printf(s, "%sUSERSPACE", delim);
+
+- helper = rcu_dereference(nfct_help(expect->master)->helper);
++ helper = rcu_dereference(expect->helper);
+ if (helper) {
+ seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
+ if (helper->expect_policy[expect->class].name[0])
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index bc66589d2194b..6a2ad31ac62f1 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -398,14 +398,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
+
+ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ {
+- struct nf_conn_help *help = nfct_help(exp->master);
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (rcu_access_pointer(exp->helper) == me)
+- return true;
+-
+- this = rcu_dereference_protected(help->helper,
++ this = rcu_dereference_protected(exp->helper,
+ lockdep_is_held(&nf_conntrack_expect_lock));
+ return this == me;
+ }
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 296386c7983f3..21592a7fa57bd 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2998,7 +2998,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ {
+ struct nf_conn *master = exp->master;
+ long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
+- struct nf_conn_help *help;
++ struct nf_conntrack_helper *helper;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+ struct nlattr *nest_parms;
+ struct nf_conntrack_tuple nat_tuple = {};
+@@ -3043,15 +3043,12 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
+ goto nla_put_failure;
+- help = nfct_help(master);
+- if (help) {
+- struct nf_conntrack_helper *helper;
+
+- helper = rcu_dereference(help->helper);
+- if (helper &&
+- nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
+- goto nla_put_failure;
+- }
++ helper = rcu_dereference(exp->helper);
++ if (helper &&
++ nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
++ goto nla_put_failure;
++
+ expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
+ if (expfn != NULL &&
+ nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
+@@ -3380,12 +3377,9 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
+ static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
+ {
+ struct nf_conntrack_helper *helper;
+- const struct nf_conn_help *m_help;
+ const char *name = data;
+
+- m_help = nfct_help(exp->master);
+-
+- helper = rcu_dereference(m_help->helper);
++ helper = rcu_dereference(exp->helper);
+ if (!helper)
+ return false;
+
+@@ -3520,9 +3514,9 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+- u_int32_t class = 0;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
++ u32 class = 0;
+ int err;
+
+ help = nfct_help(ct);
+@@ -3559,6 +3553,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ if (!helper)
++ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 6ae30a4cf3601..fda6fc1fc4c58 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -924,7 +924,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
+
+ if (!exp || exp->master == ct ||
+- nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
++ exp->helper != nfct_help(ct)->helper ||
+ exp->class != class)
+ break;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+--
+2.53.0
+
--- /dev/null
+From ec10e49b61f926112db2f5191bde3f10d62fcd5f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 5545016c107db..2a15176731fe8 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -422,7 +422,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+--
+2.53.0
+
--- /dev/null
+From d6e8713a804b32d94d3f3e53ee0ba9bf70b539df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 7a862290f1b24..fb3d529ebf5ab 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -10468,8 +10468,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -10504,6 +10502,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 2056d1e746f1adc8537c4ea0b0d1b80d0be352d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index 4fcdd9ec8de9b..6bf7d7bea1fc2 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -718,7 +718,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From 5120a59cf7e50fdb11738c032a5e084bf39f13c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 May 2023 18:53:14 +0200
+Subject: netfilter: Reorder fields in 'struct nf_conntrack_expect'
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 61e03e912da8212c3de2529054502e8388dfd484 ]
+
+Group some variables based on their sizes to reduce holes.
+On x86_64, this shrinks the size of 'struct nf_conntrack_expect' from 264
+to 256 bytes.
+
+This structure deserve a dedicated cache, so reducing its size looks nice.
+
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index f642a87ea330a..165e7a03b8e9d 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -26,6 +26,15 @@ struct nf_conntrack_expect {
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
+
++ /* Usage count. */
++ refcount_t use;
++
++ /* Flags */
++ unsigned int flags;
++
++ /* Expectation class */
++ unsigned int class;
++
+ /* Function to call after setup and insertion */
+ void (*expectfn)(struct nf_conn *new,
+ struct nf_conntrack_expect *this);
+@@ -39,15 +48,6 @@ struct nf_conntrack_expect {
+ /* Timer function; deletes the expectation. */
+ struct timer_list timeout;
+
+- /* Usage count. */
+- refcount_t use;
+-
+- /* Flags */
+- unsigned int flags;
+-
+- /* Expectation class */
+- unsigned int class;
+-
+ #if IS_ENABLED(CONFIG_NF_NAT)
+ union nf_inet_addr saved_addr;
+ /* This is the original per-proto part, used to map the
+--
+2.53.0
+
--- /dev/null
+From 7bc6ae672a42c3b6b0a4d931edd579fca0231f01 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c0f5e9a4f3c65..bfc98719684e2 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -53,6 +53,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -85,6 +88,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 6474737229ed7cc3cab085b13b026473e75658bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index c842ec693dad4..650cb725ba271 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -501,6 +501,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -1016,6 +1027,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From d34eb93db1437b75bc033c7dd40c7f2d44ab5c26 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index 07596bf5f7d6d..026d5ef825b59 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static int pn532_receive_buf(struct serdev_device *serdev,
+
+ del_timer(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From 18b715effb94aef65e89e0242837524c14ebd00f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index bf75628c5389a..2754e46f0e5ad 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -1966,12 +1966,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From d26d3dbaf8007ab769d6efea8372701eb664860b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 8f070ee7e7426..30fca2169aa7a 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -608,8 +608,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
dmaengine-xilinx_dma-fix-reset-related-timeout-with-.patch
futex-clear-stale-exiting-pointer-in-futex_lock_pi-retry-path.patch
tcp-fix-bind-regression-for-v6-only-wildcard-and-v4-mapped-v6-non-wildcard-addresses.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+btrfs-don-t-take-device_list_mutex-when-querying-zon.patch
+tg3-replace-placeholder-mac-address-with-device-prop.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch
+btrfs-reject-root-items-with-drop_progress-and-zero-.patch
+dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+asoc-ep93xx-i2s-move-enable-call-to-startup-callback.patch
+asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+netfilter-flowtable-strictly-check-for-maximum-numbe.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-reorder-fields-in-struct-nf_conntrack_expe.patch
+netfilter-nf_conntrack_expect-honor-expectation-help.patch
+netfilter-nf_conntrack_expect-use-expect-helper.patch
+netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch
+netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch
+bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-lag-check-for-lag-device-before-creating-de.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+net-hsr-fix-vlan-add-unwind-on-slave-errors.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
+bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch
--- /dev/null
+From 6b6e24f99f95b3a93248acef9c3ca14df25b8e23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index e93e7d37c8262..5e8c11fc5912a 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12217,7 +12217,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From a0114f9c65462ebb298fc89d1f4b148a03b0dea9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Mar 2026 03:24:30 +0530
+Subject: tg3: replace placeholder MAC address with device property
+
+From: Paul SAGE <paul.sage@42.fr>
+
+[ Upstream commit e4c00ba7274b613e3ab19e27eb009f0ec2e28379 ]
+
+On some systems (e.g. iMac 20,1 with BCM57766), the tg3 driver reads
+a default placeholder mac address (00:10:18:00:00:00) from the
+mailbox. The correct value on those systems are stored in the
+'local-mac-address' property.
+
+This patch, detect the default value and tries to retrieve
+the correct address from the device_get_mac_address
+function instead.
+
+The patch has been tested on two different systems:
+- iMac 20,1 (BCM57766) model which use the local-mac-address property
+- iMac 13,2 (BCM57766) model which can use the mailbox,
+ NVRAM or MAC control registers
+
+Tested-by: Rishon Jonathan R <mithicalaviator85@gmail.com>
+
+Co-developed-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Paul SAGE <paul.sage@42.fr>
+Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index 8e5236142aaca..e93e7d37c8262 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -16950,6 +16950,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
+ return err;
+ }
+
++static int tg3_is_default_mac_address(u8 *addr)
++{
++ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
++
++ return ether_addr_equal(default_mac_address, addr);
++}
++
+ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+ {
+ u32 hi, lo, mac_offset;
+@@ -17021,6 +17028,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+
+ if (!is_valid_ether_addr(addr))
+ return -EINVAL;
++
++ if (tg3_is_default_mac_address(addr))
++ return device_get_mac_address(&tp->pdev->dev, addr);
++
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 702437757a174ee29820e753770c63cffd39f2f5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Mar 2026 14:44:28 +0100
+Subject: arm64/scs: Fix handling of advance_loc4
+
+From: Pepper Gray <hello@peppergray.xyz>
+
+[ Upstream commit d499e9627d70b1269020d59b95ed3e18bee6b8cd ]
+
+DW_CFA_advance_loc4 is defined but no handler is implemented. Its
+CFA opcode defaults to EDYNSCS_INVALID_CFA_OPCODE triggering an
+error which wrongfully prevents modules from loading.
+
+Link: https://bugs.gentoo.org/971060
+Signed-off-by: Pepper Gray <hello@peppergray.xyz>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/pi/patch-scs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c
+index 49d8b40e61bc0..be7050fdfbba0 100644
+--- a/arch/arm64/kernel/pi/patch-scs.c
++++ b/arch/arm64/kernel/pi/patch-scs.c
+@@ -174,6 +174,14 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
+ size -= 2;
+ break;
+
++ case DW_CFA_advance_loc4:
++ loc += *opcode++ * code_alignment_factor;
++ loc += (*opcode++ << 8) * code_alignment_factor;
++ loc += (*opcode++ << 16) * code_alignment_factor;
++ loc += (*opcode++ << 24) * code_alignment_factor;
++ size -= 4;
++ break;
++
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended:
+ size = skip_xleb128(&opcode, size);
+--
+2.53.0
+
--- /dev/null
+From b9fbe56c91fa2b60ca6362b6c065a8268e9685b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:09:09 +0100
+Subject: ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on
+ failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+
+[ Upstream commit 622363757b2286dd2c2984b0d80255cbb35a0495 ]
+
+ep93xx_i2s_enable() calls clk_prepare_enable() on three clocks in
+sequence (mclk, sclk, lrclk) without checking the return value of any
+of them. If an intermediate enable fails, the clocks that were already
+enabled are never rolled back, leaking them until the next disable cycle
+— which may never come if the stream never started cleanly.
+
+Change ep93xx_i2s_enable() from void to int. Add error checking after
+each clk_prepare_enable() call and unwind already-enabled clocks on
+failure. Propagate the error through ep93xx_i2s_startup() and
+ep93xx_i2s_resume(), both of which already return int.
+
+Signed-off-by: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+Fixes: f4ff6b56bc8a ("ASoC: cirrus: i2s: Prepare clock before using it")
+Link: https://patch.msgid.link/20260324210909.45494-1-jihed.chaibi.dev@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/cirrus/ep93xx-i2s.c | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
+index cca01c03f0486..5dba741594fab 100644
+--- a/sound/soc/cirrus/ep93xx-i2s.c
++++ b/sound/soc/cirrus/ep93xx-i2s.c
+@@ -91,16 +91,28 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ return __raw_readl(info->regs + reg);
+ }
+
+-static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
++static int ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ {
+ unsigned base_reg;
++ int err;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+- clk_prepare_enable(info->mclk);
+- clk_prepare_enable(info->sclk);
+- clk_prepare_enable(info->lrclk);
++ err = clk_prepare_enable(info->mclk);
++ if (err)
++ return err;
++ err = clk_prepare_enable(info->sclk);
++ if (err) {
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
++ err = clk_prepare_enable(info->lrclk);
++ if (err) {
++ clk_disable_unprepare(info->sclk);
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+@@ -119,6 +131,8 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
+ EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
+ EP93XX_I2S_TXCTRL_TXUFIE);
++
++ return 0;
+ }
+
+ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+@@ -195,9 +209,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ {
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+- ep93xx_i2s_enable(info, substream->stream);
+-
+- return 0;
++ return ep93xx_i2s_enable(info, substream->stream);
+ }
+
+ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+@@ -373,14 +385,16 @@ static int ep93xx_i2s_suspend(struct snd_soc_component *component)
+ static int ep93xx_i2s_resume(struct snd_soc_component *component)
+ {
+ struct ep93xx_i2s_info *info = snd_soc_component_get_drvdata(component);
++ int err;
+
+ if (!snd_soc_component_active(component))
+ return 0;
+
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
++ err = ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
++ if (err)
++ return err;
+
+- return 0;
++ return ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ #else
+ #define ep93xx_i2s_suspend NULL
+--
+2.53.0
+
--- /dev/null
+From 278a42bbcd2d49d7e11f4ef07415046f6322cc02 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:15:21 +0000
+Subject: ASoC: Intel: boards: fix unmet dependency on PINCTRL
+
+From: Julian Braha <julianbraha@gmail.com>
+
+[ Upstream commit e920c36f2073d533bdf19ba6ab690432c8173b63 ]
+
+This reverts commit c073f0757663 ("ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43")
+
+Currently, SND_SOC_INTEL_SOUNDWIRE_SOF_MACH selects PINCTRL_CS42L43
+without also selecting or depending on PINCTRL, despite PINCTRL_CS42L43
+depending on PINCTRL.
+
+See the following Kbuild warning:
+
+WARNING: unmet direct dependencies detected for PINCTRL_CS42L43
+ Depends on [n]: PINCTRL [=n] && MFD_CS42L43 [=m]
+ Selected by [m]:
+ - SND_SOC_INTEL_SOUNDWIRE_SOF_MACH [=m] && SOUND [=y] && SND [=m] && SND_SOC [=m] && SND_SOC_INTEL_MACH [=y] && (SND_SOC_SOF_INTEL_COMMON [=m] || !SND_SOC_SOF_INTEL_COMMON [=m]) && SND_SOC_SOF_INTEL_SOUNDWIRE [=m] && I2C [=y] && SPI_MASTER [=y] && ACPI [=y] && (MFD_INTEL_LPSS [=n] || COMPILE_TEST [=y]) && (SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES [=n] || COMPILE_TEST [=y]) && SOUNDWIRE [=m]
+
+In response to v1 of this patch [1], Arnd pointed out that there is
+no compile-time dependency sof_sdw and the PINCTRL_CS42L43 driver.
+After testing, I can confirm that the kernel compiled with
+SND_SOC_INTEL_SOUNDWIRE_SOF_MACH enabled and PINCTRL_CS42L43 disabled.
+
+This unmet dependency was detected by kconfirm, a static analysis
+tool for Kconfig.
+
+Link: https://lore.kernel.org/all/b8aecc71-1fed-4f52-9f6c-263fbe56d493@app.fastmail.com/ [1]
+Fixes: c073f0757663 ("ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43")
+Signed-off-by: Julian Braha <julianbraha@gmail.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://patch.msgid.link/20260325001522.1727678-1-julianbraha@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/Kconfig | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
+index aed95d1583e09..1a05e701a9e00 100644
+--- a/sound/soc/intel/boards/Kconfig
++++ b/sound/soc/intel/boards/Kconfig
+@@ -532,8 +532,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
+ select SND_SOC_CS42L43_SDW
+ select MFD_CS42L43
+ select MFD_CS42L43_SDW
+- select PINCTRL_CS42L43
+- select SPI_CS42L43
+ select SND_SOC_CS35L56_SPI
+ select SND_SOC_CS35L56_SDW
+ select SND_SOC_DMIC
+--
+2.53.0
+
--- /dev/null
+From 770c971a830757fd1a6d7c98882ce2551609c314 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index 4a8ca2d7ff595..4f236dd7d34ba 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From b43ebd0f1c52b6ff4cef815334da6336c752c425 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:01 +0300
+Subject: Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a2639a7f0f5bf7d73f337f8f077c19415c62ed2c ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+set_cig_params_sync, otherwise it's possible it is freed concurrently.
+
+Take hdev lock to prevent hci_conn from being deleted or modified
+concurrently. Just RCU lock is not suitable here, as we also want to
+avoid "tearing" in the configuration.
+
+Fixes: a091289218202 ("Bluetooth: hci_conn: Fix hci_le_set_cig_params")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_conn.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index 447d29c67e7c1..b36fa056e8796 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -1767,9 +1767,13 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+ u8 aux_num_cis = 0;
+ u8 cis_id;
+
++ hci_dev_lock(hdev);
++
+ conn = hci_conn_hash_lookup_cig(hdev, cig_id);
+- if (!conn)
++ if (!conn) {
++ hci_dev_unlock(hdev);
+ return 0;
++ }
+
+ qos = &conn->iso_qos;
+ pdu->cig_id = cig_id;
+@@ -1808,6 +1812,8 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+ }
+ pdu->num_cis = aux_num_cis;
+
++ hci_dev_unlock(hdev);
++
+ if (!pdu->num_cis)
+ return 0;
+
+--
+2.53.0
+
--- /dev/null
+From 94b73c852ddf773b3806ec9a2c1754dbdec39ba1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:02 +0300
+Subject: Bluetooth: hci_event: fix potential UAF in
+ hci_le_remote_conn_param_req_evt
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit b255531b27da336571411248c2a72a350662bd09 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_le_remote_conn_param_req_evt, otherwise it's possible it is freed
+concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage.
+
+Fixes: 95118dd4edfec ("Bluetooth: hci_event: Use of a function table to handle LE subevents")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 33 ++++++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 498b7e4c76d59..0dd021c881cc4 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -6616,25 +6616,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ latency = le16_to_cpu(ev->latency);
+ timeout = le16_to_cpu(ev->timeout);
+
++ hci_dev_lock(hdev);
++
+ hcon = hci_conn_hash_lookup_handle(hdev, handle);
+- if (!hcon || hcon->state != BT_CONNECTED)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_UNKNOWN_CONN_ID);
++ if (!hcon || hcon->state != BT_CONNECTED) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_UNKNOWN_CONN_ID);
++ goto unlock;
++ }
+
+- if (max > hcon->le_conn_max_interval)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (max > hcon->le_conn_max_interval) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+- if (hci_check_conn_params(min, max, latency, timeout))
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (hci_check_conn_params(min, max, latency, timeout)) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+ if (hcon->role == HCI_ROLE_MASTER) {
+ struct hci_conn_params *params;
+ u8 store_hint;
+
+- hci_dev_lock(hdev);
+-
+ params = hci_conn_params_lookup(hdev, &hcon->dst,
+ hcon->dst_type);
+ if (params) {
+@@ -6647,8 +6653,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ store_hint = 0x00;
+ }
+
+- hci_dev_unlock(hdev);
+-
+ mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
+ store_hint, min, max, latency, timeout);
+ }
+@@ -6662,6 +6666,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ cp.max_ce_len = 0;
+
+ hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
+--
+2.53.0
+
--- /dev/null
+From 63f1d1c753a7e0ca3b29a42048ee8a515acfc1dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 21:07:46 +0200
+Subject: Bluetooth: hci_sync: call destroy in hci_cmd_sync_run if immediate
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a834a0b66ec6fb743377201a0f4229bb2503f4ce ]
+
+hci_cmd_sync_run() may run the work immediately if called from existing
+sync work (otherwise it queues a new sync work). In this case it fails
+to call the destroy() function.
+
+On immediate run, make it behave same way as if item was queued
+successfully: call destroy, and return 0.
+
+The only callsite is hci_abort_conn() via hci_cmd_sync_run_once(), and
+this changes its return value. However, its return value is not used
+except as the return value for hci_disconnect(), and nothing uses the
+return value of hci_disconnect(). Hence there should be no behavior
+change anywhere.
+
+Fixes: c898f6d7b093b ("Bluetooth: hci_sync: Introduce hci_cmd_sync_run/hci_cmd_sync_run_once")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index 1656448649b9f..4f0fdb646d943 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -801,8 +801,15 @@ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+ return -ENETDOWN;
+
+ /* If on cmd_sync_work then run immediately otherwise queue */
+- if (current_work() == &hdev->cmd_sync_work)
+- return func(hdev, data);
++ if (current_work() == &hdev->cmd_sync_work) {
++ int err;
++
++ err = func(hdev, data);
++ if (destroy)
++ destroy(hdev, data, err);
++
++ return 0;
++ }
+
+ return hci_cmd_sync_submit(hdev, func, data, destroy);
+ }
+--
+2.53.0
+
--- /dev/null
+From a8fcd4792c93db61e8e1366e41371c897702fdb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index ba6651f23d5d0..aa114fb218b2f 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -7265,6 +7265,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From ed5a278c34e586796aa179f743dde44c5c7849f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 22:25:26 +0800
+Subject: Bluetooth: MGMT: validate mesh send advertising payload length
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit bda93eec78cdbfe5cda00785cefebd443e56b88b ]
+
+mesh_send() currently bounds MGMT_OP_MESH_SEND by total command
+length, but it never verifies that the bytes supplied for the
+flexible adv_data[] array actually match the embedded adv_data_len
+field. MGMT_MESH_SEND_SIZE only covers the fixed header, so a
+truncated command can still pass the existing 20..50 byte range
+check and later drive the async mesh send path past the end of the
+queued command buffer.
+
+Keep rejecting zero-length and oversized advertising payloads, but
+validate adv_data_len explicitly and require the command length to
+exactly match the flexible array size before queueing the request.
+
+Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index aa114fb218b2f..0b2d130e492ca 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -2455,6 +2455,7 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ struct mgmt_mesh_tx *mesh_tx;
+ struct mgmt_cp_mesh_send *send = data;
+ struct mgmt_rp_mesh_read_features rp;
++ u16 expected_len;
+ bool sending;
+ int err = 0;
+
+@@ -2462,12 +2463,19 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ !hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_NOT_SUPPORTED);
+- if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
+- len <= MGMT_MESH_SEND_SIZE ||
+- len > (MGMT_MESH_SEND_SIZE + 31))
++ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_REJECTED);
++
++ if (!send->adv_data_len || send->adv_data_len > 31)
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_REJECTED);
+
++ expected_len = struct_size(send, adv_data, send->adv_data_len);
++ if (expected_len != len)
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_INVALID_PARAMS);
++
+ hci_dev_lock(hdev);
+
+ memset(&rp, 0, sizeof(rp));
+--
+2.53.0
+
--- /dev/null
+From 93ea7cf32176f005ddac7d3ec65c28d9ca5690b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 23:16:45 +0800
+Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect()
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit 8a5b0135d4a5d9683203a3d9a12a711ccec5936b ]
+
+sco_sock_connect() checks sk_state and sk_type without holding
+the socket lock. Two concurrent connect() syscalls on the same
+socket can both pass the check and enter sco_connect(), leading
+to use-after-free.
+
+The buggy scenario involves three participants and was confirmed
+with additional logging instrumentation:
+
+ Thread A (connect): HCI disconnect: Thread B (connect):
+
+ sco_sock_connect(sk) sco_sock_connect(sk)
+ sk_state==BT_OPEN sk_state==BT_OPEN
+ (pass, no lock) (pass, no lock)
+ sco_connect(sk): sco_connect(sk):
+ hci_dev_lock hci_dev_lock
+ hci_connect_sco <- blocked
+ -> hcon1
+ sco_conn_add->conn1
+ lock_sock(sk)
+ sco_chan_add:
+ conn1->sk = sk
+ sk->conn = conn1
+ sk_state=BT_CONNECT
+ release_sock
+ hci_dev_unlock
+ hci_dev_lock
+ sco_conn_del:
+ lock_sock(sk)
+ sco_chan_del:
+ sk->conn=NULL
+ conn1->sk=NULL
+ sk_state=
+ BT_CLOSED
+ SOCK_ZAPPED
+ release_sock
+ hci_dev_unlock
+ (unblocked)
+ hci_connect_sco
+ -> hcon2
+ sco_conn_add
+ -> conn2
+ lock_sock(sk)
+ sco_chan_add:
+ sk->conn=conn2
+ sk_state=
+ BT_CONNECT
+ // zombie sk!
+ release_sock
+ hci_dev_unlock
+
+Thread B revives a BT_CLOSED + SOCK_ZAPPED socket back to
+BT_CONNECT. Subsequent cleanup triggers double sock_put() and
+use-after-free. Meanwhile conn1 is leaked as it was orphaned
+when sco_conn_del() cleared the association.
+
+Fix this by:
+- Moving lock_sock() before the sk_state/sk_type checks in
+ sco_sock_connect() to serialize concurrent connect attempts
+- Fixing the sk_type != SOCK_SEQPACKET check to actually
+ return the error instead of just assigning it
+- Adding a state re-check in sco_connect() after lock_sock()
+ to catch state changes during the window between the locks
+- Adding sco_pi(sk)->conn check in sco_chan_add() to prevent
+ double-attach of a socket to multiple connections
+- Adding hci_conn_drop() on sco_chan_add failure to prevent
+ HCI connection leaks
+
+Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm")
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/sco.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index ad3439bd4d51a..ded0c52ccf0b9 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -238,7 +238,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+ int err = 0;
+
+ sco_conn_lock(conn);
+- if (conn->sk)
++ if (conn->sk || sco_pi(sk)->conn)
+ err = -EBUSY;
+ else
+ __sco_chan_add(conn, sk, parent);
+@@ -293,9 +293,20 @@ static int sco_connect(struct sock *sk)
+
+ lock_sock(sk);
+
++ /* Recheck state after reacquiring the socket lock, as another
++ * thread may have changed it (e.g., closed the socket).
++ */
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
++ hci_conn_drop(hcon);
++ err = -EBADFD;
++ goto unlock;
++ }
++
+ err = sco_chan_add(conn, sk, NULL);
+ if (err) {
+ release_sock(sk);
++ hci_conn_drop(hcon);
+ goto unlock;
+ }
+
+@@ -602,13 +613,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
+ addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
+- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
++ lock_sock(sk);
++
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
+ return -EBADFD;
++ }
+
+- if (sk->sk_type != SOCK_SEQPACKET)
+- err = -EINVAL;
++ if (sk->sk_type != SOCK_SEQPACKET) {
++ release_sock(sk);
++ return -EINVAL;
++ }
+
+- lock_sock(sk);
+ /* Set destination address and psm */
+ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
+ release_sock(sk);
+--
+2.53.0
+
--- /dev/null
+From 2749c932f0b429ee0a1746832aa8b82817f2129d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Nov 2024 07:14:31 -0800
+Subject: bnxt_en: Allocate backing store memory for FW trace logs
+
+From: Shruti Parab <shruti.parab@broadcom.com>
+
+[ Upstream commit 24d694aec139e9e0a31c60993db79bd8ad575afe ]
+
+Allocate the new FW trace log backing store context memory types
+if they are supported by the FW. FW debug logs are DMA'ed to the host
+backing store memory when the on-chip buffers are full. If host
+memory cannot be allocated for these memory types, the driver
+will not abort.
+
+Reviewed-by: Hongguang Gao <hongguang.gao@broadcom.com>
+Signed-off-by: Shruti Parab <shruti.parab@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20241115151438.550106-6-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 43 ++++++++++++++++++-----
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 27 +++++++++++---
+ 2 files changed, 57 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 7b84ed5c300e6..d5f4cd752c680 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -2484,6 +2484,15 @@ static bool bnxt_auto_speed_updated(struct bnxt_link_info *link_info)
+ return false;
+ }
+
++bool bnxt_bs_trace_avail(struct bnxt *bp, u16 type)
++{
++ u32 flags = bp->ctx->ctx_arr[type].flags;
++
++ return (flags & BNXT_CTX_MEM_TYPE_VALID) &&
++ ((flags & BNXT_CTX_MEM_FW_TRACE) ||
++ (flags & BNXT_CTX_MEM_FW_BIN_TRACE));
++}
++
+ #define BNXT_EVENT_THERMAL_CURRENT_TEMP(data2) \
+ ((data2) & \
+ ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA2_CURRENT_TEMP_MASK)
+@@ -8863,16 +8872,34 @@ static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena)
+ {
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+ struct bnxt_ctx_mem_type *ctxm;
+- u16 last_type;
++ u16 last_type = BNXT_CTX_INV;
+ int rc = 0;
+ u16 type;
+
+- if (!ena)
+- return 0;
+- else if (ena & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM)
+- last_type = BNXT_CTX_MAX - 1;
+- else
+- last_type = BNXT_CTX_L2_MAX - 1;
++ for (type = BNXT_CTX_SRT; type <= BNXT_CTX_RIGP1; type++) {
++ ctxm = &ctx->ctx_arr[type];
++ if (!bnxt_bs_trace_avail(bp, type))
++ continue;
++ if (!ctxm->mem_valid) {
++ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm,
++ ctxm->max_entries, 1);
++ if (rc) {
++ netdev_warn(bp->dev, "Unable to setup ctx page for type:0x%x.\n",
++ type);
++ continue;
++ }
++ last_type = type;
++ }
++ }
++
++ if (last_type == BNXT_CTX_INV) {
++ if (!ena)
++ return 0;
++ else if (ena & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM)
++ last_type = BNXT_CTX_MAX - 1;
++ else
++ last_type = BNXT_CTX_L2_MAX - 1;
++ }
+ ctx->ctx_arr[last_type].last = 1;
+
+ for (type = 0 ; type < BNXT_CTX_V2_MAX; type++) {
+@@ -8895,7 +8922,7 @@ static void bnxt_free_one_ctx_mem(struct bnxt *bp,
+
+ ctxm->last = 0;
+
+- if (ctxm->mem_valid && !force)
++ if (ctxm->mem_valid && !force && (ctxm->flags & BNXT_CTX_MEM_PERSIST))
+ return;
+
+ ctx_pg = ctxm->pg_info;
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 38690fdc3c46c..abdcbcce68acf 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -1882,6 +1882,13 @@ struct bnxt_ctx_mem_type {
+ u16 entry_size;
+ u32 flags;
+ #define BNXT_CTX_MEM_TYPE_VALID FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID
++#define BNXT_CTX_MEM_FW_TRACE \
++ FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_DBG_TRACE
++#define BNXT_CTX_MEM_FW_BIN_TRACE \
++ FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_BIN_DBG_TRACE
++#define BNXT_CTX_MEM_PERSIST \
++ FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_NEXT_BS_OFFSET
++
+ u32 instance_bmap;
+ u8 init_value;
+ u8 entry_multiple;
+@@ -1922,21 +1929,30 @@ struct bnxt_ctx_mem_type {
+ #define BNXT_CTX_FTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_FP_TQM_RING
+ #define BNXT_CTX_MRAV FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MRAV
+ #define BNXT_CTX_TIM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TIM
+-#define BNXT_CTX_TKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TKC
+-#define BNXT_CTX_RKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RKC
++#define BNXT_CTX_TCK FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TX_CK
++#define BNXT_CTX_RCK FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RX_CK
+ #define BNXT_CTX_MTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MP_TQM_RING
+ #define BNXT_CTX_SQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SQ_DB_SHADOW
+ #define BNXT_CTX_RQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RQ_DB_SHADOW
+ #define BNXT_CTX_SRQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRQ_DB_SHADOW
+ #define BNXT_CTX_CQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CQ_DB_SHADOW
+-#define BNXT_CTX_QTKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_TKC
+-#define BNXT_CTX_QRKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_RKC
+ #define BNXT_CTX_TBLSC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TBL_SCOPE
+ #define BNXT_CTX_XPAR FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_XID_PARTITION
++#define BNXT_CTX_SRT FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRT_TRACE
++#define BNXT_CTX_SRT2 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRT2_TRACE
++#define BNXT_CTX_CRT FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CRT_TRACE
++#define BNXT_CTX_CRT2 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CRT2_TRACE
++#define BNXT_CTX_RIGP0 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP0_TRACE
++#define BNXT_CTX_L2HWRM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_L2_HWRM_TRACE
++#define BNXT_CTX_REHWRM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_ROCE_HWRM_TRACE
++#define BNXT_CTX_CA0 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA0_TRACE
++#define BNXT_CTX_CA1 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA1_TRACE
++#define BNXT_CTX_CA2 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA2_TRACE
++#define BNXT_CTX_RIGP1 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP1_TRACE
+
+ #define BNXT_CTX_MAX (BNXT_CTX_TIM + 1)
+ #define BNXT_CTX_L2_MAX (BNXT_CTX_FTQM + 1)
+-#define BNXT_CTX_V2_MAX (BNXT_CTX_XPAR + 1)
++#define BNXT_CTX_V2_MAX (BNXT_CTX_RIGP1 + 1)
+ #define BNXT_CTX_INV ((u16)-1)
+
+ struct bnxt_ctx_mem_info {
+@@ -2795,6 +2811,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
+ u16 prod, gfp_t gfp);
+ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data);
+ u32 bnxt_fw_health_readl(struct bnxt *bp, int reg_idx);
++bool bnxt_bs_trace_avail(struct bnxt *bp, u16 type);
+ void bnxt_set_tpa_flags(struct bnxt *bp);
+ void bnxt_set_ring_params(struct bnxt *);
+ void bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode);
+--
+2.53.0
+
--- /dev/null
+From 6718d9e19aece13ba758b7029fe3f9f8c8643e7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Nov 2024 07:14:33 -0800
+Subject: bnxt_en: Do not free FW log context memory
+
+From: Hongguang Gao <hongguang.gao@broadcom.com>
+
+[ Upstream commit de999362ad33d80ae5162670795d990f275960dd ]
+
+If FW supports appending new FW logs to an offset in the context
+memory after FW reset, then do not free this type of context memory
+during reset. The driver will provide the initial offset to the FW
+when configuring this type of context memory. This way, we don't lose
+the older FW logs after reset.
+
+Signed-off-by: Hongguang Gao <hongguang.gao@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20241115151438.550106-8-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 43 +++++++++++++++----
+ .../net/ethernet/broadcom/bnxt/bnxt_devlink.c | 2 +-
+ 2 files changed, 36 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index ccde8a7f54382..7c67c38fbf2f5 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -8419,6 +8419,9 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max)
+ return 0;
+ }
+
++static void bnxt_free_one_ctx_mem(struct bnxt *bp,
++ struct bnxt_ctx_mem_type *ctxm, bool force);
++
+ #define BNXT_CTX_INIT_VALID(flags) \
+ (!!((flags) & \
+ FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ENABLE_CTX_KIND_INIT))
+@@ -8447,6 +8450,8 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ for (type = 0; type < BNXT_CTX_V2_MAX; ) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ u8 init_val, init_off, i;
++ u32 max_entries;
++ u16 entry_size;
+ __le32 *p;
+ u32 flags;
+
+@@ -8456,15 +8461,26 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ goto ctx_done;
+ 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))
++ if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) {
++ bnxt_free_one_ctx_mem(bp, ctxm, true);
+ continue;
+-
++ }
++ entry_size = le16_to_cpu(resp->entry_size);
++ max_entries = le32_to_cpu(resp->max_num_entries);
++ if (ctxm->mem_valid) {
++ if (!(flags & BNXT_CTX_MEM_PERSIST) ||
++ ctxm->entry_size != entry_size ||
++ ctxm->max_entries != max_entries)
++ bnxt_free_one_ctx_mem(bp, ctxm, true);
++ else
++ continue;
++ }
+ ctxm->type = le16_to_cpu(resp->type);
+- ctxm->entry_size = le16_to_cpu(resp->entry_size);
++ ctxm->entry_size = entry_size;
+ ctxm->flags = flags;
+ ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
+ ctxm->entry_multiple = resp->entry_multiple;
+- ctxm->max_entries = le32_to_cpu(resp->max_num_entries);
++ ctxm->max_entries = max_entries;
+ ctxm->min_entries = le32_to_cpu(resp->min_num_entries);
+ init_val = resp->ctx_init_value;
+ init_off = resp->ctx_init_offset;
+@@ -8909,6 +8925,16 @@ static int bnxt_hwrm_func_backing_store_cfg_v2(struct bnxt *bp,
+ hwrm_req_hold(bp, req);
+ req->type = cpu_to_le16(ctxm->type);
+ req->entry_size = cpu_to_le16(ctxm->entry_size);
++ if ((ctxm->flags & BNXT_CTX_MEM_PERSIST) &&
++ bnxt_bs_trace_avail(bp, ctxm->type)) {
++ struct bnxt_bs_trace_info *bs_trace;
++ u32 enables;
++
++ enables = FUNC_BACKING_STORE_CFG_V2_REQ_ENABLES_NEXT_BS_OFFSET;
++ req->enables = cpu_to_le32(enables);
++ bs_trace = &bp->bs_trace[bnxt_bstore_to_trace[ctxm->type]];
++ req->next_bs_offset = cpu_to_le32(bs_trace->last_offset);
++ }
+ req->subtype_valid_cnt = ctxm->split_entry_cnt;
+ for (i = 0, p = &req->split_entry_0; i < ctxm->split_entry_cnt; i++)
+ p[i] = cpu_to_le32(ctxm->split[i]);
+@@ -9003,6 +9029,7 @@ static void bnxt_free_one_ctx_mem(struct bnxt *bp,
+ ctxm->pg_info = NULL;
+ ctxm->mem_valid = 0;
+ }
++ memset(ctxm, 0, sizeof(*ctxm));
+ }
+
+ void bnxt_free_ctx_mem(struct bnxt *bp, bool force)
+@@ -12052,7 +12079,7 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
+ set_bit(BNXT_STATE_FW_RESET_DET, &bp->state);
+ if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
+ bnxt_ulp_irq_stop(bp);
+- bnxt_free_ctx_mem(bp, true);
++ bnxt_free_ctx_mem(bp, false);
+ bnxt_dcb_free(bp);
+ rc = bnxt_fw_init_one(bp);
+ if (rc) {
+@@ -13776,7 +13803,7 @@ static void bnxt_fw_reset_close(struct bnxt *bp)
+ bnxt_hwrm_func_drv_unrgtr(bp);
+ if (pci_is_enabled(bp->pdev))
+ pci_disable_device(bp->pdev);
+- bnxt_free_ctx_mem(bp, true);
++ bnxt_free_ctx_mem(bp, false);
+ }
+
+ static bool is_bnxt_fw_ok(struct bnxt *bp)
+@@ -16370,7 +16397,7 @@ static int bnxt_suspend(struct device *device)
+ bnxt_hwrm_func_drv_unrgtr(bp);
+ bnxt_ptp_clear(bp);
+ pci_disable_device(bp->pdev);
+- bnxt_free_ctx_mem(bp, true);
++ bnxt_free_ctx_mem(bp, false);
+ rtnl_unlock();
+ return rc;
+ }
+@@ -16486,7 +16513,7 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
+
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
+- bnxt_free_ctx_mem(bp, true);
++ bnxt_free_ctx_mem(bp, false);
+ rtnl_unlock();
+
+ /* Request a slot slot reset. */
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+index 901fd36757ed6..ef8288fd68f4c 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+@@ -463,7 +463,7 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
+ break;
+ }
+ bnxt_cancel_reservations(bp, false);
+- bnxt_free_ctx_mem(bp, true);
++ bnxt_free_ctx_mem(bp, false);
+ break;
+ }
+ case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: {
+--
+2.53.0
+
--- /dev/null
+From 25947381eec5795cce4283b58dcca204d3eaf98d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Nov 2024 07:14:32 -0800
+Subject: bnxt_en: Manage the FW trace context memory
+
+From: Shruti Parab <shruti.parab@broadcom.com>
+
+[ Upstream commit 84fcd9449fd7882ddfb05ba64d75f9be2d29b2e9 ]
+
+The FW trace memory pages will be added to the ethtool -w coredump
+in later patches. In addition to the raw data, the driver has to
+add a header to provide the head and tail information on each FW
+trace log segment when creating the coredump. The FW sends an async
+message to the driver after DMAing a chunk of logs to the context
+memory to indicate the last offset containing the tail of the logs.
+The driver needs to keep track of that.
+
+Reviewed-by: Hongguang Gao <hongguang.gao@broadcom.com>
+Signed-off-by: Shruti Parab <shruti.parab@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20241115151438.550106-7-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 67 +++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 22 ++++++++
+ 2 files changed, 89 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index d5f4cd752c680..ccde8a7f54382 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -247,6 +247,21 @@ static const u16 bnxt_async_events_arr[] = {
+ ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP,
+ ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT,
+ ASYNC_EVENT_CMPL_EVENT_ID_PHC_UPDATE,
++ ASYNC_EVENT_CMPL_EVENT_ID_DBG_BUF_PRODUCER,
++};
++
++const u16 bnxt_bstore_to_trace[] = {
++ [BNXT_CTX_SRT] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT_TRACE,
++ [BNXT_CTX_SRT2] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT2_TRACE,
++ [BNXT_CTX_CRT] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT_TRACE,
++ [BNXT_CTX_CRT2] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT2_TRACE,
++ [BNXT_CTX_RIGP0] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP0_TRACE,
++ [BNXT_CTX_L2HWRM] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_L2_HWRM_TRACE,
++ [BNXT_CTX_REHWRM] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ROCE_HWRM_TRACE,
++ [BNXT_CTX_CA0] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA0_TRACE,
++ [BNXT_CTX_CA1] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA1_TRACE,
++ [BNXT_CTX_CA2] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA2_TRACE,
++ [BNXT_CTX_RIGP1] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP1_TRACE,
+ };
+
+ static struct workqueue_struct *bnxt_pf_wq;
+@@ -2493,6 +2508,50 @@ bool bnxt_bs_trace_avail(struct bnxt *bp, u16 type)
+ (flags & BNXT_CTX_MEM_FW_BIN_TRACE));
+ }
+
++static void bnxt_bs_trace_init(struct bnxt *bp, struct bnxt_ctx_mem_type *ctxm)
++{
++ u32 mem_size, pages, rem_bytes, magic_byte_offset;
++ u16 trace_type = bnxt_bstore_to_trace[ctxm->type];
++ struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
++ struct bnxt_ring_mem_info *rmem, *rmem_pg_tbl;
++ struct bnxt_bs_trace_info *bs_trace;
++ int last_pg;
++
++ if (ctxm->instance_bmap && ctxm->instance_bmap > 1)
++ return;
++
++ mem_size = ctxm->max_entries * ctxm->entry_size;
++ rem_bytes = mem_size % BNXT_PAGE_SIZE;
++ pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE);
++
++ last_pg = (pages - 1) & (MAX_CTX_PAGES - 1);
++ magic_byte_offset = (rem_bytes ? rem_bytes : BNXT_PAGE_SIZE) - 1;
++
++ rmem = &ctx_pg[0].ring_mem;
++ bs_trace = &bp->bs_trace[trace_type];
++ bs_trace->ctx_type = ctxm->type;
++ bs_trace->trace_type = trace_type;
++ if (pages > MAX_CTX_PAGES) {
++ int last_pg_dir = rmem->nr_pages - 1;
++
++ rmem_pg_tbl = &ctx_pg[0].ctx_pg_tbl[last_pg_dir]->ring_mem;
++ bs_trace->magic_byte = rmem_pg_tbl->pg_arr[last_pg];
++ } else {
++ bs_trace->magic_byte = rmem->pg_arr[last_pg];
++ }
++ bs_trace->magic_byte += magic_byte_offset;
++ *bs_trace->magic_byte = BNXT_TRACE_BUF_MAGIC_BYTE;
++}
++
++#define BNXT_EVENT_BUF_PRODUCER_TYPE(data1) \
++ (((data1) & ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_MASK) >>\
++ ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SFT)
++
++#define BNXT_EVENT_BUF_PRODUCER_OFFSET(data2) \
++ (((data2) & \
++ ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_MASK) >>\
++ ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_SFT)
++
+ #define BNXT_EVENT_THERMAL_CURRENT_TEMP(data2) \
+ ((data2) & \
+ ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA2_CURRENT_TEMP_MASK)
+@@ -2809,6 +2868,13 @@ static int bnxt_async_event_process(struct bnxt *bp,
+ hwrm_update_token(bp, seq_id, BNXT_HWRM_DEFERRED);
+ goto async_event_process_exit;
+ }
++ case ASYNC_EVENT_CMPL_EVENT_ID_DBG_BUF_PRODUCER: {
++ u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1);
++ u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2);
++
++ bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset);
++ goto async_event_process_exit;
++ }
+ default:
+ goto async_event_process_exit;
+ }
+@@ -8888,6 +8954,7 @@ static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena)
+ type);
+ continue;
+ }
++ bnxt_bs_trace_init(bp, ctxm);
+ last_type = type;
+ }
+ }
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index abdcbcce68acf..77e93bddf5b8a 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -2114,6 +2114,26 @@ enum board_idx {
+ NETXTREME_E_P7_VF_HV,
+ };
+
++#define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc)
++#define BNXT_TRACE_MAX 11
++
++struct bnxt_bs_trace_info {
++ u8 *magic_byte;
++ u32 last_offset;
++ u8 wrapped:1;
++ u16 ctx_type;
++ u16 trace_type;
++};
++
++static inline void bnxt_bs_trace_check_wrap(struct bnxt_bs_trace_info *bs_trace,
++ u32 offset)
++{
++ if (!bs_trace->wrapped &&
++ *bs_trace->magic_byte != BNXT_TRACE_BUF_MAGIC_BYTE)
++ bs_trace->wrapped = 1;
++ bs_trace->last_offset = offset;
++}
++
+ struct bnxt {
+ void __iomem *bar0;
+ void __iomem *bar1;
+@@ -2670,6 +2690,7 @@ struct bnxt {
+
+ struct bnxt_ctx_pg_info *fw_crash_mem;
+ u32 fw_crash_len;
++ struct bnxt_bs_trace_info bs_trace[BNXT_TRACE_MAX];
+ };
+
+ #define BNXT_NUM_RX_RING_STATS 8
+@@ -2805,6 +2826,7 @@ static inline bool bnxt_sriov_cfg(struct bnxt *bp)
+ #endif
+ }
+
++extern const u16 bnxt_bstore_to_trace[];
+ extern const u16 bnxt_lhint_arr[];
+
+ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
+--
+2.53.0
+
--- /dev/null
+From f033e66fc0b303a45ceb664208b4724f455fc08c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 23:51:38 -0700
+Subject: bnxt_en: Restore default stat ctxs for ULP when resource is available
+
+From: Pavan Chebbi <pavan.chebbi@broadcom.com>
+
+[ Upstream commit 071dbfa304e85a6b04a593e950d18fa170997288 ]
+
+During resource reservation, if the L2 driver does not have enough
+MSIX vectors to provide to the RoCE driver, it sets the stat ctxs for
+ULP also to 0 so that we don't have to reserve it unnecessarily.
+
+However, subsequently the user may reduce L2 rings thereby freeing up
+some resources that the L2 driver can now earmark for RoCE. In this
+case, the driver should restore the default ULP stat ctxs to make
+sure that all RoCE resources are ready for use.
+
+The RoCE driver may fail to initialize in this scenario without this
+fix.
+
+Fixes: d630624ebd70 ("bnxt_en: Utilize ulp client resources if RoCE is not registered")
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260331065138.948205-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 95d8419411a48..38f6112ed5389 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -7823,6 +7823,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
+ ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
+ if (!ulp_msix)
+ bnxt_set_ulp_stat_ctxs(bp, 0);
++ else
++ bnxt_set_dflt_ulp_stat_ctxs(bp);
+
+ if (ulp_msix > bp->ulp_num_msix_want)
+ ulp_msix = bp->ulp_num_msix_want;
+--
+2.53.0
+
--- /dev/null
+From fc13ea785682358c9537f610e344b10cb3c056a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 07:43:56 +0800
+Subject: bnxt_en: set backing store type from query type
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 4ee937107d52f9e5c350e4b5e629760e328b3d9f ]
+
+bnxt_hwrm_func_backing_store_qcaps_v2() stores resp->type from the
+firmware response in ctxm->type and later uses that value to index
+fixed backing-store metadata arrays such as ctx_arr[] and
+bnxt_bstore_to_trace[].
+
+ctxm->type is fixed by the current backing-store query type and matches
+the array index of ctx->ctx_arr. Set ctxm->type from the current loop
+variable instead of depending on resp->type.
+
+Also update the loop to advance type from next_valid_type in the for
+statement, which keeps the control flow simpler for non-valid and
+unchanged entries.
+
+Fixes: 6a4d0774f02d ("bnxt_en: Add support for new backing store query firmware API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Tested-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 7c67c38fbf2f5..95d8419411a48 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -8431,7 +8431,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ struct hwrm_func_backing_store_qcaps_v2_output *resp;
+ struct hwrm_func_backing_store_qcaps_v2_input *req;
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+- u16 type;
++ u16 type, next_type = 0;
+ int rc;
+
+ rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2);
+@@ -8447,7 +8447,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+
+ resp = hwrm_req_hold(bp, req);
+
+- for (type = 0; type < BNXT_CTX_V2_MAX; ) {
++ for (type = 0; type < BNXT_CTX_V2_MAX; type = next_type) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ u8 init_val, init_off, i;
+ u32 max_entries;
+@@ -8460,7 +8460,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ if (rc)
+ goto ctx_done;
+ flags = le32_to_cpu(resp->flags);
+- type = le16_to_cpu(resp->next_valid_type);
++ next_type = le16_to_cpu(resp->next_valid_type);
+ if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) {
+ bnxt_free_one_ctx_mem(bp, ctxm, true);
+ continue;
+@@ -8475,7 +8475,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ else
+ continue;
+ }
+- ctxm->type = le16_to_cpu(resp->type);
++ ctxm->type = type;
+ ctxm->entry_size = entry_size;
+ ctxm->flags = flags;
+ ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
+--
+2.53.0
+
--- /dev/null
+From 390ba44d3b6f35bddb17e6e0a7ccf30fec634256 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Nov 2024 07:14:27 -0800
+Subject: bnxt_en: Update firmware interface spec to 1.10.3.85
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit ff00bcc9ecccf4a1ce3a06eb38a9b4592f870f80 ]
+
+The major change is the new firmware command to flush the FW debug
+logs to the host backing store context memory buffers.
+
+Reviewed-by: Hongguang Gao <hongguang.gao@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20241115151438.550106-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 173 ++++++++++++++----
+ 1 file changed, 136 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+index f8ef6f1a1964e..5f8de16343788 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+@@ -42,6 +42,10 @@ struct hwrm_resp_hdr {
+ #define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL
+ #define TLV_TYPE_QUERY_ROCE_CC_GEN2 0x6UL
+ #define TLV_TYPE_MODIFY_ROCE_CC_GEN2 0x7UL
++#define TLV_TYPE_QUERY_ROCE_CC_GEN1_EXT 0x8UL
++#define TLV_TYPE_MODIFY_ROCE_CC_GEN1_EXT 0x9UL
++#define TLV_TYPE_QUERY_ROCE_CC_GEN2_EXT 0xaUL
++#define TLV_TYPE_MODIFY_ROCE_CC_GEN2_EXT 0xbUL
+ #define TLV_TYPE_ENGINE_CKV_ALIAS_ECC_PUBLIC_KEY 0x8001UL
+ #define TLV_TYPE_ENGINE_CKV_IV 0x8003UL
+ #define TLV_TYPE_ENGINE_CKV_AUTH_TAG 0x8004UL
+@@ -509,6 +513,7 @@ struct cmd_nums {
+ #define HWRM_TFC_IF_TBL_GET 0x399UL
+ #define HWRM_TFC_TBL_SCOPE_CONFIG_GET 0x39aUL
+ #define HWRM_TFC_RESC_USAGE_QUERY 0x39bUL
++ #define HWRM_TFC_GLOBAL_ID_FREE 0x39cUL
+ #define HWRM_SV 0x400UL
+ #define HWRM_DBG_SERDES_TEST 0xff0eUL
+ #define HWRM_DBG_LOG_BUFFER_FLUSH 0xff0fUL
+@@ -624,8 +629,8 @@ struct hwrm_err_output {
+ #define HWRM_VERSION_MAJOR 1
+ #define HWRM_VERSION_MINOR 10
+ #define HWRM_VERSION_UPDATE 3
+-#define HWRM_VERSION_RSVD 68
+-#define HWRM_VERSION_STR "1.10.3.68"
++#define HWRM_VERSION_RSVD 85
++#define HWRM_VERSION_STR "1.10.3.85"
+
+ /* hwrm_ver_get_input (size:192b/24B) */
+ struct hwrm_ver_get_input {
+@@ -1302,6 +1307,43 @@ struct hwrm_async_event_cmpl_error_report {
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_DATA1_ERROR_TYPE_SFT 0
+ };
+
++/* hwrm_async_event_cmpl_dbg_buf_producer (size:128b/16B) */
++struct hwrm_async_event_cmpl_dbg_buf_producer {
++ __le16 type;
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_MASK 0x3fUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_SFT 0
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_HWRM_ASYNC_EVENT 0x2eUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_HWRM_ASYNC_EVENT
++ __le16 event_id;
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_DBG_BUF_PRODUCER 0x4cUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_DBG_BUF_PRODUCER
++ __le32 event_data2;
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_MASK 0xffffffffUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_SFT 0
++ u8 opaque_v;
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_V 0x1UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_OPAQUE_MASK 0xfeUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_OPAQUE_SFT 1
++ u8 timestamp_lo;
++ __le16 timestamp_hi;
++ __le32 event_data1;
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_MASK 0xffffUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SFT 0
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SRT_TRACE 0x0UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SRT2_TRACE 0x1UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CRT_TRACE 0x2UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CRT2_TRACE 0x3UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP0_TRACE 0x4UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_L2_HWRM_TRACE 0x5UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_ROCE_HWRM_TRACE 0x6UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA0_TRACE 0x7UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA1_TRACE 0x8UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA2_TRACE 0x9UL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP1_TRACE 0xaUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE 0xbUL
++ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE
++};
++
+ /* hwrm_async_event_cmpl_hwrm_error (size:128b/16B) */
+ struct hwrm_async_event_cmpl_hwrm_error {
+ __le16 type;
+@@ -1864,7 +1906,10 @@ struct hwrm_func_qcaps_output {
+ __le32 roce_vf_max_gid;
+ __le32 flags_ext3;
+ #define FUNC_QCAPS_RESP_FLAGS_EXT3_RM_RSV_WHILE_ALLOC_CAP 0x1UL
+- u8 unused_3[7];
++ #define FUNC_QCAPS_RESP_FLAGS_EXT3_REQUIRE_L2_FILTER 0x2UL
++ #define FUNC_QCAPS_RESP_FLAGS_EXT3_MAX_ROCE_VFS_SUPPORTED 0x4UL
++ __le16 max_roce_vfs;
++ u8 unused_3[5];
+ u8 valid;
+ };
+
+@@ -2253,17 +2298,18 @@ struct hwrm_func_cfg_input {
+ #define FUNC_CFG_REQ_FLAGS2_KTLS_KEY_CTX_ASSETS_TEST 0x1UL
+ #define FUNC_CFG_REQ_FLAGS2_QUIC_KEY_CTX_ASSETS_TEST 0x2UL
+ __le32 enables2;
+- #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL
+- #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL
+- #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL
+- #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL
+- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL
+- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL
+- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL
+- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL
+- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL
+- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL
+- #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL
++ #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL
++ #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL
++ #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL
++ #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL
++ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL
++ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL
++ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL
++ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL
++ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL
++ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL
++ #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL
++ #define FUNC_CFG_REQ_ENABLES2_PHYSICAL_SLOT_NUMBER 0x800UL
+ u8 port_kdnet_mode;
+ #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL
+ #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL
+@@ -2281,7 +2327,7 @@ struct hwrm_func_cfg_input {
+ #define FUNC_CFG_REQ_DB_PAGE_SIZE_2MB 0x9UL
+ #define FUNC_CFG_REQ_DB_PAGE_SIZE_4MB 0xaUL
+ #define FUNC_CFG_REQ_DB_PAGE_SIZE_LAST FUNC_CFG_REQ_DB_PAGE_SIZE_4MB
+- u8 unused_1[2];
++ __le16 physical_slot_number;
+ __le32 num_ktls_tx_key_ctxs;
+ __le32 num_ktls_rx_key_ctxs;
+ __le32 num_quic_tx_key_ctxs;
+@@ -3683,7 +3729,7 @@ struct hwrm_func_ptp_ext_qcfg_output {
+ u8 valid;
+ };
+
+-/* hwrm_func_backing_store_cfg_v2_input (size:448b/56B) */
++/* hwrm_func_backing_store_cfg_v2_input (size:512b/64B) */
+ struct hwrm_func_backing_store_cfg_v2_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+@@ -3721,6 +3767,7 @@ struct hwrm_func_backing_store_cfg_v2_input {
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA1_TRACE 0x27UL
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA2_TRACE 0x28UL
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL
++ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID 0xffffUL
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID
+ __le16 instance;
+@@ -3752,6 +3799,9 @@ struct hwrm_func_backing_store_cfg_v2_input {
+ __le32 split_entry_1;
+ __le32 split_entry_2;
+ __le32 split_entry_3;
++ __le32 enables;
++ #define FUNC_BACKING_STORE_CFG_V2_REQ_ENABLES_NEXT_BS_OFFSET 0x1UL
++ __le32 next_bs_offset;
+ };
+
+ /* hwrm_func_backing_store_cfg_v2_output (size:128b/16B) */
+@@ -3802,6 +3852,7 @@ struct hwrm_func_backing_store_qcfg_v2_input {
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA1_TRACE 0x27UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA2_TRACE 0x28UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL
++ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID
+ __le16 instance;
+@@ -3963,6 +4014,7 @@ struct hwrm_func_backing_store_qcaps_v2_input {
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA1_TRACE 0x27UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA2_TRACE 0x28UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP1_TRACE 0x29UL
++ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID 0xffffUL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID
+ u8 rsvd[6];
+@@ -4005,6 +4057,7 @@ struct hwrm_func_backing_store_qcaps_v2_output {
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA1_TRACE 0x27UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA2_TRACE 0x28UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RIGP1_TRACE 0x29UL
++ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID 0xffffUL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID
+ __le16 entry_size;
+@@ -4014,6 +4067,8 @@ struct hwrm_func_backing_store_qcaps_v2_output {
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_DRIVER_MANAGED_MEMORY 0x4UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ROCE_QP_PSEUDO_STATIC_ALLOC 0x8UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_DBG_TRACE 0x10UL
++ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_BIN_DBG_TRACE 0x20UL
++ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_NEXT_BS_OFFSET 0x40UL
+ __le32 instance_bit_map;
+ u8 ctx_init_value;
+ u8 ctx_init_offset;
+@@ -4034,7 +4089,8 @@ struct hwrm_func_backing_store_qcaps_v2_output {
+ __le32 split_entry_1;
+ __le32 split_entry_2;
+ __le32 split_entry_3;
+- u8 rsvd3[3];
++ __le16 max_instance_count;
++ u8 rsvd3;
+ u8 valid;
+ };
+
+@@ -4535,11 +4591,12 @@ struct hwrm_port_phy_qcfg_output {
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_800G_BASEDR8 0x3dUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_800G_BASEDR8
+ u8 media_type;
+- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL
+- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL
+- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC 0x2UL
+- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE 0x3UL
+- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_LAST PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE
++ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL
++ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL
++ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC 0x2UL
++ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE 0x3UL
++ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_BACKPLANE 0x4UL
++ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_LAST PORT_PHY_QCFG_RESP_MEDIA_TYPE_BACKPLANE
+ u8 xcvr_pkg_type;
+ #define PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL 0x1UL
+ #define PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_EXTERNAL 0x2UL
+@@ -4654,7 +4711,8 @@ struct hwrm_port_phy_qcfg_output {
+ #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL
+ #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL
+ u8 link_down_reason;
+- #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL
++ #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL
++ #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_OTP_SPEED_VIOLATION 0x2UL
+ __le16 support_speeds2;
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL
+@@ -9241,20 +9299,22 @@ struct hwrm_fw_set_time_output {
+ /* hwrm_struct_hdr (size:128b/16B) */
+ struct hwrm_struct_hdr {
+ __le16 struct_id;
+- #define STRUCT_HDR_STRUCT_ID_LLDP_CFG 0x41bUL
+- #define STRUCT_HDR_STRUCT_ID_DCBX_ETS 0x41dUL
+- #define STRUCT_HDR_STRUCT_ID_DCBX_PFC 0x41fUL
+- #define STRUCT_HDR_STRUCT_ID_DCBX_APP 0x421UL
+- #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL
+- #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL
+- #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL
+- #define STRUCT_HDR_STRUCT_ID_POWER_BKUP 0x427UL
+- #define STRUCT_HDR_STRUCT_ID_PEER_MMAP 0x429UL
+- #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL
+- #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL
+- #define STRUCT_HDR_STRUCT_ID_RSS_V2 0x64UL
+- #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL
+- #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_MSIX_PER_VF
++ #define STRUCT_HDR_STRUCT_ID_LLDP_CFG 0x41bUL
++ #define STRUCT_HDR_STRUCT_ID_DCBX_ETS 0x41dUL
++ #define STRUCT_HDR_STRUCT_ID_DCBX_PFC 0x41fUL
++ #define STRUCT_HDR_STRUCT_ID_DCBX_APP 0x421UL
++ #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL
++ #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL
++ #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL
++ #define STRUCT_HDR_STRUCT_ID_POWER_BKUP 0x427UL
++ #define STRUCT_HDR_STRUCT_ID_PEER_MMAP 0x429UL
++ #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL
++ #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL
++ #define STRUCT_HDR_STRUCT_ID_RSS_V2 0x64UL
++ #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL
++ #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_COUNT 0x12cUL
++ #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND 0x12dUL
++ #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND
+ __le16 len;
+ u8 version;
+ u8 count;
+@@ -9756,6 +9816,7 @@ struct hwrm_dbg_qcaps_output {
+ #define DBG_QCAPS_RESP_FLAGS_COREDUMP_HOST_DDR 0x10UL
+ #define DBG_QCAPS_RESP_FLAGS_COREDUMP_HOST_CAPTURE 0x20UL
+ #define DBG_QCAPS_RESP_FLAGS_PTRACE 0x40UL
++ #define DBG_QCAPS_RESP_FLAGS_REG_ACCESS_RESTRICTED 0x80UL
+ u8 unused_1[3];
+ u8 valid;
+ };
+@@ -9996,6 +10057,43 @@ struct hwrm_dbg_ring_info_get_output {
+ u8 valid;
+ };
+
++/* hwrm_dbg_log_buffer_flush_input (size:192b/24B) */
++struct hwrm_dbg_log_buffer_flush_input {
++ __le16 req_type;
++ __le16 cmpl_ring;
++ __le16 seq_id;
++ __le16 target_id;
++ __le64 resp_addr;
++ __le16 type;
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT_TRACE 0x0UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT2_TRACE 0x1UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT_TRACE 0x2UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT2_TRACE 0x3UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP0_TRACE 0x4UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_L2_HWRM_TRACE 0x5UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ROCE_HWRM_TRACE 0x6UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA0_TRACE 0x7UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA1_TRACE 0x8UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA2_TRACE 0x9UL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP1_TRACE 0xaUL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE 0xbUL
++ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_LAST DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE
++ u8 unused_1[2];
++ __le32 flags;
++ #define DBG_LOG_BUFFER_FLUSH_REQ_FLAGS_FLUSH_ALL_BUFFERS 0x1UL
++};
++
++/* hwrm_dbg_log_buffer_flush_output (size:128b/16B) */
++struct hwrm_dbg_log_buffer_flush_output {
++ __le16 error_code;
++ __le16 req_type;
++ __le16 seq_id;
++ __le16 resp_len;
++ __le32 current_buffer_offset;
++ u8 unused_1[3];
++ u8 valid;
++};
++
+ /* hwrm_nvm_read_input (size:320b/40B) */
+ struct hwrm_nvm_read_input {
+ __le16 req_type;
+@@ -10080,6 +10178,7 @@ struct hwrm_nvm_write_input {
+ #define NVM_WRITE_REQ_FLAGS_KEEP_ORIG_ACTIVE_IMG 0x1UL
+ #define NVM_WRITE_REQ_FLAGS_BATCH_MODE 0x2UL
+ #define NVM_WRITE_REQ_FLAGS_BATCH_LAST 0x4UL
++ #define NVM_WRITE_REQ_FLAGS_SKIP_CRID_CHECK 0x8UL
+ __le32 dir_item_length;
+ __le32 offset;
+ __le32 len;
+--
+2.53.0
+
--- /dev/null
+From f3e41d8bfc1b096b919c4b301a996347d819f23f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 68fa30852051e..9bdc19587948c 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -17562,8 +17562,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From edd3edc6f7e961c35c7555dde401154264eaf398 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 17:29:22 +0800
+Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit b0db1accbc7395657c2b79db59fa9fae0d6656f3 ]
+
+check_mem_access() matches PTR_TO_BUF via base_type() which strips
+PTR_MAYBE_NULL, allowing direct dereference without a null check.
+
+Map iterator ctx->key and ctx->value are PTR_TO_BUF | PTR_MAYBE_NULL.
+On stop callbacks these are NULL, causing a kernel NULL dereference.
+
+Add a type_may_be_null() guard to the PTR_TO_BUF branch, matching the
+existing PTR_TO_BTF_ID pattern.
+
+Fixes: 20b2aff4bc15 ("bpf: Introduce MEM_RDONLY flag")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 9bdc19587948c..ff16bc2bff589 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -7224,7 +7224,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ } else if (reg->type == CONST_PTR_TO_MAP) {
+ err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+ value_regno);
+- } else if (base_type(reg->type) == PTR_TO_BUF) {
++ } else if (base_type(reg->type) == PTR_TO_BUF &&
++ !type_may_be_null(reg->type)) {
+ bool rdonly_mem = type_is_rdonly_mem(reg->type);
+ u32 *max_access;
+
+--
+2.53.0
+
--- /dev/null
+From b2714984a4e532f2e6d33dac149a8a6c93054a57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 00:54:15 +0000
+Subject: bpf: sockmap: Fix use-after-free of sk->sk_socket in
+ sk_psock_verdict_data_ready().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit ad8391d37f334ee73ba91926f8b4e4cf6d31ea04 ]
+
+syzbot reported use-after-free of AF_UNIX socket's sk->sk_socket
+in sk_psock_verdict_data_ready(). [0]
+
+In unix_stream_sendmsg(), the peer socket's ->sk_data_ready() is
+called after dropping its unix_state_lock().
+
+Although the sender socket holds the peer's refcount, it does not
+prevent the peer's sock_orphan(), and the peer's sk_socket might
+be freed after one RCU grace period.
+
+Let's fetch the peer's sk->sk_socket and sk->sk_socket->ops under
+RCU in sk_psock_verdict_data_ready().
+
+[0]:
+BUG: KASAN: slab-use-after-free in sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+Read of size 8 at addr ffff8880594da860 by task syz.4.1842/11013
+
+CPU: 1 UID: 0 PID: 11013 Comm: syz.4.1842 Not tainted syzkaller #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:378 [inline]
+ print_report+0xba/0x230 mm/kasan/report.c:482
+ kasan_report+0x117/0x150 mm/kasan/report.c:595
+ sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+ unix_stream_sendmsg+0x8a3/0xe80 net/unix/af_unix.c:2482
+ sock_sendmsg_nosec net/socket.c:721 [inline]
+ __sock_sendmsg net/socket.c:736 [inline]
+ ____sys_sendmsg+0x972/0x9f0 net/socket.c:2585
+ ___sys_sendmsg+0x2a5/0x360 net/socket.c:2639
+ __sys_sendmsg net/socket.c:2671 [inline]
+ __do_sys_sendmsg net/socket.c:2676 [inline]
+ __se_sys_sendmsg net/socket.c:2674 [inline]
+ __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2674
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7facf899c819
+Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007facf9827028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007facf8c15fa0 RCX: 00007facf899c819
+RDX: 0000000000000000 RSI: 0000200000000500 RDI: 0000000000000004
+RBP: 00007facf8a32c91 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 00007facf8c16038 R14: 00007facf8c15fa0 R15: 00007ffd41b01c78
+ </TASK>
+
+Allocated by task 11013:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ unpoison_slab_object mm/kasan/common.c:340 [inline]
+ __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:366
+ kasan_slab_alloc include/linux/kasan.h:253 [inline]
+ slab_post_alloc_hook mm/slub.c:4538 [inline]
+ slab_alloc_node mm/slub.c:4866 [inline]
+ kmem_cache_alloc_lru_noprof+0x2b8/0x640 mm/slub.c:4885
+ sock_alloc_inode+0x28/0xc0 net/socket.c:316
+ alloc_inode+0x6a/0x1b0 fs/inode.c:347
+ new_inode_pseudo include/linux/fs.h:3003 [inline]
+ sock_alloc net/socket.c:631 [inline]
+ __sock_create+0x12d/0x9d0 net/socket.c:1562
+ sock_create net/socket.c:1656 [inline]
+ __sys_socketpair+0x1c4/0x560 net/socket.c:1803
+ __do_sys_socketpair net/socket.c:1856 [inline]
+ __se_sys_socketpair net/socket.c:1853 [inline]
+ __x64_sys_socketpair+0x9b/0xb0 net/socket.c:1853
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 15:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
+ poison_slab_object mm/kasan/common.c:253 [inline]
+ __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
+ kasan_slab_free include/linux/kasan.h:235 [inline]
+ slab_free_hook mm/slub.c:2685 [inline]
+ slab_free mm/slub.c:6165 [inline]
+ kmem_cache_free+0x187/0x630 mm/slub.c:6295
+ rcu_do_batch kernel/rcu/tree.c:2617 [inline]
+ rcu_core+0x7cd/0x1070 kernel/rcu/tree.c:2869
+ handle_softirqs+0x22a/0x870 kernel/softirq.c:622
+ run_ksoftirqd+0x36/0x60 kernel/softirq.c:1063
+ smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160
+ kthread+0x388/0x470 kernel/kthread.c:436
+ ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
+
+Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()")
+Closes: https://lore.kernel.org/bpf/69cc6b9f.a70a0220.128fd0.004b.GAE@google.com/
+Reported-by: syzbot+2184232f07e3677fbaef@syzkaller.appspotmail.com
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/skmsg.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/skmsg.c b/net/core/skmsg.c
+index 6ece4eaecd489..2e89087b95c24 100644
+--- a/net/core/skmsg.c
++++ b/net/core/skmsg.c
+@@ -1266,17 +1266,20 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)
+
+ static void sk_psock_verdict_data_ready(struct sock *sk)
+ {
+- struct socket *sock = sk->sk_socket;
+- const struct proto_ops *ops;
++ const struct proto_ops *ops = NULL;
++ struct socket *sock;
+ int copied;
+
+ trace_sk_data_ready(sk);
+
+- if (unlikely(!sock))
+- return;
+- ops = READ_ONCE(sock->ops);
++ rcu_read_lock();
++ sock = READ_ONCE(sk->sk_socket);
++ if (likely(sock))
++ ops = READ_ONCE(sock->ops);
++ rcu_read_unlock();
+ if (!ops || !ops->read_skb)
+ return;
++
+ copied = ops->read_skb(sk, sk_psock_verdict_recv);
+ if (copied >= 0) {
+ struct sk_psock *psock;
+--
+2.53.0
+
--- /dev/null
+From d38740294b73d082bbcbc6244b4f4f59351d6e7a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index c7869a286df40..b8bfc336ff7a7 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -248,12 +248,12 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -261,7 +261,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -278,6 +278,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -465,9 +467,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From c3ebc1a3f8e1df1b053dca4f72ae4af18a42166f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 11:53:46 +0100
+Subject: btrfs: don't take device_list_mutex when querying zone info
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 77603ab10429fe713a03345553ca8dbbfb1d91c6 ]
+
+Shin'ichiro reported sporadic hangs when running generic/013 in our CI
+system. When enabling lockdep, there is a lockdep splat when calling
+btrfs_get_dev_zone_info_all_devices() in the mount path that can be
+triggered by i.e. generic/013:
+
+ ======================================================
+ WARNING: possible circular locking dependency detected
+ 7.0.0-rc1+ #355 Not tainted
+ ------------------------------------------------------
+ mount/1043 is trying to acquire lock:
+ ffff8881020b5470 (&vblk->vdev_mutex){+.+.}-{4:4}, at: virtblk_report_zones+0xda/0x430
+
+ but task is already holding lock:
+ ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #4 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
+ __mutex_lock+0xa3/0x1360
+ btrfs_create_pending_block_groups+0x1f4/0x9d0
+ __btrfs_end_transaction+0x3e/0x2e0
+ btrfs_zoned_reserve_data_reloc_bg+0x2f8/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #3 (btrfs_trans_num_extwriters){++++}-{0:0}:
+ join_transaction+0xc2/0x5c0
+ start_transaction+0x17c/0xbc0
+ btrfs_zoned_reserve_data_reloc_bg+0x2b4/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #2 (btrfs_trans_num_writers){++++}-{0:0}:
+ lock_release+0x163/0x4b0
+ __btrfs_end_transaction+0x1c7/0x2e0
+ btrfs_dirty_inode+0x6f/0xd0
+ touch_atime+0xe5/0x2c0
+ btrfs_file_mmap_prepare+0x65/0x90
+ __mmap_region+0x4b9/0xf00
+ mmap_region+0xf7/0x120
+ do_mmap+0x43d/0x610
+ vm_mmap_pgoff+0xd6/0x190
+ ksys_mmap_pgoff+0x7e/0xc0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #1 (&mm->mmap_lock){++++}-{4:4}:
+ __might_fault+0x68/0xa0
+ _copy_to_user+0x22/0x70
+ blkdev_copy_zone_to_user+0x22/0x40
+ virtblk_report_zones+0x282/0x430
+ blkdev_report_zones_ioctl+0xfd/0x130
+ blkdev_ioctl+0x20f/0x2c0
+ __x64_sys_ioctl+0x86/0xd0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #0 (&vblk->vdev_mutex){+.+.}-{4:4}:
+ __lock_acquire+0x1522/0x2680
+ lock_acquire+0xd5/0x2f0
+ __mutex_lock+0xa3/0x1360
+ virtblk_report_zones+0xda/0x430
+ blkdev_report_zones_cached+0x162/0x190
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ other info that might help us debug this:
+
+ Chain exists of:
+ &vblk->vdev_mutex --> btrfs_trans_num_extwriters --> &fs_devs->device_list_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&fs_devs->device_list_mutex);
+ lock(btrfs_trans_num_extwriters);
+ lock(&fs_devs->device_list_mutex);
+ lock(&vblk->vdev_mutex);
+
+ *** DEADLOCK ***
+
+ 3 locks held by mount/1043:
+ #0: ffff88811063e878 (&fc->uapi_mutex){+.+.}-{4:4}, at: __do_sys_fsconfig+0x2ae/0x680
+ #1: ffff88810cb9f0e8 (&type->s_umount_key#31/1){+.+.}-{4:4}, at: alloc_super+0xc0/0x3e0
+ #2: ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 1043 Comm: mount Not tainted 7.0.0-rc1+ #355 PREEMPT(full)
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x80
+ print_circular_bug.cold+0x18d/0x1d8
+ check_noncircular+0x10d/0x130
+ __lock_acquire+0x1522/0x2680
+ ? vmap_small_pages_range_noflush+0x3ef/0x820
+ lock_acquire+0xd5/0x2f0
+ ? virtblk_report_zones+0xda/0x430
+ ? lock_is_held_type+0xcd/0x130
+ __mutex_lock+0xa3/0x1360
+ ? virtblk_report_zones+0xda/0x430
+ ? virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ ? virtblk_report_zones+0xda/0x430
+ virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ blkdev_report_zones_cached+0x162/0x190
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ ? rcu_is_watching+0x18/0x50
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ RIP: 0033:0x7f615e27a40e
+ RSP: 002b:00007fff11b18fb8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ RAX: ffffffffffffffda RBX: 000055572e92ab10 RCX: 00007f615e27a40e
+ RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ RBP: 00007fff11b19100 R08: 0000000000000000 R09: 0000000000000000
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055572e92bc40 R14: 00007f615e3faa60 R15: 000055572e92bd08
+ </TASK>
+
+Don't hold the device_list_mutex while calling into
+btrfs_get_dev_zone_info() in btrfs_get_dev_zone_info_all_devices() to
+mitigate the issue. This is safe, as no other thread can touch the device
+list at the moment of execution.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index e0c5ff2e08c1f..d9c26f4be6634 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -331,7 +331,10 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (!btrfs_fs_incompat(fs_info, ZONED))
+ return 0;
+
+- mutex_lock(&fs_devices->device_list_mutex);
++ /*
++ * No need to take the device_list mutex here, we're still in the mount
++ * path and devices cannot be added to or removed from the list yet.
++ */
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ /* We can skip reading of zone info for missing devices */
+ if (!device->bdev)
+@@ -341,7 +344,6 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (ret)
+ break;
+ }
+- mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
+ }
+--
+2.53.0
+
--- /dev/null
+From 036d74c03e59ac8db079e9d6f6b9c8900a9756cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Mar 2026 08:14:43 +0800
+Subject: btrfs: reject root items with drop_progress and zero drop_level
+
+From: ZhengYuan Huang <gality369@gmail.com>
+
+[ Upstream commit b17b79ff896305fd74980a5f72afec370ee88ca4 ]
+
+[BUG]
+When recovering relocation at mount time, merge_reloc_root() and
+btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
+an impossible state: a non-zero drop_progress combined with a zero
+drop_level in a root_item, which can be triggered:
+
+------------[ cut here ]------------
+kernel BUG at fs/btrfs/relocation.c:1545!
+Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
+CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
+Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
+RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
+Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
+Call Trace:
+ merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
+ btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
+ btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
+ open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
+ btrfs_fill_super fs/btrfs/super.c:987 [inline]
+ btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
+ btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
+ btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
+ vfs_get_tree+0x9a/0x370 fs/super.c:1758
+ fc_mount fs/namespace.c:1199 [inline]
+ do_new_mount_fc fs/namespace.c:3642 [inline]
+ do_new_mount fs/namespace.c:3718 [inline]
+ path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
+ do_mount fs/namespace.c:4041 [inline]
+ __do_sys_mount fs/namespace.c:4229 [inline]
+ __se_sys_mount fs/namespace.c:4206 [inline]
+ __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
+ ...
+RIP: 0033:0x7f969c9a8fde
+Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
+---[ end trace 0000000000000000 ]---
+
+The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
+metadata fuzzing tool that corrupts btrfs metadata at runtime.
+
+[CAUSE]
+A non-zero drop_progress.objectid means an interrupted
+btrfs_drop_snapshot() left a resume point on disk, and in that case
+drop_level must be greater than 0 because the checkpoint is only
+saved at internal node levels.
+
+Although this invariant is enforced when the kernel writes the root
+item, it is not validated when the root item is read back from disk.
+That allows on-disk corruption to provide an invalid state with
+drop_progress.objectid != 0 and drop_level == 0.
+
+When relocation recovery later processes such a root item,
+merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
+same invalid metadata can also trigger the corresponding BUG_ON() in
+btrfs_drop_snapshot().
+
+[FIX]
+Fix this by validating the root_item invariant in tree-checker when
+reading root items from disk: if drop_progress.objectid is non-zero,
+drop_level must also be non-zero. Reject such malformed metadata with
+-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
+and triggers the BUG_ON.
+
+After the fix, the same corruption is correctly rejected by tree-checker
+and the BUG_ON is no longer triggered.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 7e9475e2a047b..7376ce6049a92 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -1248,6 +1248,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
+ btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
+ return -EUCLEAN;
+ }
++ /*
++ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
++ * interrupted and the resume point was recorded in drop_progress and
++ * drop_level. In that case drop_level must be >= 1: level 0 is the
++ * leaf level and drop_snapshot never saves a checkpoint there (it
++ * only records checkpoints at internal node levels in DROP_REFERENCE
++ * stage). A zero drop_level combined with a non-zero drop_progress
++ * objectid indicates on-disk corruption and would cause a BUG_ON in
++ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
++ */
++ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
++ btrfs_root_drop_level(&ri) == 0)) {
++ generic_err(leaf, slot,
++ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
++ btrfs_disk_key_objectid(&ri.drop_progress));
++ return -EUCLEAN;
++ }
+
+ /* Flags check */
+ if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
+--
+2.53.0
+
--- /dev/null
+From 16aec98240998e5e50b56ddb8b772da2fbadb0de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Feb 2026 16:08:53 +0000
+Subject: btrfs: reserve enough transaction items for qgroup ioctls
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit f9a4e3015db1aeafbef407650eb8555445ca943e ]
+
+Currently our qgroup ioctls don't reserve any space, they just do a
+transaction join, which does not reserve any space, neither for the quota
+tree updates nor for the delayed refs generated when updating the quota
+tree. The quota root uses the global block reserve, which is fine most of
+the time since we don't expect a lot of updates to the quota root, or to
+be too close to -ENOSPC such that other critical metadata updates need to
+resort to the global reserve.
+
+However this is not optimal, as not reserving proper space may result in a
+transaction abort due to not reserving space for delayed refs and then
+abusing the use of the global block reserve.
+
+For example, the following reproducer (which is unlikely to model any
+real world use case, but just to illustrate the problem), triggers such a
+transaction abort due to -ENOSPC when running delayed refs:
+
+ $ cat test.sh
+ #!/bin/bash
+
+ DEV=/dev/nullb0
+ MNT=/mnt/nullb0
+
+ umount $DEV &> /dev/null
+ # Limit device to 1G so that it's much faster to reproduce the issue.
+ mkfs.btrfs -f -b 1G $DEV
+ mount -o commit=600 $DEV $MNT
+
+ fallocate -l 800M $MNT/filler
+ btrfs quota enable $MNT
+
+ for ((i = 1; i <= 400000; i++)); do
+ btrfs qgroup create 1/$i $MNT
+ done
+
+ umount $MNT
+
+When running this, we can see in dmesg/syslog that a transaction abort
+happened:
+
+ [436.490] BTRFS error (device nullb0): failed to run delayed ref for logical 30408704 num_bytes 16384 type 176 action 1 ref_mod 1: -28
+ [436.493] ------------[ cut here ]------------
+ [436.494] BTRFS: Transaction aborted (error -28)
+ [436.495] WARNING: fs/btrfs/extent-tree.c:2247 at btrfs_run_delayed_refs+0xd9/0x110 [btrfs], CPU#4: umount/2495372
+ [436.497] Modules linked in: btrfs loop (...)
+ [436.508] CPU: 4 UID: 0 PID: 2495372 Comm: umount Tainted: G W 6.19.0-rc8-btrfs-next-225+ #1 PREEMPT(full)
+ [436.510] Tainted: [W]=WARN
+ [436.511] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
+ [436.513] RIP: 0010:btrfs_run_delayed_refs+0xdf/0x110 [btrfs]
+ [436.514] Code: 0f 82 ea (...)
+ [436.518] RSP: 0018:ffffd511850b7d78 EFLAGS: 00010292
+ [436.519] RAX: 00000000ffffffe4 RBX: ffff8f120dad37e0 RCX: 0000000002040001
+ [436.520] RDX: 0000000000000002 RSI: 00000000ffffffe4 RDI: ffffffffc090fd80
+ [436.522] RBP: 0000000000000000 R08: 0000000000000001 R09: ffffffffc04d1867
+ [436.523] R10: ffff8f18dc1fffa8 R11: 0000000000000003 R12: ffff8f173aa89400
+ [436.524] R13: 0000000000000000 R14: ffff8f173aa89400 R15: 0000000000000000
+ [436.526] FS: 00007fe59045d840(0000) GS:ffff8f192e22e000(0000) knlGS:0000000000000000
+ [436.527] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ [436.528] CR2: 00007fe5905ff2b0 CR3: 000000060710a002 CR4: 0000000000370ef0
+ [436.530] Call Trace:
+ [436.530] <TASK>
+ [436.530] btrfs_commit_transaction+0x73/0xc00 [btrfs]
+ [436.531] ? btrfs_attach_transaction_barrier+0x1e/0x70 [btrfs]
+ [436.532] sync_filesystem+0x7a/0x90
+ [436.533] generic_shutdown_super+0x28/0x180
+ [436.533] kill_anon_super+0x12/0x40
+ [436.534] btrfs_kill_super+0x12/0x20 [btrfs]
+ [436.534] deactivate_locked_super+0x2f/0xb0
+ [436.534] cleanup_mnt+0xea/0x180
+ [436.535] task_work_run+0x58/0xa0
+ [436.535] exit_to_user_mode_loop+0xed/0x480
+ [436.536] ? __x64_sys_umount+0x68/0x80
+ [436.536] do_syscall_64+0x2a5/0xf20
+ [436.537] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ [436.537] RIP: 0033:0x7fe5906b6217
+ [436.538] Code: 0d 00 f7 (...)
+ [436.540] RSP: 002b:00007ffcd87a61f8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+ [436.541] RAX: 0000000000000000 RBX: 00005618b9ecadc8 RCX: 00007fe5906b6217
+ [436.541] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00005618b9ecb100
+ [436.542] RBP: 0000000000000000 R08: 00007ffcd87a4fe0 R09: 00000000ffffffff
+ [436.544] R10: 0000000000000103 R11: 0000000000000246 R12: 00007fe59081626c
+ [436.544] R13: 00005618b9ecb100 R14: 0000000000000000 R15: 00005618b9ecacc0
+ [436.545] </TASK>
+ [436.545] ---[ end trace 0000000000000000 ]---
+
+Fix this by changing the qgroup ioctls to use start transaction instead of
+joining so that proper space is reserved for the delayed refs generated
+for the updates to the quota root. This way we don't get any transaction
+abort.
+
+Reviewed-by: Boris Burkov <boris@bur.io>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ioctl.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index 9a548f2eec3af..45852dbf9dfbc 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3861,7 +3861,8 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
+ }
+ }
+
+- trans = btrfs_join_transaction(root);
++ /* 2 BTRFS_QGROUP_RELATION_KEY items. */
++ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+@@ -3933,7 +3934,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
+ goto out;
+ }
+
+- trans = btrfs_join_transaction(root);
++ /*
++ * 1 BTRFS_QGROUP_INFO_KEY item.
++ * 1 BTRFS_QGROUP_LIMIT_KEY item.
++ */
++ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+@@ -3982,7 +3987,8 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
+ goto drop_write;
+ }
+
+- trans = btrfs_join_transaction(root);
++ /* 1 BTRFS_QGROUP_LIMIT_KEY item. */
++ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+--
+2.53.0
+
--- /dev/null
+From 09894ce72fbbfcac92727ebc35b0ff4827064003 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 6c271e55f44d9..78e995dddf879 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -623,8 +623,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From 6510646894f03afac4e828a28aacababdede4a7f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:13 +0200
+Subject: crypto: caam - fix DMA corruption on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 5ddfdcbe10dc5f97afc4e46ca22be2be717e8caf ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The rounding was performed, but never actually used for the allocation.
+Fix this by replacing kmemdup with kmalloc for a larger buffer,
+followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Reported-by: Paul Bunyan <pbunyan@redhat.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamhash.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
+index 25c02e2672585..053af748be86d 100644
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -441,9 +441,10 @@ static int ahash_setkey(struct crypto_ahash *ahash,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, keylen, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From f5f523a227b76d5438677c8b144ff9747752f2f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:14 +0200
+Subject: crypto: caam - fix overflow on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 80688afb9c35b3934ce2d6be9973758915e2e0ef ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The copying is performed using kmemdup, however this leads to an overflow:
+reading more bytes (aligned_len - keylen) from the keylen source buffer.
+Fix this by replacing kmemdup with kmalloc, followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamalg_qi2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
+index ece9f1e5a689f..9ef8ee77c52aa 100644
+--- a/drivers/crypto/caam/caamalg_qi2.c
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -3325,9 +3325,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, aligned_len, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From 48fd9ee11b6b778864b811a18e14f8d9cc07d651 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Mar 2026 16:59:55 -0500
+Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix
+ common property warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 398c0c8bbc8f5a9d2f43863275a427a9d3720b6f ]
+
+Change additionalProperties to unevaluatedProperties because it refs to
+/schemas/input/matrix-keymap.yaml.
+
+Fix below CHECK_DTBS warnings:
+arch/arm/boot/dts/nxp/imx/imx6dl-victgo.dtb: keypad@70 (holtek,ht16k33): 'keypad,num-columns', 'keypad,num-rows' do not match any of the regexes: '^pinctrl-[0-9]+$'
+ from schema $id: http://devicetree.org/schemas/auxdisplay/holtek,ht16k33.yaml#
+
+Fixes: f12b457c6b25c ("dt-bindings: auxdisplay: ht16k33: Convert to json-schema")
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../devicetree/bindings/auxdisplay/holtek,ht16k33.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+index b90eec2077b4b..fe1272e86467e 100644
+--- a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++++ b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+@@ -66,7 +66,7 @@ then:
+ required:
+ - refresh-rate-hz
+
+-additionalProperties: false
++unevaluatedProperties: false
+
+ examples:
+ - |
+--
+2.53.0
+
--- /dev/null
+From f6c23ec1550fa3f9a10760a84e15501aa694d25d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 12:51:22 -0700
+Subject: eth: fbnic: Account for page fragments when updating BDQ tail
+
+From: Dimitri Daskalakis <daskald@meta.com>
+
+[ Upstream commit b38c55320bf85a84a4f04803c57b261fc87e9b4b ]
+
+FBNIC supports fixed size buffers of 4K. When PAGE_SIZE > 4K, we
+fragment the page across multiple descriptors (FBNIC_BD_FRAG_COUNT).
+When refilling the BDQ, the correct number of entries are populated,
+but tail was only incremented by one. So on a system with 64K pages,
+HW would get one descriptor refilled for every 16 we populate.
+
+Additionally, we program the ring size in the HW when enabling the BDQ.
+This was not accounting for page fragments, so on systems with 64K pages,
+the HW used 1/16th of the ring.
+
+Fixes: 0cb4c0a13723 ("eth: fbnic: Implement Rx queue alloc/start/stop/free")
+Signed-off-by: Dimitri Daskalakis <daskald@meta.com>
+Link: https://patch.msgid.link/20260324195123.3486219-2-dimitri.daskalakis1@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+index fc52db8e36f2e..16a0e30f8aaa5 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+@@ -544,7 +544,7 @@ static void fbnic_fill_bdq(struct fbnic_napi_vector *nv, struct fbnic_ring *bdq)
+ /* Force DMA writes to flush before writing to tail */
+ dma_wmb();
+
+- writel(i, bdq->doorbell);
++ writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell);
+ }
+ }
+
+@@ -1783,7 +1783,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
+ hpq->tail = 0;
+ hpq->head = 0;
+
+- log_size = fls(hpq->size_mask);
++ log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+
+ /* Store descriptor ring address and size */
+ fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma));
+@@ -1795,7 +1795,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
+ if (!ppq->size_mask)
+ goto write_ctl;
+
+- log_size = fls(ppq->size_mask);
++ log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+
+ /* Add enabling of PPQ to BDQ control */
+ bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;
+--
+2.53.0
+
--- /dev/null
+From 6b0d8919c38c9c0793681fc2f113f4aefbda1726 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Mar 2026 20:19:33 +0100
+Subject: HID: logitech-hidpp: Enable MX Master 4 over bluetooth
+
+From: Adrian Freund <adrian@freund.io>
+
+[ Upstream commit 70031e70ca15ede6a39db4d978e53a6cc720d454 ]
+
+The Logitech MX Master 4 can be connected over bluetooth or through a
+Logitech Bolt receiver. This change adds support for non-standard HID
+features, such as high resolution scrolling when the mouse is connected
+over bluetooth.
+Because no Logitech Bolt receiver driver exists yet those features
+won't be available when the mouse is connected through the receiver.
+
+Signed-off-by: Adrian Freund <adrian@freund.io>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-hidpp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
+index 492a02ca80594..c9df222e894a1 100644
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4695,6 +4695,8 @@ static const struct hid_device_id hidpp_devices[] = {
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
+ { /* Slim Solar+ K980 Keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
++ { /* MX Master 4 mouse over Bluetooth */
++ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb042) },
+ {}
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 8d2118cf4d85428cbe9fab70896eb25a1d76cf89 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 10:09:38 +0000
+Subject: HID: logitech-hidpp: Prevent use-after-free on force feedback
+ initialisation failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit f7a4c78bfeb320299c1b641500fe7761eadbd101 ]
+
+Presently, if the force feedback initialisation fails when probing the
+Logitech G920 Driving Force Racing Wheel for Xbox One, an error number
+will be returned and propagated before the userspace infrastructure
+(sysfs and /dev/input) has been torn down. If userspace ignores the
+errors and continues to use its references to these dangling entities, a
+UAF will promptly follow.
+
+We have 2 options; continue to return the error, but ensure that all of
+the infrastructure is torn down accordingly or continue to treat this
+condition as a warning by emitting the message but returning success.
+It is thought that the original author's intention was to emit the
+warning but keep the device functional, less the force feedback feature,
+so let's go with that.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Reviewed-by: Günther Noack <gnoack@google.com>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-hidpp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
+index c9df222e894a1..d60cd4379e866 100644
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4514,10 +4514,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ if (!ret)
+ ret = hidpp_ff_init(hidpp, &data);
+
+- if (ret)
++ if (ret) {
+ hid_warn(hidpp->hid_dev,
+ "Unable to initialize force feedback support, errno %d\n",
+ ret);
++ ret = 0;
++ }
+ }
+
+ /*
+--
+2.53.0
+
--- /dev/null
+From 7b467e2ac1b850e2fd47e8f28164b1bb18e4bba7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index eb148988484bf..fcf9a806f109a 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -493,12 +493,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From b3f22fa417be9611dec5cd22de757c775628711e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index a076dc0b60ee2..5b97df856d3ea 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1210,10 +1210,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From e448303a5a42e279acb249dced824e2129349883 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:32:11 +0900
+Subject: i2c: tegra: Don't mark devices with pins as IRQ safe
+
+From: Mikko Perttunen <mperttunen@nvidia.com>
+
+[ Upstream commit ec69c9e88315c4be70c283f18c2ff130da6320b5 ]
+
+I2C devices with associated pinctrl states (DPAUX I2C controllers)
+will change pinctrl state during runtime PM. This requires taking
+a mutex, so these devices cannot be marked as IRQ safe.
+
+Add PINCTRL as dependency to avoid build errors.
+
+Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
+Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/Kconfig | 2 ++
+ drivers/i2c/busses/i2c-tegra.c | 5 ++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 0e679cc501488..b0185c09660b2 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -1177,6 +1177,8 @@ config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
+ # COMPILE_TEST needs architectures with readsX()/writesX() primitives
++ depends on PINCTRL
++ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
+index fbab82d457fb0..c57a2af5ea8cc 100644
+--- a/drivers/i2c/busses/i2c-tegra.c
++++ b/drivers/i2c/busses/i2c-tegra.c
+@@ -1786,8 +1786,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
+ *
+ * VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
+ * be used for atomic transfers. ACPI device is not IRQ safe also.
++ *
++ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
++ * state transitions during runtime PM require mutexes.
+ */
+- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
++ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
+ pm_runtime_irq_safe(i2c_dev->dev);
+
+ pm_runtime_enable(i2c_dev->dev);
+--
+2.53.0
+
--- /dev/null
+From 1b49143271fba772b111f1daef3f0cc5dfb3847c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 9f1b66bb513c7..f0a8350eb52eb 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From 6dc20d7258ba7506b70af613471fe097ebd5e2b9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index fff78496803da..9a83f658cd892 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -762,6 +762,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -923,9 +924,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -968,12 +973,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From 36bcc65a567db2b6a7fdf894493a0dec5bf80bfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index e43b49f1ddbb2..387400829b207 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -681,6 +681,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From c8027a5ccc36965ede8e4e95efaab75394277ff6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 63ada312061c6..e104ec8efe1c0 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3642,12 +3642,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 85dbe88a74fc5aa0c3d10b5e45aa525be6b72a50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:48:21 +0100
+Subject: net: airoha: Add missing cleanup bits in
+ airoha_qdma_cleanup_rx_queue()
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit 514aac3599879a7ed48b7dc19e31145beb6958ac ]
+
+In order to properly cleanup hw rx QDMA queues and bring the device to
+the initial state, reset rx DMA queue head/tail index. Moreover, reset
+queued DMA descriptor fields.
+
+Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
+Tested-by: Madhur Agrawal <Madhur.Agrawal@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260327-airoha_qdma_cleanup_rx_queue-fix-v1-1-369d6ab1511a@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mediatek/airoha_eth.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c
+index da259c4b03fbf..7a85550e5ecb3 100644
+--- a/drivers/net/ethernet/mediatek/airoha_eth.c
++++ b/drivers/net/ethernet/mediatek/airoha_eth.c
+@@ -1615,18 +1615,34 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
+
+ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
+ {
+- struct airoha_eth *eth = q->qdma->eth;
++ struct airoha_qdma *qdma = q->qdma;
++ struct airoha_eth *eth = qdma->eth;
++ int qid = q - &qdma->q_rx[0];
+
+ while (q->queued) {
+ struct airoha_queue_entry *e = &q->entry[q->tail];
++ struct airoha_qdma_desc *desc = &q->desc[q->tail];
+ struct page *page = virt_to_head_page(e->buf);
+
+ dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
+ page_pool_get_dma_dir(q->page_pool));
+ page_pool_put_full_page(q->page_pool, page, false);
++ /* Reset DMA descriptor */
++ WRITE_ONCE(desc->ctrl, 0);
++ WRITE_ONCE(desc->addr, 0);
++ WRITE_ONCE(desc->data, 0);
++ WRITE_ONCE(desc->msg0, 0);
++ WRITE_ONCE(desc->msg1, 0);
++ WRITE_ONCE(desc->msg2, 0);
++ WRITE_ONCE(desc->msg3, 0);
++
+ q->tail = (q->tail + 1) % q->ndesc;
+ q->queued--;
+ }
++
++ q->head = q->tail;
++ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
++ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
+ }
+
+ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
+--
+2.53.0
+
--- /dev/null
+From b135fa59e132a4101a90668c05580c12afb28dbc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:52:32 +0800
+Subject: net: enetc: check whether the RSS algorithm is Toeplitz
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit d389954a6cae7bf76b7b082ac3511d177b77ef2d ]
+
+Both ENETC v1 and v4 only provide Toeplitz RSS support. This patch adds
+a validation check to reject attempts to configure other RSS algorithms,
+avoiding misleading configuration options for users.
+
+Fixes: d382563f541b ("enetc: Add RFS and RSS support")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Link: https://patch.msgid.link/20260326075233.3628047-2-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+index 7ec6e4a54b8ec..0aac39e2acab1 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -731,6 +731,10 @@ static int enetc_set_rxfh(struct net_device *ndev,
+ struct enetc_hw *hw = &priv->si->hw;
+ int err = 0;
+
++ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
++ rxfh->hfunc != ETH_RSS_HASH_TOP)
++ return -EOPNOTSUPP;
++
+ /* set hash key, if PF */
+ if (rxfh->key && hw->port)
+ enetc_set_rss_key(hw, rxfh->key);
+--
+2.53.0
+
--- /dev/null
+From 095b9576e0755474f0e64224978ea01eaa074f58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:32:30 +0100
+Subject: net: fec: fix the PTP periodic output sysfs interface
+
+From: Buday Csaba <buday.csaba@prolan.hu>
+
+[ Upstream commit e8e44c98f789dee45cfd24ffb9d4936e0606d7c6 ]
+
+When the PPS channel configuration was implemented, the channel
+index for the periodic outputs was configured as the hardware
+channel number.
+
+The sysfs interface uses a logical channel index, and rejects numbers
+greater than `n_per_out` (see period_store() in ptp_sysfs.c).
+That property was left at 1, since the driver implements channel
+selection, not simultaneous operation of multiple PTP hardware timer
+channels.
+
+A second check in fec_ptp_enable() returns -EOPNOTSUPP when the two
+channel numbers disagree, making channels 1..3 unusable from sysfs.
+
+Fix by removing this redundant check in the FEC PTP driver.
+
+Fixes: 566c2d83887f ("net: fec: make PPS channel configurable")
+Signed-off-by: Buday Csaba <buday.csaba@prolan.hu>
+Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/fec_ptp.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
+index 4bb894b5afcb9..778713c2fed40 100644
+--- a/drivers/net/ethernet/freescale/fec_ptp.c
++++ b/drivers/net/ethernet/freescale/fec_ptp.c
+@@ -546,9 +546,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
+ if (rq->perout.flags)
+ return -EOPNOTSUPP;
+
+- if (rq->perout.index != fep->pps_channel)
+- return -EOPNOTSUPP;
+-
+ period.tv_sec = rq->perout.period.sec;
+ period.tv_nsec = rq->perout.period.nsec;
+ period_ns = timespec64_to_ns(&period);
+--
+2.53.0
+
--- /dev/null
+From dc1f19d0157b4913d509f8b361de3f709b748bbe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 11:22:43 +0200
+Subject: net: hsr: fix VLAN add unwind on slave errors
+
+From: Luka Gejak <luka.gejak@linux.dev>
+
+[ Upstream commit 2e3514e63bfb0e972b1f19668547a455d0129e88 ]
+
+When vlan_vid_add() fails for a secondary slave, the error path calls
+vlan_vid_del() on the failing port instead of the peer slave that had
+already succeeded. This results in asymmetric VLAN state across the HSR
+pair.
+
+Fix this by switching to a centralized unwind path that removes the VID
+from any slave device that was already programmed.
+
+Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
+Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
+Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index acbd77ce6afce..fddc80c4bd24d 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -531,8 +531,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+ {
+- bool is_slave_a_added = false;
+- bool is_slave_b_added = false;
++ struct net_device *slave_a_dev = NULL;
++ struct net_device *slave_b_dev = NULL;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+@@ -548,33 +548,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+- /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+- if (is_slave_b_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_a_added = true;
++ slave_a_dev = port->dev;
+ break;
+-
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+- /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+- if (is_slave_a_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_b_added = true;
++ slave_b_dev = port->dev;
+ break;
+ default:
++ if (ret)
++ goto unwind;
+ break;
+ }
+ }
+
+ return 0;
++
++unwind:
++ if (slave_a_dev)
++ vlan_vid_del(slave_a_dev, proto, vid);
++
++ if (slave_b_dev)
++ vlan_vid_del(slave_b_dev, proto, vid);
++
++ return ret;
+ }
+
+ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+--
+2.53.0
+
--- /dev/null
+From 87993bc3daa75d1d4036a78542b2cca63df52576 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Jan 2026 17:11:27 +0100
+Subject: net: introduce mangleid_features
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit 31c5a71d982b57df75858974634c2f0a338f2fc6 ]
+
+Some/most devices implementing gso_partial need to disable the GSO partial
+features when the IP ID can't be mangled; to that extend each of them
+implements something alike the following[1]:
+
+ if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID))
+ features &= ~NETIF_F_TSO;
+
+in the ndo_features_check() op, which leads to a bit of duplicate code.
+
+Later patch in the series will implement GSO partial support for virtual
+devices, and the current status quo will require more duplicate code and
+a new indirect call in the TX path for them.
+
+Introduce the mangleid_features mask, allowing the core to disable NIC
+features based on/requiring MANGLEID, without any further intervention
+from the driver.
+
+The same functionality could be alternatively implemented adding a single
+boolean flag to the struct net_device, but would require an additional
+checks in ndo_features_check().
+
+Also note that [1] is incorrect if the NIC additionally implements
+NETIF_F_GSO_UDP_L4, mangleid_features transparently handle even such a
+case.
+
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/5a7cdaeea40b0a29b88e525b6c942d73ed3b8ce7.1769011015.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: ddc748a391dd ("net: use skb_header_pointer() for TCPv4 GSO frag_off check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netdevice.h | 3 +++
+ net/core/dev.c | 5 ++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index fcc1509ca7cb8..ea9b40b196de2 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1760,6 +1760,8 @@ enum netdev_reg_state {
+ *
+ * @mpls_features: Mask of features inheritable by MPLS
+ * @gso_partial_features: value(s) from NETIF_F_GSO\*
++ * @mangleid_features: Mask of features requiring MANGLEID, will be
++ * disabled together with the latter.
+ *
+ * @ifindex: interface index
+ * @group: The group the device belongs to
+@@ -2133,6 +2135,7 @@ struct net_device {
+ netdev_features_t vlan_features;
+ netdev_features_t hw_enc_features;
+ netdev_features_t mpls_features;
++ netdev_features_t mangleid_features;
+
+ unsigned int min_mtu;
+ unsigned int max_mtu;
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 336257b515f04..2748ee051bd1b 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3613,7 +3613,7 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
+ inner_ip_hdr(skb) : ip_hdr(skb);
+
+ if (!(iph->frag_off & htons(IP_DF)))
+- features &= ~NETIF_F_TSO_MANGLEID;
++ features &= ~dev->mangleid_features;
+ }
+
+ /* NETIF_F_IPV6_CSUM does not support IPv6 extension headers,
+@@ -10579,6 +10579,9 @@ int register_netdevice(struct net_device *dev)
+ if (dev->hw_enc_features & NETIF_F_TSO)
+ dev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
+
++ /* TSO_MANGLEID belongs in mangleid_features by definition */
++ dev->mangleid_features |= NETIF_F_TSO_MANGLEID;
++
+ /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
+ */
+ dev->vlan_features |= NETIF_F_HIGHDMA;
+--
+2.53.0
+
--- /dev/null
+From 49bf4797b12c23dfd46aa6db9e5d74aa5803663c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index eca07e10e21fc..9d06d6a50c6d2 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From bfc7052b2d560dacabc76d23852a38ebeb5b3a61 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 15:41:52 +0800
+Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 5e67ba9bb531e1ec6599a82a065dea9040b9ce50 ]
+
+ioam6_fill_trace_data() stores the schema contribution to the trace
+length in a u8. With bit 22 enabled and the largest schema payload,
+sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
+remaining-space check. __ioam6_fill_trace_data() then positions the
+write cursor without reserving the schema area but still copies the
+4-byte schema header and the full schema payload, overrunning the trace
+buffer.
+
+Keep sclen in an unsigned int so the remaining-space check and the write
+cursor calculation both see the full schema length.
+
+Fixes: 8c6f6fa67726 ("ipv6: ioam: IOAM Generic Netlink API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ioam6.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
+index b6ed67d7027c1..868a25c57b924 100644
+--- a/net/ipv6/ioam6.c
++++ b/net/ipv6/ioam6.c
+@@ -712,7 +712,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
+ struct ioam6_namespace *ns,
+ struct ioam6_trace_hdr *trace,
+ struct ioam6_schema *sc,
+- u8 sclen, bool is_input)
++ unsigned int sclen, bool is_input)
+ {
+ struct timespec64 ts;
+ ktime_t tstamp;
+@@ -942,7 +942,7 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
+ bool is_input)
+ {
+ struct ioam6_schema *sc;
+- u8 sclen = 0;
++ unsigned int sclen = 0;
+
+ /* Skip if Overflow flag is set
+ */
+--
+2.53.0
+
--- /dev/null
+From 73a70322e149bea35391b9454c62896ec8423ab3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 480c906cb374c..64bd0cbb67d70 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1220,6 +1220,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From 6429cf407f17f222949ff5c18558d4497c96b842 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index fc4f5aee6ab3f..0ce5b736ea438 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -109,10 +109,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 790701f7bcdb892d6cb704ca9c04a278b134b219 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 0ce5b736ea438..b79dec17e6b09 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -96,10 +96,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -113,8 +113,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From d2b72d3891542c31d8f77a40be7ae3bf0db0b69d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index e9d49afc31db5..0a818bddd0e2f 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -53,9 +53,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index 76ad46bf477d6..5b0c98642b997 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -803,48 +803,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index 6b82a494bd323..1ca75f1815ef6 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -373,8 +373,8 @@ int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ #ifdef CONFIG_MLX5_CORE_EN
+ int mlx5e_init(void);
+--
+2.53.0
+
--- /dev/null
+From 545d6842b908bfb4c2636c16ebf170fba64b1e00 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:15 +0300
+Subject: net/mlx5: Fix switchdev mode rollback in case of failure
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 403186400a1a6166efe7031edc549c15fee4723f ]
+
+If for some internal reason switchdev mode fails, we rollback to legacy
+mode, before this patch, rollback will unregister the uplink netdev and
+leave it unregistered causing the below kernel bug.
+
+To fix this, we need to avoid netdev unregister by setting the proper
+rollback flag 'MLX5_PRIV_FLAGS_SWITCH_LEGACY' to indicate legacy mode.
+
+devlink (431) used greatest stack depth: 11048 bytes left
+mlx5_core 0000:00:03.0: E-Switch: Disable: mode(LEGACY), nvfs(0), \
+ necvfs(0), active vports(0)
+mlx5_core 0000:00:03.0: E-Switch: Supported tc chains and prios offload
+mlx5_core 0000:00:03.0: Loading uplink representor for vport 65535
+mlx5_core 0000:00:03.0: mlx5_cmd_out_err:816:(pid 456): \
+ QUERY_HCA_CAP(0x100) op_mod(0x0) failed, \
+ status bad parameter(0x3), syndrome (0x3a3846), err(-22)
+mlx5_core 0000:00:03.0 enp0s3np0 (unregistered): Unloading uplink \
+ representor for vport 65535
+ ------------[ cut here ]------------
+kernel BUG at net/core/dev.c:12070!
+Oops: invalid opcode: 0000 [#1] SMP NOPTI
+CPU: 2 UID: 0 PID: 456 Comm: devlink Not tainted 6.16.0-rc3+ \
+ #9 PREEMPT(voluntary)
+RIP: 0010:unregister_netdevice_many_notify+0x123/0xae0
+...
+Call Trace:
+[ 90.923094] unregister_netdevice_queue+0xad/0xf0
+[ 90.923323] unregister_netdev+0x1c/0x40
+[ 90.923522] mlx5e_vport_rep_unload+0x61/0xc6
+[ 90.923736] esw_offloads_enable+0x8e6/0x920
+[ 90.923947] mlx5_eswitch_enable_locked+0x349/0x430
+[ 90.924182] ? is_mp_supported+0x57/0xb0
+[ 90.924376] mlx5_devlink_eswitch_mode_set+0x167/0x350
+[ 90.924628] devlink_nl_eswitch_set_doit+0x6f/0xf0
+[ 90.924862] genl_family_rcv_msg_doit+0xe8/0x140
+[ 90.925088] genl_rcv_msg+0x18b/0x290
+[ 90.925269] ? __pfx_devlink_nl_pre_doit+0x10/0x10
+[ 90.925506] ? __pfx_devlink_nl_eswitch_set_doit+0x10/0x10
+[ 90.925766] ? __pfx_devlink_nl_post_doit+0x10/0x10
+[ 90.926001] ? __pfx_genl_rcv_msg+0x10/0x10
+[ 90.926206] netlink_rcv_skb+0x52/0x100
+[ 90.926393] genl_rcv+0x28/0x40
+[ 90.926557] netlink_unicast+0x27d/0x3d0
+[ 90.926749] netlink_sendmsg+0x1f7/0x430
+[ 90.926942] __sys_sendto+0x213/0x220
+[ 90.927127] ? __sys_recvmsg+0x6a/0xd0
+[ 90.927312] __x64_sys_sendto+0x24/0x30
+[ 90.927504] do_syscall_64+0x50/0x1c0
+[ 90.927687] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+[ 90.927929] RIP: 0033:0x7f7d0363e047
+
+Fixes: 2a4f56fbcc47 ("net/mlx5e: Keep netdev when leave switchdev for devlink set legacy only")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Jianbo Liu <jianbol@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-4-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+index b122003d8bcde..39b8b272f4b1c 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+@@ -3575,6 +3575,8 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
+ return 0;
+
+ err_vports:
++ /* rollback to legacy, indicates don't unregister the uplink netdev */
++ esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY;
+ mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK);
+ err_uplink:
+ esw_offloads_steering_cleanup(esw);
+--
+2.53.0
+
--- /dev/null
+From 457522e235e1bd1389e5f5fb1eb9726db98d9b60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:13 +0300
+Subject: net/mlx5: lag: Check for LAG device before creating debugfs
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit bf16bca6653679d8a514d6c1c5a2c67065033f14 ]
+
+__mlx5_lag_dev_add_mdev() may return 0 (success) even when an error
+occurs that is handled gracefully. Consequently, the initialization
+flow proceeds to call mlx5_ldev_add_debugfs() even when there is no
+valid LAG context.
+
+mlx5_ldev_add_debugfs() blindly created the debugfs directory and
+attributes. This exposed interfaces (like the members file) that rely on
+a valid ldev pointer, leading to potential NULL pointer dereferences if
+accessed when ldev is NULL.
+
+Add a check to verify that mlx5_lag_dev(dev) returns a valid pointer
+before attempting to create the debugfs entries.
+
+Fixes: 7f46a0b7327a ("net/mlx5: Lag, add debugfs to query hardware lag state")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Mark Bloch <mbloch@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+index f4b777d4e1086..41ddca52e9547 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+@@ -163,8 +163,11 @@ DEFINE_SHOW_ATTRIBUTE(members);
+
+ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
+ {
++ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+ struct dentry *dbg;
+
++ if (!ldev)
++ return;
+ dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
+ dev->priv.dbg.lag_debugfs = dbg;
+
+--
+2.53.0
+
--- /dev/null
+From 16e38c5814b9232075f1162bdf87d342a2fbd4e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 00c51cf693f3d..b703e4c645853 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -118,7 +118,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -129,7 +129,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -172,6 +172,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -189,11 +190,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -228,9 +227,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -269,12 +266,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -326,9 +324,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -599,7 +595,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -627,6 +623,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -649,10 +646,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From 7cf9b415600e47ab9eab394ddc2f658597ca303c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index d301d0ea2d315..24c1d0480bc54 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2958,6 +2958,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From 719faf09e927550d7b5660b480d9a06f33110a4e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 5c2580a07530e..7eeead60ec23b 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -503,8 +503,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From 23d33246dab73a83b185367d832600c722c3581f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index cdddc86952284..83a7372ea15c2 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -247,8 +247,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From d0b820648b369765b7b5eb9b16806d2b97d07cfa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index d8fd35da32a7c..57221522fe56d 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -555,7 +555,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -598,7 +598,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From 1e8ccd1a1f28be7c39d54208692b1ec39274a235 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:00:21 +0800
+Subject: net/sched: sch_netem: fix out-of-bounds access in packet corruption
+
+From: Yucheng Lu <kanolyc@gmail.com>
+
+[ Upstream commit d64cb81dcbd54927515a7f65e5e24affdc73c14b ]
+
+In netem_enqueue(), the packet corruption logic uses
+get_random_u32_below(skb_headlen(skb)) to select an index for
+modifying skb->data. When an AF_PACKET TX_RING sends fully non-linear
+packets over an IPIP tunnel, skb_headlen(skb) evaluates to 0.
+
+Passing 0 to get_random_u32_below() takes the variable-ceil slow path
+which returns an unconstrained 32-bit random integer. Using this
+unconstrained value as an offset into skb->data results in an
+out-of-bounds memory access.
+
+Fix this by verifying skb_headlen(skb) is non-zero before attempting
+to corrupt the linear data area. Fully non-linear packets will silently
+bypass the corruption logic.
+
+Fixes: c865e5d99e25 ("[PKT_SCHED] netem: packet corruption option")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yuhang Zheng <z1652074432@gmail.com>
+Signed-off-by: Yucheng Lu <kanolyc@gmail.com>
+Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
+Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_netem.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
+index 2270547b51df8..825c398aa1232 100644
+--- a/net/sched/sch_netem.c
++++ b/net/sched/sch_netem.c
+@@ -517,8 +517,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+ goto finish_segs;
+ }
+
+- skb->data[get_random_u32_below(skb_headlen(skb))] ^=
+- 1<<get_random_u32_below(8);
++ if (skb_headlen(skb))
++ skb->data[get_random_u32_below(skb_headlen(skb))] ^=
++ 1 << get_random_u32_below(8);
+ }
+
+ if (unlikely(q->t_len >= sch->limit)) {
+--
+2.53.0
+
--- /dev/null
+From 53f215d2bbebbaa9e8015f905c276b33bf6c03fe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:20:38 +0100
+Subject: net: sfp: Fix Ubiquiti U-Fiber Instant SFP module on mvneta
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marek Behún <kabel@kernel.org>
+
+[ Upstream commit eeee5a710f26ce57807024ef330fe5a850eaecd8 ]
+
+In commit 8110633db49d7de2 ("net: sfp-bus: allow SFP quirks to override
+Autoneg and pause bits") we moved the setting of Autoneg and pause bits
+before the call to SFP quirk when parsing SFP module support.
+
+Since the quirk for Ubiquiti U-Fiber Instant SFP module zeroes the
+support bits and sets 1000baseX_Full only, the above mentioned commit
+changed the overall computed support from
+ 1000baseX_Full, Autoneg, Pause, Asym_Pause
+to just
+ 1000baseX_Full.
+
+This broke the SFP module for mvneta, which requires Autoneg for
+1000baseX since commit c762b7fac1b249a9 ("net: mvneta: deny disabling
+autoneg for 802.3z modes").
+
+Fix this by setting back the Autoneg, Pause and Asym_Pause bits in the
+quirk.
+
+Fixes: 8110633db49d7de2 ("net: sfp-bus: allow SFP quirks to override Autoneg and pause bits")
+Signed-off-by: Marek Behún <kabel@kernel.org>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/20260326122038.2489589-1-kabel@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/sfp.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
+index dd8d37b44aac8..9d9c1779da900 100644
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -473,11 +473,16 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
+ {
+ /* Ubiquiti U-Fiber Instant module claims that support all transceiver
+ * types including 10G Ethernet which is not truth. So clear all claimed
+- * modes and set only one mode which module supports: 1000baseX_Full.
++ * modes and set only one mode which module supports: 1000baseX_Full,
++ * along with the Autoneg and pause bits.
+ */
+ linkmode_zero(caps->link_modes);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+ caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, caps->link_modes);
++
+ phy_interface_zero(caps->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, caps->interfaces);
+ }
+--
+2.53.0
+
--- /dev/null
+From 78512bd234f0698948500d32cb06473ce4b8f61a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 23:35:07 +0800
+Subject: net: use skb_header_pointer() for TCPv4 GSO frag_off check
+
+From: Guoyu Su <yss2813483011xxl@gmail.com>
+
+[ Upstream commit ddc748a391dd8642ba6b2e4fe22e7f2ddf84b7f0 ]
+
+Syzbot reported a KMSAN uninit-value warning in gso_features_check()
+called from netif_skb_features() [1].
+
+gso_features_check() reads iph->frag_off to decide whether to clear
+mangleid_features. Accessing the IPv4 header via ip_hdr()/inner_ip_hdr()
+can rely on skb header offsets that are not always safe for direct
+dereference on packets injected from PF_PACKET paths.
+
+Use skb_header_pointer() for the TCPv4 frag_off check so the header read
+is robust whether data is already linear or needs copying.
+
+[1] https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
+
+Link: https://lore.kernel.org/netdev/willemdebruijn.kernel.1a9f35039caab@gmail.com/
+Fixes: cbc53e08a793 ("GSO: Add GSO type for fixed IPv4 ID")
+Reported-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
+Tested-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
+Signed-off-by: Guoyu Su <yss2813483011xxl@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20260327153507.39742-1-yss2813483011xxl@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/dev.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 2748ee051bd1b..9c4f0e5f2c136 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3609,10 +3609,15 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
+ * IPv4 header has the potential to be fragmented.
+ */
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
+- struct iphdr *iph = skb->encapsulation ?
+- inner_ip_hdr(skb) : ip_hdr(skb);
++ const struct iphdr *iph;
++ struct iphdr _iph;
++ int nhoff = skb->encapsulation ?
++ skb_inner_network_offset(skb) :
++ skb_network_offset(skb);
+
+- if (!(iph->frag_off & htons(IP_DF)))
++ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
++
++ if (!iph || !(iph->frag_off & htons(IP_DF)))
+ features &= ~dev->mangleid_features;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 3019c41bdbc350ca81e500500db00f620d2e2aeb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 0dbc73efab1cb..e47ebd8acd21b 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 9e19a5b40dad849c55a412e088ddf5e83f310ede Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index b981a4828d08c..0dbc73efab1cb 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From 2e816a6314cb3feef543e038d82ad575cc5d8609 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index d64b8abcf0186..cbdca0fb89454 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -104,7 +104,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -130,7 +130,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From 397a7fa2536b5c21f0c33207030177b572db6b8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 11:26:22 +0200
+Subject: netfilter: ctnetlink: ignore explicit helper on new expectations
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 917b61fa2042f11e2af4c428e43f08199586633a ]
+
+Use the existing master conntrack helper, anything else is not really
+supported and it just makes validation more complicated, so just ignore
+what helper userspace suggests for this expectation.
+
+This was uncovered when validating CTA_EXPECT_CLASS via different helper
+provided by userspace than the existing master conntrack helper:
+
+ BUG: KASAN: slab-out-of-bounds in nf_ct_expect_related_report+0x2479/0x27c0
+ Read of size 4 at addr ffff8880043fe408 by task poc/102
+ Call Trace:
+ nf_ct_expect_related_report+0x2479/0x27c0
+ ctnetlink_create_expect+0x22b/0x3b0
+ ctnetlink_new_expect+0x4bd/0x5c0
+ nfnetlink_rcv_msg+0x67a/0x950
+ netlink_rcv_skb+0x120/0x350
+
+Allowing to read kernel memory bytes off the expectation boundary.
+
+CTA_EXPECT_HELP_NAME is still used to offer the helper name to userspace
+via netlink dump.
+
+Fixes: bd0779370588 ("netfilter: nfnetlink_queue: allow to attach expectations to conntracks")
+Reported-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 54 +++++-----------------------
+ 1 file changed, 9 insertions(+), 45 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index d262e64f1c152..323e147fe282b 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2630,7 +2630,6 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask);
+
+@@ -2859,7 +2858,6 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ {
+ struct nlattr *cda[CTA_EXPECT_MAX+1];
+ struct nf_conntrack_tuple tuple, mask;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ int err;
+
+@@ -2873,17 +2871,8 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ if (err < 0)
+ return err;
+
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+- nf_ct_protonum(ct));
+- if (helper == NULL)
+- return -EOPNOTSUPP;
+- }
+-
+ exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
+- helper, &tuple, &mask);
++ &tuple, &mask);
+ if (IS_ERR(exp))
+ return PTR_ERR(exp);
+
+@@ -3512,11 +3501,11 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+ struct net *net = read_pnet(&ct->ct_net);
++ struct nf_conntrack_helper *helper;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3526,7 +3515,11 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ if (!help)
+ return ERR_PTR(-EOPNOTSUPP);
+
+- if (cda[CTA_EXPECT_CLASS] && helper) {
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return ERR_PTR(-EOPNOTSUPP);
++
++ if (cda[CTA_EXPECT_CLASS]) {
+ class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
+ if (class > helper->expect_class_max)
+ return ERR_PTR(-EINVAL);
+@@ -3560,8 +3553,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+ exp->zone = ct->zone;
+ #endif
+- if (!helper)
+- helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+@@ -3593,7 +3584,6 @@ ctnetlink_create_expect(struct net *net,
+ {
+ struct nf_conntrack_tuple tuple, mask, master_tuple;
+ struct nf_conntrack_tuple_hash *h = NULL;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn *ct;
+ int err;
+@@ -3619,33 +3609,7 @@ ctnetlink_create_expect(struct net *net,
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ rcu_read_lock();
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper == NULL) {
+- rcu_read_unlock();
+-#ifdef CONFIG_MODULES
+- if (request_module("nfct-helper-%s", helpname) < 0) {
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- rcu_read_lock();
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper) {
+- err = -EAGAIN;
+- goto err_rcu;
+- }
+- rcu_read_unlock();
+-#endif
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- }
+-
+- exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
++ exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask);
+ if (IS_ERR(exp)) {
+ err = PTR_ERR(exp);
+ goto err_rcu;
+@@ -3655,8 +3619,8 @@ ctnetlink_create_expect(struct net *net,
+ nf_ct_expect_put(exp);
+ err_rcu:
+ rcu_read_unlock();
+-err_ct:
+ nf_ct_put(ct);
++
+ return err;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 78e838fd0862ff628d1fc98101f4d4ea67f75479 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 3fe37bdd625eb..1fd4371ff6369 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3571,6 +3571,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From 149a8451eb2b1ec0d7d2e234ba246def05c06b88 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:17:09 +0100
+Subject: netfilter: flowtable: strictly check for maximum number of actions
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 76522fcdbc3a02b568f5d957f7e66fc194abb893 ]
+
+The maximum number of flowtable hardware offload actions in IPv6 is:
+
+* ethernet mangling (4 payload actions, 2 for each ethernet address)
+* SNAT (4 payload actions)
+* DNAT (4 payload actions)
+* Double VLAN (4 vlan actions, 2 for popping vlan, and 2 for pushing)
+ for QinQ.
+* Redirect (1 action)
+
+Which makes 17, while the maximum is 16. But act_ct supports for tunnels
+actions too. Note that payload action operates at 32-bit word level, so
+mangling an IPv6 address takes 4 payload actions.
+
+Update flow_action_entry_next() calls to check for the maximum number of
+supported actions.
+
+While at it, rise the maximum number of actions per flow from 16 to 24
+so this works fine with IPv6 setups.
+
+Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_offload.c | 196 +++++++++++++++++---------
+ 1 file changed, 130 insertions(+), 66 deletions(-)
+
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index e06bc36f49fe7..4f346f51d7d74 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -13,6 +13,8 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
+
++#define NF_FLOW_RULE_ACTION_MAX 24
++
+ static struct workqueue_struct *nf_flow_offload_add_wq;
+ static struct workqueue_struct *nf_flow_offload_del_wq;
+ static struct workqueue_struct *nf_flow_offload_stats_wq;
+@@ -215,7 +217,12 @@ static void flow_offload_mangle(struct flow_action_entry *entry,
+ static inline struct flow_action_entry *
+ flow_action_entry_next(struct nf_flow_rule *flow_rule)
+ {
+- int i = flow_rule->rule->action.num_entries++;
++ int i;
++
++ if (unlikely(flow_rule->rule->action.num_entries >= NF_FLOW_RULE_ACTION_MAX))
++ return NULL;
++
++ i = flow_rule->rule->action.num_entries++;
+
+ return &flow_rule->rule->action.entries[i];
+ }
+@@ -233,6 +240,9 @@ static int flow_offload_eth_src(struct net *net,
+ u32 mask, val;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -283,6 +293,9 @@ static int flow_offload_eth_dst(struct net *net,
+ u8 nud_state;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -324,16 +337,19 @@ static int flow_offload_eth_dst(struct net *net,
+ return 0;
+ }
+
+-static void flow_offload_ipv4_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
+@@ -344,23 +360,27 @@ static void flow_offload_ipv4_snat(struct net *net,
+ offset = offsetof(struct iphdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
+@@ -371,14 +391,15 @@ static void flow_offload_ipv4_dnat(struct net *net,
+ offset = offsetof(struct iphdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
++static int flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+ unsigned int offset,
+ const __be32 *addr, const __be32 *mask)
+ {
+@@ -387,15 +408,20 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+
+ for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i++) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
++
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
+ offset + i * sizeof(u32), &addr[i], mask);
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_ipv6_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -411,16 +437,16 @@ static void flow_offload_ipv6_snat(struct net *net,
+ offset = offsetof(struct ipv6hdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+-static void flow_offload_ipv6_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -436,10 +462,10 @@ static void flow_offload_ipv6_dnat(struct net *net,
+ offset = offsetof(struct ipv6hdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+ static int flow_offload_l4proto(const struct flow_offload *flow)
+@@ -461,15 +487,18 @@ static int flow_offload_l4proto(const struct flow_offload *flow)
+ return type;
+ }
+
+-static void flow_offload_port_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
+@@ -484,22 +513,26 @@ static void flow_offload_port_snat(struct net *net,
+ mask = ~htonl(0xffff);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_port_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port);
+@@ -514,20 +547,24 @@ static void flow_offload_port_dnat(struct net *net,
+ mask = ~htonl(0xffff0000);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_checksum(struct net *net,
+- const struct flow_offload *flow,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_checksum(struct net *net,
++ const struct flow_offload *flow,
++ struct nf_flow_rule *flow_rule)
+ {
+ u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+
++ if (!entry)
++ return -E2BIG;
++
+ entry->id = FLOW_ACTION_CSUM;
+ entry->csum_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+@@ -539,12 +576,14 @@ static void flow_offload_ipv4_checksum(struct net *net,
+ entry->csum_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+ break;
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_redirect(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_redirect(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple, *other_tuple;
+ struct flow_action_entry *entry;
+@@ -562,21 +601,28 @@ static void flow_offload_redirect(struct net *net,
+ ifindex = other_tuple->iifidx;
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ dev = dev_get_by_index(net, ifindex);
+ if (!dev)
+- return;
++ return -ENODEV;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry) {
++ dev_put(dev);
++ return -E2BIG;
++ }
++
+ entry->id = FLOW_ACTION_REDIRECT;
+ entry->dev = dev;
++
++ return 0;
+ }
+
+-static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_encap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple;
+ struct flow_action_entry *entry;
+@@ -584,7 +630,7 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+
+ this_tuple = &flow->tuplehash[dir].tuple;
+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = this_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -593,15 +639,19 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+ entry->tunnel = tun_info;
+ }
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_decap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *other_tuple;
+ struct flow_action_entry *entry;
+@@ -609,7 +659,7 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+
+ other_tuple = &flow->tuplehash[!dir].tuple;
+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = other_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -618,9 +668,13 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_DECAP;
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -632,8 +686,9 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ const struct flow_offload_tuple *tuple;
+ int i;
+
+- flow_offload_decap_tunnel(flow, dir, flow_rule);
+- flow_offload_encap_tunnel(flow, dir, flow_rule);
++ if (flow_offload_decap_tunnel(flow, dir, flow_rule) < 0 ||
++ flow_offload_encap_tunnel(flow, dir, flow_rule) < 0)
++ return -1;
+
+ if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
+ flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
+@@ -649,6 +704,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+
+ if (tuple->encap[i].proto == htons(ETH_P_8021Q)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+ entry->id = FLOW_ACTION_VLAN_POP;
+ }
+ }
+@@ -662,6 +719,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ continue;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+
+ switch (other_tuple->encap[i].proto) {
+ case htons(ETH_P_PPP_SES):
+@@ -687,18 +746,22 @@ int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv4_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_SNAT, &flow->flags) ||
+ test_bit(NF_FLOW_DNAT, &flow->flags))
+- flow_offload_ipv4_checksum(net, flow, flow_rule);
++ if (flow_offload_ipv4_checksum(net, flow, flow_rule) < 0)
++ return -1;
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+@@ -712,22 +775,23 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv6_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
+
+-#define NF_FLOW_RULE_ACTION_MAX 16
+-
+ static struct nf_flow_rule *
+ nf_flow_offload_rule_alloc(struct net *net,
+ const struct flow_offload_work *offload,
+--
+2.53.0
+
--- /dev/null
+From 0f7c201d13f38724cd92756fd15ddf8373281ef9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index e9f4f845d760a..b98331572ad29 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -309,7 +309,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index cc20e6d56807c..a4e1d7951b2c6 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -821,7 +821,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -830,7 +830,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index db794fe1300e6..83e1fdcc752d6 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From 6374af5414d861a014f9fc36e7e9b8dd1847da44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:02 +0100
+Subject: netfilter: nf_conntrack_expect: honor expectation helper field
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 9c42bc9db90a154bc61ae337a070465f3393485a ]
+
+The expectation helper field is mostly unused. As a result, the
+netfilter codebase relies on accessing the helper through exp->master.
+
+Always set on the expectation helper field so it can be used to reach
+the helper.
+
+nf_ct_expect_init() is called from packet path where the skb owns
+the ct object, therefore accessing exp->master for the newly created
+expectation is safe. This saves a lot of updates in all callsites
+to pass the ct object as parameter to nf_ct_expect_init().
+
+This is a preparation patches for follow up fixes.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 2 +-
+ net/netfilter/nf_conntrack_broadcast.c | 2 +-
+ net/netfilter/nf_conntrack_expect.c | 14 +++++++++++++-
+ net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------
+ net/netfilter/nf_conntrack_helper.c | 7 ++++++-
+ net/netfilter/nf_conntrack_netlink.c | 2 +-
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 7 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 165e7a03b8e9d..1b01400b10bdb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -40,7 +40,7 @@ struct nf_conntrack_expect {
+ struct nf_conntrack_expect *this);
+
+ /* Helper to assign to new connection */
+- struct nf_conntrack_helper *helper;
++ struct nf_conntrack_helper __rcu *helper;
+
+ /* The conntrack of the master connection */
+ struct nf_conn *master;
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index cfa0fe0356de6..656cb1033e9c3 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -70,7 +70,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->expectfn = NULL;
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+- exp->helper = NULL;
++ rcu_assign_pointer(exp->helper, helper);
+
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index afbf3c5100f76..ba53192d0b50a 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -309,12 +309,19 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
+
++/* This function can only be used from packet path, where accessing
++ * master's helper is safe, because the packet holds a reference on
++ * the conntrack object. Never use it from control plane.
++ */
+ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ u_int8_t family,
+ const union nf_inet_addr *saddr,
+ const union nf_inet_addr *daddr,
+ u_int8_t proto, const __be16 *src, const __be16 *dst)
+ {
++ struct nf_conntrack_helper *helper = NULL;
++ struct nf_conn *ct = exp->master;
++ struct nf_conn_help *help;
+ int len;
+
+ if (family == AF_INET)
+@@ -325,7 +332,12 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ exp->flags = 0;
+ exp->class = class;
+ exp->expectfn = NULL;
+- exp->helper = NULL;
++
++ help = nfct_help(ct);
++ if (help)
++ helper = rcu_dereference(help->helper);
++
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
+index ed983421e2eb2..791aafe9f3960 100644
+--- a/net/netfilter/nf_conntrack_h323_main.c
++++ b/net/netfilter/nf_conntrack_h323_main.c
+@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = &nf_conntrack_helper_h245;
++ rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3 : NULL,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+ exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_UDP, NULL, &port);
+- exp->helper = nf_conntrack_helper_ras;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect RAS ");
+@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 9d7d36ac83083..a21c976701f79 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -399,7 +399,7 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (exp->helper == me)
++ if (rcu_access_pointer(exp->helper) == me)
+ return true;
+
+ this = rcu_dereference_protected(help->helper,
+@@ -421,6 +421,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
++
++ /* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
++ * last step, this ensures rcu readers of exp->helper are done.
++ * No need for another synchronize_rcu() here.
++ */
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 1fd4371ff6369..fc3fd587279c1 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3561,7 +3561,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+ exp->mask.src.u.all = mask->src.u.all;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 84334537c6067..6ae30a4cf3601 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -1303,7 +1303,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
+ nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
+ saddr, &daddr, proto, NULL, &port);
+ exp->timeout.expires = sip_timeout * HZ;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
+
+ hooks = rcu_dereference(nf_nat_sip_hooks);
+--
+2.53.0
+
--- /dev/null
+From 805a02cc26d24f93047e8a1bc007d2c21eab5775 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 22:39:55 +0100
+Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 02a3231b6d82efe750da6554ebf280e4a6f78756 ]
+
+__nf_ct_expect_find() and nf_ct_expect_find_get() are called under
+rcu_read_lock() but they dereference the master conntrack via
+exp->master.
+
+Since the expectation does not hold a reference on the master conntrack,
+this could be dying conntrack or different recycled conntrack than the
+real master due to SLAB_TYPESAFE_RCU.
+
+Store the netns, the master_tuple and the zone in struct
+nf_conntrack_expect as a safety measure.
+
+This patch is required by the follow up fix not to dump expectations
+that do not belong to this netns.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++++++++++-
+ net/netfilter/nf_conntrack_broadcast.c | 6 +++++-
+ net/netfilter/nf_conntrack_expect.c | 9 +++++++--
+ net/netfilter/nf_conntrack_netlink.c | 5 +++++
+ 4 files changed, 34 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 1b01400b10bdb..e9a8350e7ccfb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
+ /* Hash member */
+ struct hlist_node hnode;
+
++ /* Network namespace */
++ possible_net_t net;
++
+ /* We expect this tuple, with the following mask */
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
+
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ struct nf_conntrack_zone zone;
++#endif
+ /* Usage count. */
+ refcount_t use;
+
+@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
+
+ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
+ {
+- return nf_ct_net(exp->master);
++ return read_pnet(&exp->net);
++}
++
++static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
++ const struct nf_conntrack_zone *b)
++{
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ return a->zone.id == b->id;
++#else
++ return true;
++#endif
+ }
+
+ #define NF_CT_EXP_POLICY_NAME_LEN 16
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 656cb1033e9c3..f9528d4db0a82 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ unsigned int timeout)
+ {
+ const struct nf_conntrack_helper *helper;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = skb_rtable(skb);
+@@ -71,7 +72,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+ rcu_assign_pointer(exp->helper, helper);
+-
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index b85a8d630d819..f5c45989df573 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -112,8 +112,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
+ const struct net *net)
+ {
+ return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+- net_eq(net, nf_ct_net(i->master)) &&
+- nf_ct_zone_equal_any(i->master, zone);
++ net_eq(net, read_pnet(&i->net)) &&
++ nf_ct_exp_zone_equal_any(i, zone);
+ }
+
+ bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
+@@ -321,6 +321,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ {
+ struct nf_conntrack_helper *helper = NULL;
+ struct nf_conn *ct = exp->master;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conn_help *help;
+ int len;
+
+@@ -338,6 +339,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ helper = rcu_dereference(help->helper);
+
+ rcu_assign_pointer(exp->helper, helper);
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 421e96c338bb9..d262e64f1c152 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3516,6 +3516,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3555,6 +3556,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ if (!helper)
+ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+--
+2.53.0
+
--- /dev/null
+From dc707da2cc7716f4df5210cb378a275e99064d84 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:03 +0100
+Subject: netfilter: nf_conntrack_expect: use expect->helper
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit f01794106042ee27e54af6fdf5b319a2fe3df94d ]
+
+Use expect->helper in ctnetlink and /proc to dump the helper name.
+Using nfct_help() without holding a reference to the master conntrack
+is unsafe.
+
+Use exp->master->helper in ctnetlink path if userspace does not provide
+an explicit helper when creating an expectation to retain the existing
+behaviour. The ctnetlink expectation path holds the reference on the
+master conntrack and nf_conntrack_expect lock and the nfnetlink glue
+path refers to the master ct that is attached to the skb.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_expect.c | 2 +-
+ net/netfilter/nf_conntrack_helper.c | 6 +-----
+ net/netfilter/nf_conntrack_netlink.c | 24 ++++++++++--------------
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 4 files changed, 13 insertions(+), 21 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index ba53192d0b50a..b85a8d630d819 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -670,7 +670,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
+ if (expect->flags & NF_CT_EXPECT_USERSPACE)
+ seq_printf(s, "%sUSERSPACE", delim);
+
+- helper = rcu_dereference(nfct_help(expect->master)->helper);
++ helper = rcu_dereference(expect->helper);
+ if (helper) {
+ seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
+ if (helper->expect_policy[expect->class].name[0])
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index a21c976701f79..a715304a53d8c 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -395,14 +395,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
+
+ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ {
+- struct nf_conn_help *help = nfct_help(exp->master);
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (rcu_access_pointer(exp->helper) == me)
+- return true;
+-
+- this = rcu_dereference_protected(help->helper,
++ this = rcu_dereference_protected(exp->helper,
+ lockdep_is_held(&nf_conntrack_expect_lock));
+ return this == me;
+ }
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index fc3fd587279c1..421e96c338bb9 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3000,7 +3000,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ {
+ struct nf_conn *master = exp->master;
+ long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
+- struct nf_conn_help *help;
++ struct nf_conntrack_helper *helper;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+ struct nlattr *nest_parms;
+ struct nf_conntrack_tuple nat_tuple = {};
+@@ -3045,15 +3045,12 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
+ goto nla_put_failure;
+- help = nfct_help(master);
+- if (help) {
+- struct nf_conntrack_helper *helper;
+
+- helper = rcu_dereference(help->helper);
+- if (helper &&
+- nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
+- goto nla_put_failure;
+- }
++ helper = rcu_dereference(exp->helper);
++ if (helper &&
++ nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
++ goto nla_put_failure;
++
+ expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
+ if (expfn != NULL &&
+ nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
+@@ -3382,12 +3379,9 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
+ static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
+ {
+ struct nf_conntrack_helper *helper;
+- const struct nf_conn_help *m_help;
+ const char *name = data;
+
+- m_help = nfct_help(exp->master);
+-
+- helper = rcu_dereference(m_help->helper);
++ helper = rcu_dereference(exp->helper);
+ if (!helper)
+ return false;
+
+@@ -3522,9 +3516,9 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+- u_int32_t class = 0;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
++ u32 class = 0;
+ int err;
+
+ help = nfct_help(ct);
+@@ -3561,6 +3555,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ if (!helper)
++ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 6ae30a4cf3601..fda6fc1fc4c58 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -924,7 +924,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
+
+ if (!exp || exp->master == ct ||
+- nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
++ exp->helper != nfct_help(ct)->helper ||
+ exp->class != class)
+ break;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+--
+2.53.0
+
--- /dev/null
+From 0d094bc1bbe9b975ff0e3a0f2107200cb0d0b24d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index ceb48c3ca0a43..9d7d36ac83083 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -419,7 +419,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+--
+2.53.0
+
--- /dev/null
+From 828501180ffdb366ce93bc2becfe799666c15f82 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 663c064135181..e373afdf0f072 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -11355,8 +11355,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -11391,6 +11389,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 182c72cb7ac7c8deab579a1785ac23b1252b9f39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index aa5fc9bffef0c..f96421ad14afb 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -726,7 +726,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From b3f3a7a26daf7c02410c4bac6b538bfdc766d92c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c0f5e9a4f3c65..bfc98719684e2 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -53,6 +53,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -85,6 +88,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 0ce8aac5bbb6c0283e7c979b8c6e79579a5627a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index ada27e24f7021..efe7b7d71e7f7 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -501,6 +501,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -1016,6 +1027,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From dbdea64d37758c06fd953d751f70a9fc09bab6a5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index cfbbe0713317f..1393f83f3149b 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
+
+ del_timer(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From f4591454e1403adef6fa3fe14356bad3e8eaa5a5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index ad83bb3197225..b75ddb3fca0df 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -2174,12 +2174,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From 8cee9d3afc962dcd1312a83720d6a83589e33012 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 8f070ee7e7426..30fca2169aa7a 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -608,8 +608,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
io_uring-kbuf-use-write_once-for-userspace-shared-buffer-ring-fields.patch
io_uring-kbuf-fix-missing-buf_more-for-incremental-buffers-at-eof.patch
io_uring-kbuf-propagate-buf_more-through-early-buffer-commit-path.patch
+arm64-scs-fix-handling-of-advance_loc4.patch
+hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch
+wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+btrfs-don-t-take-device_list_mutex-when-querying-zon.patch
+tg3-replace-placeholder-mac-address-with-device-prop.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+btrfs-reserve-enough-transaction-items-for-qgroup-io.patch
+i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch
+btrfs-reject-root-items-with-drop_progress-and-zero-.patch
+spi-geni-qcom-check-dma-interrupts-early-in-isr.patch
+dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch
+wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch
+crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch
+crypto-caam-fix-overflow-on-long-hmac-keys.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+eth-fbnic-account-for-page-fragments-when-updating-b.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch
+net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch
+asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch
+net-introduce-mangleid_features.patch
+net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+bnxt_en-update-firmware-interface-spec-to-1.10.3.85.patch
+bnxt_en-allocate-backing-store-memory-for-fw-trace-l.patch
+bnxt_en-manage-the-fw-trace-context-memory.patch
+bnxt_en-do-not-free-fw-log-context-memory.patch
+bnxt_en-set-backing-store-type-from-query-type.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+netfilter-flowtable-strictly-check-for-maximum-numbe.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-nf_conntrack_expect-honor-expectation-help.patch
+netfilter-nf_conntrack_expect-use-expect-helper.patch
+netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch
+netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch
+bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch
+bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch
+bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch
+net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-lag-check-for-lag-device-before-creating-de.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch
+bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+net-hsr-fix-vlan-add-unwind-on-slave-errors.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
+bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch
--- /dev/null
+From 886f480b444cbba6bb53ab2131112cde9c89c478 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 21:49:01 +0530
+Subject: spi: geni-qcom: Check DMA interrupts early in ISR
+
+From: Praveen Talari <praveen.talari@oss.qualcomm.com>
+
+[ Upstream commit 8c89a077ca796a2fe248c584e9d7e66cff0388c8 ]
+
+The current interrupt handler only checks the GENI main IRQ status
+(m_irq) before deciding to return IRQ_NONE. This can lead to spurious
+IRQ_NONE returns when DMA interrupts are pending but m_irq is zero.
+
+Move the DMA TX/RX status register reads to the beginning of the ISR,
+right after reading m_irq. Update the early return condition to check
+all three status registers (m_irq, dma_tx_status, dma_rx_status) before
+returning IRQ_NONE.
+
+Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-geni-qcom.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
+index 38606c9e12ee8..dea4e524553c4 100644
+--- a/drivers/spi/spi-geni-qcom.c
++++ b/drivers/spi/spi-geni-qcom.c
+@@ -952,10 +952,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ struct spi_controller *spi = data;
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+- u32 m_irq;
++ u32 m_irq, dma_tx_status, dma_rx_status;
+
+ m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
+- if (!m_irq)
++ dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
++ dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
++
++ if (!m_irq && !dma_tx_status && !dma_rx_status)
+ return IRQ_NONE;
+
+ if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
+@@ -1003,8 +1006,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ }
+ } else if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ const struct spi_transfer *xfer = mas->cur_xfer;
+- u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+- u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (dma_tx_status)
+ writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
+--
+2.53.0
+
--- /dev/null
+From f5006e311ec9ea4353ea38979d298bebaff90ca3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index 288ab0e007557..752f33ae98383 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12277,7 +12277,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From 1a5bcb2ff5446680bba6d25c47210491d4d33618 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Mar 2026 03:24:30 +0530
+Subject: tg3: replace placeholder MAC address with device property
+
+From: Paul SAGE <paul.sage@42.fr>
+
+[ Upstream commit e4c00ba7274b613e3ab19e27eb009f0ec2e28379 ]
+
+On some systems (e.g. iMac 20,1 with BCM57766), the tg3 driver reads
+a default placeholder mac address (00:10:18:00:00:00) from the
+mailbox. The correct value on those systems are stored in the
+'local-mac-address' property.
+
+This patch, detect the default value and tries to retrieve
+the correct address from the device_get_mac_address
+function instead.
+
+The patch has been tested on two different systems:
+- iMac 20,1 (BCM57766) model which use the local-mac-address property
+- iMac 13,2 (BCM57766) model which can use the mailbox,
+ NVRAM or MAC control registers
+
+Tested-by: Rishon Jonathan R <mithicalaviator85@gmail.com>
+
+Co-developed-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Paul SAGE <paul.sage@42.fr>
+Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index dc170feee8ad7..288ab0e007557 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -17015,6 +17015,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
+ return err;
+ }
+
++static int tg3_is_default_mac_address(u8 *addr)
++{
++ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
++
++ return ether_addr_equal(default_mac_address, addr);
++}
++
+ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+ {
+ u32 hi, lo, mac_offset;
+@@ -17086,6 +17093,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+
+ if (!is_valid_ether_addr(addr))
+ return -EINVAL;
++
++ if (tg3_is_default_mac_address(addr))
++ return device_get_mac_address(&tp->pdev->dev, addr);
++
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f391974165147e826d7bb09c156c3a5dcb4e64e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Mar 2026 12:26:08 +0530
+Subject: wifi: ath11k: Pass the correct value of each TID during a stop AMPDU
+ session
+
+From: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+
+[ Upstream commit e225b36f83d7926c1f2035923bb0359d851fdb73 ]
+
+During ongoing traffic, a request to stop an AMPDU session
+for one TID could incorrectly affect other active sessions.
+This can happen because an incorrect TID reference would be
+passed when updating the BA session state, causing the wrong
+session to be stopped. As a result, the affected session would
+be reduced to a minimal BA size, leading to a noticeable
+throughput degradation.
+
+Fix this issue by passing the correct argument from
+ath11k_dp_rx_ampdu_stop() to ath11k_peer_rx_tid_reo_update()
+during a stop AMPDU session. Instead of passing peer->tx_tid, which
+is the base address of the array, corresponding to TID 0; pass
+the value of &peer->rx_tid[params->tid], where the different TID numbers
+are accounted for.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1
+
+Fixes: d5c65159f2895 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
+Signed-off-by: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index ff97c2649ce52..e3eabd9e223aa 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_peer *peer;
+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
++ struct dp_rx_tid *rx_tid;
+ int vdev_id = arsta->arvif->vdev_id;
+- dma_addr_t paddr;
+- bool active;
+ int ret;
+
+ spin_lock_bh(&ab->base_lock);
+@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ return -ENOENT;
+ }
+
+- paddr = peer->rx_tid[params->tid].paddr;
+- active = peer->rx_tid[params->tid].active;
++ rx_tid = &peer->rx_tid[params->tid];
+
+- if (!active) {
++ if (!rx_tid->active) {
+ spin_unlock_bh(&ab->base_lock);
+ return 0;
+ }
+
+- ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
++ ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
+ spin_unlock_bh(&ab->base_lock);
+ if (ret) {
+ ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
+@@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ }
+
+ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
+- params->sta->addr, paddr,
++ params->sta->addr,
++ rx_tid->paddr,
+ params->tid, 1, 1);
+ if (ret)
+ ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
+--
+2.53.0
+
--- /dev/null
+From 824f27658b20966544ef8f1b9ba13cf5a8d0cddd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 14:54:17 +0530
+Subject: wifi: mac80211: check tdls flag in ieee80211_tdls_oper
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 7d73872d949c488a1d7c308031d6a9d89b5e0a8b ]
+
+When NL80211_TDLS_ENABLE_LINK is called, the code only checks if the
+station exists but not whether it is actually a TDLS station. This
+allows the operation to proceed for non-TDLS stations, causing
+unintended side effects like modifying channel context and HT
+protection before failing.
+
+Add a check for sta->sta.tdls early in the ENABLE_LINK case, before
+any side effects occur, to ensure the operation is only allowed for
+actual TDLS peers.
+
+Reported-by: syzbot+56b6a844a4ea74487b7b@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=56b6a844a4ea74487b7b
+Tested-by: syzbot+56b6a844a4ea74487b7b@syzkaller.appspotmail.com
+Suggested-by: Johannes Berg <johannes@sipsolutions.net>
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Link: https://patch.msgid.link/20260313092417.520807-1-kartikey406@gmail.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/tdls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
+index 1cb42c5b9b04b..92ab7be3d4824 100644
+--- a/net/mac80211/tdls.c
++++ b/net/mac80211/tdls.c
+@@ -1448,7 +1448,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ }
+
+ sta = sta_info_get(sdata, peer);
+- if (!sta)
++ if (!sta || !sta->sta.tdls)
+ return -ENOLINK;
+
+ iee80211_tdls_recalc_chanctx(sdata, sta);
+--
+2.53.0
+
--- /dev/null
+From 19abdef03a0d15c73ff210cd549224601e89ca5e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 16:01:27 +1030
+Subject: ALSA: usb-audio: Exclude Scarlett 2i2 1st Gen (8016) from
+ SKIP_IFACE_SETUP
+
+From: Geoffrey D. Bennett <g@b4.vu>
+
+[ Upstream commit a0dafdbd1049a8ea661a1a471be1b840bd8aed13 ]
+
+Same issue as the other 1st Gen Scarletts: QUIRK_FLAG_SKIP_IFACE_SETUP
+causes distorted audio on this revision of the Scarlett 2i2 1st Gen
+(1235:8016).
+
+Fixes: 38c322068a26 ("ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP")
+Reported-by: lukas-reineke [https://github.com/geoffreybennett/linux-fcp/issues/54]
+Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
+Link: https://patch.msgid.link/acytr8aEUba4VXmZ@m.b4.vu
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 2c01412a225ef..9f585dbc770cb 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2424,6 +2424,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_VALIDATE_RATES),
+ DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */
+ DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */
++ DEVICE_FLG(0x1235, 0x8016, 0), /* Focusrite Scarlett 2i2 1st Gen */
+ DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */
+ VENDOR_FLG(0x1235, /* Focusrite Novation */
+ QUIRK_FLAG_SKIP_IFACE_SETUP),
+--
+2.53.0
+
--- /dev/null
+From 6911b316834ec1ee530622d945e9f65a2f445342 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 19:04:20 +0200
+Subject: ALSA: usb-audio: Exclude Scarlett Solo 1st Gen from SKIP_IFACE_SETUP
+
+From: Dag Smedberg <dag@dsmedberg.se>
+
+[ Upstream commit f025ac8c698ac7d29eb3b5025bcdaf7ad675785d ]
+
+Same issue that the Scarlett 2i2 1st Gen had:
+QUIRK_FLAG_SKIP_IFACE_SETUP causes distorted audio on the
+Scarlett Solo 1st Gen (1235:801c).
+
+Fixes: 38c322068a26 ("ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP")
+Reported-by: Dag Smedberg <dag@dsmedberg.se>
+Tested-by: Dag Smedberg <dag@dsmedberg.se>
+Signed-off-by: Dag Smedberg <dag@dsmedberg.se>
+Link: https://patch.msgid.link/20260329170420.4122-1-dag@dsmedberg.se
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 45d0e1364dd98..2c01412a225ef 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2424,6 +2424,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_VALIDATE_RATES),
+ DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */
+ DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */
++ DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */
+ VENDOR_FLG(0x1235, /* Focusrite Novation */
+ QUIRK_FLAG_SKIP_IFACE_SETUP),
+ VENDOR_FLG(0x1511, /* AURALiC */
+--
+2.53.0
+
--- /dev/null
+From db24f3f4466d97218b3447d1955a1406d472a63a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Mar 2026 14:44:28 +0100
+Subject: arm64/scs: Fix handling of advance_loc4
+
+From: Pepper Gray <hello@peppergray.xyz>
+
+[ Upstream commit d499e9627d70b1269020d59b95ed3e18bee6b8cd ]
+
+DW_CFA_advance_loc4 is defined but no handler is implemented. Its
+CFA opcode defaults to EDYNSCS_INVALID_CFA_OPCODE triggering an
+error which wrongfully prevents modules from loading.
+
+Link: https://bugs.gentoo.org/971060
+Signed-off-by: Pepper Gray <hello@peppergray.xyz>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/pi/patch-scs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c
+index bbe7d30ed12b3..dac568e4a54f2 100644
+--- a/arch/arm64/kernel/pi/patch-scs.c
++++ b/arch/arm64/kernel/pi/patch-scs.c
+@@ -192,6 +192,14 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
+ size -= 2;
+ break;
+
++ case DW_CFA_advance_loc4:
++ loc += *opcode++ * code_alignment_factor;
++ loc += (*opcode++ << 8) * code_alignment_factor;
++ loc += (*opcode++ << 16) * code_alignment_factor;
++ loc += (*opcode++ << 24) * code_alignment_factor;
++ size -= 4;
++ break;
++
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended:
+ size = skip_xleb128(&opcode, size);
+--
+2.53.0
+
--- /dev/null
+From 1c9f830dca7b9cc3098811ba0723bdb0dd180de8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:09:09 +0100
+Subject: ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on
+ failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+
+[ Upstream commit 622363757b2286dd2c2984b0d80255cbb35a0495 ]
+
+ep93xx_i2s_enable() calls clk_prepare_enable() on three clocks in
+sequence (mclk, sclk, lrclk) without checking the return value of any
+of them. If an intermediate enable fails, the clocks that were already
+enabled are never rolled back, leaking them until the next disable cycle
+— which may never come if the stream never started cleanly.
+
+Change ep93xx_i2s_enable() from void to int. Add error checking after
+each clk_prepare_enable() call and unwind already-enabled clocks on
+failure. Propagate the error through ep93xx_i2s_startup() and
+ep93xx_i2s_resume(), both of which already return int.
+
+Signed-off-by: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+Fixes: f4ff6b56bc8a ("ASoC: cirrus: i2s: Prepare clock before using it")
+Link: https://patch.msgid.link/20260324210909.45494-1-jihed.chaibi.dev@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/cirrus/ep93xx-i2s.c | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
+index cca01c03f0486..5dba741594fab 100644
+--- a/sound/soc/cirrus/ep93xx-i2s.c
++++ b/sound/soc/cirrus/ep93xx-i2s.c
+@@ -91,16 +91,28 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ return __raw_readl(info->regs + reg);
+ }
+
+-static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
++static int ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ {
+ unsigned base_reg;
++ int err;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+- clk_prepare_enable(info->mclk);
+- clk_prepare_enable(info->sclk);
+- clk_prepare_enable(info->lrclk);
++ err = clk_prepare_enable(info->mclk);
++ if (err)
++ return err;
++ err = clk_prepare_enable(info->sclk);
++ if (err) {
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
++ err = clk_prepare_enable(info->lrclk);
++ if (err) {
++ clk_disable_unprepare(info->sclk);
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+@@ -119,6 +131,8 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
+ EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
+ EP93XX_I2S_TXCTRL_TXUFIE);
++
++ return 0;
+ }
+
+ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+@@ -195,9 +209,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ {
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+- ep93xx_i2s_enable(info, substream->stream);
+-
+- return 0;
++ return ep93xx_i2s_enable(info, substream->stream);
+ }
+
+ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+@@ -373,14 +385,16 @@ static int ep93xx_i2s_suspend(struct snd_soc_component *component)
+ static int ep93xx_i2s_resume(struct snd_soc_component *component)
+ {
+ struct ep93xx_i2s_info *info = snd_soc_component_get_drvdata(component);
++ int err;
+
+ if (!snd_soc_component_active(component))
+ return 0;
+
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
++ err = ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
++ if (err)
++ return err;
+
+- return 0;
++ return ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ #else
+ #define ep93xx_i2s_suspend NULL
+--
+2.53.0
+
--- /dev/null
+From c193c40d8c83d9bade72e6783184bec9883d63ca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:15:21 +0000
+Subject: ASoC: Intel: boards: fix unmet dependency on PINCTRL
+
+From: Julian Braha <julianbraha@gmail.com>
+
+[ Upstream commit e920c36f2073d533bdf19ba6ab690432c8173b63 ]
+
+This reverts commit c073f0757663 ("ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43")
+
+Currently, SND_SOC_INTEL_SOUNDWIRE_SOF_MACH selects PINCTRL_CS42L43
+without also selecting or depending on PINCTRL, despite PINCTRL_CS42L43
+depending on PINCTRL.
+
+See the following Kbuild warning:
+
+WARNING: unmet direct dependencies detected for PINCTRL_CS42L43
+ Depends on [n]: PINCTRL [=n] && MFD_CS42L43 [=m]
+ Selected by [m]:
+ - SND_SOC_INTEL_SOUNDWIRE_SOF_MACH [=m] && SOUND [=y] && SND [=m] && SND_SOC [=m] && SND_SOC_INTEL_MACH [=y] && (SND_SOC_SOF_INTEL_COMMON [=m] || !SND_SOC_SOF_INTEL_COMMON [=m]) && SND_SOC_SOF_INTEL_SOUNDWIRE [=m] && I2C [=y] && SPI_MASTER [=y] && ACPI [=y] && (MFD_INTEL_LPSS [=n] || COMPILE_TEST [=y]) && (SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES [=n] || COMPILE_TEST [=y]) && SOUNDWIRE [=m]
+
+In response to v1 of this patch [1], Arnd pointed out that there is
+no compile-time dependency sof_sdw and the PINCTRL_CS42L43 driver.
+After testing, I can confirm that the kernel compiled with
+SND_SOC_INTEL_SOUNDWIRE_SOF_MACH enabled and PINCTRL_CS42L43 disabled.
+
+This unmet dependency was detected by kconfirm, a static analysis
+tool for Kconfig.
+
+Link: https://lore.kernel.org/all/b8aecc71-1fed-4f52-9f6c-263fbe56d493@app.fastmail.com/ [1]
+Fixes: c073f0757663 ("ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43")
+Signed-off-by: Julian Braha <julianbraha@gmail.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://patch.msgid.link/20260325001522.1727678-1-julianbraha@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/Kconfig | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
+index c23fdb6aad4ca..1031d6497f55e 100644
+--- a/sound/soc/intel/boards/Kconfig
++++ b/sound/soc/intel/boards/Kconfig
+@@ -525,8 +525,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
+ select SND_SOC_CS42L43_SDW
+ select MFD_CS42L43
+ select MFD_CS42L43_SDW
+- select PINCTRL_CS42L43
+- select SPI_CS42L43
+ select SND_SOC_CS35L56_SPI
+ select SND_SOC_CS35L56_SDW
+ select SND_SOC_DMIC
+--
+2.53.0
+
--- /dev/null
+From 994e50f21381dc3868bfe9196fcca2123bf9db1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index c39dc5d367979..b6f764e524f7c 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From 4e35347fd52fc18a96ea8bcd23c4bb26c33b8225 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:01 +0300
+Subject: Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a2639a7f0f5bf7d73f337f8f077c19415c62ed2c ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+set_cig_params_sync, otherwise it's possible it is freed concurrently.
+
+Take hdev lock to prevent hci_conn from being deleted or modified
+concurrently. Just RCU lock is not suitable here, as we also want to
+avoid "tearing" in the configuration.
+
+Fixes: a091289218202 ("Bluetooth: hci_conn: Fix hci_le_set_cig_params")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_conn.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index 8906526ff32c5..24b71ec8897ff 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -1826,9 +1826,13 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+ u8 aux_num_cis = 0;
+ u8 cis_id;
+
++ hci_dev_lock(hdev);
++
+ conn = hci_conn_hash_lookup_cig(hdev, cig_id);
+- if (!conn)
++ if (!conn) {
++ hci_dev_unlock(hdev);
+ return 0;
++ }
+
+ qos = &conn->iso_qos;
+ pdu->cig_id = cig_id;
+@@ -1867,6 +1871,8 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+ }
+ pdu->num_cis = aux_num_cis;
+
++ hci_dev_unlock(hdev);
++
+ if (!pdu->num_cis)
+ return 0;
+
+--
+2.53.0
+
--- /dev/null
+From c7b9d439e8e2d585c7e210f8facd55c453c863c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:02 +0300
+Subject: Bluetooth: hci_event: fix potential UAF in
+ hci_le_remote_conn_param_req_evt
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit b255531b27da336571411248c2a72a350662bd09 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_le_remote_conn_param_req_evt, otherwise it's possible it is freed
+concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage.
+
+Fixes: 95118dd4edfec ("Bluetooth: hci_event: Use of a function table to handle LE subevents")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 33 ++++++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 3838b90343d91..7794f4f981596 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -6653,25 +6653,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ latency = le16_to_cpu(ev->latency);
+ timeout = le16_to_cpu(ev->timeout);
+
++ hci_dev_lock(hdev);
++
+ hcon = hci_conn_hash_lookup_handle(hdev, handle);
+- if (!hcon || hcon->state != BT_CONNECTED)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_UNKNOWN_CONN_ID);
++ if (!hcon || hcon->state != BT_CONNECTED) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_UNKNOWN_CONN_ID);
++ goto unlock;
++ }
+
+- if (max > hcon->le_conn_max_interval)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (max > hcon->le_conn_max_interval) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+- if (hci_check_conn_params(min, max, latency, timeout))
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (hci_check_conn_params(min, max, latency, timeout)) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+ if (hcon->role == HCI_ROLE_MASTER) {
+ struct hci_conn_params *params;
+ u8 store_hint;
+
+- hci_dev_lock(hdev);
+-
+ params = hci_conn_params_lookup(hdev, &hcon->dst,
+ hcon->dst_type);
+ if (params) {
+@@ -6684,8 +6690,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ store_hint = 0x00;
+ }
+
+- hci_dev_unlock(hdev);
+-
+ mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
+ store_hint, min, max, latency, timeout);
+ }
+@@ -6699,6 +6703,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ cp.max_ce_len = 0;
+
+ hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
+--
+2.53.0
+
--- /dev/null
+From ad11d4d0f29479751243970f84e613cb946f7902 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 11:47:21 +0100
+Subject: Bluetooth: hci_h4: Fix race during initialization
+
+From: Jonathan Rissanen <jonathan.rissanen@axis.com>
+
+[ Upstream commit 0ffac654e95c1bdfe2d4edf28fb18d6ba1f103e6 ]
+
+Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during
+initialization") fixed a race for hci commands sent during initialization.
+However, there is still a race that happens if an hci event from one of
+these commands is received before HCI_UART_REGISTERED has been set at
+the end of hci_uart_register_dev(). The event will be ignored which
+causes the command to fail with a timeout in the log:
+
+"Bluetooth: hci0: command 0x1003 tx timeout"
+
+This is because the hci event receive path (hci_uart_tty_receive ->
+h4_recv) requires HCI_UART_REGISTERED to be set in h4_recv(), while the
+hci command transmit path (hci_uart_send_frame -> h4_enqueue) only
+requires HCI_UART_PROTO_INIT to be set in hci_uart_send_frame().
+
+The check for HCI_UART_REGISTERED was originally added in commit
+c2578202919a ("Bluetooth: Fix H4 crash from incoming UART packets")
+to fix a crash caused by hu->hdev being null dereferenced. That can no
+longer happen: once HCI_UART_PROTO_INIT is set in hci_uart_register_dev()
+all pointers (hu, hu->priv and hu->hdev) are valid, and
+hci_uart_tty_receive() already calls h4_recv() on HCI_UART_PROTO_INIT
+or HCI_UART_PROTO_READY.
+
+Remove the check for HCI_UART_REGISTERED in h4_recv() to fix the race
+condition.
+
+Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization")
+Signed-off-by: Jonathan Rissanen <jonathan.rissanen@axis.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/hci_h4.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
+index ec017df8572c8..1e9e2cad9ddf6 100644
+--- a/drivers/bluetooth/hci_h4.c
++++ b/drivers/bluetooth/hci_h4.c
+@@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
+ {
+ struct h4_struct *h4 = hu->priv;
+
+- if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+- return -EUNATCH;
+-
+ h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
+ h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
+ if (IS_ERR(h4->rx_skb)) {
+--
+2.53.0
+
--- /dev/null
+From 00d3bcc6d0fb77728a8a79aca1fd6fb9b3c2df4e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 21:07:46 +0200
+Subject: Bluetooth: hci_sync: call destroy in hci_cmd_sync_run if immediate
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a834a0b66ec6fb743377201a0f4229bb2503f4ce ]
+
+hci_cmd_sync_run() may run the work immediately if called from existing
+sync work (otherwise it queues a new sync work). In this case it fails
+to call the destroy() function.
+
+On immediate run, make it behave same way as if item was queued
+successfully: call destroy, and return 0.
+
+The only callsite is hci_abort_conn() via hci_cmd_sync_run_once(), and
+this changes its return value. However, its return value is not used
+except as the return value for hci_disconnect(), and nothing uses the
+return value of hci_disconnect(). Hence there should be no behavior
+change anywhere.
+
+Fixes: c898f6d7b093b ("Bluetooth: hci_sync: Introduce hci_cmd_sync_run/hci_cmd_sync_run_once")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index e94b62844e1ef..635ce5929dc5d 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -801,8 +801,15 @@ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+ return -ENETDOWN;
+
+ /* If on cmd_sync_work then run immediately otherwise queue */
+- if (current_work() == &hdev->cmd_sync_work)
+- return func(hdev, data);
++ if (current_work() == &hdev->cmd_sync_work) {
++ int err;
++
++ err = func(hdev, data);
++ if (destroy)
++ destroy(hdev, data, err);
++
++ return 0;
++ }
+
+ return hci_cmd_sync_submit(hdev, func, data, destroy);
+ }
+--
+2.53.0
+
--- /dev/null
+From 757f103d90ded71c079fbf0f4077a078c47d67b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index 5d70b1f69bb6d..d3df358cbe139 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -7166,6 +7166,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From 4de508b4ea74d3be6cda32e13cb5e000c1130876 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 22:25:26 +0800
+Subject: Bluetooth: MGMT: validate mesh send advertising payload length
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit bda93eec78cdbfe5cda00785cefebd443e56b88b ]
+
+mesh_send() currently bounds MGMT_OP_MESH_SEND by total command
+length, but it never verifies that the bytes supplied for the
+flexible adv_data[] array actually match the embedded adv_data_len
+field. MGMT_MESH_SEND_SIZE only covers the fixed header, so a
+truncated command can still pass the existing 20..50 byte range
+check and later drive the async mesh send path past the end of the
+queued command buffer.
+
+Keep rejecting zero-length and oversized advertising payloads, but
+validate adv_data_len explicitly and require the command length to
+exactly match the flexible array size before queueing the request.
+
+Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index d3df358cbe139..9065a864bc65d 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -2466,6 +2466,7 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ struct mgmt_mesh_tx *mesh_tx;
+ struct mgmt_cp_mesh_send *send = data;
+ struct mgmt_rp_mesh_read_features rp;
++ u16 expected_len;
+ bool sending;
+ int err = 0;
+
+@@ -2473,12 +2474,19 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ !hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_NOT_SUPPORTED);
+- if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
+- len <= MGMT_MESH_SEND_SIZE ||
+- len > (MGMT_MESH_SEND_SIZE + 31))
++ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_REJECTED);
++
++ if (!send->adv_data_len || send->adv_data_len > 31)
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_REJECTED);
+
++ expected_len = struct_size(send, adv_data, send->adv_data_len);
++ if (expected_len != len)
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_INVALID_PARAMS);
++
+ hci_dev_lock(hdev);
+
+ memset(&rp, 0, sizeof(rp));
+--
+2.53.0
+
--- /dev/null
+From 81a3060046da8440b0072d8047bd9fa00ffc668e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 23:16:45 +0800
+Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect()
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit 8a5b0135d4a5d9683203a3d9a12a711ccec5936b ]
+
+sco_sock_connect() checks sk_state and sk_type without holding
+the socket lock. Two concurrent connect() syscalls on the same
+socket can both pass the check and enter sco_connect(), leading
+to use-after-free.
+
+The buggy scenario involves three participants and was confirmed
+with additional logging instrumentation:
+
+ Thread A (connect): HCI disconnect: Thread B (connect):
+
+ sco_sock_connect(sk) sco_sock_connect(sk)
+ sk_state==BT_OPEN sk_state==BT_OPEN
+ (pass, no lock) (pass, no lock)
+ sco_connect(sk): sco_connect(sk):
+ hci_dev_lock hci_dev_lock
+ hci_connect_sco <- blocked
+ -> hcon1
+ sco_conn_add->conn1
+ lock_sock(sk)
+ sco_chan_add:
+ conn1->sk = sk
+ sk->conn = conn1
+ sk_state=BT_CONNECT
+ release_sock
+ hci_dev_unlock
+ hci_dev_lock
+ sco_conn_del:
+ lock_sock(sk)
+ sco_chan_del:
+ sk->conn=NULL
+ conn1->sk=NULL
+ sk_state=
+ BT_CLOSED
+ SOCK_ZAPPED
+ release_sock
+ hci_dev_unlock
+ (unblocked)
+ hci_connect_sco
+ -> hcon2
+ sco_conn_add
+ -> conn2
+ lock_sock(sk)
+ sco_chan_add:
+ sk->conn=conn2
+ sk_state=
+ BT_CONNECT
+ // zombie sk!
+ release_sock
+ hci_dev_unlock
+
+Thread B revives a BT_CLOSED + SOCK_ZAPPED socket back to
+BT_CONNECT. Subsequent cleanup triggers double sock_put() and
+use-after-free. Meanwhile conn1 is leaked as it was orphaned
+when sco_conn_del() cleared the association.
+
+Fix this by:
+- Moving lock_sock() before the sk_state/sk_type checks in
+ sco_sock_connect() to serialize concurrent connect attempts
+- Fixing the sk_type != SOCK_SEQPACKET check to actually
+ return the error instead of just assigning it
+- Adding a state re-check in sco_connect() after lock_sock()
+ to catch state changes during the window between the locks
+- Adding sco_pi(sk)->conn check in sco_chan_add() to prevent
+ double-attach of a socket to multiple connections
+- Adding hci_conn_drop() on sco_chan_add failure to prevent
+ HCI connection leaks
+
+Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm")
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/sco.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index f7b50cc730476..1a38577135d44 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -298,7 +298,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+ int err = 0;
+
+ sco_conn_lock(conn);
+- if (conn->sk)
++ if (conn->sk || sco_pi(sk)->conn)
+ err = -EBUSY;
+ else
+ __sco_chan_add(conn, sk, parent);
+@@ -353,9 +353,20 @@ static int sco_connect(struct sock *sk)
+
+ lock_sock(sk);
+
++ /* Recheck state after reacquiring the socket lock, as another
++ * thread may have changed it (e.g., closed the socket).
++ */
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
++ hci_conn_drop(hcon);
++ err = -EBADFD;
++ goto unlock;
++ }
++
+ err = sco_chan_add(conn, sk, NULL);
+ if (err) {
+ release_sock(sk);
++ hci_conn_drop(hcon);
+ goto unlock;
+ }
+
+@@ -656,13 +667,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
+ addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
+- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
++ lock_sock(sk);
++
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
+ return -EBADFD;
++ }
+
+- if (sk->sk_type != SOCK_SEQPACKET)
+- err = -EINVAL;
++ if (sk->sk_type != SOCK_SEQPACKET) {
++ release_sock(sk);
++ return -EINVAL;
++ }
+
+- lock_sock(sk);
+ /* Set destination address and psm */
+ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
+ release_sock(sk);
+--
+2.53.0
+
--- /dev/null
+From a9e643ec94493b04355107ebecfdba42a8e0a033 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 23:51:38 -0700
+Subject: bnxt_en: Restore default stat ctxs for ULP when resource is available
+
+From: Pavan Chebbi <pavan.chebbi@broadcom.com>
+
+[ Upstream commit 071dbfa304e85a6b04a593e950d18fa170997288 ]
+
+During resource reservation, if the L2 driver does not have enough
+MSIX vectors to provide to the RoCE driver, it sets the stat ctxs for
+ULP also to 0 so that we don't have to reserve it unnecessarily.
+
+However, subsequently the user may reduce L2 rings thereby freeing up
+some resources that the L2 driver can now earmark for RoCE. In this
+case, the driver should restore the default ULP stat ctxs to make
+sure that all RoCE resources are ready for use.
+
+The RoCE driver may fail to initialize in this scenario without this
+fix.
+
+Fixes: d630624ebd70 ("bnxt_en: Utilize ulp client resources if RoCE is not registered")
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260331065138.948205-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 04aa5d9eb8513..d02ccf79e3b6f 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -7991,6 +7991,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
+ ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
+ if (!ulp_msix)
+ bnxt_set_ulp_stat_ctxs(bp, 0);
++ else
++ bnxt_set_dflt_ulp_stat_ctxs(bp);
+
+ if (ulp_msix > bp->ulp_num_msix_want)
+ ulp_msix = bp->ulp_num_msix_want;
+--
+2.53.0
+
--- /dev/null
+From f2c16128a6974e1922888ccec8650d22fa945346 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 07:43:56 +0800
+Subject: bnxt_en: set backing store type from query type
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 4ee937107d52f9e5c350e4b5e629760e328b3d9f ]
+
+bnxt_hwrm_func_backing_store_qcaps_v2() stores resp->type from the
+firmware response in ctxm->type and later uses that value to index
+fixed backing-store metadata arrays such as ctx_arr[] and
+bnxt_bstore_to_trace[].
+
+ctxm->type is fixed by the current backing-store query type and matches
+the array index of ctx->ctx_arr. Set ctxm->type from the current loop
+variable instead of depending on resp->type.
+
+Also update the loop to advance type from next_valid_type in the for
+statement, which keeps the control flow simpler for non-valid and
+unchanged entries.
+
+Fixes: 6a4d0774f02d ("bnxt_en: Add support for new backing store query firmware API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Tested-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index e9f40ca8bb4fb..04aa5d9eb8513 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -8607,7 +8607,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ struct hwrm_func_backing_store_qcaps_v2_output *resp;
+ struct hwrm_func_backing_store_qcaps_v2_input *req;
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+- u16 type;
++ u16 type, next_type = 0;
+ int rc;
+
+ rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2);
+@@ -8623,7 +8623,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+
+ resp = hwrm_req_hold(bp, req);
+
+- for (type = 0; type < BNXT_CTX_V2_MAX; ) {
++ for (type = 0; type < BNXT_CTX_V2_MAX; type = next_type) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ u8 init_val, init_off, i;
+ u32 max_entries;
+@@ -8636,7 +8636,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ if (rc)
+ goto ctx_done;
+ flags = le32_to_cpu(resp->flags);
+- type = le16_to_cpu(resp->next_valid_type);
++ next_type = le16_to_cpu(resp->next_valid_type);
+ if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) {
+ bnxt_free_one_ctx_mem(bp, ctxm, true);
+ continue;
+@@ -8651,7 +8651,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ else
+ continue;
+ }
+- ctxm->type = le16_to_cpu(resp->type);
++ ctxm->type = type;
+ ctxm->entry_size = entry_size;
+ ctxm->flags = flags;
+ ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
+--
+2.53.0
+
--- /dev/null
+From d2da1b74dc5d49d11ff51bc6fc90ba50210e3069 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 3eaff8453e9a9..ecdbc821bd1a4 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -18985,8 +18985,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From ace3534e5c022501abbad468bfeeb022923d9a88 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 17:29:22 +0800
+Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit b0db1accbc7395657c2b79db59fa9fae0d6656f3 ]
+
+check_mem_access() matches PTR_TO_BUF via base_type() which strips
+PTR_MAYBE_NULL, allowing direct dereference without a null check.
+
+Map iterator ctx->key and ctx->value are PTR_TO_BUF | PTR_MAYBE_NULL.
+On stop callbacks these are NULL, causing a kernel NULL dereference.
+
+Add a type_may_be_null() guard to the PTR_TO_BUF branch, matching the
+existing PTR_TO_BTF_ID pattern.
+
+Fixes: 20b2aff4bc15 ("bpf: Introduce MEM_RDONLY flag")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index ecdbc821bd1a4..db1c591a1da3b 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -7737,7 +7737,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ } else if (reg->type == CONST_PTR_TO_MAP) {
+ err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+ value_regno);
+- } else if (base_type(reg->type) == PTR_TO_BUF) {
++ } else if (base_type(reg->type) == PTR_TO_BUF &&
++ !type_may_be_null(reg->type)) {
+ bool rdonly_mem = type_is_rdonly_mem(reg->type);
+ u32 *max_access;
+
+--
+2.53.0
+
--- /dev/null
+From 2c354c907b06d8f7c53a6b22d7621676c6e6f22f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 00:41:25 +0530
+Subject: bpf: Reject sleepable kprobe_multi programs at attach time
+
+From: Varun R Mallya <varunrmallya@gmail.com>
+
+[ Upstream commit eb7024bfcc5f68ed11ed9dd4891a3073c15f04a8 ]
+
+kprobe.multi programs run in atomic/RCU context and cannot sleep.
+However, bpf_kprobe_multi_link_attach() did not validate whether the
+program being attached had the sleepable flag set, allowing sleepable
+helpers such as bpf_copy_from_user() to be invoked from a non-sleepable
+context.
+
+This causes a "sleeping function called from invalid context" splat:
+
+ BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:169
+ in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1787, name: sudo
+ preempt_count: 1, expected: 0
+ RCU nest depth: 2, expected: 0
+
+Fix this by rejecting sleepable programs early in
+bpf_kprobe_multi_link_attach(), before any further processing.
+
+Fixes: 0dcac2725406 ("bpf: Add multi kprobe link")
+Signed-off-by: Varun R Mallya <varunrmallya@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Acked-by: Leon Hwang <leon.hwang@linux.dev>
+Acked-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20260401191126.440683-1-varunrmallya@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/bpf_trace.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
+index d8da00fe73f0b..70f1292b7ddbd 100644
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2739,6 +2739,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
+ if (!is_kprobe_multi(prog))
+ return -EINVAL;
+
++ /* kprobe_multi is not allowed to be sleepable. */
++ if (prog->sleepable)
++ return -EINVAL;
++
+ /* Writing to context is not allowed for kprobes. */
+ if (prog->aux->kprobe_write_ctx)
+ return -EINVAL;
+--
+2.53.0
+
--- /dev/null
+From 0acbd185f03cec6b55e0a21026e9c3a61f165872 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 00:54:15 +0000
+Subject: bpf: sockmap: Fix use-after-free of sk->sk_socket in
+ sk_psock_verdict_data_ready().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit ad8391d37f334ee73ba91926f8b4e4cf6d31ea04 ]
+
+syzbot reported use-after-free of AF_UNIX socket's sk->sk_socket
+in sk_psock_verdict_data_ready(). [0]
+
+In unix_stream_sendmsg(), the peer socket's ->sk_data_ready() is
+called after dropping its unix_state_lock().
+
+Although the sender socket holds the peer's refcount, it does not
+prevent the peer's sock_orphan(), and the peer's sk_socket might
+be freed after one RCU grace period.
+
+Let's fetch the peer's sk->sk_socket and sk->sk_socket->ops under
+RCU in sk_psock_verdict_data_ready().
+
+[0]:
+BUG: KASAN: slab-use-after-free in sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+Read of size 8 at addr ffff8880594da860 by task syz.4.1842/11013
+
+CPU: 1 UID: 0 PID: 11013 Comm: syz.4.1842 Not tainted syzkaller #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:378 [inline]
+ print_report+0xba/0x230 mm/kasan/report.c:482
+ kasan_report+0x117/0x150 mm/kasan/report.c:595
+ sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+ unix_stream_sendmsg+0x8a3/0xe80 net/unix/af_unix.c:2482
+ sock_sendmsg_nosec net/socket.c:721 [inline]
+ __sock_sendmsg net/socket.c:736 [inline]
+ ____sys_sendmsg+0x972/0x9f0 net/socket.c:2585
+ ___sys_sendmsg+0x2a5/0x360 net/socket.c:2639
+ __sys_sendmsg net/socket.c:2671 [inline]
+ __do_sys_sendmsg net/socket.c:2676 [inline]
+ __se_sys_sendmsg net/socket.c:2674 [inline]
+ __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2674
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7facf899c819
+Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007facf9827028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007facf8c15fa0 RCX: 00007facf899c819
+RDX: 0000000000000000 RSI: 0000200000000500 RDI: 0000000000000004
+RBP: 00007facf8a32c91 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 00007facf8c16038 R14: 00007facf8c15fa0 R15: 00007ffd41b01c78
+ </TASK>
+
+Allocated by task 11013:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ unpoison_slab_object mm/kasan/common.c:340 [inline]
+ __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:366
+ kasan_slab_alloc include/linux/kasan.h:253 [inline]
+ slab_post_alloc_hook mm/slub.c:4538 [inline]
+ slab_alloc_node mm/slub.c:4866 [inline]
+ kmem_cache_alloc_lru_noprof+0x2b8/0x640 mm/slub.c:4885
+ sock_alloc_inode+0x28/0xc0 net/socket.c:316
+ alloc_inode+0x6a/0x1b0 fs/inode.c:347
+ new_inode_pseudo include/linux/fs.h:3003 [inline]
+ sock_alloc net/socket.c:631 [inline]
+ __sock_create+0x12d/0x9d0 net/socket.c:1562
+ sock_create net/socket.c:1656 [inline]
+ __sys_socketpair+0x1c4/0x560 net/socket.c:1803
+ __do_sys_socketpair net/socket.c:1856 [inline]
+ __se_sys_socketpair net/socket.c:1853 [inline]
+ __x64_sys_socketpair+0x9b/0xb0 net/socket.c:1853
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 15:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
+ poison_slab_object mm/kasan/common.c:253 [inline]
+ __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
+ kasan_slab_free include/linux/kasan.h:235 [inline]
+ slab_free_hook mm/slub.c:2685 [inline]
+ slab_free mm/slub.c:6165 [inline]
+ kmem_cache_free+0x187/0x630 mm/slub.c:6295
+ rcu_do_batch kernel/rcu/tree.c:2617 [inline]
+ rcu_core+0x7cd/0x1070 kernel/rcu/tree.c:2869
+ handle_softirqs+0x22a/0x870 kernel/softirq.c:622
+ run_ksoftirqd+0x36/0x60 kernel/softirq.c:1063
+ smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160
+ kthread+0x388/0x470 kernel/kthread.c:436
+ ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
+
+Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()")
+Closes: https://lore.kernel.org/bpf/69cc6b9f.a70a0220.128fd0.004b.GAE@google.com/
+Reported-by: syzbot+2184232f07e3677fbaef@syzkaller.appspotmail.com
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/skmsg.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/skmsg.c b/net/core/skmsg.c
+index 12fbb0545c712..35a6acbf9a579 100644
+--- a/net/core/skmsg.c
++++ b/net/core/skmsg.c
+@@ -1267,17 +1267,20 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)
+
+ static void sk_psock_verdict_data_ready(struct sock *sk)
+ {
+- struct socket *sock = sk->sk_socket;
+- const struct proto_ops *ops;
++ const struct proto_ops *ops = NULL;
++ struct socket *sock;
+ int copied;
+
+ trace_sk_data_ready(sk);
+
+- if (unlikely(!sock))
+- return;
+- ops = READ_ONCE(sock->ops);
++ rcu_read_lock();
++ sock = READ_ONCE(sk->sk_socket);
++ if (likely(sock))
++ ops = READ_ONCE(sock->ops);
++ rcu_read_unlock();
+ if (!ops || !ops->read_skb)
+ return;
++
+ copied = ops->read_skb(sk, sk_psock_verdict_recv);
+ if (copied >= 0) {
+ struct sk_psock *psock;
+--
+2.53.0
+
--- /dev/null
+From b10716ffc5af9f686c48a3cf208d8d516b39b79d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index 1e2b51769eec8..af3d1e33f50b8 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -251,12 +251,12 @@ struct nd_msg *br_is_nd_neigh_msg(const struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -264,7 +264,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -281,6 +281,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -472,9 +474,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From fdb471276c8b64186f01b39d72134b0722fbb443 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 11:53:46 +0100
+Subject: btrfs: don't take device_list_mutex when querying zone info
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 77603ab10429fe713a03345553ca8dbbfb1d91c6 ]
+
+Shin'ichiro reported sporadic hangs when running generic/013 in our CI
+system. When enabling lockdep, there is a lockdep splat when calling
+btrfs_get_dev_zone_info_all_devices() in the mount path that can be
+triggered by i.e. generic/013:
+
+ ======================================================
+ WARNING: possible circular locking dependency detected
+ 7.0.0-rc1+ #355 Not tainted
+ ------------------------------------------------------
+ mount/1043 is trying to acquire lock:
+ ffff8881020b5470 (&vblk->vdev_mutex){+.+.}-{4:4}, at: virtblk_report_zones+0xda/0x430
+
+ but task is already holding lock:
+ ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #4 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
+ __mutex_lock+0xa3/0x1360
+ btrfs_create_pending_block_groups+0x1f4/0x9d0
+ __btrfs_end_transaction+0x3e/0x2e0
+ btrfs_zoned_reserve_data_reloc_bg+0x2f8/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #3 (btrfs_trans_num_extwriters){++++}-{0:0}:
+ join_transaction+0xc2/0x5c0
+ start_transaction+0x17c/0xbc0
+ btrfs_zoned_reserve_data_reloc_bg+0x2b4/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #2 (btrfs_trans_num_writers){++++}-{0:0}:
+ lock_release+0x163/0x4b0
+ __btrfs_end_transaction+0x1c7/0x2e0
+ btrfs_dirty_inode+0x6f/0xd0
+ touch_atime+0xe5/0x2c0
+ btrfs_file_mmap_prepare+0x65/0x90
+ __mmap_region+0x4b9/0xf00
+ mmap_region+0xf7/0x120
+ do_mmap+0x43d/0x610
+ vm_mmap_pgoff+0xd6/0x190
+ ksys_mmap_pgoff+0x7e/0xc0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #1 (&mm->mmap_lock){++++}-{4:4}:
+ __might_fault+0x68/0xa0
+ _copy_to_user+0x22/0x70
+ blkdev_copy_zone_to_user+0x22/0x40
+ virtblk_report_zones+0x282/0x430
+ blkdev_report_zones_ioctl+0xfd/0x130
+ blkdev_ioctl+0x20f/0x2c0
+ __x64_sys_ioctl+0x86/0xd0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #0 (&vblk->vdev_mutex){+.+.}-{4:4}:
+ __lock_acquire+0x1522/0x2680
+ lock_acquire+0xd5/0x2f0
+ __mutex_lock+0xa3/0x1360
+ virtblk_report_zones+0xda/0x430
+ blkdev_report_zones_cached+0x162/0x190
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ other info that might help us debug this:
+
+ Chain exists of:
+ &vblk->vdev_mutex --> btrfs_trans_num_extwriters --> &fs_devs->device_list_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&fs_devs->device_list_mutex);
+ lock(btrfs_trans_num_extwriters);
+ lock(&fs_devs->device_list_mutex);
+ lock(&vblk->vdev_mutex);
+
+ *** DEADLOCK ***
+
+ 3 locks held by mount/1043:
+ #0: ffff88811063e878 (&fc->uapi_mutex){+.+.}-{4:4}, at: __do_sys_fsconfig+0x2ae/0x680
+ #1: ffff88810cb9f0e8 (&type->s_umount_key#31/1){+.+.}-{4:4}, at: alloc_super+0xc0/0x3e0
+ #2: ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 1043 Comm: mount Not tainted 7.0.0-rc1+ #355 PREEMPT(full)
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x80
+ print_circular_bug.cold+0x18d/0x1d8
+ check_noncircular+0x10d/0x130
+ __lock_acquire+0x1522/0x2680
+ ? vmap_small_pages_range_noflush+0x3ef/0x820
+ lock_acquire+0xd5/0x2f0
+ ? virtblk_report_zones+0xda/0x430
+ ? lock_is_held_type+0xcd/0x130
+ __mutex_lock+0xa3/0x1360
+ ? virtblk_report_zones+0xda/0x430
+ ? virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ ? virtblk_report_zones+0xda/0x430
+ virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ blkdev_report_zones_cached+0x162/0x190
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ ? rcu_is_watching+0x18/0x50
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ RIP: 0033:0x7f615e27a40e
+ RSP: 002b:00007fff11b18fb8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ RAX: ffffffffffffffda RBX: 000055572e92ab10 RCX: 00007f615e27a40e
+ RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ RBP: 00007fff11b19100 R08: 0000000000000000 R09: 0000000000000000
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055572e92bc40 R14: 00007f615e3faa60 R15: 000055572e92bd08
+ </TASK>
+
+Don't hold the device_list_mutex while calling into
+btrfs_get_dev_zone_info() in btrfs_get_dev_zone_info_all_devices() to
+mitigate the issue. This is safe, as no other thread can touch the device
+list at the moment of execution.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index e14a4234954ba..16818dbf48a46 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -335,7 +335,10 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (!btrfs_fs_incompat(fs_info, ZONED))
+ return 0;
+
+- mutex_lock(&fs_devices->device_list_mutex);
++ /*
++ * No need to take the device_list mutex here, we're still in the mount
++ * path and devices cannot be added to or removed from the list yet.
++ */
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ /* We can skip reading of zone info for missing devices */
+ if (!device->bdev)
+@@ -345,7 +348,6 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (ret)
+ break;
+ }
+- mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
+ }
+--
+2.53.0
+
--- /dev/null
+From 44b7488ac4b53b1be93c791a7689c60c3cf6b34f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Mar 2026 08:14:43 +0800
+Subject: btrfs: reject root items with drop_progress and zero drop_level
+
+From: ZhengYuan Huang <gality369@gmail.com>
+
+[ Upstream commit b17b79ff896305fd74980a5f72afec370ee88ca4 ]
+
+[BUG]
+When recovering relocation at mount time, merge_reloc_root() and
+btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
+an impossible state: a non-zero drop_progress combined with a zero
+drop_level in a root_item, which can be triggered:
+
+------------[ cut here ]------------
+kernel BUG at fs/btrfs/relocation.c:1545!
+Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
+CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
+Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
+RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
+Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
+Call Trace:
+ merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
+ btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
+ btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
+ open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
+ btrfs_fill_super fs/btrfs/super.c:987 [inline]
+ btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
+ btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
+ btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
+ vfs_get_tree+0x9a/0x370 fs/super.c:1758
+ fc_mount fs/namespace.c:1199 [inline]
+ do_new_mount_fc fs/namespace.c:3642 [inline]
+ do_new_mount fs/namespace.c:3718 [inline]
+ path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
+ do_mount fs/namespace.c:4041 [inline]
+ __do_sys_mount fs/namespace.c:4229 [inline]
+ __se_sys_mount fs/namespace.c:4206 [inline]
+ __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
+ ...
+RIP: 0033:0x7f969c9a8fde
+Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
+---[ end trace 0000000000000000 ]---
+
+The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
+metadata fuzzing tool that corrupts btrfs metadata at runtime.
+
+[CAUSE]
+A non-zero drop_progress.objectid means an interrupted
+btrfs_drop_snapshot() left a resume point on disk, and in that case
+drop_level must be greater than 0 because the checkpoint is only
+saved at internal node levels.
+
+Although this invariant is enforced when the kernel writes the root
+item, it is not validated when the root item is read back from disk.
+That allows on-disk corruption to provide an invalid state with
+drop_progress.objectid != 0 and drop_level == 0.
+
+When relocation recovery later processes such a root item,
+merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
+same invalid metadata can also trigger the corresponding BUG_ON() in
+btrfs_drop_snapshot().
+
+[FIX]
+Fix this by validating the root_item invariant in tree-checker when
+reading root items from disk: if drop_progress.objectid is non-zero,
+drop_level must also be non-zero. Reject such malformed metadata with
+-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
+and triggers the BUG_ON.
+
+After the fix, the same corruption is correctly rejected by tree-checker
+and the BUG_ON is no longer triggered.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 9b11b0a529dba..33a45737c4cf4 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -1260,6 +1260,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
+ btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
+ return -EUCLEAN;
+ }
++ /*
++ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
++ * interrupted and the resume point was recorded in drop_progress and
++ * drop_level. In that case drop_level must be >= 1: level 0 is the
++ * leaf level and drop_snapshot never saves a checkpoint there (it
++ * only records checkpoints at internal node levels in DROP_REFERENCE
++ * stage). A zero drop_level combined with a non-zero drop_progress
++ * objectid indicates on-disk corruption and would cause a BUG_ON in
++ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
++ */
++ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
++ btrfs_root_drop_level(&ri) == 0)) {
++ generic_err(leaf, slot,
++ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
++ btrfs_disk_key_objectid(&ri.drop_progress));
++ return -EUCLEAN;
++ }
+
+ /* Flags check */
+ if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
+--
+2.53.0
+
--- /dev/null
+From 59dcad1f1c1f46ea36cacf2bbf2829368e89a14d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Feb 2026 16:08:53 +0000
+Subject: btrfs: reserve enough transaction items for qgroup ioctls
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit f9a4e3015db1aeafbef407650eb8555445ca943e ]
+
+Currently our qgroup ioctls don't reserve any space, they just do a
+transaction join, which does not reserve any space, neither for the quota
+tree updates nor for the delayed refs generated when updating the quota
+tree. The quota root uses the global block reserve, which is fine most of
+the time since we don't expect a lot of updates to the quota root, or to
+be too close to -ENOSPC such that other critical metadata updates need to
+resort to the global reserve.
+
+However this is not optimal, as not reserving proper space may result in a
+transaction abort due to not reserving space for delayed refs and then
+abusing the use of the global block reserve.
+
+For example, the following reproducer (which is unlikely to model any
+real world use case, but just to illustrate the problem), triggers such a
+transaction abort due to -ENOSPC when running delayed refs:
+
+ $ cat test.sh
+ #!/bin/bash
+
+ DEV=/dev/nullb0
+ MNT=/mnt/nullb0
+
+ umount $DEV &> /dev/null
+ # Limit device to 1G so that it's much faster to reproduce the issue.
+ mkfs.btrfs -f -b 1G $DEV
+ mount -o commit=600 $DEV $MNT
+
+ fallocate -l 800M $MNT/filler
+ btrfs quota enable $MNT
+
+ for ((i = 1; i <= 400000; i++)); do
+ btrfs qgroup create 1/$i $MNT
+ done
+
+ umount $MNT
+
+When running this, we can see in dmesg/syslog that a transaction abort
+happened:
+
+ [436.490] BTRFS error (device nullb0): failed to run delayed ref for logical 30408704 num_bytes 16384 type 176 action 1 ref_mod 1: -28
+ [436.493] ------------[ cut here ]------------
+ [436.494] BTRFS: Transaction aborted (error -28)
+ [436.495] WARNING: fs/btrfs/extent-tree.c:2247 at btrfs_run_delayed_refs+0xd9/0x110 [btrfs], CPU#4: umount/2495372
+ [436.497] Modules linked in: btrfs loop (...)
+ [436.508] CPU: 4 UID: 0 PID: 2495372 Comm: umount Tainted: G W 6.19.0-rc8-btrfs-next-225+ #1 PREEMPT(full)
+ [436.510] Tainted: [W]=WARN
+ [436.511] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
+ [436.513] RIP: 0010:btrfs_run_delayed_refs+0xdf/0x110 [btrfs]
+ [436.514] Code: 0f 82 ea (...)
+ [436.518] RSP: 0018:ffffd511850b7d78 EFLAGS: 00010292
+ [436.519] RAX: 00000000ffffffe4 RBX: ffff8f120dad37e0 RCX: 0000000002040001
+ [436.520] RDX: 0000000000000002 RSI: 00000000ffffffe4 RDI: ffffffffc090fd80
+ [436.522] RBP: 0000000000000000 R08: 0000000000000001 R09: ffffffffc04d1867
+ [436.523] R10: ffff8f18dc1fffa8 R11: 0000000000000003 R12: ffff8f173aa89400
+ [436.524] R13: 0000000000000000 R14: ffff8f173aa89400 R15: 0000000000000000
+ [436.526] FS: 00007fe59045d840(0000) GS:ffff8f192e22e000(0000) knlGS:0000000000000000
+ [436.527] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ [436.528] CR2: 00007fe5905ff2b0 CR3: 000000060710a002 CR4: 0000000000370ef0
+ [436.530] Call Trace:
+ [436.530] <TASK>
+ [436.530] btrfs_commit_transaction+0x73/0xc00 [btrfs]
+ [436.531] ? btrfs_attach_transaction_barrier+0x1e/0x70 [btrfs]
+ [436.532] sync_filesystem+0x7a/0x90
+ [436.533] generic_shutdown_super+0x28/0x180
+ [436.533] kill_anon_super+0x12/0x40
+ [436.534] btrfs_kill_super+0x12/0x20 [btrfs]
+ [436.534] deactivate_locked_super+0x2f/0xb0
+ [436.534] cleanup_mnt+0xea/0x180
+ [436.535] task_work_run+0x58/0xa0
+ [436.535] exit_to_user_mode_loop+0xed/0x480
+ [436.536] ? __x64_sys_umount+0x68/0x80
+ [436.536] do_syscall_64+0x2a5/0xf20
+ [436.537] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ [436.537] RIP: 0033:0x7fe5906b6217
+ [436.538] Code: 0d 00 f7 (...)
+ [436.540] RSP: 002b:00007ffcd87a61f8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+ [436.541] RAX: 0000000000000000 RBX: 00005618b9ecadc8 RCX: 00007fe5906b6217
+ [436.541] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00005618b9ecb100
+ [436.542] RBP: 0000000000000000 R08: 00007ffcd87a4fe0 R09: 00000000ffffffff
+ [436.544] R10: 0000000000000103 R11: 0000000000000246 R12: 00007fe59081626c
+ [436.544] R13: 00005618b9ecb100 R14: 0000000000000000 R15: 00005618b9ecacc0
+ [436.545] </TASK>
+ [436.545] ---[ end trace 0000000000000000 ]---
+
+Fix this by changing the qgroup ioctls to use start transaction instead of
+joining so that proper space is reserved for the delayed refs generated
+for the updates to the quota root. This way we don't get any transaction
+abort.
+
+Reviewed-by: Boris Burkov <boris@bur.io>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ioctl.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index c7977bd5442b3..bfe253c2849a5 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3749,7 +3749,8 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
+ }
+ }
+
+- trans = btrfs_join_transaction(root);
++ /* 2 BTRFS_QGROUP_RELATION_KEY items. */
++ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+@@ -3821,7 +3822,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
+ goto out;
+ }
+
+- trans = btrfs_join_transaction(root);
++ /*
++ * 1 BTRFS_QGROUP_INFO_KEY item.
++ * 1 BTRFS_QGROUP_LIMIT_KEY item.
++ */
++ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+@@ -3870,7 +3875,8 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
+ goto drop_write;
+ }
+
+- trans = btrfs_join_transaction(root);
++ /* 1 BTRFS_QGROUP_LIMIT_KEY item. */
++ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+--
+2.53.0
+
--- /dev/null
+From 73a76d6438fe0ef9d3f8402769f44cff95088f6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 6c271e55f44d9..78e995dddf879 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -623,8 +623,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From cb9db7522aed39078b0c06780961de150fbc7f8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:30:20 +0900
+Subject: crypto: algif_aead - Revert to operating out-of-place
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 ]
+
+This mostly reverts commit 72548b093ee3 except for the copying of
+the associated data.
+
+There is no benefit in operating in-place in algif_aead since the
+source and destination come from different mappings. Get rid of
+all the complexity added for in-place operation and just copy the
+AD directly.
+
+Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst")
+Reported-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 49 ++++----------------
+ crypto/algif_aead.c | 100 ++++++++--------------------------------
+ crypto/algif_skcipher.c | 6 +--
+ include/crypto/if_alg.h | 5 +-
+ 4 files changed, 34 insertions(+), 126 deletions(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 78e995dddf879..3236601aa6dc0 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -637,15 +637,13 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ /**
+ * af_alg_count_tsgl - Count number of TX SG entries
+ *
+- * The counting starts from the beginning of the SGL to @bytes. If
+- * an @offset is provided, the counting of the SG entries starts at the @offset.
++ * The counting starts from the beginning of the SGL to @bytes.
+ *
+ * @sk: socket of connection to user space
+ * @bytes: Count the number of SG entries holding given number of bytes.
+- * @offset: Start the counting of SG entries from the given offset.
+ * Return: Number of TX SG entries found given the constraints
+ */
+-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset)
++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes)
+ {
+ const struct alg_sock *ask = alg_sk(sk);
+ const struct af_alg_ctx *ctx = ask->private;
+@@ -660,25 +658,11 @@ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset)
+ const struct scatterlist *sg = sgl->sg;
+
+ for (i = 0; i < sgl->cur; i++) {
+- size_t bytes_count;
+-
+- /* Skip offset */
+- if (offset >= sg[i].length) {
+- offset -= sg[i].length;
+- bytes -= sg[i].length;
+- continue;
+- }
+-
+- bytes_count = sg[i].length - offset;
+-
+- offset = 0;
+ sgl_count++;
+-
+- /* If we have seen requested number of bytes, stop */
+- if (bytes_count >= bytes)
++ if (sg[i].length >= bytes)
+ return sgl_count;
+
+- bytes -= bytes_count;
++ bytes -= sg[i].length;
+ }
+ }
+
+@@ -690,19 +674,14 @@ EXPORT_SYMBOL_GPL(af_alg_count_tsgl);
+ * af_alg_pull_tsgl - Release the specified buffers from TX SGL
+ *
+ * If @dst is non-null, reassign the pages to @dst. The caller must release
+- * the pages. If @dst_offset is given only reassign the pages to @dst starting
+- * at the @dst_offset (byte). The caller must ensure that @dst is large
+- * enough (e.g. by using af_alg_count_tsgl with the same offset).
++ * the pages.
+ *
+ * @sk: socket of connection to user space
+ * @used: Number of bytes to pull from TX SGL
+ * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The
+ * caller must release the buffers in dst.
+- * @dst_offset: Reassign the TX SGL from given offset. All buffers before
+- * reaching the offset is released.
+ */
+-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
+- size_t dst_offset)
++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst)
+ {
+ struct alg_sock *ask = alg_sk(sk);
+ struct af_alg_ctx *ctx = ask->private;
+@@ -727,18 +706,10 @@ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
+ * SG entries in dst.
+ */
+ if (dst) {
+- if (dst_offset >= plen) {
+- /* discard page before offset */
+- dst_offset -= plen;
+- } else {
+- /* reassign page to dst after offset */
+- get_page(page);
+- sg_set_page(dst + j, page,
+- plen - dst_offset,
+- sg[i].offset + dst_offset);
+- dst_offset = 0;
+- j++;
+- }
++ /* reassign page to dst after offset */
++ get_page(page);
++ sg_set_page(dst + j, page, plen, sg[i].offset);
++ j++;
+ }
+
+ sg[i].length -= plen;
+diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
+index 79b016a899a1e..dda15bb05e892 100644
+--- a/crypto/algif_aead.c
++++ b/crypto/algif_aead.c
+@@ -26,7 +26,6 @@
+ #include <crypto/internal/aead.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/if_alg.h>
+-#include <crypto/skcipher.h>
+ #include <linux/init.h>
+ #include <linux/list.h>
+ #include <linux/kernel.h>
+@@ -72,9 +71,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
+ struct alg_sock *pask = alg_sk(psk);
+ struct af_alg_ctx *ctx = ask->private;
+ struct crypto_aead *tfm = pask->private;
+- unsigned int i, as = crypto_aead_authsize(tfm);
++ unsigned int as = crypto_aead_authsize(tfm);
+ struct af_alg_async_req *areq;
+- struct af_alg_tsgl *tsgl, *tmp;
+ struct scatterlist *rsgl_src, *tsgl_src = NULL;
+ int err = 0;
+ size_t used = 0; /* [in] TX bufs to be en/decrypted */
+@@ -154,23 +152,24 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
+ outlen -= less;
+ }
+
++ /*
++ * Create a per request TX SGL for this request which tracks the
++ * SG entries from the global TX SGL.
++ */
+ processed = used + ctx->aead_assoclen;
+- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) {
+- for (i = 0; i < tsgl->cur; i++) {
+- struct scatterlist *process_sg = tsgl->sg + i;
+-
+- if (!(process_sg->length) || !sg_page(process_sg))
+- continue;
+- tsgl_src = process_sg;
+- break;
+- }
+- if (tsgl_src)
+- break;
+- }
+- if (processed && !tsgl_src) {
+- err = -EFAULT;
++ areq->tsgl_entries = af_alg_count_tsgl(sk, processed);
++ if (!areq->tsgl_entries)
++ areq->tsgl_entries = 1;
++ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
++ areq->tsgl_entries),
++ GFP_KERNEL);
++ if (!areq->tsgl) {
++ err = -ENOMEM;
+ goto free;
+ }
++ sg_init_table(areq->tsgl, areq->tsgl_entries);
++ af_alg_pull_tsgl(sk, processed, areq->tsgl);
++ tsgl_src = areq->tsgl;
+
+ /*
+ * Copy of AAD from source to destination
+@@ -179,76 +178,15 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
+ * when user space uses an in-place cipher operation, the kernel
+ * will copy the data as it does not see whether such in-place operation
+ * is initiated.
+- *
+- * To ensure efficiency, the following implementation ensure that the
+- * ciphers are invoked to perform a crypto operation in-place. This
+- * is achieved by memory management specified as follows.
+ */
+
+ /* Use the RX SGL as source (and destination) for crypto op. */
+ rsgl_src = areq->first_rsgl.sgl.sgt.sgl;
+
+- if (ctx->enc) {
+- /*
+- * Encryption operation - The in-place cipher operation is
+- * achieved by the following operation:
+- *
+- * TX SGL: AAD || PT
+- * | |
+- * | copy |
+- * v v
+- * RX SGL: AAD || PT || Tag
+- */
+- memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src,
+- processed);
+- af_alg_pull_tsgl(sk, processed, NULL, 0);
+- } else {
+- /*
+- * Decryption operation - To achieve an in-place cipher
+- * operation, the following SGL structure is used:
+- *
+- * TX SGL: AAD || CT || Tag
+- * | | ^
+- * | copy | | Create SGL link.
+- * v v |
+- * RX SGL: AAD || CT ----+
+- */
+-
+- /* Copy AAD || CT to RX SGL buffer for in-place operation. */
+- memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src, outlen);
+-
+- /* Create TX SGL for tag and chain it to RX SGL. */
+- areq->tsgl_entries = af_alg_count_tsgl(sk, processed,
+- processed - as);
+- if (!areq->tsgl_entries)
+- areq->tsgl_entries = 1;
+- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
+- areq->tsgl_entries),
+- GFP_KERNEL);
+- if (!areq->tsgl) {
+- err = -ENOMEM;
+- goto free;
+- }
+- sg_init_table(areq->tsgl, areq->tsgl_entries);
+-
+- /* Release TX SGL, except for tag data and reassign tag data. */
+- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as);
+-
+- /* chain the areq TX SGL holding the tag with RX SGL */
+- if (usedpages) {
+- /* RX SGL present */
+- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl;
+- struct scatterlist *sg = sgl_prev->sgt.sgl;
+-
+- sg_unmark_end(sg + sgl_prev->sgt.nents - 1);
+- sg_chain(sg, sgl_prev->sgt.nents + 1, areq->tsgl);
+- } else
+- /* no RX SGL present (e.g. authentication only) */
+- rsgl_src = areq->tsgl;
+- }
++ memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen);
+
+ /* Initialize the crypto operation */
+- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src,
++ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src,
+ areq->first_rsgl.sgl.sgt.sgl, used, ctx->iv);
+ aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen);
+ aead_request_set_tfm(&areq->cra_u.aead_req, tfm);
+@@ -450,7 +388,7 @@ static void aead_sock_destruct(struct sock *sk)
+ struct crypto_aead *tfm = pask->private;
+ unsigned int ivlen = crypto_aead_ivsize(tfm);
+
+- af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
++ af_alg_pull_tsgl(sk, ctx->used, NULL);
+ sock_kzfree_s(sk, ctx->iv, ivlen);
+ sock_kfree_s(sk, ctx, ctx->len);
+ af_alg_release_parent(sk);
+diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
+index 125d395c5e009..82735e51be108 100644
+--- a/crypto/algif_skcipher.c
++++ b/crypto/algif_skcipher.c
+@@ -138,7 +138,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ * Create a per request TX SGL for this request which tracks the
+ * SG entries from the global TX SGL.
+ */
+- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0);
++ areq->tsgl_entries = af_alg_count_tsgl(sk, len);
+ if (!areq->tsgl_entries)
+ areq->tsgl_entries = 1;
+ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
+@@ -149,7 +149,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ goto free;
+ }
+ sg_init_table(areq->tsgl, areq->tsgl_entries);
+- af_alg_pull_tsgl(sk, len, areq->tsgl, 0);
++ af_alg_pull_tsgl(sk, len, areq->tsgl);
+
+ /* Initialize the crypto operation */
+ skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm);
+@@ -363,7 +363,7 @@ static void skcipher_sock_destruct(struct sock *sk)
+ struct alg_sock *pask = alg_sk(psk);
+ struct crypto_skcipher *tfm = pask->private;
+
+- af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
++ af_alg_pull_tsgl(sk, ctx->used, NULL);
+ sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
+ if (ctx->state)
+ sock_kzfree_s(sk, ctx->state, crypto_skcipher_statesize(tfm));
+diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
+index 107b797c33ecf..0cc8fa749f68d 100644
+--- a/include/crypto/if_alg.h
++++ b/include/crypto/if_alg.h
+@@ -230,9 +230,8 @@ static inline bool af_alg_readable(struct sock *sk)
+ return PAGE_SIZE <= af_alg_rcvbuf(sk);
+ }
+
+-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset);
+-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
+- size_t dst_offset);
++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes);
++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst);
+ void af_alg_wmem_wakeup(struct sock *sk);
+ int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min);
+ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
+--
+2.53.0
+
--- /dev/null
+From b59966ca212361fdeb1d422673b2288108f96771 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 15:04:17 +0900
+Subject: crypto: authencesn - Do not place hiseq at end of dst for
+ out-of-place decryption
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit e02494114ebf7c8b42777c6cd6982f113bfdbec7 ]
+
+When decrypting data that is not in-place (src != dst), there is
+no need to save the high-order sequence bits in dst as it could
+simply be re-copied from the source.
+
+However, the data to be hashed need to be rearranged accordingly.
+
+Reported-by: Taeyang Lee <0wn@theori.io>
+Fixes: 104880a6b470 ("crypto: authencesn - Convert to new AEAD interface")
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+
+Thanks,
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/authencesn.c | 48 +++++++++++++++++++++++++++------------------
+ 1 file changed, 29 insertions(+), 19 deletions(-)
+
+diff --git a/crypto/authencesn.c b/crypto/authencesn.c
+index 542a978663b9e..c0a01d738d9bc 100644
+--- a/crypto/authencesn.c
++++ b/crypto/authencesn.c
+@@ -207,6 +207,7 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
+ u8 *ohash = areq_ctx->tail;
+ unsigned int cryptlen = req->cryptlen - authsize;
+ unsigned int assoclen = req->assoclen;
++ struct scatterlist *src = req->src;
+ struct scatterlist *dst = req->dst;
+ u8 *ihash = ohash + crypto_ahash_digestsize(auth);
+ u32 tmp[2];
+@@ -214,23 +215,27 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
+ if (!authsize)
+ goto decrypt;
+
+- /* Move high-order bits of sequence number back. */
+- scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
+- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
+- scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
++ if (src == dst) {
++ /* Move high-order bits of sequence number back. */
++ scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
++ scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
++ } else
++ memcpy_sglist(dst, src, assoclen);
+
+ if (crypto_memneq(ihash, ohash, authsize))
+ return -EBADMSG;
+
+ decrypt:
+
+- sg_init_table(areq_ctx->dst, 2);
++ if (src != dst)
++ src = scatterwalk_ffwd(areq_ctx->src, src, assoclen);
+ dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
+
+ skcipher_request_set_tfm(skreq, ctx->enc);
+ skcipher_request_set_callback(skreq, flags,
+ req->base.complete, req->base.data);
+- skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv);
++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
+
+ return crypto_skcipher_decrypt(skreq);
+ }
+@@ -255,6 +260,7 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req)
+ unsigned int assoclen = req->assoclen;
+ unsigned int cryptlen = req->cryptlen;
+ u8 *ihash = ohash + crypto_ahash_digestsize(auth);
++ struct scatterlist *src = req->src;
+ struct scatterlist *dst = req->dst;
+ u32 tmp[2];
+ int err;
+@@ -262,24 +268,28 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req)
+ if (assoclen < 8)
+ return -EINVAL;
+
+- cryptlen -= authsize;
+-
+- if (req->src != dst)
+- memcpy_sglist(dst, req->src, assoclen + cryptlen);
++ if (!authsize)
++ goto tail;
+
++ cryptlen -= authsize;
+ scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
+ authsize, 0);
+
+- if (!authsize)
+- goto tail;
+-
+ /* Move high-order bits of sequence number to the end. */
+- scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
+- scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
+- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
+-
+- sg_init_table(areq_ctx->dst, 2);
+- dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
++ scatterwalk_map_and_copy(tmp, src, 0, 8, 0);
++ if (src == dst) {
++ scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
++ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
++ } else {
++ scatterwalk_map_and_copy(tmp, dst, 0, 4, 1);
++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1);
++
++ src = scatterwalk_ffwd(areq_ctx->src, src, 8);
++ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
++ memcpy_sglist(dst, src, assoclen + cryptlen - 8);
++ dst = req->dst;
++ }
+
+ ahash_request_set_tfm(ahreq, auth);
+ ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen);
+--
+2.53.0
+
--- /dev/null
+From 4dd9338deb60919509bcc4bc79faf01a2a1d4303 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:13 +0200
+Subject: crypto: caam - fix DMA corruption on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 5ddfdcbe10dc5f97afc4e46ca22be2be717e8caf ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The rounding was performed, but never actually used for the allocation.
+Fix this by replacing kmemdup with kmalloc for a larger buffer,
+followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Reported-by: Paul Bunyan <pbunyan@redhat.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamhash.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
+index 25c02e2672585..053af748be86d 100644
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -441,9 +441,10 @@ static int ahash_setkey(struct crypto_ahash *ahash,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, keylen, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From 05db72961167e14f83b9f2ca474ab0d60a74efe2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:14 +0200
+Subject: crypto: caam - fix overflow on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 80688afb9c35b3934ce2d6be9973758915e2e0ef ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The copying is performed using kmemdup, however this leads to an overflow:
+reading more bytes (aligned_len - keylen) from the keylen source buffer.
+Fix this by replacing kmemdup with kmalloc, followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamalg_qi2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
+index c6117c23eb25b..07665494c8758 100644
+--- a/drivers/crypto/caam/caamalg_qi2.c
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -3326,9 +3326,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, aligned_len, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From ea92eeabe1efef51640000c14550f8c8a6bf3ff4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 16:31:38 +0100
+Subject: crypto: deflate - fix spurious -ENOSPC
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+[ Upstream commit 6d89f743e57cb34e233a8217b394c7ee09abf225 ]
+
+The code in deflate_decompress_one may erroneously return -ENOSPC even if
+it didn't run out of output space. The error happens under this
+condition:
+
+- Suppose that there are two input pages, the compressed data fits into
+ the first page and the zlib checksum is placed in the second page.
+
+- The code iterates over the first page, decompresses the data and fully
+ fills the destination buffer, zlib_inflate returns Z_OK becuse zlib
+ hasn't seen the checksum yet.
+
+- The outer do-while loop is iterated again, acomp_walk_next_src sets the
+ input parameters to the second page containing the checksum.
+
+- We go into the inner do-while loop, execute "dcur =
+ acomp_walk_next_dst(&walk);". "dcur" is zero, so we break out of the
+ loop and return -ENOSPC, despite the fact that the decompressed data
+ fit into the destination buffer.
+
+In order to fix this bug, this commit changes the logic when to report
+the -ENOSPC error. We report the error if the destination buffer is empty
+*and* if zlib_inflate didn't make any progress consuming the input
+buffer. If zlib_inflate consumes the trailing checksum, we see that it
+made progress and we will not return -ENOSPC.
+
+Fixes: 08cabc7d3c86 ("crypto: deflate - Convert to acomp")
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/deflate.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/crypto/deflate.c b/crypto/deflate.c
+index 21404515dc77e..fd388dad5d60b 100644
+--- a/crypto/deflate.c
++++ b/crypto/deflate.c
+@@ -163,18 +163,21 @@ static int deflate_decompress_one(struct acomp_req *req,
+
+ do {
+ unsigned int dcur;
++ unsigned long avail_in;
+
+ dcur = acomp_walk_next_dst(&walk);
+- if (!dcur) {
+- out_of_space = true;
+- break;
+- }
+
+ stream->avail_out = dcur;
+ stream->next_out = walk.dst.virt.addr;
++ avail_in = stream->avail_in;
+
+ ret = zlib_inflate(stream, Z_NO_FLUSH);
+
++ if (!dcur && avail_in == stream->avail_in) {
++ out_of_space = true;
++ break;
++ }
++
+ dcur -= stream->avail_out;
+ acomp_walk_done_dst(&walk, dcur);
+ } while (ret == Z_OK && stream->avail_in);
+--
+2.53.0
+
--- /dev/null
+From e62662dc2057a8b11f2e1db8908105036d19e305 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Mar 2026 16:59:55 -0500
+Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix
+ common property warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 398c0c8bbc8f5a9d2f43863275a427a9d3720b6f ]
+
+Change additionalProperties to unevaluatedProperties because it refs to
+/schemas/input/matrix-keymap.yaml.
+
+Fix below CHECK_DTBS warnings:
+arch/arm/boot/dts/nxp/imx/imx6dl-victgo.dtb: keypad@70 (holtek,ht16k33): 'keypad,num-columns', 'keypad,num-rows' do not match any of the regexes: '^pinctrl-[0-9]+$'
+ from schema $id: http://devicetree.org/schemas/auxdisplay/holtek,ht16k33.yaml#
+
+Fixes: f12b457c6b25c ("dt-bindings: auxdisplay: ht16k33: Convert to json-schema")
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../devicetree/bindings/auxdisplay/holtek,ht16k33.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+index b90eec2077b4b..fe1272e86467e 100644
+--- a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++++ b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+@@ -66,7 +66,7 @@ then:
+ required:
+ - refresh-rate-hz
+
+-additionalProperties: false
++unevaluatedProperties: false
+
+ examples:
+ - |
+--
+2.53.0
+
--- /dev/null
+From dae616f72972b4f817967eb9916e165d6423d97e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 12:51:22 -0700
+Subject: eth: fbnic: Account for page fragments when updating BDQ tail
+
+From: Dimitri Daskalakis <daskald@meta.com>
+
+[ Upstream commit b38c55320bf85a84a4f04803c57b261fc87e9b4b ]
+
+FBNIC supports fixed size buffers of 4K. When PAGE_SIZE > 4K, we
+fragment the page across multiple descriptors (FBNIC_BD_FRAG_COUNT).
+When refilling the BDQ, the correct number of entries are populated,
+but tail was only incremented by one. So on a system with 64K pages,
+HW would get one descriptor refilled for every 16 we populate.
+
+Additionally, we program the ring size in the HW when enabling the BDQ.
+This was not accounting for page fragments, so on systems with 64K pages,
+the HW used 1/16th of the ring.
+
+Fixes: 0cb4c0a13723 ("eth: fbnic: Implement Rx queue alloc/start/stop/free")
+Signed-off-by: Dimitri Daskalakis <daskald@meta.com>
+Link: https://patch.msgid.link/20260324195123.3486219-2-dimitri.daskalakis1@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+index fbdf79b6ad2de..6e21f6c17c658 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+@@ -925,7 +925,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq)
+ /* Force DMA writes to flush before writing to tail */
+ dma_wmb();
+
+- writel(i, bdq->doorbell);
++ writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell);
+ }
+ }
+
+@@ -2546,7 +2546,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
+ hpq->tail = 0;
+ hpq->head = 0;
+
+- log_size = fls(hpq->size_mask);
++ log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+
+ /* Store descriptor ring address and size */
+ fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma));
+@@ -2558,7 +2558,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
+ if (!ppq->size_mask)
+ goto write_ctl;
+
+- log_size = fls(ppq->size_mask);
++ log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+
+ /* Add enabling of PPQ to BDQ control */
+ bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;
+--
+2.53.0
+
--- /dev/null
+From ad1c0537a536e6ec5476241656295736ea06c044 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 09:28:48 -0700
+Subject: eth: fbnic: Increase FBNIC_QUEUE_SIZE_MIN to 64
+
+From: Dimitri Daskalakis <daskald@meta.com>
+
+[ Upstream commit ec7067e661193403a7a00980bda8612db5954142 ]
+
+On systems with 64K pages, RX queues will be wedged if users set the
+descriptor count to the current minimum (16). Fbnic fragments large
+pages into 4K chunks, and scales down the ring size accordingly. With
+64K pages and 16 descriptors, the ring size mask is 0 and will never
+be filled.
+
+32 descriptors is another special case that wedges the RX rings.
+Internally, the rings track pages for the head/tail pointers, not page
+fragments. So with 32 descriptors, there's only 1 usable page as one
+ring slot is kept empty to disambiguate between an empty/full ring.
+As a result, the head pointer never advances and the HW stalls after
+consuming 16 page fragments.
+
+Fixes: 0cb4c0a13723 ("eth: fbnic: Implement Rx queue alloc/start/stop/free")
+Signed-off-by: Dimitri Daskalakis <daskald@meta.com>
+Link: https://patch.msgid.link/20260401162848.2335350-1-dimitri.daskalakis1@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+index 51a98f27d5d91..f2ee2cbf3486b 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+@@ -38,7 +38,7 @@ struct fbnic_net;
+ #define FBNIC_MAX_XDPQS 128u
+
+ /* These apply to TWQs, TCQ, RCQ */
+-#define FBNIC_QUEUE_SIZE_MIN 16u
++#define FBNIC_QUEUE_SIZE_MIN 64u
+ #define FBNIC_QUEUE_SIZE_MAX SZ_64K
+
+ #define FBNIC_TXQ_SIZE_DEFAULT 1024
+--
+2.53.0
+
--- /dev/null
+From 4606655b8439d0f1d8ccb76cb4320262b08d734b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 14:59:29 +0000
+Subject: HID: core: Mitigate potential OOB by removing bogus memset()
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit 0a3fe972a7cb1404f693d6f1711f32bc1d244b1c ]
+
+The memset() in hid_report_raw_event() has the good intention of
+clearing out bogus data by zeroing the area from the end of the incoming
+data string to the assumed end of the buffer. However, as we have
+previously seen, doing so can easily result in OOB reads and writes in
+the subsequent thread of execution.
+
+The current suggestion from one of the HID maintainers is to remove the
+memset() and simply return if the incoming event buffer size is not
+large enough to fill the associated report.
+
+Suggested-by Benjamin Tissoires <bentiss@kernel.org>
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+[bentiss: changed the return value]
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index a5b3a8ca2fcbc..f5587b786f875 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -2057,9 +2057,10 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
+ rsize = max_buffer_size;
+
+ if (csize < rsize) {
+- dbg_hid("report %d is too short, (%d < %d)\n", report->id,
+- csize, rsize);
+- memset(cdata + csize, 0, rsize - csize);
++ hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
++ report->id, rsize, csize);
++ ret = -EINVAL;
++ goto out;
+ }
+
+ if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
+--
+2.53.0
+
--- /dev/null
+From d35b5f799b4731e8e2958829d341b112b22ceeac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Mar 2026 20:19:33 +0100
+Subject: HID: logitech-hidpp: Enable MX Master 4 over bluetooth
+
+From: Adrian Freund <adrian@freund.io>
+
+[ Upstream commit 70031e70ca15ede6a39db4d978e53a6cc720d454 ]
+
+The Logitech MX Master 4 can be connected over bluetooth or through a
+Logitech Bolt receiver. This change adds support for non-standard HID
+features, such as high resolution scrolling when the mouse is connected
+over bluetooth.
+Because no Logitech Bolt receiver driver exists yet those features
+won't be available when the mouse is connected through the receiver.
+
+Signed-off-by: Adrian Freund <adrian@freund.io>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-hidpp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
+index 6b463ce112a3c..3522e69da78d7 100644
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4667,6 +4667,8 @@ static const struct hid_device_id hidpp_devices[] = {
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
+ { /* Slim Solar+ K980 Keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
++ { /* MX Master 4 mouse over Bluetooth */
++ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb042) },
+ {}
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 8e54a1f5daac9c0c4c0c1dee7d519ae398454633 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 10:09:38 +0000
+Subject: HID: logitech-hidpp: Prevent use-after-free on force feedback
+ initialisation failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit f7a4c78bfeb320299c1b641500fe7761eadbd101 ]
+
+Presently, if the force feedback initialisation fails when probing the
+Logitech G920 Driving Force Racing Wheel for Xbox One, an error number
+will be returned and propagated before the userspace infrastructure
+(sysfs and /dev/input) has been torn down. If userspace ignores the
+errors and continues to use its references to these dangling entities, a
+UAF will promptly follow.
+
+We have 2 options; continue to return the error, but ensure that all of
+the infrastructure is torn down accordingly or continue to treat this
+condition as a warning by emitting the message but returning success.
+It is thought that the original author's intention was to emit the
+warning but keep the device functional, less the force feedback feature,
+so let's go with that.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Reviewed-by: Günther Noack <gnoack@google.com>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-hidpp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
+index 3522e69da78d7..faef80cb2adbd 100644
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4486,10 +4486,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ if (!ret)
+ ret = hidpp_ff_init(hidpp, &data);
+
+- if (ret)
++ if (ret) {
+ hid_warn(hidpp->hid_dev,
+ "Unable to initialize force feedback support, errno %d\n",
+ ret);
++ ret = 0;
++ }
+ }
+
+ /*
+--
+2.53.0
+
--- /dev/null
+From 685f40fed775ee368a172d7d7103b4f2f7b93ccd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index af19e089b0122..21bfaf9bbd733 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -524,12 +524,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 89607f1704a5d4d24879112d54e731c38f7041c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 9b2c710f8da18..da1f0ea85625d 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1208,10 +1208,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From f0311fd57b5b808752b77add63168190798f6f53 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:32:11 +0900
+Subject: i2c: tegra: Don't mark devices with pins as IRQ safe
+
+From: Mikko Perttunen <mperttunen@nvidia.com>
+
+[ Upstream commit ec69c9e88315c4be70c283f18c2ff130da6320b5 ]
+
+I2C devices with associated pinctrl states (DPAUX I2C controllers)
+will change pinctrl state during runtime PM. This requires taking
+a mutex, so these devices cannot be marked as IRQ safe.
+
+Add PINCTRL as dependency to avoid build errors.
+
+Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
+Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/Kconfig | 2 ++
+ drivers/i2c/busses/i2c-tegra.c | 5 ++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index fd81e49638aaa..4515ded4338c5 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -1218,6 +1218,8 @@ config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
+ # COMPILE_TEST needs architectures with readsX()/writesX() primitives
++ depends on PINCTRL
++ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
+index e533460bccc39..a9aed411e3190 100644
+--- a/drivers/i2c/busses/i2c-tegra.c
++++ b/drivers/i2c/busses/i2c-tegra.c
+@@ -1837,8 +1837,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
+ *
+ * VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
+ * be used for atomic transfers. ACPI device is not IRQ safe also.
++ *
++ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
++ * state transitions during runtime PM require mutexes.
+ */
+- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
++ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
+ pm_runtime_irq_safe(i2c_dev->dev);
+
+ pm_runtime_enable(i2c_dev->dev);
+--
+2.53.0
+
--- /dev/null
+From 0ee4fa9489353a3c00d65ca59fc2e2939393cf4f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index c1f39735a2367..9e2449db0bdf2 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From 69eccb5422cef5d6dd2747567e3874a3930485ef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 33ebe93d80e3c..8933fa4c3dd50 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -762,6 +762,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -923,9 +924,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -968,12 +973,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From e0845ae1d79e493f5cd1fcb88b6ece1344237f46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index 54ad4c7578679..aa39aabe4417e 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -675,6 +675,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From 0979558e3e9c11b564e8417cd7ccbacfb86dadb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 4a745566b760d..2d4c3d9c1a2a5 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3621,12 +3621,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 3b6abe5493645bcba11ca1d1045c724446a3639b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Jan 2026 20:24:24 +0100
+Subject: mptcp: add eat_recv_skb helper
+
+From: Geliang Tang <tanggeliang@kylinos.cn>
+
+[ Upstream commit 436510df0cafb1bc36f12e92e0e76599be28d8f4 ]
+
+This patch extracts the free skb related code in __mptcp_recvmsg_mskq()
+into a new helper mptcp_eat_recv_skb().
+
+This new helper will be used in the next patch.
+
+Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260130-net-next-mptcp-splice-v2-1-31332ba70d7f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index 8f18509204b67..c14e5a1f13336 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -1963,6 +1963,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+
+ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);
+
++static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
++{
++ /* avoid the indirect call, we know the destructor is sock_rfree */
++ skb->destructor = NULL;
++ skb->sk = NULL;
++ atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
++ sk_mem_uncharge(sk, skb->truesize);
++ __skb_unlink(skb, &sk->sk_receive_queue);
++ skb_attempt_defer_free(skb);
++}
++
+ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ size_t len, int flags, int copied_total,
+ struct scm_timestamping_internal *tss,
+@@ -2017,13 +2028,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ break;
+ }
+
+- /* avoid the indirect call, we know the destructor is sock_rfree */
+- skb->destructor = NULL;
+- skb->sk = NULL;
+- atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
+- sk_mem_uncharge(sk, skb->truesize);
+- __skb_unlink(skb, &sk->sk_receive_queue);
+- skb_attempt_defer_free(skb);
++ mptcp_eat_recv_skb(sk, skb);
+ }
+
+ if (copied >= len)
+--
+2.53.0
+
--- /dev/null
+From d42d2ff8921af350608ed1ee4a4008770ad7d223 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 20:03:35 +0800
+Subject: mptcp: fix soft lockup in mptcp_recvmsg()
+
+From: Li Xiasong <lixiasong1@huawei.com>
+
+[ Upstream commit 5dd8025a49c268ab6b94d978532af3ad341132a7 ]
+
+syzbot reported a soft lockup in mptcp_recvmsg() [0].
+
+When receiving data with MSG_PEEK | MSG_WAITALL flags, the skb is not
+removed from the sk_receive_queue. This causes sk_wait_data() to always
+find available data and never perform actual waiting, leading to a soft
+lockup.
+
+Fix this by adding a 'last' parameter to track the last peeked skb.
+This allows sk_wait_data() to make informed waiting decisions and prevent
+infinite loops when MSG_PEEK is used.
+
+[0]:
+watchdog: BUG: soft lockup - CPU#2 stuck for 156s! [server:1963]
+Modules linked in:
+CPU: 2 UID: 0 PID: 1963 Comm: server Not tainted 6.19.0-rc8 #61 PREEMPT(none)
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
+RIP: 0010:sk_wait_data+0x15/0x190
+Code: 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 41 56 41 55 41 54 49 89 f4 55 48 89 d5 53 48 89 fb <48> 83 ec 30 65 48 8b 05 17 a4 6b 01 48 89 44 24 28 31 c0 65 48 8b
+RSP: 0018:ffffc90000603ca0 EFLAGS: 00000246
+RAX: 0000000000000000 RBX: ffff888102bf0800 RCX: 0000000000000001
+RDX: 0000000000000000 RSI: ffffc90000603d18 RDI: ffff888102bf0800
+RBP: 0000000000000000 R08: 0000000000000002 R09: 0000000000000101
+R10: 0000000000000000 R11: 0000000000000075 R12: ffffc90000603d18
+R13: ffff888102bf0800 R14: ffff888102bf0800 R15: 0000000000000000
+FS: 00007f6e38b8c4c0(0000) GS:ffff8881b877e000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 000055aa7bff1680 CR3: 0000000105cbe000 CR4: 00000000000006f0
+Call Trace:
+ <TASK>
+ mptcp_recvmsg+0x547/0x8c0 net/mptcp/protocol.c:2329
+ inet_recvmsg+0x11f/0x130 net/ipv4/af_inet.c:891
+ sock_recvmsg+0x94/0xc0 net/socket.c:1100
+ __sys_recvfrom+0xb2/0x130 net/socket.c:2256
+ __x64_sys_recvfrom+0x1f/0x30 net/socket.c:2267
+ do_syscall_64+0x59/0x2d0 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e arch/x86/entry/entry_64.S:131
+RIP: 0033:0x7f6e386a4a1d
+Code: 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8d 05 f1 de 2c 00 41 89 ca 8b 00 85 c0 75 20 45 31 c9 45 31 c0 b8 2d 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 6b f3 c3 66 0f 1f 84 00 00 00 00 00 41 56 41
+RSP: 002b:00007ffc3c4bb078 EFLAGS: 00000246 ORIG_RAX: 000000000000002d
+RAX: ffffffffffffffda RBX: 000000000000861e RCX: 00007f6e386a4a1d
+RDX: 00000000000003ff RSI: 00007ffc3c4bb150 RDI: 0000000000000004
+RBP: 00007ffc3c4bb570 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000103 R11: 0000000000000246 R12: 00005605dbc00be0
+R13: 00007ffc3c4bb650 R14: 0000000000000000 R15: 0000000000000000
+ </TASK>
+
+Fixes: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
+Signed-off-by: Li Xiasong <lixiasong1@huawei.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260330120335.659027-1-lixiasong1@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index c14e5a1f13336..7b92da6e49d6c 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -1977,7 +1977,7 @@ static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
+ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ size_t len, int flags, int copied_total,
+ struct scm_timestamping_internal *tss,
+- int *cmsg_flags)
++ int *cmsg_flags, struct sk_buff **last)
+ {
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ struct sk_buff *skb, *tmp;
+@@ -1994,6 +1994,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ /* skip already peeked skbs */
+ if (total_data_len + data_len <= copied_total) {
+ total_data_len += data_len;
++ *last = skb;
+ continue;
+ }
+
+@@ -2029,6 +2030,8 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ }
+
+ mptcp_eat_recv_skb(sk, skb);
++ } else {
++ *last = skb;
+ }
+
+ if (copied >= len)
+@@ -2223,10 +2226,12 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
+ cmsg_flags = MPTCP_CMSG_INQ;
+
+ while (copied < len) {
++ struct sk_buff *last = NULL;
+ int err, bytes_read;
+
+ bytes_read = __mptcp_recvmsg_mskq(sk, msg, len - copied, flags,
+- copied, &tss, &cmsg_flags);
++ copied, &tss, &cmsg_flags,
++ &last);
+ if (unlikely(bytes_read < 0)) {
+ if (!copied)
+ copied = bytes_read;
+@@ -2278,7 +2283,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
+
+ pr_debug("block timeout %ld\n", timeo);
+ mptcp_cleanup_rbuf(msk, copied);
+- err = sk_wait_data(sk, &timeo, NULL);
++ err = sk_wait_data(sk, &timeo, last);
+ if (err < 0) {
+ err = copied ? : err;
+ goto out_err;
+--
+2.53.0
+
--- /dev/null
+From 638fabf79b557c52d8e38dd68f27089758d445e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:48:21 +0100
+Subject: net: airoha: Add missing cleanup bits in
+ airoha_qdma_cleanup_rx_queue()
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit 514aac3599879a7ed48b7dc19e31145beb6958ac ]
+
+In order to properly cleanup hw rx QDMA queues and bring the device to
+the initial state, reset rx DMA queue head/tail index. Moreover, reset
+queued DMA descriptor fields.
+
+Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
+Tested-by: Madhur Agrawal <Madhur.Agrawal@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260327-airoha_qdma_cleanup_rx_queue-fix-v1-1-369d6ab1511a@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
+index b16b9ae7d3311..4fc6bd282b465 100644
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -806,18 +806,34 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
+
+ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
+ {
+- struct airoha_eth *eth = q->qdma->eth;
++ struct airoha_qdma *qdma = q->qdma;
++ struct airoha_eth *eth = qdma->eth;
++ int qid = q - &qdma->q_rx[0];
+
+ while (q->queued) {
+ struct airoha_queue_entry *e = &q->entry[q->tail];
++ struct airoha_qdma_desc *desc = &q->desc[q->tail];
+ struct page *page = virt_to_head_page(e->buf);
+
+ dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
+ page_pool_get_dma_dir(q->page_pool));
+ page_pool_put_full_page(q->page_pool, page, false);
++ /* Reset DMA descriptor */
++ WRITE_ONCE(desc->ctrl, 0);
++ WRITE_ONCE(desc->addr, 0);
++ WRITE_ONCE(desc->data, 0);
++ WRITE_ONCE(desc->msg0, 0);
++ WRITE_ONCE(desc->msg1, 0);
++ WRITE_ONCE(desc->msg2, 0);
++ WRITE_ONCE(desc->msg3, 0);
++
+ q->tail = (q->tail + 1) % q->ndesc;
+ q->queued--;
+ }
++
++ q->head = q->tail;
++ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
++ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
+ }
+
+ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
+--
+2.53.0
+
--- /dev/null
+From 5303719b1bdbbffd5b11b6646105a543a2506cfa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:55:53 -0700
+Subject: net: bonding: fix use-after-free in bond_xmit_broadcast()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 2884bf72fb8f03409e423397319205de48adca16 ]
+
+bond_xmit_broadcast() reuses the original skb for the last slave
+(determined by bond_is_last_slave()) and clones it for others.
+Concurrent slave enslave/release can mutate the slave list during
+RCU-protected iteration, changing which slave is "last" mid-loop.
+This causes the original skb to be double-consumed (double-freed).
+
+Replace the racy bond_is_last_slave() check with a simple index
+comparison (i + 1 == slaves_count) against the pre-snapshot slave
+count taken via READ_ONCE() before the loop. This preserves the
+zero-copy optimization for the last slave while making the "last"
+determination stable against concurrent list mutations.
+
+The UAF can trigger the following crash:
+
+==================================================================
+BUG: KASAN: slab-use-after-free in skb_clone
+Read of size 8 at addr ffff888100ef8d40 by task exploit/147
+
+CPU: 1 UID: 0 PID: 147 Comm: exploit Not tainted 7.0.0-rc3+ #4 PREEMPTLAZY
+Call Trace:
+ <TASK>
+ dump_stack_lvl (lib/dump_stack.c:123)
+ print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
+ kasan_report (mm/kasan/report.c:597)
+ skb_clone (include/linux/skbuff.h:1724 include/linux/skbuff.h:1792 include/linux/skbuff.h:3396 net/core/skbuff.c:2108)
+ bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5334)
+ bond_start_xmit (drivers/net/bonding/bond_main.c:5567 drivers/net/bonding/bond_main.c:5593)
+ dev_hard_start_xmit (include/linux/netdevice.h:5325 include/linux/netdevice.h:5334 net/core/dev.c:3871 net/core/dev.c:3887)
+ __dev_queue_xmit (include/linux/netdevice.h:3601 net/core/dev.c:4838)
+ ip6_finish_output2 (include/net/neighbour.h:540 include/net/neighbour.h:554 net/ipv6/ip6_output.c:136)
+ ip6_finish_output (net/ipv6/ip6_output.c:208 net/ipv6/ip6_output.c:219)
+ ip6_output (net/ipv6/ip6_output.c:250)
+ ip6_send_skb (net/ipv6/ip6_output.c:1985)
+ udp_v6_send_skb (net/ipv6/udp.c:1442)
+ udpv6_sendmsg (net/ipv6/udp.c:1733)
+ __sys_sendto (net/socket.c:730 net/socket.c:742 net/socket.c:2206)
+ __x64_sys_sendto (net/socket.c:2209)
+ 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:130)
+ </TASK>
+
+Allocated by task 147:
+
+Freed by task 147:
+
+The buggy address belongs to the object at ffff888100ef8c80
+ which belongs to the cache skbuff_head_cache of size 224
+The buggy address is located 192 bytes inside of
+ freed 224-byte region [ffff888100ef8c80, ffff888100ef8d60)
+
+Memory state around the buggy address:
+ ffff888100ef8c00: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff888100ef8c80: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+>ffff888100ef8d00: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
+ ^
+ ffff888100ef8d80: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
+ ffff888100ef8e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+==================================================================
+
+Fixes: 4e5bd03ae346 ("net: bonding: fix bond_xmit_broadcast return value error bug")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 106cfe732a15e..1d84e348f2cc7 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -5300,7 +5300,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb,
+ if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
+ continue;
+
+- if (bond_is_last_slave(bond, slave)) {
++ if (i + 1 == slaves_count) {
+ skb2 = skb;
+ skb_used = true;
+ } else {
+--
+2.53.0
+
--- /dev/null
+From 04410039349298b8b10b294465809aefc0ec660e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:52:32 +0800
+Subject: net: enetc: check whether the RSS algorithm is Toeplitz
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit d389954a6cae7bf76b7b082ac3511d177b77ef2d ]
+
+Both ENETC v1 and v4 only provide Toeplitz RSS support. This patch adds
+a validation check to reject attempts to configure other RSS algorithms,
+avoiding misleading configuration options for users.
+
+Fixes: d382563f541b ("enetc: Add RFS and RSS support")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Link: https://patch.msgid.link/20260326075233.3628047-2-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+index 0250ed95e48ca..8349d38dbd896 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -770,6 +770,10 @@ static int enetc_set_rxfh(struct net_device *ndev,
+ struct enetc_si *si = priv->si;
+ int err = 0;
+
++ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
++ rxfh->hfunc != ETH_RSS_HASH_TOP)
++ return -EOPNOTSUPP;
++
+ /* set hash key, if PF */
+ if (rxfh->key && enetc_si_is_pf(si))
+ enetc_set_rss_key(si, rxfh->key);
+--
+2.53.0
+
--- /dev/null
+From 81318b8c362b08ec8e7fa763dcbe70a5ea1470f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:52:33 +0800
+Subject: net: enetc: do not allow VF to configure the RSS key
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit a142d139168cce8d5776245b5494c7f7f5d7fb7d ]
+
+VFs do not have privilege to configure the RSS key because the registers
+are owned by the PF. Currently, if VF attempts to configure the RSS key,
+enetc_set_rxfh() simply skips the configuration and does not generate a
+warning, which may mislead users into thinking the feature is supported.
+To improve this situation, add a check to reject RSS key configuration
+on VFs.
+
+Fixes: d382563f541b ("enetc: Add RFS and RSS support")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Link: https://patch.msgid.link/20260326075233.3628047-3-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+index 8349d38dbd896..5166f16f196ff 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -775,8 +775,12 @@ static int enetc_set_rxfh(struct net_device *ndev,
+ return -EOPNOTSUPP;
+
+ /* set hash key, if PF */
+- if (rxfh->key && enetc_si_is_pf(si))
++ if (rxfh->key) {
++ if (!enetc_si_is_pf(si))
++ return -EOPNOTSUPP;
++
+ enetc_set_rss_key(si, rxfh->key);
++ }
+
+ /* set RSS table */
+ if (rxfh->indir)
+--
+2.53.0
+
--- /dev/null
+From 65e4c4c237affaa5638235ed2de676fa3682382d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:21:19 +0800
+Subject: net: enetc: reset PIR and CIR if they are not equal when initializing
+ TX ring
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit 0239fd701d33475a39428daa3dc627407cd417a6 ]
+
+Currently the driver does not reset the producer index register (PIR) and
+consumer index register (CIR) when initializing a TX BD ring. The driver
+only reads the PIR and CIR and initializes the software indexes. If the
+TX BD ring is reinitialized when it still contains unsent frames, its PIR
+and CIR will not be equal after the reinitialization. However, the BDs
+between CIR and PIR have been freed and become invalid and this can lead
+to a hardware malfunction, causing the TX BD ring will not work properly.
+
+For ENETC v4, it supports software to set the PIR and CIR, so the driver
+can reset these two registers if they are not equal when reinitializing
+the TX BD ring. Therefore, add this solution for ENETC v4. Note that this
+patch does not work for ENETC v1 because it does not support software to
+set the PIR and CIR.
+
+Fixes: 99100d0d9922 ("net: enetc: add preliminary support for i.MX95 ENETC PF")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324062121.2745033-2-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
+index d97a76718dd89..b5dd49337513d 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -2570,6 +2570,7 @@ EXPORT_SYMBOL_GPL(enetc_free_si_resources);
+
+ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
+ {
++ struct enetc_si *si = container_of(hw, struct enetc_si, hw);
+ int idx = tx_ring->index;
+ u32 tbmr;
+
+@@ -2583,10 +2584,20 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
+ enetc_txbdr_wr(hw, idx, ENETC_TBLENR,
+ ENETC_RTBLENR_LEN(tx_ring->bd_count));
+
+- /* clearing PI/CI registers for Tx not supported, adjust sw indexes */
++ /* For ENETC v1, clearing PI/CI registers for Tx not supported,
++ * adjust sw indexes
++ */
+ tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR);
+ tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR);
+
++ if (tx_ring->next_to_use != tx_ring->next_to_clean &&
++ !is_enetc_rev1(si)) {
++ tx_ring->next_to_use = 0;
++ tx_ring->next_to_clean = 0;
++ enetc_txbdr_wr(hw, idx, ENETC_TBPIR, 0);
++ enetc_txbdr_wr(hw, idx, ENETC_TBCIR, 0);
++ }
++
+ /* enable Tx ints by setting pkt thr to 1 */
+ enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1);
+
+--
+2.53.0
+
--- /dev/null
+From 92055f4506f3ae782b58ce8b46d6f1a0c28ec8fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:32:30 +0100
+Subject: net: fec: fix the PTP periodic output sysfs interface
+
+From: Buday Csaba <buday.csaba@prolan.hu>
+
+[ Upstream commit e8e44c98f789dee45cfd24ffb9d4936e0606d7c6 ]
+
+When the PPS channel configuration was implemented, the channel
+index for the periodic outputs was configured as the hardware
+channel number.
+
+The sysfs interface uses a logical channel index, and rejects numbers
+greater than `n_per_out` (see period_store() in ptp_sysfs.c).
+That property was left at 1, since the driver implements channel
+selection, not simultaneous operation of multiple PTP hardware timer
+channels.
+
+A second check in fec_ptp_enable() returns -EOPNOTSUPP when the two
+channel numbers disagree, making channels 1..3 unusable from sysfs.
+
+Fix by removing this redundant check in the FEC PTP driver.
+
+Fixes: 566c2d83887f ("net: fec: make PPS channel configurable")
+Signed-off-by: Buday Csaba <buday.csaba@prolan.hu>
+Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/fec_ptp.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
+index 4b7bad9a485df..56801c2009d59 100644
+--- a/drivers/net/ethernet/freescale/fec_ptp.c
++++ b/drivers/net/ethernet/freescale/fec_ptp.c
+@@ -545,9 +545,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
+ if (rq->perout.flags)
+ return -EOPNOTSUPP;
+
+- if (rq->perout.index != fep->pps_channel)
+- return -EOPNOTSUPP;
+-
+ period.tv_sec = rq->perout.period.sec;
+ period.tv_nsec = rq->perout.period.nsec;
+ period_ns = timespec64_to_ns(&period);
+--
+2.53.0
+
--- /dev/null
+From a3142164d0e89ef02f777600ebd178edffb76c8a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 11:22:43 +0200
+Subject: net: hsr: fix VLAN add unwind on slave errors
+
+From: Luka Gejak <luka.gejak@linux.dev>
+
+[ Upstream commit 2e3514e63bfb0e972b1f19668547a455d0129e88 ]
+
+When vlan_vid_add() fails for a secondary slave, the error path calls
+vlan_vid_del() on the failing port instead of the peer slave that had
+already succeeded. This results in asymmetric VLAN state across the HSR
+pair.
+
+Fix this by switching to a centralized unwind path that removes the VID
+from any slave device that was already programmed.
+
+Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
+Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
+Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index d1bfc49b5f017..fd2fea25eff0d 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -532,8 +532,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+ {
+- bool is_slave_a_added = false;
+- bool is_slave_b_added = false;
++ struct net_device *slave_a_dev = NULL;
++ struct net_device *slave_b_dev = NULL;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+@@ -549,33 +549,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+- /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+- if (is_slave_b_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_a_added = true;
++ slave_a_dev = port->dev;
+ break;
+-
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+- /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+- if (is_slave_a_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_b_added = true;
++ slave_b_dev = port->dev;
+ break;
+ default:
++ if (ret)
++ goto unwind;
+ break;
+ }
+ }
+
+ return 0;
++
++unwind:
++ if (slave_a_dev)
++ vlan_vid_del(slave_a_dev, proto, vid);
++
++ if (slave_b_dev)
++ vlan_vid_del(slave_b_dev, proto, vid);
++
++ return ret;
+ }
+
+ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+--
+2.53.0
+
--- /dev/null
+From d3443dcf37847ace14832d7e237ee5fd75e22436 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Jan 2026 17:11:27 +0100
+Subject: net: introduce mangleid_features
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit 31c5a71d982b57df75858974634c2f0a338f2fc6 ]
+
+Some/most devices implementing gso_partial need to disable the GSO partial
+features when the IP ID can't be mangled; to that extend each of them
+implements something alike the following[1]:
+
+ if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID))
+ features &= ~NETIF_F_TSO;
+
+in the ndo_features_check() op, which leads to a bit of duplicate code.
+
+Later patch in the series will implement GSO partial support for virtual
+devices, and the current status quo will require more duplicate code and
+a new indirect call in the TX path for them.
+
+Introduce the mangleid_features mask, allowing the core to disable NIC
+features based on/requiring MANGLEID, without any further intervention
+from the driver.
+
+The same functionality could be alternatively implemented adding a single
+boolean flag to the struct net_device, but would require an additional
+checks in ndo_features_check().
+
+Also note that [1] is incorrect if the NIC additionally implements
+NETIF_F_GSO_UDP_L4, mangleid_features transparently handle even such a
+case.
+
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/5a7cdaeea40b0a29b88e525b6c942d73ed3b8ce7.1769011015.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: ddc748a391dd ("net: use skb_header_pointer() for TCPv4 GSO frag_off check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netdevice.h | 3 +++
+ net/core/dev.c | 5 ++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 20bd42fa160c9..fc55157a44860 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1817,6 +1817,8 @@ enum netdev_reg_state {
+ *
+ * @mpls_features: Mask of features inheritable by MPLS
+ * @gso_partial_features: value(s) from NETIF_F_GSO\*
++ * @mangleid_features: Mask of features requiring MANGLEID, will be
++ * disabled together with the latter.
+ *
+ * @ifindex: interface index
+ * @group: The group the device belongs to
+@@ -2205,6 +2207,7 @@ struct net_device {
+ netdev_features_t vlan_features;
+ netdev_features_t hw_enc_features;
+ netdev_features_t mpls_features;
++ netdev_features_t mangleid_features;
+
+ unsigned int min_mtu;
+ unsigned int max_mtu;
+diff --git a/net/core/dev.c b/net/core/dev.c
+index c8e49eef45198..90b029c311a14 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3795,7 +3795,7 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
+ inner_ip_hdr(skb) : ip_hdr(skb);
+
+ if (!(iph->frag_off & htons(IP_DF)))
+- features &= ~NETIF_F_TSO_MANGLEID;
++ features &= ~dev->mangleid_features;
+ }
+
+ /* NETIF_F_IPV6_CSUM does not support IPv6 extension headers,
+@@ -11295,6 +11295,9 @@ int register_netdevice(struct net_device *dev)
+ if (dev->hw_enc_features & NETIF_F_TSO)
+ dev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
+
++ /* TSO_MANGLEID belongs in mangleid_features by definition */
++ dev->mangleid_features |= NETIF_F_TSO_MANGLEID;
++
+ /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
+ */
+ dev->vlan_features |= NETIF_F_HIGHDMA;
+--
+2.53.0
+
--- /dev/null
+From fe180e3bbe83f9da8c06b2bcd05b74bcbcbb9abc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index 60d0be47a9f31..8aa29b3d3daca 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From dd656a1ec1b48c55912c80c39f98fab441b1eb92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 15:41:52 +0800
+Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 5e67ba9bb531e1ec6599a82a065dea9040b9ce50 ]
+
+ioam6_fill_trace_data() stores the schema contribution to the trace
+length in a u8. With bit 22 enabled and the largest schema payload,
+sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
+remaining-space check. __ioam6_fill_trace_data() then positions the
+write cursor without reserving the schema area but still copies the
+4-byte schema header and the full schema payload, overrunning the trace
+buffer.
+
+Keep sclen in an unsigned int so the remaining-space check and the write
+cursor calculation both see the full schema length.
+
+Fixes: 8c6f6fa67726 ("ipv6: ioam: IOAM Generic Netlink API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ioam6.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
+index 08b7ac8c99b7e..8db7f965696aa 100644
+--- a/net/ipv6/ioam6.c
++++ b/net/ipv6/ioam6.c
+@@ -708,7 +708,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
+ struct ioam6_namespace *ns,
+ struct ioam6_trace_hdr *trace,
+ struct ioam6_schema *sc,
+- u8 sclen, bool is_input)
++ unsigned int sclen, bool is_input)
+ {
+ struct net_device *dev = skb_dst_dev(skb);
+ struct timespec64 ts;
+@@ -939,7 +939,7 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
+ bool is_input)
+ {
+ struct ioam6_schema *sc;
+- u8 sclen = 0;
++ unsigned int sclen = 0;
+
+ /* Skip if Overflow flag is set
+ */
+--
+2.53.0
+
--- /dev/null
+From c1eb919aedc991e296aed1e4d9b83d9667aad951 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 0fd3f53dbb52e..ded2d3a0660c3 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1209,6 +1209,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From fd67a7a525580d04500de9534312389af204f45e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index fc4f5aee6ab3f..0ce5b736ea438 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -109,10 +109,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From bbb259514ca8884e79a1fda42325365f3f932750 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 0ce5b736ea438..b79dec17e6b09 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -96,10 +96,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -113,8 +113,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 6a5bf5651353b07eda56b229bbd7e87a09af0354 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:14:28 -0700
+Subject: net: mana: Fix RX skb truesize accounting
+
+From: Dipayaan Roy <dipayanroy@linux.microsoft.com>
+
+[ Upstream commit f73896b4197ed53cf0894657c899265ef7c86b7a ]
+
+MANA passes rxq->alloc_size to napi_build_skb() for all RX buffers.
+It is correct for fragment-backed RX buffers, where alloc_size matches
+the actual backing allocation used for each packet buffer. However, in
+the non-fragment RX path mana allocates a full page, or a higher-order
+page, per RX buffer. In that case alloc_size only reflects the usable
+packet area and not the actual backing memory.
+
+This causes napi_build_skb() to underestimate the skb backing allocation
+in the single-buffer RX path, so skb->truesize is derived from a value
+smaller than the real RX buffer allocation.
+
+Fix this by updating alloc_size in the non-fragment RX path to the
+actual backing allocation size before it is passed to napi_build_skb().
+
+Fixes: 730ff06d3f5c ("net: mana: Use page pool fragments for RX buffers instead of full pages to improve memory efficiency.")
+Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
+Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
+Link: https://patch.msgid.link/acLUhLpLum6qrD/N@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/microsoft/mana/mana_en.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
+index 50d4437a518fd..8e72cb6ccbc18 100644
+--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
+@@ -660,6 +660,13 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
+ }
+
+ *frag_count = 1;
++
++ /* In the single-buffer path, napi_build_skb() must see the
++ * actual backing allocation size so skb->truesize reflects
++ * the full page (or higher-order page), not just the usable
++ * packet area.
++ */
++ *alloc_size = PAGE_SIZE << get_order(*alloc_size);
+ return;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 8ad5166861ab77632fbf935c023ba992c759b8cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index ea77fbd98396a..055ee020c56f4 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -107,9 +107,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index eeb4437975f20..c1f220e5fe185 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -822,48 +822,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index da5345e19082d..09c544bdf70da 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -391,8 +391,8 @@ int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ #ifdef CONFIG_MLX5_CORE_EN
+ int mlx5e_init(void);
+--
+2.53.0
+
--- /dev/null
+From 311e29c0c1d7b7cce8ea76ff71842087e1941c49 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:15 +0300
+Subject: net/mlx5: Fix switchdev mode rollback in case of failure
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 403186400a1a6166efe7031edc549c15fee4723f ]
+
+If for some internal reason switchdev mode fails, we rollback to legacy
+mode, before this patch, rollback will unregister the uplink netdev and
+leave it unregistered causing the below kernel bug.
+
+To fix this, we need to avoid netdev unregister by setting the proper
+rollback flag 'MLX5_PRIV_FLAGS_SWITCH_LEGACY' to indicate legacy mode.
+
+devlink (431) used greatest stack depth: 11048 bytes left
+mlx5_core 0000:00:03.0: E-Switch: Disable: mode(LEGACY), nvfs(0), \
+ necvfs(0), active vports(0)
+mlx5_core 0000:00:03.0: E-Switch: Supported tc chains and prios offload
+mlx5_core 0000:00:03.0: Loading uplink representor for vport 65535
+mlx5_core 0000:00:03.0: mlx5_cmd_out_err:816:(pid 456): \
+ QUERY_HCA_CAP(0x100) op_mod(0x0) failed, \
+ status bad parameter(0x3), syndrome (0x3a3846), err(-22)
+mlx5_core 0000:00:03.0 enp0s3np0 (unregistered): Unloading uplink \
+ representor for vport 65535
+ ------------[ cut here ]------------
+kernel BUG at net/core/dev.c:12070!
+Oops: invalid opcode: 0000 [#1] SMP NOPTI
+CPU: 2 UID: 0 PID: 456 Comm: devlink Not tainted 6.16.0-rc3+ \
+ #9 PREEMPT(voluntary)
+RIP: 0010:unregister_netdevice_many_notify+0x123/0xae0
+...
+Call Trace:
+[ 90.923094] unregister_netdevice_queue+0xad/0xf0
+[ 90.923323] unregister_netdev+0x1c/0x40
+[ 90.923522] mlx5e_vport_rep_unload+0x61/0xc6
+[ 90.923736] esw_offloads_enable+0x8e6/0x920
+[ 90.923947] mlx5_eswitch_enable_locked+0x349/0x430
+[ 90.924182] ? is_mp_supported+0x57/0xb0
+[ 90.924376] mlx5_devlink_eswitch_mode_set+0x167/0x350
+[ 90.924628] devlink_nl_eswitch_set_doit+0x6f/0xf0
+[ 90.924862] genl_family_rcv_msg_doit+0xe8/0x140
+[ 90.925088] genl_rcv_msg+0x18b/0x290
+[ 90.925269] ? __pfx_devlink_nl_pre_doit+0x10/0x10
+[ 90.925506] ? __pfx_devlink_nl_eswitch_set_doit+0x10/0x10
+[ 90.925766] ? __pfx_devlink_nl_post_doit+0x10/0x10
+[ 90.926001] ? __pfx_genl_rcv_msg+0x10/0x10
+[ 90.926206] netlink_rcv_skb+0x52/0x100
+[ 90.926393] genl_rcv+0x28/0x40
+[ 90.926557] netlink_unicast+0x27d/0x3d0
+[ 90.926749] netlink_sendmsg+0x1f7/0x430
+[ 90.926942] __sys_sendto+0x213/0x220
+[ 90.927127] ? __sys_recvmsg+0x6a/0xd0
+[ 90.927312] __x64_sys_sendto+0x24/0x30
+[ 90.927504] do_syscall_64+0x50/0x1c0
+[ 90.927687] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+[ 90.927929] RIP: 0033:0x7f7d0363e047
+
+Fixes: 2a4f56fbcc47 ("net/mlx5e: Keep netdev when leave switchdev for devlink set legacy only")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Jianbo Liu <jianbol@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-4-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+index f1585df13b732..8be0961cb6c7e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+@@ -3623,6 +3623,8 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
+ return 0;
+
+ err_vports:
++ /* rollback to legacy, indicates don't unregister the uplink netdev */
++ esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY;
+ mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK);
+ err_uplink:
+ esw_offloads_steering_cleanup(esw);
+--
+2.53.0
+
--- /dev/null
+From 27f47ae3817826582feac09917f3e76c85406286 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:13 +0300
+Subject: net/mlx5: lag: Check for LAG device before creating debugfs
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit bf16bca6653679d8a514d6c1c5a2c67065033f14 ]
+
+__mlx5_lag_dev_add_mdev() may return 0 (success) even when an error
+occurs that is handled gracefully. Consequently, the initialization
+flow proceeds to call mlx5_ldev_add_debugfs() even when there is no
+valid LAG context.
+
+mlx5_ldev_add_debugfs() blindly created the debugfs directory and
+attributes. This exposed interfaces (like the members file) that rely on
+a valid ldev pointer, leading to potential NULL pointer dereferences if
+accessed when ldev is NULL.
+
+Add a check to verify that mlx5_lag_dev(dev) returns a valid pointer
+before attempting to create the debugfs entries.
+
+Fixes: 7f46a0b7327a ("net/mlx5: Lag, add debugfs to query hardware lag state")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Mark Bloch <mbloch@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+index 62b6faa4276aa..b8d5f6a44d26a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+@@ -160,8 +160,11 @@ DEFINE_SHOW_ATTRIBUTE(members);
+
+ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
+ {
++ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+ struct dentry *dbg;
+
++ if (!ldev)
++ return;
+ dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
+ dev->priv.dbg.lag_debugfs = dbg;
+
+--
+2.53.0
+
--- /dev/null
+From f3ba3386ecd6c6f3029bfb9d0aae300760b5ff66 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 00c51cf693f3d..b703e4c645853 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -118,7 +118,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -129,7 +129,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -172,6 +172,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -189,11 +190,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -228,9 +227,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -269,12 +266,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -326,9 +324,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -599,7 +595,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -627,6 +623,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -649,10 +646,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From efc0ad09c6fbaec78571e45e7aaef409f0a5c207 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index bac9cd71ff8e9..b03dc4fe20e52 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2969,6 +2969,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From 2424fdba385f56f7f95869014f192b9398e0243f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 5693b41b093f3..edf1252c1fde7 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -503,8 +503,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From b073a0ba9063e366850470fc987982c5dfeaed12 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index cdddc86952284..83a7372ea15c2 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -247,8 +247,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From 446687164741b051b2b819e2b33ee1b040244d5e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index d8fd35da32a7c..57221522fe56d 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -555,7 +555,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -598,7 +598,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From 94d3eab37e78910917a2172eeea1d0661ad0088a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:00:21 +0800
+Subject: net/sched: sch_netem: fix out-of-bounds access in packet corruption
+
+From: Yucheng Lu <kanolyc@gmail.com>
+
+[ Upstream commit d64cb81dcbd54927515a7f65e5e24affdc73c14b ]
+
+In netem_enqueue(), the packet corruption logic uses
+get_random_u32_below(skb_headlen(skb)) to select an index for
+modifying skb->data. When an AF_PACKET TX_RING sends fully non-linear
+packets over an IPIP tunnel, skb_headlen(skb) evaluates to 0.
+
+Passing 0 to get_random_u32_below() takes the variable-ceil slow path
+which returns an unconstrained 32-bit random integer. Using this
+unconstrained value as an offset into skb->data results in an
+out-of-bounds memory access.
+
+Fix this by verifying skb_headlen(skb) is non-zero before attempting
+to corrupt the linear data area. Fully non-linear packets will silently
+bypass the corruption logic.
+
+Fixes: c865e5d99e25 ("[PKT_SCHED] netem: packet corruption option")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yuhang Zheng <z1652074432@gmail.com>
+Signed-off-by: Yucheng Lu <kanolyc@gmail.com>
+Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
+Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_netem.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
+index eafc316ae319e..6f8fcc4b504ce 100644
+--- a/net/sched/sch_netem.c
++++ b/net/sched/sch_netem.c
+@@ -518,8 +518,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+ goto finish_segs;
+ }
+
+- skb->data[get_random_u32_below(skb_headlen(skb))] ^=
+- 1<<get_random_u32_below(8);
++ if (skb_headlen(skb))
++ skb->data[get_random_u32_below(skb_headlen(skb))] ^=
++ 1 << get_random_u32_below(8);
+ }
+
+ if (unlikely(q->t_len >= sch->limit)) {
+--
+2.53.0
+
--- /dev/null
+From 5a72331222a3d1a71abaa375c44734457523c594 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:20:38 +0100
+Subject: net: sfp: Fix Ubiquiti U-Fiber Instant SFP module on mvneta
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marek Behún <kabel@kernel.org>
+
+[ Upstream commit eeee5a710f26ce57807024ef330fe5a850eaecd8 ]
+
+In commit 8110633db49d7de2 ("net: sfp-bus: allow SFP quirks to override
+Autoneg and pause bits") we moved the setting of Autoneg and pause bits
+before the call to SFP quirk when parsing SFP module support.
+
+Since the quirk for Ubiquiti U-Fiber Instant SFP module zeroes the
+support bits and sets 1000baseX_Full only, the above mentioned commit
+changed the overall computed support from
+ 1000baseX_Full, Autoneg, Pause, Asym_Pause
+to just
+ 1000baseX_Full.
+
+This broke the SFP module for mvneta, which requires Autoneg for
+1000baseX since commit c762b7fac1b249a9 ("net: mvneta: deny disabling
+autoneg for 802.3z modes").
+
+Fix this by setting back the Autoneg, Pause and Asym_Pause bits in the
+quirk.
+
+Fixes: 8110633db49d7de2 ("net: sfp-bus: allow SFP quirks to override Autoneg and pause bits")
+Signed-off-by: Marek Behún <kabel@kernel.org>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/20260326122038.2489589-1-kabel@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/sfp.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
+index ca09925335725..7a85b758fb1e6 100644
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -480,11 +480,16 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
+ {
+ /* Ubiquiti U-Fiber Instant module claims that support all transceiver
+ * types including 10G Ethernet which is not truth. So clear all claimed
+- * modes and set only one mode which module supports: 1000baseX_Full.
++ * modes and set only one mode which module supports: 1000baseX_Full,
++ * along with the Autoneg and pause bits.
+ */
+ linkmode_zero(caps->link_modes);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+ caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, caps->link_modes);
++
+ phy_interface_zero(caps->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, caps->interfaces);
+ }
+--
+2.53.0
+
--- /dev/null
+From 522ca63ab79c9566e1cfad4e82f9189494084b8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 09:55:51 +0100
+Subject: net: stmmac: skip VLAN restore when VLAN hash ops are missing
+
+From: Michal Piekos <michal.piekos@mmpsystems.pl>
+
+[ Upstream commit 48b3cd69265f346f64b93064723492da46206e9b ]
+
+stmmac_vlan_restore() unconditionally calls stmmac_vlan_update() when
+NETIF_F_VLAN_FEATURES is set. On platforms where priv->hw->vlan (or
+->update_vlan_hash) is not provided, stmmac_update_vlan_hash() returns
+-EINVAL via stmmac_do_void_callback(), resulting in a spurious
+"Failed to restore VLANs" error even when no VLAN filtering is in use.
+
+Remove not needed comment.
+Remove not used return value from stmmac_vlan_restore().
+
+Tested on Orange Pi Zero 3.
+
+Fixes: bd7ad51253a7 ("net: stmmac: Fix VLAN HW state restore")
+Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
+Link: https://patch.msgid.link/20260328-vlan-restore-error-v4-1-f88624c530dc@mmpsystems.pl
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index eeeb9f50c265c..f8df0609e0e69 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -139,7 +139,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
+ static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
+ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
+ u32 rxmode, u32 chan);
+-static int stmmac_vlan_restore(struct stmmac_priv *priv);
++static void stmmac_vlan_restore(struct stmmac_priv *priv);
+
+ #ifdef CONFIG_DEBUG_FS
+ static const struct net_device_ops stmmac_netdev_ops;
+@@ -6668,21 +6668,15 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
+ return ret;
+ }
+
+-static int stmmac_vlan_restore(struct stmmac_priv *priv)
++static void stmmac_vlan_restore(struct stmmac_priv *priv)
+ {
+- int ret;
+-
+ if (!(priv->dev->features & NETIF_F_VLAN_FEATURES))
+- return 0;
++ return;
+
+ if (priv->hw->num_vlan)
+ stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw);
+
+- ret = stmmac_vlan_update(priv, priv->num_double_vlans);
+- if (ret)
+- netdev_err(priv->dev, "Failed to restore VLANs\n");
+-
+- return ret;
++ stmmac_vlan_update(priv, priv->num_double_vlans);
+ }
+
+ static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
+--
+2.53.0
+
--- /dev/null
+From 1ad7ddb9bc4bbd475efb5b9f28f5b88735996620 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 23:35:07 +0800
+Subject: net: use skb_header_pointer() for TCPv4 GSO frag_off check
+
+From: Guoyu Su <yss2813483011xxl@gmail.com>
+
+[ Upstream commit ddc748a391dd8642ba6b2e4fe22e7f2ddf84b7f0 ]
+
+Syzbot reported a KMSAN uninit-value warning in gso_features_check()
+called from netif_skb_features() [1].
+
+gso_features_check() reads iph->frag_off to decide whether to clear
+mangleid_features. Accessing the IPv4 header via ip_hdr()/inner_ip_hdr()
+can rely on skb header offsets that are not always safe for direct
+dereference on packets injected from PF_PACKET paths.
+
+Use skb_header_pointer() for the TCPv4 frag_off check so the header read
+is robust whether data is already linear or needs copying.
+
+[1] https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
+
+Link: https://lore.kernel.org/netdev/willemdebruijn.kernel.1a9f35039caab@gmail.com/
+Fixes: cbc53e08a793 ("GSO: Add GSO type for fixed IPv4 ID")
+Reported-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
+Tested-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
+Signed-off-by: Guoyu Su <yss2813483011xxl@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20260327153507.39742-1-yss2813483011xxl@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/dev.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 90b029c311a14..1ef939d935cf6 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3791,10 +3791,15 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
+ * segmentation-offloads.rst).
+ */
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
+- struct iphdr *iph = skb->encapsulation ?
+- inner_ip_hdr(skb) : ip_hdr(skb);
++ const struct iphdr *iph;
++ struct iphdr _iph;
++ int nhoff = skb->encapsulation ?
++ skb_inner_network_offset(skb) :
++ skb_network_offset(skb);
+
+- if (!(iph->frag_off & htons(IP_DF)))
++ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
++
++ if (!iph || !(iph->frag_off & htons(IP_DF)))
+ features &= ~dev->mangleid_features;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 6c2cf4cb9ff2698ce63da42abbe34f7e3deb43c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 0dbc73efab1cb..e47ebd8acd21b 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 3c29576cbb5728005fb91a932bfb21f790b76af9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index b981a4828d08c..0dbc73efab1cb 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From 75c967ddf0f8146cf35bf68cc0e76b5fa307fc67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index 5ff742103beb9..fcd3aaef27fc3 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -105,7 +105,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -130,7 +130,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From 87508d132e469ffd7f10842436133bb58853652f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:38 +0530
+Subject: net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit d1978d03e86785872871bff9c2623174b10740de ]
+
+When a TX packet spans multiple buffer descriptors (scatter-gather),
+axienet_free_tx_chain sums the per-BD actual length from descriptor
+status into a caller-provided accumulator. That sum is reset on each
+NAPI poll. If the BDs for a single packet complete across different
+polls, the earlier bytes are lost and never credited to BQL. This
+causes BQL to think bytes are permanently in-flight, eventually
+stalling the TX queue.
+
+The SKB pointer is stored only on the last BD of a packet. When that
+BD completes, use skb->len for the byte count instead of summing
+per-BD status lengths. This matches netdev_sent_queue(), which debits
+skb->len, and naturally survives across polls because no partial
+packet contributes to the accumulator.
+
+Fixes: c900e49d58eb ("net: xilinx: axienet: Implement BQL")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-3-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+index 284031fb2e2c7..eefe54ce66852 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+@@ -770,8 +770,8 @@ static int axienet_device_reset(struct net_device *ndev)
+ * @first_bd: Index of first descriptor to clean up
+ * @nr_bds: Max number of descriptors to clean up
+ * @force: Whether to clean descriptors even if not complete
+- * @sizep: Pointer to a u32 filled with the total sum of all bytes
+- * in all cleaned-up descriptors. Ignored if NULL.
++ * @sizep: Pointer to a u32 accumulating the total byte count of
++ * completed packets (using skb->len). Ignored if NULL.
+ * @budget: NAPI budget (use 0 when not called from NAPI poll)
+ *
+ * Would either be called after a successful transmit operation, or after
+@@ -805,6 +805,8 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
+ DMA_TO_DEVICE);
+
+ if (cur_p->skb && (status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
++ if (sizep)
++ *sizep += cur_p->skb->len;
+ napi_consume_skb(cur_p->skb, budget);
+ packets++;
+ }
+@@ -818,9 +820,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
+ wmb();
+ cur_p->cntrl = 0;
+ cur_p->status = 0;
+-
+- if (sizep)
+- *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
+ }
+
+ if (!force) {
+--
+2.53.0
+
--- /dev/null
+From 84dac6fea62590abb15f37ed6a00abf49f81ff96 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:08:56 +0800
+Subject: netdevsim: fix build if SKB_EXTENSIONS=n
+
+From: Qingfang Deng <dqfext@gmail.com>
+
+[ Upstream commit 57a04a13aac1f247d171c3f3aef93efc69e6979e ]
+
+__skb_ext_put() is not declared if SKB_EXTENSIONS is not enabled, which
+causes a build error:
+
+drivers/net/netdevsim/netdev.c: In function 'nsim_forward_skb':
+drivers/net/netdevsim/netdev.c:114:25: error: implicit declaration of function '__skb_ext_put'; did you mean 'skb_ext_put'? [-Werror=implicit-function-declaration]
+ 114 | __skb_ext_put(psp_ext);
+ | ^~~~~~~~~~~~~
+ | skb_ext_put
+cc1: some warnings being treated as errors
+
+Add a stub to fix the build.
+
+Fixes: 7d9351435ebb ("netdevsim: drop PSP ext ref on forward failure")
+Signed-off-by: Qingfang Deng <dqfext@gmail.com>
+Link: https://patch.msgid.link/20260324140857.783-1-dqfext@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/skbuff.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 50f127451dc65..def9cca948178 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -5018,6 +5018,7 @@ static inline bool skb_has_extensions(struct sk_buff *skb)
+ return unlikely(skb->active_extensions);
+ }
+ #else
++static inline void __skb_ext_put(struct skb_ext *ext) {}
+ static inline void skb_ext_put(struct sk_buff *skb) {}
+ static inline void skb_ext_reset(struct sk_buff *skb) {}
+ static inline void skb_ext_del(struct sk_buff *skb, int unused) {}
+--
+2.53.0
+
--- /dev/null
+From 34cbc0a4586c70cf4f204c16408678decc49283e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 11:26:22 +0200
+Subject: netfilter: ctnetlink: ignore explicit helper on new expectations
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 917b61fa2042f11e2af4c428e43f08199586633a ]
+
+Use the existing master conntrack helper, anything else is not really
+supported and it just makes validation more complicated, so just ignore
+what helper userspace suggests for this expectation.
+
+This was uncovered when validating CTA_EXPECT_CLASS via different helper
+provided by userspace than the existing master conntrack helper:
+
+ BUG: KASAN: slab-out-of-bounds in nf_ct_expect_related_report+0x2479/0x27c0
+ Read of size 4 at addr ffff8880043fe408 by task poc/102
+ Call Trace:
+ nf_ct_expect_related_report+0x2479/0x27c0
+ ctnetlink_create_expect+0x22b/0x3b0
+ ctnetlink_new_expect+0x4bd/0x5c0
+ nfnetlink_rcv_msg+0x67a/0x950
+ netlink_rcv_skb+0x120/0x350
+
+Allowing to read kernel memory bytes off the expectation boundary.
+
+CTA_EXPECT_HELP_NAME is still used to offer the helper name to userspace
+via netlink dump.
+
+Fixes: bd0779370588 ("netfilter: nfnetlink_queue: allow to attach expectations to conntracks")
+Reported-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 54 +++++-----------------------
+ 1 file changed, 9 insertions(+), 45 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 8c5ae0665eaa4..879413b9fa06a 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2635,7 +2635,6 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask);
+
+@@ -2864,7 +2863,6 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ {
+ struct nlattr *cda[CTA_EXPECT_MAX+1];
+ struct nf_conntrack_tuple tuple, mask;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ int err;
+
+@@ -2878,17 +2876,8 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ if (err < 0)
+ return err;
+
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+- nf_ct_protonum(ct));
+- if (helper == NULL)
+- return -EOPNOTSUPP;
+- }
+-
+ exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
+- helper, &tuple, &mask);
++ &tuple, &mask);
+ if (IS_ERR(exp))
+ return PTR_ERR(exp);
+
+@@ -3517,11 +3506,11 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+ struct net *net = read_pnet(&ct->ct_net);
++ struct nf_conntrack_helper *helper;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3531,7 +3520,11 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ if (!help)
+ return ERR_PTR(-EOPNOTSUPP);
+
+- if (cda[CTA_EXPECT_CLASS] && helper) {
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return ERR_PTR(-EOPNOTSUPP);
++
++ if (cda[CTA_EXPECT_CLASS]) {
+ class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
+ if (class > helper->expect_class_max)
+ return ERR_PTR(-EINVAL);
+@@ -3565,8 +3558,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+ exp->zone = ct->zone;
+ #endif
+- if (!helper)
+- helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+@@ -3598,7 +3589,6 @@ ctnetlink_create_expect(struct net *net,
+ {
+ struct nf_conntrack_tuple tuple, mask, master_tuple;
+ struct nf_conntrack_tuple_hash *h = NULL;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn *ct;
+ int err;
+@@ -3624,33 +3614,7 @@ ctnetlink_create_expect(struct net *net,
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ rcu_read_lock();
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper == NULL) {
+- rcu_read_unlock();
+-#ifdef CONFIG_MODULES
+- if (request_module("nfct-helper-%s", helpname) < 0) {
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- rcu_read_lock();
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper) {
+- err = -EAGAIN;
+- goto err_rcu;
+- }
+- rcu_read_unlock();
+-#endif
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- }
+-
+- exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
++ exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask);
+ if (IS_ERR(exp)) {
+ err = PTR_ERR(exp);
+ goto err_rcu;
+@@ -3660,8 +3624,8 @@ ctnetlink_create_expect(struct net *net,
+ nf_ct_expect_put(exp);
+ err_rcu:
+ rcu_read_unlock();
+-err_ct:
+ nf_ct_put(ct);
++
+ return err;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 0ac061756967f5e17a3387341096d18ce919a301 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 768f741f59afe..82d5abae0ad1f 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3576,6 +3576,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From 4fe622a18cd20ffff03b03c2d80a7a4105678169 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:17:09 +0100
+Subject: netfilter: flowtable: strictly check for maximum number of actions
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 76522fcdbc3a02b568f5d957f7e66fc194abb893 ]
+
+The maximum number of flowtable hardware offload actions in IPv6 is:
+
+* ethernet mangling (4 payload actions, 2 for each ethernet address)
+* SNAT (4 payload actions)
+* DNAT (4 payload actions)
+* Double VLAN (4 vlan actions, 2 for popping vlan, and 2 for pushing)
+ for QinQ.
+* Redirect (1 action)
+
+Which makes 17, while the maximum is 16. But act_ct supports for tunnels
+actions too. Note that payload action operates at 32-bit word level, so
+mangling an IPv6 address takes 4 payload actions.
+
+Update flow_action_entry_next() calls to check for the maximum number of
+supported actions.
+
+While at it, rise the maximum number of actions per flow from 16 to 24
+so this works fine with IPv6 setups.
+
+Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_offload.c | 196 +++++++++++++++++---------
+ 1 file changed, 130 insertions(+), 66 deletions(-)
+
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index e06bc36f49fe7..4f346f51d7d74 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -13,6 +13,8 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
+
++#define NF_FLOW_RULE_ACTION_MAX 24
++
+ static struct workqueue_struct *nf_flow_offload_add_wq;
+ static struct workqueue_struct *nf_flow_offload_del_wq;
+ static struct workqueue_struct *nf_flow_offload_stats_wq;
+@@ -215,7 +217,12 @@ static void flow_offload_mangle(struct flow_action_entry *entry,
+ static inline struct flow_action_entry *
+ flow_action_entry_next(struct nf_flow_rule *flow_rule)
+ {
+- int i = flow_rule->rule->action.num_entries++;
++ int i;
++
++ if (unlikely(flow_rule->rule->action.num_entries >= NF_FLOW_RULE_ACTION_MAX))
++ return NULL;
++
++ i = flow_rule->rule->action.num_entries++;
+
+ return &flow_rule->rule->action.entries[i];
+ }
+@@ -233,6 +240,9 @@ static int flow_offload_eth_src(struct net *net,
+ u32 mask, val;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -283,6 +293,9 @@ static int flow_offload_eth_dst(struct net *net,
+ u8 nud_state;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -324,16 +337,19 @@ static int flow_offload_eth_dst(struct net *net,
+ return 0;
+ }
+
+-static void flow_offload_ipv4_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
+@@ -344,23 +360,27 @@ static void flow_offload_ipv4_snat(struct net *net,
+ offset = offsetof(struct iphdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
+@@ -371,14 +391,15 @@ static void flow_offload_ipv4_dnat(struct net *net,
+ offset = offsetof(struct iphdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
++static int flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+ unsigned int offset,
+ const __be32 *addr, const __be32 *mask)
+ {
+@@ -387,15 +408,20 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+
+ for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i++) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
++
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
+ offset + i * sizeof(u32), &addr[i], mask);
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_ipv6_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -411,16 +437,16 @@ static void flow_offload_ipv6_snat(struct net *net,
+ offset = offsetof(struct ipv6hdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+-static void flow_offload_ipv6_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -436,10 +462,10 @@ static void flow_offload_ipv6_dnat(struct net *net,
+ offset = offsetof(struct ipv6hdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+ static int flow_offload_l4proto(const struct flow_offload *flow)
+@@ -461,15 +487,18 @@ static int flow_offload_l4proto(const struct flow_offload *flow)
+ return type;
+ }
+
+-static void flow_offload_port_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
+@@ -484,22 +513,26 @@ static void flow_offload_port_snat(struct net *net,
+ mask = ~htonl(0xffff);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_port_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port);
+@@ -514,20 +547,24 @@ static void flow_offload_port_dnat(struct net *net,
+ mask = ~htonl(0xffff0000);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_checksum(struct net *net,
+- const struct flow_offload *flow,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_checksum(struct net *net,
++ const struct flow_offload *flow,
++ struct nf_flow_rule *flow_rule)
+ {
+ u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+
++ if (!entry)
++ return -E2BIG;
++
+ entry->id = FLOW_ACTION_CSUM;
+ entry->csum_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+@@ -539,12 +576,14 @@ static void flow_offload_ipv4_checksum(struct net *net,
+ entry->csum_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+ break;
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_redirect(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_redirect(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple, *other_tuple;
+ struct flow_action_entry *entry;
+@@ -562,21 +601,28 @@ static void flow_offload_redirect(struct net *net,
+ ifindex = other_tuple->iifidx;
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ dev = dev_get_by_index(net, ifindex);
+ if (!dev)
+- return;
++ return -ENODEV;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry) {
++ dev_put(dev);
++ return -E2BIG;
++ }
++
+ entry->id = FLOW_ACTION_REDIRECT;
+ entry->dev = dev;
++
++ return 0;
+ }
+
+-static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_encap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple;
+ struct flow_action_entry *entry;
+@@ -584,7 +630,7 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+
+ this_tuple = &flow->tuplehash[dir].tuple;
+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = this_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -593,15 +639,19 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+ entry->tunnel = tun_info;
+ }
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_decap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *other_tuple;
+ struct flow_action_entry *entry;
+@@ -609,7 +659,7 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+
+ other_tuple = &flow->tuplehash[!dir].tuple;
+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = other_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -618,9 +668,13 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_DECAP;
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -632,8 +686,9 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ const struct flow_offload_tuple *tuple;
+ int i;
+
+- flow_offload_decap_tunnel(flow, dir, flow_rule);
+- flow_offload_encap_tunnel(flow, dir, flow_rule);
++ if (flow_offload_decap_tunnel(flow, dir, flow_rule) < 0 ||
++ flow_offload_encap_tunnel(flow, dir, flow_rule) < 0)
++ return -1;
+
+ if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
+ flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
+@@ -649,6 +704,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+
+ if (tuple->encap[i].proto == htons(ETH_P_8021Q)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+ entry->id = FLOW_ACTION_VLAN_POP;
+ }
+ }
+@@ -662,6 +719,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ continue;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+
+ switch (other_tuple->encap[i].proto) {
+ case htons(ETH_P_PPP_SES):
+@@ -687,18 +746,22 @@ int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv4_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_SNAT, &flow->flags) ||
+ test_bit(NF_FLOW_DNAT, &flow->flags))
+- flow_offload_ipv4_checksum(net, flow, flow_rule);
++ if (flow_offload_ipv4_checksum(net, flow, flow_rule) < 0)
++ return -1;
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+@@ -712,22 +775,23 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv6_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
+
+-#define NF_FLOW_RULE_ACTION_MAX 16
+-
+ static struct nf_flow_rule *
+ nf_flow_offload_rule_alloc(struct net *net,
+ const struct flow_offload_work *offload,
+--
+2.53.0
+
--- /dev/null
+From 5cc71e152c34ed623f18832884aef68ac033321d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index e9f4f845d760a..b98331572ad29 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -309,7 +309,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index cc20e6d56807c..a4e1d7951b2c6 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -821,7 +821,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -830,7 +830,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 13c7a08aa868c..34bb84d7b174c 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From a3abb613d5af13c59fcdcde284ccaa10add615e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:02 +0100
+Subject: netfilter: nf_conntrack_expect: honor expectation helper field
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 9c42bc9db90a154bc61ae337a070465f3393485a ]
+
+The expectation helper field is mostly unused. As a result, the
+netfilter codebase relies on accessing the helper through exp->master.
+
+Always set on the expectation helper field so it can be used to reach
+the helper.
+
+nf_ct_expect_init() is called from packet path where the skb owns
+the ct object, therefore accessing exp->master for the newly created
+expectation is safe. This saves a lot of updates in all callsites
+to pass the ct object as parameter to nf_ct_expect_init().
+
+This is a preparation patches for follow up fixes.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 2 +-
+ net/netfilter/nf_conntrack_broadcast.c | 2 +-
+ net/netfilter/nf_conntrack_expect.c | 14 +++++++++++++-
+ net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------
+ net/netfilter/nf_conntrack_helper.c | 7 ++++++-
+ net/netfilter/nf_conntrack_netlink.c | 2 +-
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 7 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 165e7a03b8e9d..1b01400b10bdb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -40,7 +40,7 @@ struct nf_conntrack_expect {
+ struct nf_conntrack_expect *this);
+
+ /* Helper to assign to new connection */
+- struct nf_conntrack_helper *helper;
++ struct nf_conntrack_helper __rcu *helper;
+
+ /* The conntrack of the master connection */
+ struct nf_conn *master;
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index a7552a46d6acf..1964c596c6468 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -70,7 +70,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->expectfn = NULL;
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+- exp->helper = NULL;
++ rcu_assign_pointer(exp->helper, helper);
+
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 227fb5dc39e27..6739b48c644fc 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -309,12 +309,19 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
+
++/* This function can only be used from packet path, where accessing
++ * master's helper is safe, because the packet holds a reference on
++ * the conntrack object. Never use it from control plane.
++ */
+ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ u_int8_t family,
+ const union nf_inet_addr *saddr,
+ const union nf_inet_addr *daddr,
+ u_int8_t proto, const __be16 *src, const __be16 *dst)
+ {
++ struct nf_conntrack_helper *helper = NULL;
++ struct nf_conn *ct = exp->master;
++ struct nf_conn_help *help;
+ int len;
+
+ if (family == AF_INET)
+@@ -325,7 +332,12 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ exp->flags = 0;
+ exp->class = class;
+ exp->expectfn = NULL;
+- exp->helper = NULL;
++
++ help = nfct_help(ct);
++ if (help)
++ helper = rcu_dereference(help->helper);
++
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
+index e35814d68ce30..bd7e9e13e4f68 100644
+--- a/net/netfilter/nf_conntrack_h323_main.c
++++ b/net/netfilter/nf_conntrack_h323_main.c
+@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = &nf_conntrack_helper_h245;
++ rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3 : NULL,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+ exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_UDP, NULL, &port);
+- exp->helper = nf_conntrack_helper_ras;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect RAS ");
+@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 9d7d36ac83083..a21c976701f79 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -399,7 +399,7 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (exp->helper == me)
++ if (rcu_access_pointer(exp->helper) == me)
+ return true;
+
+ this = rcu_dereference_protected(help->helper,
+@@ -421,6 +421,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
++
++ /* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
++ * last step, this ensures rcu readers of exp->helper are done.
++ * No need for another synchronize_rcu() here.
++ */
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 82d5abae0ad1f..4d720552d43df 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3566,7 +3566,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+ exp->mask.src.u.all = mask->src.u.all;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 17af0ff4ea7ab..5bddee342e122 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -1303,7 +1303,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
+ nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
+ saddr, &daddr, proto, NULL, &port);
+ exp->timeout.expires = sip_timeout * HZ;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
+
+ hooks = rcu_dereference(nf_nat_sip_hooks);
+--
+2.53.0
+
--- /dev/null
+From 8e98eb54fd93e0a51fd7fffd074cfd403c1cb0d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 22:39:55 +0100
+Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 02a3231b6d82efe750da6554ebf280e4a6f78756 ]
+
+__nf_ct_expect_find() and nf_ct_expect_find_get() are called under
+rcu_read_lock() but they dereference the master conntrack via
+exp->master.
+
+Since the expectation does not hold a reference on the master conntrack,
+this could be dying conntrack or different recycled conntrack than the
+real master due to SLAB_TYPESAFE_RCU.
+
+Store the netns, the master_tuple and the zone in struct
+nf_conntrack_expect as a safety measure.
+
+This patch is required by the follow up fix not to dump expectations
+that do not belong to this netns.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++++++++++-
+ net/netfilter/nf_conntrack_broadcast.c | 6 +++++-
+ net/netfilter/nf_conntrack_expect.c | 9 +++++++--
+ net/netfilter/nf_conntrack_netlink.c | 5 +++++
+ 4 files changed, 34 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 1b01400b10bdb..e9a8350e7ccfb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
+ /* Hash member */
+ struct hlist_node hnode;
+
++ /* Network namespace */
++ possible_net_t net;
++
+ /* We expect this tuple, with the following mask */
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
+
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ struct nf_conntrack_zone zone;
++#endif
+ /* Usage count. */
+ refcount_t use;
+
+@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
+
+ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
+ {
+- return nf_ct_net(exp->master);
++ return read_pnet(&exp->net);
++}
++
++static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
++ const struct nf_conntrack_zone *b)
++{
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ return a->zone.id == b->id;
++#else
++ return true;
++#endif
+ }
+
+ #define NF_CT_EXP_POLICY_NAME_LEN 16
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 1964c596c6468..4f39bf7c843f2 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ unsigned int timeout)
+ {
+ const struct nf_conntrack_helper *helper;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = skb_rtable(skb);
+@@ -71,7 +72,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+ rcu_assign_pointer(exp->helper, helper);
+-
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index b37ff73efb3e2..2234c444a320e 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -112,8 +112,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
+ const struct net *net)
+ {
+ return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+- net_eq(net, nf_ct_net(i->master)) &&
+- nf_ct_zone_equal_any(i->master, zone);
++ net_eq(net, read_pnet(&i->net)) &&
++ nf_ct_exp_zone_equal_any(i, zone);
+ }
+
+ bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
+@@ -321,6 +321,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ {
+ struct nf_conntrack_helper *helper = NULL;
+ struct nf_conn *ct = exp->master;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conn_help *help;
+ int len;
+
+@@ -338,6 +339,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ helper = rcu_dereference(help->helper);
+
+ rcu_assign_pointer(exp->helper, helper);
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index f00afa6648376..8c5ae0665eaa4 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3521,6 +3521,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3560,6 +3561,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ if (!helper)
+ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+--
+2.53.0
+
--- /dev/null
+From f3ddbeff3b961ba95f49437a5970ac7f6509d8cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:03 +0100
+Subject: netfilter: nf_conntrack_expect: use expect->helper
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit f01794106042ee27e54af6fdf5b319a2fe3df94d ]
+
+Use expect->helper in ctnetlink and /proc to dump the helper name.
+Using nfct_help() without holding a reference to the master conntrack
+is unsafe.
+
+Use exp->master->helper in ctnetlink path if userspace does not provide
+an explicit helper when creating an expectation to retain the existing
+behaviour. The ctnetlink expectation path holds the reference on the
+master conntrack and nf_conntrack_expect lock and the nfnetlink glue
+path refers to the master ct that is attached to the skb.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_expect.c | 2 +-
+ net/netfilter/nf_conntrack_helper.c | 6 +-----
+ net/netfilter/nf_conntrack_netlink.c | 24 ++++++++++--------------
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 4 files changed, 13 insertions(+), 21 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 6739b48c644fc..b37ff73efb3e2 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -670,7 +670,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
+ if (expect->flags & NF_CT_EXPECT_USERSPACE)
+ seq_printf(s, "%sUSERSPACE", delim);
+
+- helper = rcu_dereference(nfct_help(expect->master)->helper);
++ helper = rcu_dereference(expect->helper);
+ if (helper) {
+ seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
+ if (helper->expect_policy[expect->class].name[0])
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index a21c976701f79..a715304a53d8c 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -395,14 +395,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
+
+ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ {
+- struct nf_conn_help *help = nfct_help(exp->master);
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (rcu_access_pointer(exp->helper) == me)
+- return true;
+-
+- this = rcu_dereference_protected(help->helper,
++ this = rcu_dereference_protected(exp->helper,
+ lockdep_is_held(&nf_conntrack_expect_lock));
+ return this == me;
+ }
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 4d720552d43df..f00afa6648376 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3005,7 +3005,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ {
+ struct nf_conn *master = exp->master;
+ long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
+- struct nf_conn_help *help;
++ struct nf_conntrack_helper *helper;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+ struct nlattr *nest_parms;
+ struct nf_conntrack_tuple nat_tuple = {};
+@@ -3050,15 +3050,12 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
+ goto nla_put_failure;
+- help = nfct_help(master);
+- if (help) {
+- struct nf_conntrack_helper *helper;
+
+- helper = rcu_dereference(help->helper);
+- if (helper &&
+- nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
+- goto nla_put_failure;
+- }
++ helper = rcu_dereference(exp->helper);
++ if (helper &&
++ nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
++ goto nla_put_failure;
++
+ expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
+ if (expfn != NULL &&
+ nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
+@@ -3387,12 +3384,9 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
+ static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
+ {
+ struct nf_conntrack_helper *helper;
+- const struct nf_conn_help *m_help;
+ const char *name = data;
+
+- m_help = nfct_help(exp->master);
+-
+- helper = rcu_dereference(m_help->helper);
++ helper = rcu_dereference(exp->helper);
+ if (!helper)
+ return false;
+
+@@ -3527,9 +3521,9 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+- u_int32_t class = 0;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
++ u32 class = 0;
+ int err;
+
+ help = nfct_help(ct);
+@@ -3566,6 +3560,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ if (!helper)
++ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 5bddee342e122..939502ff7c871 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -924,7 +924,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
+
+ if (!exp || exp->master == ct ||
+- nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
++ exp->helper != nfct_help(ct)->helper ||
+ exp->class != class)
+ break;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+--
+2.53.0
+
--- /dev/null
+From 25d81aa19bd445bd3bd1483676aa75b3027e9697 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index ceb48c3ca0a43..9d7d36ac83083 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -419,7 +419,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+--
+2.53.0
+
--- /dev/null
+From 95cb661fe8487e8330b20e9fb1dc9c227d4cbe68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index a6a7fe216396d..5b25b032e285d 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -11833,8 +11833,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -11869,6 +11867,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From ad2ee5dd21b2eb5a8bbcaa611c868ecbae974147 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index 27dd35224e629..dcd2493a9a404 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -726,7 +726,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From 24171b76a78392068d91c6158d30d3776eab27b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c437fbd59ec13..43d2ae2be628d 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -65,6 +65,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -102,6 +105,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 0b372a126447fd1b44b20e35941c6e9583dde59c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index 48105ea3df152..1ca4fa9d249b8 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -501,6 +501,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -1016,6 +1027,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From 46c44d1225da66f0d93124d057fd90ad51c469a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index a081bce61c29f..49c399a571750 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
+
+ timer_delete(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From 35ebc66162390286beb5c6dcee173b5d88512c73 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index bb34484046060..bbdc4be475b1b 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -2118,12 +2118,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From 34f840864f07fe288d9657434c362e6a4bd0c0ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 6585164c70595..dd08ccc4246da 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -604,8 +604,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
--- /dev/null
+arm64-scs-fix-handling-of-advance_loc4.patch
+hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch
+wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+btrfs-don-t-take-device_list_mutex-when-querying-zon.patch
+tg3-replace-placeholder-mac-address-with-device-prop.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch
+hid-core-mitigate-potential-oob-by-removing-bogus-me.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+btrfs-reserve-enough-transaction-items-for-qgroup-io.patch
+i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch
+btrfs-reject-root-items-with-drop_progress-and-zero-.patch
+smb-client-fix-generic-694-due-to-wrong-i_blocks.patch
+spi-geni-qcom-check-dma-interrupts-early-in-isr.patch
+dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch
+wifi-iwlwifi-fix-remaining-kernel-doc-warnings.patch
+wifi-iwlwifi-mld-fix-mlo-scan-timing.patch
+wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch
+wifi-iwlwifi-cfg-add-new-device-names.patch
+wifi-iwlwifi-disable-eht-if-the-device-doesn-t-allow.patch
+wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch
+wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch
+crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch
+crypto-caam-fix-overflow-on-long-hmac-keys.patch
+crypto-deflate-fix-spurious-enospc.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+net-mana-fix-rx-skb-truesize-accounting.patch
+netdevsim-fix-build-if-skb_extensions-n.patch
+net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch
+net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+eth-fbnic-account-for-page-fragments-when-updating-b.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch
+net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch
+net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch
+alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch
+asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch
+net-introduce-mangleid_features.patch
+net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+bnxt_en-set-backing-store-type-from-query-type.patch
+crypto-algif_aead-revert-to-operating-out-of-place.patch
+crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch
+net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch
+asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+mptcp-add-eat_recv_skb-helper.patch
+mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch
+net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch
+alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch
+netfilter-flowtable-strictly-check-for-maximum-numbe.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-nf_conntrack_expect-honor-expectation-help.patch
+netfilter-nf_conntrack_expect-use-expect-helper.patch
+netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch
+netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch
+bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch
+bluetooth-hci_h4-fix-race-during-initialization.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch
+bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch
+bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch
+net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-lag-check-for-lag-device-before-creating-de.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch
+bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+net-hsr-fix-vlan-add-unwind-on-slave-errors.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
+eth-fbnic-increase-fbnic_queue_size_min-to-64.patch
+bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch
+bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch
--- /dev/null
+From 327c657f19c10437ef972a452347513d20820444 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Mar 2026 21:43:51 -0300
+Subject: smb: client: fix generic/694 due to wrong ->i_blocks
+
+From: Paulo Alcantara <pc@manguebit.org>
+
+[ Upstream commit 23b5df09c27aec13962b30d32a4167ebdd043f8e ]
+
+When updating ->i_size, make sure to always update ->i_blocks as well
+until we query new allocation size from the server.
+
+generic/694 was failing because smb3_simple_falloc() was missing the
+update of ->i_blocks after calling cifs_setsize(). So, fix this by
+updating ->i_blocks directly in cifs_setsize(), so all places that
+call it doesn't need to worry about updating ->i_blocks later.
+
+Reported-by: Shyam Prasad N <sprasad@microsoft.com>
+Closes: https://lore.kernel.org/r/CANT5p=rqgRwaADB=b_PhJkqXjtfq3SFv41SSTXSVEHnuh871pA@mail.gmail.com
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
+Cc: David Howells <dhowells@redhat.com>
+Cc: linux-cifs@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsglob.h | 6 ++++++
+ fs/smb/client/file.c | 1 -
+ fs/smb/client/inode.c | 21 ++++++---------------
+ fs/smb/client/smb2ops.c | 20 ++++----------------
+ 4 files changed, 16 insertions(+), 32 deletions(-)
+
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index b82663f609ed9..3059fcf12ed13 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -2407,4 +2407,10 @@ static inline int cifs_open_create_options(unsigned int oflags, int opts)
+ return opts;
+ }
+
++/*
++ * The number of blocks is not related to (i_size / i_blksize), but instead
++ * 512 byte (2**9) size is required for calculating num blocks.
++ */
++#define CIFS_INO_BLOCKS(size) DIV_ROUND_UP_ULL((u64)(size), 512)
++
+ #endif /* _CIFS_GLOB_H */
+diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
+index dfeb609d90e22..f0e7a8f69e8b8 100644
+--- a/fs/smb/client/file.c
++++ b/fs/smb/client/file.c
+@@ -993,7 +993,6 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
+ if (!rc) {
+ netfs_resize_file(&cinode->netfs, 0, true);
+ cifs_setsize(inode, 0);
+- inode->i_blocks = 0;
+ }
+ }
+ if (cfile)
+diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
+index cac355364e43c..7cd718dd7cb70 100644
+--- a/fs/smb/client/inode.c
++++ b/fs/smb/client/inode.c
+@@ -218,13 +218,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
+ */
+ if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) {
+ i_size_write(inode, fattr->cf_eof);
+-
+- /*
+- * i_blocks is not related to (i_size / i_blksize),
+- * but instead 512 byte (2**9) size is required for
+- * calculating num blocks.
+- */
+- inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
++ inode->i_blocks = CIFS_INO_BLOCKS(fattr->cf_bytes);
+ }
+
+ if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) {
+@@ -3008,6 +3002,11 @@ void cifs_setsize(struct inode *inode, loff_t offset)
+ {
+ spin_lock(&inode->i_lock);
+ i_size_write(inode, offset);
++ /*
++ * Until we can query the server for actual allocation size,
++ * this is best estimate we have for blocks allocated for a file.
++ */
++ inode->i_blocks = CIFS_INO_BLOCKS(offset);
+ spin_unlock(&inode->i_lock);
+ inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ truncate_pagecache(inode, offset);
+@@ -3080,14 +3079,6 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
+ if (rc == 0) {
+ netfs_resize_file(&cifsInode->netfs, size, true);
+ cifs_setsize(inode, size);
+- /*
+- * i_blocks is not related to (i_size / i_blksize), but instead
+- * 512 byte (2**9) size is required for calculating num blocks.
+- * Until we can query the server for actual allocation size,
+- * this is best estimate we have for blocks allocated for a file
+- * Number of blocks must be rounded up so size 1 is not 0 blocks
+- */
+- inode->i_blocks = (512 - 1 + size) >> 9;
+ }
+
+ return rc;
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 502b5cb05bc3e..478fa4bddb454 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -1492,6 +1492,7 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+ {
+ struct smb2_file_network_open_info file_inf;
+ struct inode *inode;
++ u64 asize;
+ int rc;
+
+ rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
+@@ -1515,14 +1516,9 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+ inode_set_atime_to_ts(inode,
+ cifs_NTtimeToUnix(file_inf.LastAccessTime));
+
+- /*
+- * i_blocks is not related to (i_size / i_blksize),
+- * but instead 512 byte (2**9) size is required for
+- * calculating num blocks.
+- */
+- if (le64_to_cpu(file_inf.AllocationSize) > 4096)
+- inode->i_blocks =
+- (512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
++ asize = le64_to_cpu(file_inf.AllocationSize);
++ if (asize > 4096)
++ inode->i_blocks = CIFS_INO_BLOCKS(asize);
+
+ /* End of file and Attributes should not have to be updated on close */
+ spin_unlock(&inode->i_lock);
+@@ -2183,14 +2179,6 @@ smb2_duplicate_extents(const unsigned int xid,
+ rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
+ if (rc)
+ goto duplicate_extents_out;
+-
+- /*
+- * Although also could set plausible allocation size (i_blocks)
+- * here in addition to setting the file size, in reflink
+- * it is likely that the target file is sparse. Its allocation
+- * size will be queried on next revalidate, but it is important
+- * to make sure that file's cached size is updated immediately
+- */
+ netfs_resize_file(netfs_inode(inode), dest_off + len, true);
+ cifs_setsize(inode, dest_off + len);
+ }
+--
+2.53.0
+
--- /dev/null
+From 240c05155643299fc312c9e3c8cf7539de7b1c8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 21:49:01 +0530
+Subject: spi: geni-qcom: Check DMA interrupts early in ISR
+
+From: Praveen Talari <praveen.talari@oss.qualcomm.com>
+
+[ Upstream commit 8c89a077ca796a2fe248c584e9d7e66cff0388c8 ]
+
+The current interrupt handler only checks the GENI main IRQ status
+(m_irq) before deciding to return IRQ_NONE. This can lead to spurious
+IRQ_NONE returns when DMA interrupts are pending but m_irq is zero.
+
+Move the DMA TX/RX status register reads to the beginning of the ISR,
+right after reading m_irq. Update the early return condition to check
+all three status registers (m_irq, dma_tx_status, dma_rx_status) before
+returning IRQ_NONE.
+
+Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-geni-qcom.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
+index acfcf870efd84..736120107184f 100644
+--- a/drivers/spi/spi-geni-qcom.c
++++ b/drivers/spi/spi-geni-qcom.c
+@@ -958,10 +958,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ struct spi_controller *spi = data;
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+- u32 m_irq;
++ u32 m_irq, dma_tx_status, dma_rx_status;
+
+ m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
+- if (!m_irq)
++ dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
++ dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
++
++ if (!m_irq && !dma_tx_status && !dma_rx_status)
+ return IRQ_NONE;
+
+ if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
+@@ -1009,8 +1012,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ }
+ } else if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ const struct spi_transfer *xfer = mas->cur_xfer;
+- u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+- u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (dma_tx_status)
+ writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
+--
+2.53.0
+
--- /dev/null
+From 933fff370316c4f43c731cf20d4d4ef141a8e806 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index a04b5eb02689d..af21952373ea1 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12300,7 +12300,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From fedf1db33e22e0a03b02e7f4e04bc8b435d9f3da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Mar 2026 03:24:30 +0530
+Subject: tg3: replace placeholder MAC address with device property
+
+From: Paul SAGE <paul.sage@42.fr>
+
+[ Upstream commit e4c00ba7274b613e3ab19e27eb009f0ec2e28379 ]
+
+On some systems (e.g. iMac 20,1 with BCM57766), the tg3 driver reads
+a default placeholder mac address (00:10:18:00:00:00) from the
+mailbox. The correct value on those systems are stored in the
+'local-mac-address' property.
+
+This patch, detect the default value and tries to retrieve
+the correct address from the device_get_mac_address
+function instead.
+
+The patch has been tested on two different systems:
+- iMac 20,1 (BCM57766) model which use the local-mac-address property
+- iMac 13,2 (BCM57766) model which can use the mailbox,
+ NVRAM or MAC control registers
+
+Tested-by: Rishon Jonathan R <mithicalaviator85@gmail.com>
+
+Co-developed-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Paul SAGE <paul.sage@42.fr>
+Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index 0397a6ebf20f9..a04b5eb02689d 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -17042,6 +17042,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
+ return err;
+ }
+
++static int tg3_is_default_mac_address(u8 *addr)
++{
++ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
++
++ return ether_addr_equal(default_mac_address, addr);
++}
++
+ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+ {
+ u32 hi, lo, mac_offset;
+@@ -17115,6 +17122,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+
+ if (!is_valid_ether_addr(addr))
+ return -EINVAL;
++
++ if (tg3_is_default_mac_address(addr))
++ return device_get_mac_address(&tp->pdev->dev, addr);
++
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e6aa8af861dab0f3fd594e0294aecd174f278b18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Mar 2026 12:26:08 +0530
+Subject: wifi: ath11k: Pass the correct value of each TID during a stop AMPDU
+ session
+
+From: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+
+[ Upstream commit e225b36f83d7926c1f2035923bb0359d851fdb73 ]
+
+During ongoing traffic, a request to stop an AMPDU session
+for one TID could incorrectly affect other active sessions.
+This can happen because an incorrect TID reference would be
+passed when updating the BA session state, causing the wrong
+session to be stopped. As a result, the affected session would
+be reduced to a minimal BA size, leading to a noticeable
+throughput degradation.
+
+Fix this issue by passing the correct argument from
+ath11k_dp_rx_ampdu_stop() to ath11k_peer_rx_tid_reo_update()
+during a stop AMPDU session. Instead of passing peer->tx_tid, which
+is the base address of the array, corresponding to TID 0; pass
+the value of &peer->rx_tid[params->tid], where the different TID numbers
+are accounted for.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1
+
+Fixes: d5c65159f2895 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
+Signed-off-by: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index b9e976ddcbbf6..44eea682c297b 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_peer *peer;
+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
++ struct dp_rx_tid *rx_tid;
+ int vdev_id = arsta->arvif->vdev_id;
+- dma_addr_t paddr;
+- bool active;
+ int ret;
+
+ spin_lock_bh(&ab->base_lock);
+@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ return -ENOENT;
+ }
+
+- paddr = peer->rx_tid[params->tid].paddr;
+- active = peer->rx_tid[params->tid].active;
++ rx_tid = &peer->rx_tid[params->tid];
+
+- if (!active) {
++ if (!rx_tid->active) {
+ spin_unlock_bh(&ab->base_lock);
+ return 0;
+ }
+
+- ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
++ ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
+ spin_unlock_bh(&ab->base_lock);
+ if (ret) {
+ ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
+@@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ }
+
+ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
+- params->sta->addr, paddr,
++ params->sta->addr,
++ rx_tid->paddr,
+ params->tid, 1, 1);
+ if (ret)
+ ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
+--
+2.53.0
+
--- /dev/null
+From 1317e6d773125c27e5ea4d7d9faad0683e18193b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Sep 2025 11:34:27 +0300
+Subject: wifi: iwlwifi: cfg: add new device names
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 30d47d8fe781469ebd4e38240999767f139effb2 ]
+
+Add a couple of device names so that these new devices will
+be shown correctly.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250915113137.1cbc0251532f.I6183a6a08a7998e598042a50c7d7a6b82f9fa58e@changeid
+Stable-dep-of: 687a95d204e7 ("wifi: iwlwifi: mld: correctly set wifi generation data")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c | 1 +
+ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 +
+ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++
+ 3 files changed, 5 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c
+index 97735175cb0ea..b8c6b06e70991 100644
+--- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c
++++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c
+@@ -13,3 +13,4 @@ const char iwl_killer_be1775i_name[] =
+
+ const char iwl_be211_name[] = "Intel(R) Wi-Fi 7 BE211 320MHz";
+ const char iwl_be213_name[] = "Intel(R) Wi-Fi 7 BE213 160MHz";
++const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz";
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+index 502c6a1cf4f86..0b34c9f90b3ff 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+@@ -688,6 +688,7 @@ extern const char iwl_killer_bn1850i_name[];
+ extern const char iwl_bn201_name[];
+ extern const char iwl_be221_name[];
+ extern const char iwl_be223_name[];
++extern const char iwl_ax221_name[];
+ #if IS_ENABLED(CONFIG_IWLDVM)
+ extern const struct iwl_rf_cfg iwl5300_agn_cfg;
+ extern const struct iwl_rf_cfg iwl5350_agn_cfg;
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+index b21a4d8eb1051..de04a84def0d8 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+@@ -1061,11 +1061,14 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = {
+
+ /* WH RF */
+ IWL_DEV_INFO(iwl_rf_wh, iwl_be211_name, RF_TYPE(WH)),
++ IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x0514)),
++ IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x4514)),
+ IWL_DEV_INFO(iwl_rf_wh_160mhz, iwl_be213_name, RF_TYPE(WH), BW_LIMITED),
+
+ /* PE RF */
+ IWL_DEV_INFO(iwl_rf_pe, iwl_bn201_name, RF_TYPE(PE)),
+ IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), SUBDEV(0x0524)),
++ IWL_DEV_INFO(iwl_rf_pe, iwl_be223_name, RF_TYPE(PE), SUBDEV(0x4524)),
+ IWL_DEV_INFO(iwl_rf_pe, iwl_be221_name, RF_TYPE(PE), SUBDEV(0x0324)),
+
+ /* Killer */
+--
+2.53.0
+
--- /dev/null
+From c1a7a296724bccbc8b920f1499a36abfe2f486fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Oct 2025 11:45:13 +0300
+Subject: wifi: iwlwifi: disable EHT if the device doesn't allow it
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit 7ed47d42943fba8ced505f62d4358f63963bb968 ]
+
+We have a few devices that don't allow EHT. Make sure we reflect this
+towards mac80211 so that we won't try to enable it.
+
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20251019114304.71121f4e5557.I49e2329d4121f9e52d0889156d0c3e8778e27d88@changeid
+Stable-dep-of: 687a95d204e7 ("wifi: iwlwifi: mld: correctly set wifi generation data")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/cfg/rf-fm.c | 1 +
+ .../net/wireless/intel/iwlwifi/cfg/rf-wh.c | 23 +++++++++++++++++++
+ .../net/wireless/intel/iwlwifi/iwl-config.h | 5 +++-
+ .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 +-
+ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 6 +++--
+ 5 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c
+index 456a666c8dfdf..fd82050e33a3c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c
++++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c
+@@ -19,6 +19,7 @@
+ .non_shared_ant = ANT_B, \
+ .vht_mu_mimo_supported = true, \
+ .uhb_supported = true, \
++ .eht_supported = true, \
+ .num_rbds = IWL_NUM_RBDS_EHT, \
+ .nvm_ver = IWL_FM_NVM_VERSION, \
+ .nvm_type = IWL_NVM_EXT
+diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c
+index b8c6b06e70991..b5803ea1eb782 100644
+--- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c
++++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-wh.c
+@@ -4,8 +4,31 @@
+ */
+ #include "iwl-config.h"
+
++/* NVM versions */
++#define IWL_WH_NVM_VERSION 0x0a1d
++
++#define IWL_DEVICE_WH \
++ .ht_params = { \
++ .stbc = true, \
++ .ldpc = true, \
++ .ht40_bands = BIT(NL80211_BAND_2GHZ) | \
++ BIT(NL80211_BAND_5GHZ), \
++ }, \
++ .led_mode = IWL_LED_RF_STATE, \
++ .non_shared_ant = ANT_B, \
++ .vht_mu_mimo_supported = true, \
++ .uhb_supported = true, \
++ .num_rbds = IWL_NUM_RBDS_EHT, \
++ .nvm_ver = IWL_WH_NVM_VERSION, \
++ .nvm_type = IWL_NVM_EXT
++
+ /* currently iwl_rf_wh/iwl_rf_wh_160mhz are just defines for the FM ones */
+
++const struct iwl_rf_cfg iwl_rf_wh_non_eht = {
++ IWL_DEVICE_WH,
++ .eht_supported = false,
++};
++
+ const char iwl_killer_be1775s_name[] =
+ "Killer(R) Wi-Fi 7 BE1775s 320MHz Wireless Network Adapter (BE211D2W)";
+ const char iwl_killer_be1775i_name[] =
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+index 0b34c9f90b3ff..3b4f990a8d0bb 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+@@ -418,6 +418,7 @@ struct iwl_mac_cfg {
+ * @vht_mu_mimo_supported: VHT MU-MIMO support
+ * @nvm_type: see &enum iwl_nvm_type
+ * @uhb_supported: ultra high band channels supported
++ * @eht_supported: EHT supported
+ * @num_rbds: number of receive buffer descriptors to use
+ * (only used for multi-queue capable devices)
+ *
+@@ -450,7 +451,8 @@ struct iwl_rf_cfg {
+ host_interrupt_operation_mode:1,
+ lp_xtal_workaround:1,
+ vht_mu_mimo_supported:1,
+- uhb_supported:1;
++ uhb_supported:1,
++ eht_supported:1;
+ u8 valid_tx_ant;
+ u8 valid_rx_ant;
+ u8 non_shared_ant;
+@@ -744,6 +746,7 @@ extern const struct iwl_rf_cfg iwl_rf_fm;
+ extern const struct iwl_rf_cfg iwl_rf_fm_160mhz;
+ #define iwl_rf_wh iwl_rf_fm
+ #define iwl_rf_wh_160mhz iwl_rf_fm_160mhz
++extern const struct iwl_rf_cfg iwl_rf_wh_non_eht;
+ #define iwl_rf_pe iwl_rf_fm
+ #endif /* CONFIG_IWLMLD */
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+index 23465e4c4b399..e021fc57d85d2 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+@@ -2080,7 +2080,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
+ !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED);
+ nvm->sku_cap_mimo_disabled =
+ !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED);
+- if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) >= IWL_CFG_RF_TYPE_FM)
++ if (trans->cfg->eht_supported)
+ nvm->sku_cap_11be_enable = true;
+
+ /* Initialize PHY sku data */
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+index de04a84def0d8..73001cdce13aa 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+@@ -1061,8 +1061,10 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = {
+
+ /* WH RF */
+ IWL_DEV_INFO(iwl_rf_wh, iwl_be211_name, RF_TYPE(WH)),
+- IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x0514)),
+- IWL_DEV_INFO(iwl_rf_wh, iwl_ax221_name, RF_TYPE(WH), SUBDEV(0x4514)),
++ IWL_DEV_INFO(iwl_rf_wh_non_eht, iwl_ax221_name, RF_TYPE(WH),
++ SUBDEV(0x0514)),
++ IWL_DEV_INFO(iwl_rf_wh_non_eht, iwl_ax221_name, RF_TYPE(WH),
++ SUBDEV(0x4514)),
+ IWL_DEV_INFO(iwl_rf_wh_160mhz, iwl_be213_name, RF_TYPE(WH), BW_LIMITED),
+
+ /* PE RF */
+--
+2.53.0
+
--- /dev/null
+From 89eec42a23f0af7e78d0827f1e55949b30d5cf5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Sep 2025 11:34:29 +0300
+Subject: wifi: iwlwifi: fix remaining kernel-doc warnings
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 58a4ebe3168813a04bef08f7858a63b199e866e1 ]
+
+Fix the remaining kernel-doc warnings across the driver.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20250915113137.f94b6d4ef142.I91007eed4cf37125ca7a012f2021615b4fa9eb66@changeid
+Stable-dep-of: ec66ec6a5a8f ("wifi: iwlwifi: mld: Fix MLO scan timing")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 1 +
+ .../wireless/intel/iwlwifi/fw/api/cmdhdr.h | 4 +-
+ .../net/wireless/intel/iwlwifi/fw/api/coex.h | 4 +-
+ .../wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 14 ++--
+ .../net/wireless/intel/iwlwifi/fw/api/debug.h | 2 +-
+ .../wireless/intel/iwlwifi/fw/api/location.h | 8 +-
+ .../net/wireless/intel/iwlwifi/fw/api/power.h | 5 +-
+ .../net/wireless/intel/iwlwifi/fw/api/scan.h | 78 ++++++++++---------
+ .../net/wireless/intel/iwlwifi/fw/api/sta.h | 6 +-
+ .../net/wireless/intel/iwlwifi/fw/api/stats.h | 39 +++++-----
+ .../net/wireless/intel/iwlwifi/fw/api/tx.h | 2 +-
+ .../wireless/intel/iwlwifi/fw/error-dump.h | 4 +-
+ drivers/net/wireless/intel/iwlwifi/fw/file.h | 74 +++++++++++++-----
+ drivers/net/wireless/intel/iwlwifi/fw/img.h | 12 ++-
+ .../net/wireless/intel/iwlwifi/fw/runtime.h | 22 +++++-
+ .../net/wireless/intel/iwlwifi/iwl-config.h | 2 +-
+ .../net/wireless/intel/iwlwifi/iwl-dbg-tlv.h | 4 +-
+ drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 3 +-
+ .../wireless/intel/iwlwifi/iwl-modparams.h | 4 +-
+ .../wireless/intel/iwlwifi/iwl-nvm-parse.h | 17 ++--
+ .../net/wireless/intel/iwlwifi/iwl-op-mode.h | 1 +
+ .../net/wireless/intel/iwlwifi/iwl-trans.h | 6 +-
+ 22 files changed, 194 insertions(+), 118 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+index 20bc6671f4eb2..06cece4ea6d95 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+@@ -151,6 +151,7 @@ union acpi_object *iwl_acpi_get_dsm_object(struct device *dev, int rev,
+ * @mcc: output buffer (3 bytes) that will get the MCC
+ *
+ * This function tries to read the current MCC from ACPI if available.
++ * Return: 0 on success, or a negative error code
+ */
+ int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc);
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h b/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h
+index d130d4f854447..073f003bdc5d2 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2005-2014 Intel Corporation
++ * Copyright (C) 2005-2014, 2025 Intel Corporation
+ * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
+ */
+@@ -98,7 +98,7 @@ struct iwl_cmd_header {
+ } __packed;
+
+ /**
+- * struct iwl_cmd_header_wide
++ * struct iwl_cmd_header_wide - wide command header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h
+index ddc84430d8959..616f00a8b6034 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2023-2024 Intel Corporation
++ * Copyright (C) 2023-2025 Intel Corporation
+ * Copyright (C) 2013-2014, 2018-2019 Intel Corporation
+ * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2017 Intel Deutschland GmbH
+@@ -52,7 +52,7 @@ struct iwl_bt_coex_cmd {
+ } __packed; /* BT_COEX_CMD_API_S_VER_6 */
+
+ /**
+- * struct iwl_bt_coex_reduced_txp_update_cmd
++ * struct iwl_bt_coex_reduced_txp_update_cmd - reduced TX power command
+ * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the
+ * bits are the sta_id (value)
+ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
+index 3173fa96cb489..b62f0687327a6 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
+@@ -16,7 +16,7 @@
+ #define IWL_FW_INI_PRESET_DISABLE 0xff
+
+ /**
+- * struct iwl_fw_ini_hcmd
++ * struct iwl_fw_ini_hcmd - debug configuration host command
+ *
+ * @id: the debug configuration command type for instance: 0xf6 / 0xf5 / DHC
+ * @group: the desired cmd group
+@@ -199,7 +199,7 @@ struct iwl_fw_ini_region_tlv {
+ } __packed; /* FW_TLV_DEBUG_REGION_API_S_VER_1 */
+
+ /**
+- * struct iwl_fw_ini_debug_info_tlv
++ * struct iwl_fw_ini_debug_info_tlv - debug info TLV
+ *
+ * debug configuration name for a specific image
+ *
+@@ -311,7 +311,7 @@ struct iwl_fw_ini_conf_set_tlv {
+ } __packed; /* FW_TLV_DEBUG_CONFIG_SET_API_S_VER_1 */
+
+ /**
+- * enum iwl_fw_ini_config_set_type
++ * enum iwl_fw_ini_config_set_type - configuration set type
+ *
+ * @IWL_FW_INI_CONFIG_SET_TYPE_INVALID: invalid config set
+ * @IWL_FW_INI_CONFIG_SET_TYPE_DEVICE_PERIPHERY_MAC: for PERIPHERY MAC configuration
+@@ -337,7 +337,7 @@ enum iwl_fw_ini_config_set_type {
+ } __packed;
+
+ /**
+- * enum iwl_fw_ini_allocation_id
++ * enum iwl_fw_ini_allocation_id - allocation ID
+ *
+ * @IWL_FW_INI_ALLOCATION_INVALID: invalid
+ * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration
+@@ -356,7 +356,7 @@ enum iwl_fw_ini_allocation_id {
+ }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */
+
+ /**
+- * enum iwl_fw_ini_buffer_location
++ * enum iwl_fw_ini_buffer_location - buffer location
+ *
+ * @IWL_FW_INI_LOCATION_INVALID: invalid
+ * @IWL_FW_INI_LOCATION_SRAM_PATH: SRAM location
+@@ -373,7 +373,7 @@ enum iwl_fw_ini_buffer_location {
+ }; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */
+
+ /**
+- * enum iwl_fw_ini_region_type
++ * enum iwl_fw_ini_region_type - region type
+ *
+ * @IWL_FW_INI_REGION_INVALID: invalid
+ * @IWL_FW_INI_REGION_TLV: uCode and debug TLVs
+@@ -437,7 +437,7 @@ enum iwl_fw_ini_region_device_memory_subtype {
+ }; /* FW_TLV_DEBUG_REGION_DEVICE_MEMORY_SUBTYPE_API_E */
+
+ /**
+- * enum iwl_fw_ini_time_point
++ * enum iwl_fw_ini_time_point - time point type
+ *
+ * Hard coded time points in which the driver can send hcmd or perform dump
+ * collection
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
+index 0cf1e5124fba7..61a850de26fcc 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
+@@ -421,7 +421,7 @@ struct iwl_dbgc1_info {
+ } __packed; /* INIT_DRAM_FRAGS_ALLOCATIONS_S_VER_1 */
+
+ /**
+- * struct iwl_dbg_host_event_cfg_cmd
++ * struct iwl_dbg_host_event_cfg_cmd - host event config command
+ * @enabled_severities: enabled severities
+ */
+ struct iwl_dbg_host_event_cfg_cmd {
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
+index 33541f92c7c73..2ee3a48aa5dfe 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
+@@ -1092,7 +1092,7 @@ struct iwl_tof_range_req_ap_entry {
+ } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_9 */
+
+ /**
+- * enum iwl_tof_response_mode
++ * enum iwl_tof_response_mode - TOF response mode
+ * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as
+ * possible (not supported for this release)
+ * @IWL_MVM_TOF_RESPONSE_TIMEOUT: report all AP measurements as a batch upon
+@@ -1108,7 +1108,7 @@ enum iwl_tof_response_mode {
+ };
+
+ /**
+- * enum iwl_tof_initiator_flags
++ * enum iwl_tof_initiator_flags - TOF initiator flags
+ *
+ * @IWL_TOF_INITIATOR_FLAGS_FAST_ALGO_DISABLED: disable fast algo, meaning run
+ * the algo on ant A+B, instead of only one of them.
+@@ -1409,7 +1409,7 @@ enum iwl_tof_range_request_status {
+ };
+
+ /**
+- * enum iwl_tof_entry_status
++ * enum iwl_tof_entry_status - TOF entry status
+ *
+ * @IWL_TOF_ENTRY_SUCCESS: successful measurement.
+ * @IWL_TOF_ENTRY_GENERAL_FAILURE: General failure.
+@@ -1856,7 +1856,7 @@ struct iwl_tof_mcsi_notif {
+ } __packed;
+
+ /**
+- * struct iwl_tof_range_abort_cmd
++ * struct iwl_tof_range_abort_cmd - TOF range abort command
+ * @request_id: corresponds to a range request
+ * @reserved: reserved
+ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+index 5eb8d10678fd4..535864e226260 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+@@ -620,7 +620,7 @@ struct iwl_sar_offset_mapping_cmd {
+ } __packed; /*SAR_OFFSET_MAPPING_TABLE_CMD_API_S*/
+
+ /**
+- * struct iwl_beacon_filter_cmd
++ * struct iwl_beacon_filter_cmd - beacon filter command
+ * REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
+ * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon
+ * to driver if delta in Energy values calculated for this and last
+@@ -762,7 +762,7 @@ enum iwl_6ghz_ap_type {
+ }; /* PHY_AP_TYPE_API_E_VER_1 */
+
+ /**
+- * struct iwl_txpower_constraints_cmd
++ * struct iwl_txpower_constraints_cmd - TX power constraints command
+ * AP_TX_POWER_CONSTRAINTS_CMD
+ * Used for VLP/LPI/AFC Access Point power constraints for 6GHz channels
+ * @link_id: linkId
+@@ -786,4 +786,5 @@ struct iwl_txpower_constraints_cmd {
+ __s8 psd_pwr[IWL_MAX_TX_EIRP_PSD_PWR_MAX_SIZE];
+ u8 reserved[3];
+ } __packed; /* PHY_AP_TX_POWER_CONSTRAINTS_CMD_API_S_VER_1 */
++
+ #endif /* __iwl_fw_api_power_h__ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+index f486d624500be..60f0a4924ddfb 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
++ * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
+ */
+@@ -129,7 +129,7 @@ struct iwl_scan_offload_profile {
+ } __packed;
+
+ /**
+- * struct iwl_scan_offload_profile_cfg_data
++ * struct iwl_scan_offload_profile_cfg_data - scan offload profile configs
+ * @blocklist_len: length of blocklist
+ * @num_profiles: num of profiles in the list
+ * @match_notify: clients waiting for match found notification
+@@ -159,7 +159,7 @@ struct iwl_scan_offload_profile_cfg_v1 {
+ } __packed; /* SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1-2*/
+
+ /**
+- * struct iwl_scan_offload_profile_cfg
++ * struct iwl_scan_offload_profile_cfg - scan offload profile config
+ * @profiles: profiles to search for match
+ * @data: the rest of the data for profile_cfg
+ */
+@@ -507,7 +507,7 @@ enum iwl_uhb_chan_cfg_flags {
+ IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE = BIT(26),
+ };
+ /**
+- * struct iwl_scan_dwell
++ * struct iwl_scan_dwell - scan dwell configuration
+ * @active: default dwell time for active scan
+ * @passive: default dwell time for passive scan
+ * @fragmented: default dwell time for fragmented scan
+@@ -728,7 +728,7 @@ enum iwl_umac_scan_general_params_flags2 {
+ };
+
+ /**
+- * struct iwl_scan_channel_cfg_umac
++ * struct iwl_scan_channel_cfg_umac - scan channel config
+ * @flags: bitmap - 0-19: directed scan to i'th ssid.
+ * @channel_num: channel number 1-13 etc.
+ * @v1: command version 1
+@@ -774,7 +774,7 @@ struct iwl_scan_channel_cfg_umac {
+ } __packed;
+
+ /**
+- * struct iwl_scan_umac_schedule
++ * struct iwl_scan_umac_schedule - scan schedule parameters
+ * @interval: interval in seconds between scan iterations
+ * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop
+ * @reserved: for alignment and future use
+@@ -815,7 +815,7 @@ struct iwl_scan_req_umac_tail_v2 {
+ } __packed;
+
+ /**
+- * struct iwl_scan_umac_chan_param
++ * struct iwl_scan_umac_chan_param - scan channel parameters
+ * @flags: channel flags &enum iwl_scan_channel_flags
+ * @count: num of channels in scan request
+ * @reserved: for future use and alignment
+@@ -827,33 +827,37 @@ struct iwl_scan_umac_chan_param {
+ } __packed; /*SCAN_CHANNEL_PARAMS_API_S_VER_1 */
+
+ /**
+- * struct iwl_scan_req_umac
++ * struct iwl_scan_req_umac - scan request command
+ * @flags: &enum iwl_umac_scan_flags
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @ooc_priority: out of channel priority - &enum iwl_scan_priority
+ * @general_flags: &enum iwl_umac_scan_general_flags
++ * @reserved: reserved
+ * @scan_start_mac_id: report the scan start TSF time according to this mac TSF
+- * @extended_dwell: dwell time for channels 1, 6 and 11
+- * @active_dwell: dwell time for active scan per LMAC
+- * @passive_dwell: dwell time for passive scan per LMAC
+- * @fragmented_dwell: dwell time for fragmented passive scan
+- * @adwell_default_n_aps: for adaptive dwell the default number of APs
++ * @v1: version 1 command data
++ * @v6: version 6 command data
++ * @v7: version 7 command data
++ * @v8: version 8 command data
++ * @v9: version 9 command data
++ * @v1.extended_dwell: dwell time for channels 1, 6 and 11
++ * @v1.active_dwell: dwell time for active scan per LMAC
++ * @v1.passive_dwell: dwell time for passive scan per LMAC
++ * @v1.fragmented_dwell: dwell time for fragmented passive scan
++ * @v7.adwell_default_n_aps: for adaptive dwell the default number of APs
+ * per channel
+- * @adwell_default_n_aps_social: for adaptive dwell the default
++ * @v7.adwell_default_n_aps_social: for adaptive dwell the default
+ * number of APs per social (1,6,11) channel
+- * @general_flags2: &enum iwl_umac_scan_general_flags2
+- * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added
+- * to total scan time
+- * @max_out_time: max out of serving channel time, per LMAC - for CDB there
+- * are 2 LMACs
+- * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs
+- * @scan_priority: scan internal prioritization &enum iwl_scan_priority
+- * @num_of_fragments: Number of fragments needed for full coverage per band.
++ * @v8.general_flags2: &enum iwl_umac_scan_general_flags2
++ * @v7.adwell_max_budget: for adaptive dwell the maximal budget of TU to be
++ * added to total scan time
++ * @v1.max_out_time: max out of serving channel time, per LMAC - for CDB
++ * there are 2 LMACs
++ * @v1.suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs
++ * @v1.scan_priority: scan internal prioritization &enum iwl_scan_priority
++ * @v8.num_of_fragments: Number of fragments needed for full coverage per band.
+ * Relevant only for fragmented scan.
+- * @channel: &struct iwl_scan_umac_chan_param
+- * @reserved: for future use and alignment
+- * @reserved3: for future use and alignment
+- * @data: &struct iwl_scan_channel_cfg_umac and
++ * @v1.channel: &struct iwl_scan_umac_chan_param
++ * @v1.data: &struct iwl_scan_channel_cfg_umac and
+ * &struct iwl_scan_req_umac_tail
+ */
+ struct iwl_scan_req_umac {
+@@ -939,7 +943,7 @@ struct iwl_scan_req_umac {
+ #define IWL_SCAN_REQ_UMAC_SIZE_V1 36
+
+ /**
+- * struct iwl_scan_probe_params_v3
++ * struct iwl_scan_probe_params_v3 - scan probe parameters
+ * @preq: scan probe request params
+ * @ssid_num: number of valid SSIDs in direct scan array
+ * @short_ssid_num: number of valid short SSIDs in short ssid array
+@@ -961,7 +965,7 @@ struct iwl_scan_probe_params_v3 {
+ } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */
+
+ /**
+- * struct iwl_scan_probe_params_v4
++ * struct iwl_scan_probe_params_v4 - scan probe parameters
+ * @preq: scan probe request params
+ * @short_ssid_num: number of valid short SSIDs in short ssid array
+ * @bssid_num: number of valid bssid in bssids array
+@@ -983,7 +987,7 @@ struct iwl_scan_probe_params_v4 {
+ #define SCAN_MAX_NUM_CHANS_V3 67
+
+ /**
+- * struct iwl_scan_channel_params_v4
++ * struct iwl_scan_channel_params_v4 - channel params
+ * @flags: channel flags &enum iwl_scan_channel_flags
+ * @count: num of channels in scan request
+ * @num_of_aps_override: override the number of APs the FW uses to calculate
+@@ -1006,7 +1010,7 @@ struct iwl_scan_channel_params_v4 {
+ SCAN_CHANNEL_PARAMS_API_S_VER_5 */
+
+ /**
+- * struct iwl_scan_channel_params_v7
++ * struct iwl_scan_channel_params_v7 - channel params
+ * @flags: channel flags &enum iwl_scan_channel_flags
+ * @count: num of channels in scan request
+ * @n_aps_override: override the number of APs the FW uses to calculate dwell
+@@ -1024,7 +1028,7 @@ struct iwl_scan_channel_params_v7 {
+ } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */
+
+ /**
+- * struct iwl_scan_general_params_v11
++ * struct iwl_scan_general_params_v11 - channel params
+ * @flags: &enum iwl_umac_scan_general_flags_v2
+ * @reserved: reserved for future
+ * @scan_start_mac_or_link_id: report the scan start TSF time according to this
+@@ -1066,7 +1070,7 @@ struct iwl_scan_general_params_v11 {
+ } __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_12, *_VER_11 and *_VER_10 */
+
+ /**
+- * struct iwl_scan_periodic_parms_v1
++ * struct iwl_scan_periodic_parms_v1 - periodicity parameters
+ * @schedule: can scheduling parameter
+ * @delay: initial delay of the periodic scan in seconds
+ * @reserved: reserved for future
+@@ -1078,7 +1082,7 @@ struct iwl_scan_periodic_parms_v1 {
+ } __packed; /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */
+
+ /**
+- * struct iwl_scan_req_params_v12
++ * struct iwl_scan_req_params_v12 - scan request parameters (v12)
+ * @general_params: &struct iwl_scan_general_params_v11
+ * @channel_params: &struct iwl_scan_channel_params_v4
+ * @periodic_params: &struct iwl_scan_periodic_parms_v1
+@@ -1106,7 +1110,7 @@ struct iwl_scan_req_params_v17 {
+ } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */
+
+ /**
+- * struct iwl_scan_req_umac_v12
++ * struct iwl_scan_req_umac_v12 - scan request command (v12)
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @ooc_priority: out of channel priority - &enum iwl_scan_priority
+ * @scan_params: scan parameters
+@@ -1130,7 +1134,7 @@ struct iwl_scan_req_umac_v17 {
+ } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */
+
+ /**
+- * struct iwl_umac_scan_abort
++ * struct iwl_umac_scan_abort - scan abort command
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @flags: reserved
+ */
+@@ -1140,7 +1144,7 @@ struct iwl_umac_scan_abort {
+ } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */
+
+ /**
+- * enum iwl_umac_scan_abort_status
++ * enum iwl_umac_scan_abort_status - scan abort status
+ *
+ * @IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS: scan was successfully aborted
+ * @IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS: scan abort is in progress
+@@ -1153,7 +1157,7 @@ enum iwl_umac_scan_abort_status {
+ };
+
+ /**
+- * struct iwl_umac_scan_complete
++ * struct iwl_umac_scan_complete - scan complete notification
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @last_schedule: last scheduling line
+ * @last_iter: last scan iteration number
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
+index ecbcd5084cd8d..e6f9abdfa546d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2012-2014, 2018-2021, 2023 Intel Corporation
++ * Copyright (C) 2012-2014, 2018-2021, 2023, 2025 Intel Corporation
+ * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
+ */
+@@ -428,7 +428,7 @@ struct iwl_mvm_rm_sta_cmd {
+ } __packed; /* REMOVE_STA_CMD_API_S_VER_2 */
+
+ /**
+- * struct iwl_mvm_mgmt_mcast_key_cmd_v1
++ * struct iwl_mvm_mgmt_mcast_key_cmd_v1 - IGTK command
+ * ( MGMT_MCAST_KEY = 0x1f )
+ * @ctrl_flags: &enum iwl_sta_key_flag
+ * @igtk: IGTK key material
+@@ -449,7 +449,7 @@ struct iwl_mvm_mgmt_mcast_key_cmd_v1 {
+ } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */
+
+ /**
+- * struct iwl_mvm_mgmt_mcast_key_cmd
++ * struct iwl_mvm_mgmt_mcast_key_cmd - IGTK command
+ * ( MGMT_MCAST_KEY = 0x1f )
+ * @ctrl_flags: &enum iwl_sta_key_flag
+ * @igtk: IGTK master key
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h
+index 00713a9918792..8d9a5058d5a54 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h
+@@ -26,7 +26,7 @@ struct mvm_statistics_div {
+ } __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */
+
+ /**
+- * struct mvm_statistics_rx_non_phy
++ * struct mvm_statistics_rx_non_phy - non-PHY RX statistics
+ * @bogus_cts: CTS received when not expecting CTS
+ * @bogus_ack: ACK received when not expecting ACK
+ * @non_channel_beacons: beacons with our bss id but not on our serving channel
+@@ -456,7 +456,7 @@ struct iwl_system_statistics_cmd {
+ } __packed; /* STATISTICS_FW_CMD_API_S_VER_1 */
+
+ /**
+- * enum iwl_fw_statistics_type
++ * enum iwl_fw_statistics_type - statistics type
+ *
+ * @FW_STATISTICS_OPERATIONAL: operational statistics
+ * @FW_STATISTICS_PHY: phy statistics
+@@ -478,7 +478,7 @@ enum iwl_fw_statistics_type {
+
+ #define IWL_STATISTICS_TYPE_MSK 0x7f
+ /**
+- * struct iwl_statistics_ntfy_hdr
++ * struct iwl_statistics_ntfy_hdr - statistics notification header
+ *
+ * @type: struct type
+ * @version: version of the struct
+@@ -491,7 +491,7 @@ struct iwl_statistics_ntfy_hdr {
+ }; /* STATISTICS_NTFY_HDR_API_S_VER_1 */
+
+ /**
+- * struct iwl_stats_ntfy_per_link
++ * struct iwl_stats_ntfy_per_link - per-link statistics
+ *
+ * @beacon_filter_average_energy: Average energy [-dBm] of the 2
+ * antennas.
+@@ -514,7 +514,7 @@ struct iwl_stats_ntfy_per_link {
+ } __packed; /* STATISTICS_NTFY_PER_LINK_API_S_VER_1 */
+
+ /**
+- * struct iwl_stats_ntfy_part1_per_link
++ * struct iwl_stats_ntfy_part1_per_link - part1 per link statistics
+ *
+ * @rx_time: rx time
+ * @tx_time: tx time
+@@ -533,7 +533,7 @@ struct iwl_stats_ntfy_part1_per_link {
+ } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_PER_LINK_API_S_VER_1 */
+
+ /**
+- * struct iwl_stats_ntfy_per_mac
++ * struct iwl_stats_ntfy_per_mac - per MAC statistics
+ *
+ * @beacon_filter_average_energy: Average energy [-dBm] of the 2
+ * antennas.
+@@ -556,7 +556,8 @@ struct iwl_stats_ntfy_per_mac {
+ } __packed; /* STATISTICS_NTFY_PER_MAC_API_S_VER_1 */
+
+ #define IWL_STATS_MAX_BW_INDEX 5
+-/** struct iwl_stats_ntfy_per_phy
++/**
++ * struct iwl_stats_ntfy_per_phy - per PHY statistics
+ * @channel_load: channel load
+ * @channel_load_by_us: device contribution to MCLM
+ * @channel_load_not_by_us: other devices' contribution to MCLM
+@@ -588,7 +589,7 @@ struct iwl_stats_ntfy_per_phy {
+ #define IWL_STATS_UNKNOWN_CHANNEL_LOAD 0xffffffff
+
+ /**
+- * struct iwl_stats_ntfy_per_sta
++ * struct iwl_stats_ntfy_per_sta - per STA statistics
+ *
+ * @average_energy: in fact it is minus the energy..
+ */
+@@ -600,7 +601,7 @@ struct iwl_stats_ntfy_per_sta {
+ #define IWL_STATS_MAX_FW_LINKS (IWL_FW_MAX_LINK_ID + 1)
+
+ /**
+- * struct iwl_system_statistics_notif_oper
++ * struct iwl_system_statistics_notif_oper - statistics notification
+ *
+ * @time_stamp: time when the notification is sent from firmware
+ * @per_link: per link statistics, &struct iwl_stats_ntfy_per_link
+@@ -615,7 +616,7 @@ struct iwl_system_statistics_notif_oper {
+ } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */
+
+ /**
+- * struct iwl_system_statistics_part1_notif_oper
++ * struct iwl_system_statistics_part1_notif_oper - part1 stats notification
+ *
+ * @time_stamp: time when the notification is sent from firmware
+ * @per_link: per link statistics &struct iwl_stats_ntfy_part1_per_link
+@@ -628,7 +629,7 @@ struct iwl_system_statistics_part1_notif_oper {
+ } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_API_S_VER_4 */
+
+ /**
+- * struct iwl_system_statistics_end_notif
++ * struct iwl_system_statistics_end_notif - statistics end notification
+ *
+ * @time_stamp: time when the notification is sent from firmware
+ */
+@@ -637,7 +638,7 @@ struct iwl_system_statistics_end_notif {
+ } __packed; /* STATISTICS_FW_NTFY_END_API_S_VER_1 */
+
+ /**
+- * struct iwl_statistics_operational_ntfy
++ * struct iwl_statistics_operational_ntfy - operational stats notification
+ *
+ * @hdr: general statistics header
+ * @flags: bitmap of possible notification structures
+@@ -662,7 +663,7 @@ struct iwl_statistics_operational_ntfy {
+ } __packed; /* STATISTICS_OPERATIONAL_NTFY_API_S_VER_15 */
+
+ /**
+- * struct iwl_statistics_operational_ntfy_ver_14
++ * struct iwl_statistics_operational_ntfy_ver_14 - operational stats notification
+ *
+ * @hdr: general statistics header
+ * @flags: bitmap of possible notification structures
+@@ -707,7 +708,7 @@ struct iwl_statistics_operational_ntfy_ver_14 {
+ } __packed; /* STATISTICS_OPERATIONAL_NTFY_API_S_VER_14 */
+
+ /**
+- * struct iwl_statistics_phy_ntfy
++ * struct iwl_statistics_phy_ntfy - PHY statistics notification
+ *
+ * @hdr: general statistics header
+ * RX PHY related statistics
+@@ -808,7 +809,7 @@ struct iwl_statistics_phy_ntfy {
+ } __packed; /* STATISTICS_PHY_NTFY_API_S_VER_1 */
+
+ /**
+- * struct iwl_statistics_mac_ntfy
++ * struct iwl_statistics_mac_ntfy - MAC statistics notification
+ *
+ * @hdr: general statistics header
+ * @bcast_filter_passed_per_mac: bcast filter passed per mac
+@@ -827,7 +828,7 @@ struct iwl_statistics_mac_ntfy {
+ } __packed; /* STATISTICS_MAC_NTFY_API_S_VER_1 */
+
+ /**
+- * struct iwl_statistics_rx_ntfy
++ * struct iwl_statistics_rx_ntfy - RX statistics notification
+ *
+ * @hdr: general statistics header
+ * @rx_agg_mpdu_cnt: aggregation frame count (number of
+@@ -867,7 +868,7 @@ struct iwl_statistics_rx_ntfy {
+ } __packed; /* STATISTICS_RX_NTFY_API_S_VER_1 */
+
+ /**
+- * struct iwl_statistics_tx_ntfy
++ * struct iwl_statistics_tx_ntfy - TX statistics notification
+ *
+ * @hdr: general statistics header
+ * @cts_timeout: timeout when waiting for CTS
+@@ -976,7 +977,7 @@ struct iwl_statistics_tx_ntfy {
+ } __packed; /* STATISTICS_TX_NTFY_API_S_VER_1 */
+
+ /**
+- * struct iwl_statistics_duration_ntfy
++ * struct iwl_statistics_duration_ntfy - burst/duration statistics
+ *
+ * @hdr: general statistics header
+ * @cont_burst_chk_cnt: number of times continuation or
+@@ -995,7 +996,7 @@ struct iwl_statistics_duration_ntfy {
+ } __packed; /* STATISTICS_DURATION_NTFY_API_S_VER_1 */
+
+ /**
+- * struct iwl_statistics_he_ntfy
++ * struct iwl_statistics_he_ntfy - HE statistics
+ *
+ * @hdr: general statistics header
+ * received HE frames
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h
+index 26d2013905ed9..31d3336726b42 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h
+@@ -963,7 +963,7 @@ struct iwl_scd_txq_cfg_cmd {
+ } __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */
+
+ /**
+- * struct iwl_scd_txq_cfg_rsp
++ * struct iwl_scd_txq_cfg_rsp - scheduler TXQ configuration response
+ * @token: taken from the command
+ * @sta_id: station id from the command
+ * @tid: tid from the command
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
+index c2a73cc85eff4..525a82030daa4 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
+@@ -266,7 +266,7 @@ struct iwl_fw_ini_error_dump_data {
+ } __packed;
+
+ /**
+- * struct iwl_fw_ini_dump_entry
++ * struct iwl_fw_ini_dump_entry - dump entry descriptor
+ * @list: list of dump entries
+ * @size: size of the data
+ * @data: entry data
+@@ -305,7 +305,7 @@ struct iwl_fw_ini_fifo_hdr {
+ * @dram_base_addr: base address of dram monitor range
+ * @page_num: page number of memory range
+ * @fifo_hdr: fifo header of memory range
+- * @fw_pkt: FW packet header of memory range
++ * @fw_pkt_hdr: FW packet header of memory range
+ * @data: the actual memory
+ */
+ struct iwl_fw_ini_error_dump_range {
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
+index b7c1ab7a30061..b9e0b69c66803 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
+@@ -222,7 +222,10 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
+ * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement.
+ * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2
+ * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL: support for adaptive dwell in scanning
++ * @IWL_UCODE_TLV_API_OCE: support for OCE
++ * @IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE: new beacon template
+ * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used
++ * @IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL: WoWLAN key material support
+ * @IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field
+ * indicating low latency direction.
+ * @IWL_UCODE_TLV_API_DEPRECATE_TTAK: RX status flag TTAK ok (bit 7) is
+@@ -245,6 +248,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
+ * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S.
+ * @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of
+ * STA_CONTEXT_DOT11AX_API_S
++ * @IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE: WoWLAN TCP-SYN wake support
+ * @IWL_UCODE_TLV_API_FTM_RTT_ACCURACY: version 7 of the range response API
+ * is supported by FW, this indicates the RTT confidence value
+ * @IWL_UCODE_TLV_API_SAR_TABLE_VER: This ucode supports different sar
+@@ -253,6 +257,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
+ * SCAN_CONFIG_DB_CMD_API_S.
+ * @IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP: support for setting adaptive dwell
+ * number of APs in the 5 GHz band
++ * @IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER: extended channel config in scan
+ * @IWL_UCODE_TLV_API_BAND_IN_RX_DATA: FW reports band number in RX notification
+ * @IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX: Firmware offloaded the station disable tx
+ * logic.
+@@ -352,16 +357,24 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
+ * @IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT: the firmware supports setting
+ * stabilization latency for SoCs.
+ * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification
++ * @IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT: binding CDB support
++ * @IWL_UCODE_TLV_CAPA_CDB_SUPPORT: CDB support
++ * @IWL_UCODE_TLV_CAPA_D0I3_END_FIRST: D0I3 end command comes first
+ * @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm
+ * @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related
+ * @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2
+- * IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command
++ * @IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command
+ * @IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS: firmware supports ultra high band
+ * (6 GHz).
+ * @IWL_UCODE_TLV_CAPA_CS_MODIFY: firmware supports modify action CSA command
++ * @IWL_UCODE_TLV_CAPA_SET_LTR_GEN2: LTR gen2 support
++ * @IWL_UCODE_TLV_CAPA_TAS_CFG: TAS configuration support
++ * @IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD: session protection command
++ * @IWL_UCODE_TLV_CAPA_SET_PPAG: PPAG support
+ * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
+ * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
+ * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
++ * @IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT: MQ RX support
+ * @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA
+ * countdown offloading. Beacon notifications are not sent to the host.
+ * The fw also offloads TBTT alignment.
+@@ -383,23 +396,46 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
+ * command size (command version 4) that supports toggling ACK TX
+ * power reduction.
+ * @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3
++ * @IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT: LED command support
+ * @IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT: MCC response support 11ax
+ * capability.
+ * @IWL_UCODE_TLV_CAPA_CSI_REPORTING: firmware is capable of being configured
+ * to report the CSI information with (certain) RX frames
++ * @IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP: suspend/resume command
++ * @IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP: support for DBGC
++ * buffer allocation command
+ * @IWL_UCODE_TLV_CAPA_FTM_CALIBRATED: has FTM calibrated and thus supports both
+ * initiator and responder
+ * @IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA: supports (de)activating UNII-4
+ * for US/CA/WW from BIOS
++ * @IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT: supports PSC channels
++ * @IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT: BIGTK support
+ * @IWL_UCODE_TLV_CAPA_PROTECTED_TWT: Supports protection of TWT action frames
+ * @IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE: Supports the firmware handshake in
+ * reset flow
+ * @IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN: Support for passive scan on 6GHz PSC
+ * channels even when these are not enabled.
++ * @IWL_UCODE_TLV_CAPA_HIDDEN_6GHZ_SCAN: hidden SSID 6 GHz scan support
++ * @IWL_UCODE_TLV_CAPA_BROADCAST_TWT: broadcast TWT support
++ * @IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO: support for BT-coex high
++ * priority for 802.1X/4-way-HS
++ * @IWL_UCODE_TLV_CAPA_BAID_ML_SUPPORT: multi-link BAID support
++ * @IWL_UCODE_TLV_CAPA_SYNCED_TIME: synced time command support
++ * @IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM: time sync support
++ * @IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT: BIGTK TX support
++ * @IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT: MLD API support
++ * @IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT: fixed antenna scan support
++ * @IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT: PPAG China BIOS support
++ * @IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT: BTM protocol offload support
++ * @IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT: STA command MFP support
++ * @IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT: sniffer validate bits support
++ * @IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT: China 2022 regulator support
+ * @IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT: Support for indicating dump collection
+ * complete to FW.
+ * @IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT: Support SPP (signaling and payload
+ * protected) A-MSDU.
++ * @IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT: support for DBGC fragmented
++ * DRAM buffers
+ * @IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT: Support secure LTF measurement.
+ * @IWL_UCODE_TLV_CAPA_MONITOR_PASSIVE_CHANS: Support monitor mode on otherwise
+ * passive channels
+@@ -407,6 +443,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
+ * for CA from BIOS.
+ * @IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT: supports %TAS_UHB_ALLOWED_CANADA
+ * @IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT: external FSEQ image support
++ * @IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT: FW reset handshake is needed
++ * during assert handling even if the dump isn't split
+ * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of
+ * handling raw DSM table data.
+ *
+@@ -487,12 +525,7 @@ enum iwl_ucode_tlv_capa {
+
+ /* set 3 */
+ IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA = (__force iwl_ucode_tlv_capa_t)96,
+-
+- /*
+- * @IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT: supports PSC channels
+- */
+ IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)98,
+-
+ IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100,
+ IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT = (__force iwl_ucode_tlv_capa_t)103,
+ IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104,
+@@ -514,11 +547,8 @@ enum iwl_ucode_tlv_capa {
+ IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT = (__force iwl_ucode_tlv_capa_t)125,
+
+ /* set 4 */
+- /**
+- * @IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT: FW reset handshake is needed
+- * during assert handling even if the dump isn't split
+- */
+- IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0),
++
++ IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0),
+ IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1),
+ NUM_IWL_UCODE_TLV_CAPA
+ /*
+@@ -852,6 +882,8 @@ struct iwl_fw_dbg_trigger_low_rssi {
+ * @start_assoc_denied: number of denied association to start recording
+ * @start_assoc_timeout: number of association timeout to start recording
+ * @start_connection_loss: number of connection loss to start recording
++ * @reserved: reserved
++ * @reserved2: reserved
+ */
+ struct iwl_fw_dbg_trigger_mlme {
+ u8 stop_auth_denied;
+@@ -885,6 +917,7 @@ struct iwl_fw_dbg_trigger_mlme {
+ * @p2p_device: timeout for the queues of a P2P device in ms
+ * @ibss: timeout for the queues of an IBSS in ms
+ * @tdls: timeout for the queues of a TDLS station in ms
++ * @reserved: reserved
+ */
+ struct iwl_fw_dbg_trigger_txq_timer {
+ __le32 command_queue;
+@@ -900,7 +933,7 @@ struct iwl_fw_dbg_trigger_txq_timer {
+
+ /**
+ * struct iwl_fw_dbg_trigger_time_event - configures a time event trigger
+- * time_Events: a list of tuples <id, action_bitmap>. The driver will issue a
++ * @time_events: a list of tuples <id, action_bitmap>. The driver will issue a
+ * trigger each time a time event notification that relates to time event
+ * id with one of the actions in the bitmap is received and
+ * BIT(notif->status) is set in status_bitmap.
+@@ -916,19 +949,19 @@ struct iwl_fw_dbg_trigger_time_event {
+
+ /**
+ * struct iwl_fw_dbg_trigger_ba - configures BlockAck related trigger
+- * rx_ba_start: tid bitmap to configure on what tid the trigger should occur
++ * @rx_ba_start: tid bitmap to configure on what tid the trigger should occur
+ * when an Rx BlockAck session is started.
+- * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur
++ * @rx_ba_stop: tid bitmap to configure on what tid the trigger should occur
+ * when an Rx BlockAck session is stopped.
+- * tx_ba_start: tid bitmap to configure on what tid the trigger should occur
++ * @tx_ba_start: tid bitmap to configure on what tid the trigger should occur
+ * when a Tx BlockAck session is started.
+- * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur
++ * @tx_ba_stop: tid bitmap to configure on what tid the trigger should occur
+ * when a Tx BlockAck session is stopped.
+- * rx_bar: tid bitmap to configure on what tid the trigger should occur
++ * @rx_bar: tid bitmap to configure on what tid the trigger should occur
+ * when a BAR is received (for a Tx BlockAck session).
+- * tx_bar: tid bitmap to configure on what tid the trigger should occur
++ * @tx_bar: tid bitmap to configure on what tid the trigger should occur
+ * when a BAR is send (for an Rx BlocAck session).
+- * frame_timeout: tid bitmap to configure on what tid the trigger should occur
++ * @frame_timeout: tid bitmap to configure on what tid the trigger should occur
+ * when a frame times out in the reordering buffer.
+ */
+ struct iwl_fw_dbg_trigger_ba {
+@@ -946,6 +979,7 @@ struct iwl_fw_dbg_trigger_ba {
+ * @action_bitmap: the TDLS action to trigger the collection upon
+ * @peer_mode: trigger on specific peer or all
+ * @peer: the TDLS peer to trigger the collection on
++ * @reserved: reserved
+ */
+ struct iwl_fw_dbg_trigger_tdls {
+ u8 action_bitmap;
+@@ -958,6 +992,7 @@ struct iwl_fw_dbg_trigger_tdls {
+ * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response
+ * status.
+ * @statuses: the list of statuses to trigger the collection on
++ * @reserved: reserved
+ */
+ struct iwl_fw_dbg_trigger_tx_status {
+ struct tx_status {
+@@ -971,6 +1006,7 @@ struct iwl_fw_dbg_trigger_tx_status {
+ * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
+ * @id: conf id
+ * @usniffer: should the uSniffer image be used
++ * @reserved: reserved
+ * @num_of_hcmds: how many HCMDs to send are present here
+ * @hcmd: a variable length host command to be sent to apply the configuration.
+ * If there is more than one HCMD to send, they will appear one after the
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h
+index 5256f20623e90..045a3e0094291 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/img.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h
+@@ -14,14 +14,13 @@
+ #include "error-dump.h"
+
+ /**
+- * enum iwl_ucode_type
+- *
+- * The type of ucode.
++ * enum iwl_ucode_type - type of ucode
+ *
+ * @IWL_UCODE_REGULAR: Normal runtime ucode
+ * @IWL_UCODE_INIT: Initial ucode
+ * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
+ * @IWL_UCODE_REGULAR_USNIFFER: Normal runtime ucode when using usniffer image
++ * @IWL_UCODE_TYPE_MAX: (internal value)
+ */
+ enum iwl_ucode_type {
+ IWL_UCODE_REGULAR,
+@@ -122,7 +121,7 @@ struct fw_img {
+ #define FW_ADDR_CACHE_CONTROL 0xC0000000UL
+
+ /**
+- * struct iwl_fw_paging
++ * struct iwl_fw_paging - FW paging descriptor
+ * @fw_paging_phys: page phy pointer
+ * @fw_paging_block: pointer to the allocated block
+ * @fw_paging_size: page size
+@@ -197,6 +196,11 @@ struct iwl_dump_exclude {
+ * @dump_excl_wowlan: image dump exclusion areas for WoWLAN image
+ * @pnvm_data: PNVM data embedded in the .ucode file, if any
+ * @pnvm_size: size of the embedded PNVM data
++ * @dbg: debug data, see &struct iwl_fw_dbg
++ * @default_calib: default calibration data
++ * @phy_config: PHY configuration flags
++ * @valid_rx_ant: valid RX antenna bitmap
++ * @valid_tx_ant: valid TX antenna bitmap
+ */
+ struct iwl_fw {
+ u32 ucode_ver;
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+index 806f9bcdf4f50..57570ff15622e 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+@@ -45,6 +45,8 @@ struct iwl_fwrt_shared_mem_cfg {
+ * struct iwl_fwrt_dump_data - dump data
+ * @trig: trigger the worker was scheduled upon
+ * @fw_pkt: packet received from FW
++ * @desc: dump descriptor
++ * @monitor_only: only dump for monitor
+ *
+ * Note that the decision which part of the union is used
+ * is based on iwl_trans_dbg_ini_valid(): the 'trig' part
+@@ -68,6 +70,7 @@ struct iwl_fwrt_dump_data {
+ * struct iwl_fwrt_wk_data - dump worker data struct
+ * @idx: index of the worker
+ * @wk: worker
++ * @dump_data: dump data
+ */
+ struct iwl_fwrt_wk_data {
+ u8 idx;
+@@ -91,8 +94,8 @@ struct iwl_txf_iter_data {
+
+ /**
+ * struct iwl_fw_runtime - runtime data for firmware
++ * @trans: transport pointer
+ * @fw: firmware image
+- * @cfg: NIC configuration
+ * @dev: device pointer
+ * @ops: user ops
+ * @ops_ctx: user ops context
+@@ -117,6 +120,23 @@ struct iwl_txf_iter_data {
+ * zero (default initialization) means it hasn't been read yet,
+ * and BIT(0) is set when it has since function 0 also has this
+ * bitmap and is always supported
++ * @geo_enabled: WGDS table is present
++ * @geo_num_profiles: number of geo profiles
++ * @geo_rev: geo profiles table revision
++ * @ppag_chains: PPAG table data
++ * @ppag_flags: PPAG flags
++ * @reduced_power_flags: reduced power flags
++ * @sanitize_ctx: context for dump sanitizer
++ * @sanitize_ops: dump sanitizer ops
++ * @sar_chain_a_profile: SAR chain A profile
++ * @sar_chain_b_profile: SAR chain B profile
++ * @sgom_enabled: SGOM enabled
++ * @sgom_table: SGOM table
++ * @timestamp: timestamp marker data
++ * @timestamp.wk: timestamp marking worker
++ * @timestamp.seq: timestamp marking sequence
++ * @timestamp.delay: timestamp marking worker delay
++ * @tpc_enabled: TPC enabled
+ */
+ struct iwl_fw_runtime {
+ struct iwl_trans *trans;
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+index a607e7ab914ba..502c6a1cf4f86 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+@@ -385,7 +385,7 @@ struct iwl_mac_cfg {
+ #define IWL_NUM_RBDS_EHT (512 * 8)
+
+ /**
+- * struct iwl_rf_cfg
++ * struct iwl_rf_cfg - RF/CRF configuration data
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ * (.ucode) will be added to filename before loading from disk. The
+ * filename is constructed as <fw_name_pre>-<api>.ucode.
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h
+index 7ed6329fd8ca1..fe4e46a0edbda 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2018-2023 Intel Corporation
++ * Copyright (C) 2018-2023, 2025 Intel Corporation
+ */
+ #ifndef __iwl_dbg_tlv_h__
+ #define __iwl_dbg_tlv_h__
+@@ -32,7 +32,7 @@ union iwl_dbg_tlv_tp_data {
+ };
+
+ /**
+- * struct iwl_dbg_tlv_time_point_data
++ * struct iwl_dbg_tlv_time_point_data - debug time point data
+ * @trig_list: list of triggers
+ * @active_trig_list: list of active triggers
+ * @hcmd_list: list of host commands
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
+index 595300a14639d..a0b67e8aba8da 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
+@@ -62,7 +62,8 @@ struct iwl_rf_cfg;
+ * starts the driver: fetches the firmware. This should be called by bus
+ * specific system flows implementations. For example, the bus specific probe
+ * function should do bus related operations only, and then call to this
+- * function. It returns the driver object or %NULL if an error occurred.
++ * function.
++ * Return: the driver object or %NULL if an error occurred.
+ */
+ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans);
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
+index 21eabfc3ffc84..0476df7b7f179 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
+@@ -1,6 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+ /*
+- * Copyright (C) 2005-2014, 2018-2022, 2024 Intel Corporation
++ * Copyright (C) 2005-2014, 2018-2022, 2024-2025 Intel Corporation
+ */
+ #ifndef __iwl_modparams_h__
+ #define __iwl_modparams_h__
+@@ -42,7 +42,7 @@ enum iwl_uapsd_disable {
+ };
+
+ /**
+- * struct iwl_mod_params
++ * struct iwl_mod_params - module parameters for iwlwifi
+ *
+ * Holds the module parameters
+ *
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+index cbc92abf9f87a..12f28bb0e859d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+@@ -115,11 +115,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
+ * iwl_parse_nvm_mcc_info - parse MCC (mobile country code) info coming from FW
+ *
+ * This function parses the regulatory channel data received as a
+- * MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain,
+- * to be fed into the regulatory core. In case the geo_info is set handle
+- * accordingly. An ERR_PTR is returned on error.
+- * If not given to the regulatory core, the user is responsible for freeing
+- * the regdomain returned here with kfree.
++ * MCC_UPDATE_CMD command.
++ *
++ * Return: a newly allocation regulatory domain, to be given to the regulatory
++ * core. In case the geo_info is set handle accordingly. An ERR_PTR is
++ * returned on error. If not given to the regulatory core, the user is
++ * responsible for freeing the regdomain returned here with kfree().
+ *
+ * @trans: the transport
+ * @num_of_ch: the number of channels
+@@ -140,6 +141,8 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
+ * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD,
+ * and saved for later use by the driver. Not all NVM sections are saved
+ * this way, only the needed ones.
++ * @length: length of the section
++ * @data: section data
+ */
+ struct iwl_nvm_section {
+ u16 length;
+@@ -148,6 +151,10 @@ struct iwl_nvm_section {
+
+ /**
+ * iwl_read_external_nvm - Reads external NVM from a file into nvm_sections
++ * @trans: the transport
++ * @nvm_file_name: the filename to request
++ * @nvm_sections: sections data to fill
++ * Return: 0 on success or an error code
+ */
+ int iwl_read_external_nvm(struct iwl_trans *trans,
+ const char *nvm_file_name,
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
+index a146d0e399f22..df6341dfc4a12 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
+@@ -185,6 +185,7 @@ void iwl_opmode_deregister(const char *name);
+ /**
+ * struct iwl_op_mode - operational mode
+ * @ops: pointer to its own ops
++ * @op_mode_specific: per-opmode data
+ *
+ * This holds an implementation of the mac80211 / fw API.
+ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+index a0cc5d7745e8f..a552669db6e2a 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+@@ -121,7 +121,7 @@ enum CMD_MODE {
+ #define DEF_CMD_PAYLOAD_SIZE 320
+
+ /**
+- * struct iwl_device_cmd
++ * struct iwl_device_cmd - device command structure
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for commands that
+@@ -516,7 +516,7 @@ enum iwl_trans_state {
+ */
+
+ /**
+- * enum iwl_ini_cfg_state
++ * enum iwl_ini_cfg_state - debug config state
+ * @IWL_INI_CFG_STATE_NOT_LOADED: no debug cfg was given
+ * @IWL_INI_CFG_STATE_LOADED: debug cfg was found and loaded
+ * @IWL_INI_CFG_STATE_CORRUPTED: debug cfg was found and some of the TLVs
+@@ -532,7 +532,7 @@ enum iwl_ini_cfg_state {
+ #define IWL_TRANS_NMI_TIMEOUT (HZ / 4)
+
+ /**
+- * struct iwl_dram_data
++ * struct iwl_dram_data - DRAM data descriptor
+ * @physical: page phy pointer
+ * @block: pointer to the allocated block/page
+ * @size: size of the block/page
+--
+2.53.0
+
--- /dev/null
+From b759c54760072eccf2dfe6a462c2080e1dd63885 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:33:26 +0200
+Subject: wifi: iwlwifi: mld: correctly set wifi generation data
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 687a95d204e72e52f2e6bc7a994cc82f76b2678f ]
+
+In each MAC context, the firmware expects the wifi generation
+data, i.e. whether or not HE/EHT (and in the future UHR) is
+enabled on that MAC.
+
+However, this is currently handled wrong in two ways:
+ - EHT is only enabled when the interface is also an MLD, but
+ we currently allow (despite the spec) connecting with EHT
+ but without MLO.
+ - when HE or EHT are used by TDLS peers, the firmware needs
+ to have them enabled regardless of the AP
+
+Fix this by iterating setting up the data depending on the
+interface type:
+ - for AP, just set it according to the BSS configuration
+ - for monitor, set it according to HW capabilities
+ - otherwise, particularly for client, iterate all stations
+ and then their links on the interface in question and set
+ according to their capabilities, this handles the AP and
+ TDLS peers. Re-calculate this whenever a TDLS station is
+ marked associated or removed so that it's kept updated,
+ for the AP it's already updated on assoc/disassoc.
+
+Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20260319110722.404713b22177.Ic972b5e557d011a5438f8f97c1e793cc829e2ea9@changeid
+Link: https://patch.msgid.link/20260324093333.2953495-1-miriam.rachel.korenblit@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/mld/iface.c | 101 ++++++++++++------
+ .../net/wireless/intel/iwlwifi/mld/mac80211.c | 19 ++++
+ 2 files changed, 88 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+index 240ce19996b34..80bcd18930c57 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+@@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
+ IEEE80211_HE_MAC_CAP2_ACK_EN);
+ }
+
+-static void iwl_mld_set_he_support(struct iwl_mld *mld,
+- struct ieee80211_vif *vif,
+- struct iwl_mac_config_cmd *cmd)
++struct iwl_mld_mac_wifi_gen_sta_iter_data {
++ struct ieee80211_vif *vif;
++ struct iwl_mac_wifi_gen_support *support;
++};
++
++static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
++ struct ieee80211_sta *sta)
+ {
+- if (vif->type == NL80211_IFTYPE_AP)
+- cmd->wifi_gen.he_ap_support = 1;
+- else
+- cmd->wifi_gen.he_support = 1;
++ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
++ struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
++ struct ieee80211_link_sta *link_sta;
++ unsigned int link_id;
++
++ if (mld_sta->vif != data->vif)
++ return;
++
++ for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
++ if (link_sta->he_cap.has_he)
++ data->support->he_support = 1;
++ if (link_sta->eht_cap.has_eht)
++ data->support->eht_support = 1;
++ }
++}
++
++static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
++ struct ieee80211_vif *vif,
++ struct iwl_mac_wifi_gen_support *support)
++{
++ struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
++ .vif = vif,
++ .support = support,
++ };
++ struct ieee80211_bss_conf *link_conf;
++ unsigned int link_id;
++
++ switch (vif->type) {
++ case NL80211_IFTYPE_MONITOR:
++ /* for sniffer, set to HW capabilities */
++ support->he_support = 1;
++ support->eht_support = mld->trans->cfg->eht_supported;
++ break;
++ case NL80211_IFTYPE_AP:
++ /* for AP set according to the link configs */
++ for_each_vif_active_link(vif, link_conf, link_id) {
++ support->he_ap_support |= link_conf->he_support;
++ support->eht_support |= link_conf->eht_support;
++ }
++ break;
++ default:
++ /*
++ * If we have MLO enabled, then the firmware needs to enable
++ * address translation for the station(s) we add. That depends
++ * on having EHT enabled in firmware, which in turn depends on
++ * mac80211 in the iteration below.
++ * However, mac80211 doesn't enable capabilities on the AP STA
++ * until it has parsed the association response successfully,
++ * so set EHT (and HE as a pre-requisite for EHT) when the vif
++ * is an MLD.
++ */
++ if (ieee80211_vif_is_mld(vif)) {
++ support->he_support = 1;
++ support->eht_support = 1;
++ }
++
++ ieee80211_iterate_stations_mtx(mld->hw,
++ iwl_mld_mac_wifi_gen_sta_iter,
++ &sta_iter_data);
++ break;
++ }
+ }
+
+ /* fill the common part for all interface types */
+@@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
+ u32 action)
+ {
+ struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+- struct ieee80211_bss_conf *link_conf;
+- unsigned int link_id;
+
+ lockdep_assert_wiphy(mld->wiphy);
+
+@@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
+ cmd->nic_not_ack_enabled =
+ cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
+
+- /* If we have MLO enabled, then the firmware needs to enable
+- * address translation for the station(s) we add. That depends
+- * on having EHT enabled in firmware, which in turn depends on
+- * mac80211 in the code below.
+- * However, mac80211 doesn't enable HE/EHT until it has parsed
+- * the association response successfully, so just skip all that
+- * and enable both when we have MLO.
+- */
+- if (ieee80211_vif_is_mld(vif)) {
+- iwl_mld_set_he_support(mld, vif, cmd);
+- cmd->wifi_gen.eht_support = 1;
+- return;
+- }
+-
+- for_each_vif_active_link(vif, link_conf, link_id) {
+- if (!link_conf->he_support)
+- continue;
+-
+- iwl_mld_set_he_support(mld, vif, cmd);
+-
+- /* EHT, if supported, was already set above */
+- break;
+- }
++ iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
+ }
+
+ static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+index 0f2db3ed58530..67b61765adf39 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+@@ -1686,6 +1686,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ iwl_mld_link_set_2mhz_block(mld, vif, sta);
++
++ if (sta->tdls) {
++ /*
++ * update MAC since wifi generation flags may change,
++ * we also update MAC on association to the AP via the
++ * vif assoc change
++ */
++ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
++ }
++
+ /* Now the link_sta's capabilities are set, update the FW */
+ iwl_mld_config_tlc(mld, vif, sta);
+
+@@ -1795,6 +1805,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,
+ /* just removed last TDLS STA, so enable PM */
+ iwl_mld_update_mac_power(mld, vif, false);
+ }
++
++ if (sta->tdls) {
++ /*
++ * update MAC since wifi generation flags may change,
++ * we also update MAC on disassociation to the AP via
++ * the vif assoc change
++ */
++ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
++ }
+ } else {
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From d3c2401ad580a8821cb9628c662cb2e860303b5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:33:24 +0200
+Subject: wifi: iwlwifi: mld: Fix MLO scan timing
+
+From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+
+[ Upstream commit ec66ec6a5a8f53e7c70085749e8d68f4431c630f ]
+
+Calculate MLO scan start time based on actual
+scan start notification from firmware instead of recording
+time when scan command is sent.
+
+Currently, MLO scan start time was captured immediately
+after sending the scan command to firmware. However, the
+actual scan start time may differ due to the FW being busy
+with a previous scan.
+
+In that case, the link selection code will think that the MLO
+scan is too old, and will warn.
+
+To fix it, Implement start scan notification handling to
+capture the precise moment when firmware begins the scan
+operation.
+
+Fixes: 9324731b9985 ("wifi: iwlwifi: mld: avoid selecting bad links")
+Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20260324113316.4c56b8bac533.I6e656d8cc30bb82c96aabadedd62bd67f4c46bf9@changeid
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../wireless/intel/iwlwifi/fw/api/commands.h | 5 ++++
+ .../net/wireless/intel/iwlwifi/fw/api/scan.h | 10 +++++++
+ drivers/net/wireless/intel/iwlwifi/mld/mld.c | 1 +
+ drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 4 +--
+ .../net/wireless/intel/iwlwifi/mld/notif.c | 5 ++++
+ drivers/net/wireless/intel/iwlwifi/mld/scan.c | 30 +++++++++++++++++--
+ drivers/net/wireless/intel/iwlwifi/mld/scan.h | 9 ++++--
+ 7 files changed, 56 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+index 997b0c9ce9840..6b3e7c614e54c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+@@ -296,6 +296,11 @@ enum iwl_legacy_cmds {
+ */
+ SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
+
++ /**
++ * @SCAN_START_NOTIFICATION_UMAC: uses &struct iwl_umac_scan_start
++ */
++ SCAN_START_NOTIFICATION_UMAC = 0xb2,
++
+ /**
+ * @MATCH_FOUND_NOTIFICATION: scan match found
+ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+index 60f0a4924ddfb..46fcc32608e34 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+@@ -1156,6 +1156,16 @@ enum iwl_umac_scan_abort_status {
+ IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
+ };
+
++/**
++ * struct iwl_umac_scan_start - scan start notification
++ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
++ * @reserved: for future use
++ */
++struct iwl_umac_scan_start {
++ __le32 uid;
++ __le32 reserved;
++} __packed; /* SCAN_START_UMAC_API_S_VER_1 */
++
+ /**
+ * struct iwl_umac_scan_complete - scan complete notification
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+index a6962256bdd12..3cfe1bcb7d4e5 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+@@ -171,6 +171,7 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = {
+ HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
+ HCMD_NAME(MAC_PM_POWER_TABLE),
+ HCMD_NAME(MFUART_LOAD_NOTIFICATION),
++ HCMD_NAME(SCAN_START_NOTIFICATION_UMAC),
+ HCMD_NAME(RSS_CONFIG_CMD),
+ HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
+ HCMD_NAME(REPLY_RX_MPDU_CMD),
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+index bf70e71aa5143..836f15dc54b52 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+@@ -732,7 +732,7 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld,
+
+ /* Ignore any BSS that was not seen in the last MLO scan */
+ if (ktime_before(link_conf->bss->ts_boottime,
+- mld->scan.last_mlo_scan_time))
++ mld->scan.last_mlo_scan_start_time))
+ continue;
+
+ data[n_data].link_id = link_id;
+@@ -939,7 +939,7 @@ static void _iwl_mld_select_links(struct iwl_mld *mld,
+ if (!mld_vif->authorized || hweight16(usable_links) <= 1)
+ return;
+
+- if (WARN(ktime_before(mld->scan.last_mlo_scan_time,
++ if (WARN(ktime_before(mld->scan.last_mlo_scan_start_time,
+ ktime_sub_ns(ktime_get_boottime_ns(),
+ 5ULL * NSEC_PER_SEC)),
+ "Last MLO scan was too long ago, can't select links\n"))
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+index 884973d0b3440..a3fd0b7387d69 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+@@ -284,6 +284,8 @@ static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld,
+ * at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
+ */
+
++CMD_VERSIONS(scan_start_notif,
++ CMD_VER_ENTRY(1, iwl_umac_scan_start))
+ CMD_VERSIONS(scan_complete_notif,
+ CMD_VER_ENTRY(1, iwl_umac_scan_complete))
+ CMD_VERSIONS(scan_iter_complete_notif,
+@@ -355,6 +357,7 @@ DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif,
+ link_id)
+ DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity)
+ DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid)
++DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid)
+ DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif,
+ mac_id)
+ DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif,
+@@ -397,6 +400,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
+ RX_HANDLER_SYNC)
+ RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif,
+ RX_HANDLER_SYNC)
++ RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC,
++ scan_start_notif)
+ RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC,
+ scan_complete_notif)
+ RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC,
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+index fd1022ddc9122..76ac6fd5f9ff3 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+@@ -473,6 +473,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld,
+ params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN;
+
++ if (scan_status == IWL_MLD_SCAN_INT_MLO)
++ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START;
++
+ if (params->enable_6ghz_passive)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN;
+
+@@ -1817,9 +1820,6 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,
+ ret = _iwl_mld_single_scan_start(mld, vif, req, &ies,
+ IWL_MLD_SCAN_INT_MLO);
+
+- if (!ret)
+- mld->scan.last_mlo_scan_time = ktime_get_boottime_ns();
+-
+ IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);
+ }
+
+@@ -1904,6 +1904,30 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
+ ieee80211_sched_scan_results(mld->hw);
+ }
+
++void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
++ struct iwl_rx_packet *pkt)
++{
++ struct iwl_umac_scan_complete *notif = (void *)pkt->data;
++ u32 uid = le32_to_cpu(notif->uid);
++
++ if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),
++ "FW reports out-of-range scan UID %d\n", uid))
++ return;
++
++ if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status),
++ "FW reports scan UID %d we didn't trigger\n", uid))
++ return;
++
++ IWL_DEBUG_SCAN(mld, "Scan started: uid=%u type=%u\n", uid,
++ mld->scan.uid_status[uid]);
++ if (IWL_FW_CHECK(mld, mld->scan.uid_status[uid] != IWL_MLD_SCAN_INT_MLO,
++ "FW reports scan start notification %d we didn't trigger\n",
++ mld->scan.uid_status[uid]))
++ return;
++
++ mld->scan.last_mlo_scan_start_time = ktime_get_boottime_ns();
++}
++
+ void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt)
+ {
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+index 69110f0cfc8e2..de5620e7f463b 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+@@ -27,6 +27,9 @@ int iwl_mld_sched_scan_start(struct iwl_mld *mld,
+ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt);
+
++void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
++ struct iwl_rx_packet *pkt);
++
+ void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt);
+
+@@ -114,8 +117,8 @@ enum iwl_mld_traffic_load {
+ * in jiffies.
+ * @last_start_time_jiffies: stores the last start time in jiffies
+ * (interface up/reset/resume).
+- * @last_mlo_scan_time: start time of the last MLO scan in nanoseconds since
+- * boot.
++ * @last_mlo_scan_start_time: start time of the last MLO scan in nanoseconds
++ * since boot.
+ */
+ struct iwl_mld_scan {
+ /* Add here fields that need clean up on restart */
+@@ -136,7 +139,7 @@ struct iwl_mld_scan {
+ void *cmd;
+ unsigned long last_6ghz_passive_jiffies;
+ unsigned long last_start_time_jiffies;
+- u64 last_mlo_scan_time;
++ u64 last_mlo_scan_start_time;
+ };
+
+ /**
+--
+2.53.0
+
--- /dev/null
+From e4e817851f6c1adb6a97e3da2bbaa6846a6ad716 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:33:25 +0200
+Subject: wifi: iwlwifi: mvm: don't send a 6E related command when not
+ supported
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit 323156c3541e23da7e582008a7ac30cd51b60acd ]
+
+MCC_ALLOWED_AP_TYPE_CMD is related to 6E support. Do not send it if the
+device doesn't support 6E.
+Apparently, the firmware is mistakenly advertising support for this
+command even on AX201 which does not support 6E and then the firmware
+crashes.
+
+Fixes: 0d2fc8821a7d ("wifi: iwlwifi: nvm: parse the VLP/AFC bit from regulatory")
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220804
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20260324113316.e171f0163f2a.I0c444d1f82d1773054e7ffc391ad49697d58f44e@changeid
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+index 865f973f677db..aa517978fc7a3 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+@@ -479,7 +479,8 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
+ .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+ };
+
+- if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
++ if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210 ||
++ !mvm->trans->cfg->uhb_supported) {
+ IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");
+ return;
+ }
+--
+2.53.0
+
--- /dev/null
+From 14d46c9ac199ac7068f7fc8ce842ca040a63e4bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 14:54:17 +0530
+Subject: wifi: mac80211: check tdls flag in ieee80211_tdls_oper
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 7d73872d949c488a1d7c308031d6a9d89b5e0a8b ]
+
+When NL80211_TDLS_ENABLE_LINK is called, the code only checks if the
+station exists but not whether it is actually a TDLS station. This
+allows the operation to proceed for non-TDLS stations, causing
+unintended side effects like modifying channel context and HT
+protection before failing.
+
+Add a check for sta->sta.tdls early in the ENABLE_LINK case, before
+any side effects occur, to ensure the operation is only allowed for
+actual TDLS peers.
+
+Reported-by: syzbot+56b6a844a4ea74487b7b@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=56b6a844a4ea74487b7b
+Tested-by: syzbot+56b6a844a4ea74487b7b@syzkaller.appspotmail.com
+Suggested-by: Johannes Berg <johannes@sipsolutions.net>
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Link: https://patch.msgid.link/20260313092417.520807-1-kartikey406@gmail.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/tdls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
+index ba5fbacbeeda6..1536cd71878c7 100644
+--- a/net/mac80211/tdls.c
++++ b/net/mac80211/tdls.c
+@@ -1449,7 +1449,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ }
+
+ sta = sta_info_get(sdata, peer);
+- if (!sta)
++ if (!sta || !sta->sta.tdls)
+ return -ENOLINK;
+
+ iee80211_tdls_recalc_chanctx(sdata, sta);
+--
+2.53.0
+
--- /dev/null
+From 919f770334f52053663716a5298cab950f8f69ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 16:01:27 +1030
+Subject: ALSA: usb-audio: Exclude Scarlett 2i2 1st Gen (8016) from
+ SKIP_IFACE_SETUP
+
+From: Geoffrey D. Bennett <g@b4.vu>
+
+[ Upstream commit a0dafdbd1049a8ea661a1a471be1b840bd8aed13 ]
+
+Same issue as the other 1st Gen Scarletts: QUIRK_FLAG_SKIP_IFACE_SETUP
+causes distorted audio on this revision of the Scarlett 2i2 1st Gen
+(1235:8016).
+
+Fixes: 38c322068a26 ("ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP")
+Reported-by: lukas-reineke [https://github.com/geoffreybennett/linux-fcp/issues/54]
+Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
+Link: https://patch.msgid.link/acytr8aEUba4VXmZ@m.b4.vu
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index f0554f023d3cb..a56fb8ef987ea 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2427,6 +2427,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_VALIDATE_RATES),
+ DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */
+ DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */
++ DEVICE_FLG(0x1235, 0x8016, 0), /* Focusrite Scarlett 2i2 1st Gen */
+ DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */
+ VENDOR_FLG(0x1235, /* Focusrite Novation */
+ QUIRK_FLAG_SKIP_IFACE_SETUP),
+--
+2.53.0
+
--- /dev/null
+From d21f301bc4002ddeb5e1f50510bd276f20c015fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 19:04:20 +0200
+Subject: ALSA: usb-audio: Exclude Scarlett Solo 1st Gen from SKIP_IFACE_SETUP
+
+From: Dag Smedberg <dag@dsmedberg.se>
+
+[ Upstream commit f025ac8c698ac7d29eb3b5025bcdaf7ad675785d ]
+
+Same issue that the Scarlett 2i2 1st Gen had:
+QUIRK_FLAG_SKIP_IFACE_SETUP causes distorted audio on the
+Scarlett Solo 1st Gen (1235:801c).
+
+Fixes: 38c322068a26 ("ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP")
+Reported-by: Dag Smedberg <dag@dsmedberg.se>
+Tested-by: Dag Smedberg <dag@dsmedberg.se>
+Signed-off-by: Dag Smedberg <dag@dsmedberg.se>
+Link: https://patch.msgid.link/20260329170420.4122-1-dag@dsmedberg.se
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index 09ed935107580..f0554f023d3cb 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2427,6 +2427,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_VALIDATE_RATES),
+ DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */
+ DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */
++ DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */
+ VENDOR_FLG(0x1235, /* Focusrite Novation */
+ QUIRK_FLAG_SKIP_IFACE_SETUP),
+ VENDOR_FLG(0x1511, /* AURALiC */
+--
+2.53.0
+
--- /dev/null
+From 83aeb5b79e350a8ae43af1511212b532729e7ef3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Mar 2026 14:44:28 +0100
+Subject: arm64/scs: Fix handling of advance_loc4
+
+From: Pepper Gray <hello@peppergray.xyz>
+
+[ Upstream commit d499e9627d70b1269020d59b95ed3e18bee6b8cd ]
+
+DW_CFA_advance_loc4 is defined but no handler is implemented. Its
+CFA opcode defaults to EDYNSCS_INVALID_CFA_OPCODE triggering an
+error which wrongfully prevents modules from loading.
+
+Link: https://bugs.gentoo.org/971060
+Signed-off-by: Pepper Gray <hello@peppergray.xyz>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/pi/patch-scs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c
+index bbe7d30ed12b3..dac568e4a54f2 100644
+--- a/arch/arm64/kernel/pi/patch-scs.c
++++ b/arch/arm64/kernel/pi/patch-scs.c
+@@ -192,6 +192,14 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
+ size -= 2;
+ break;
+
++ case DW_CFA_advance_loc4:
++ loc += *opcode++ * code_alignment_factor;
++ loc += (*opcode++ << 8) * code_alignment_factor;
++ loc += (*opcode++ << 16) * code_alignment_factor;
++ loc += (*opcode++ << 24) * code_alignment_factor;
++ size -= 4;
++ break;
++
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended:
+ size = skip_xleb128(&opcode, size);
+--
+2.53.0
+
--- /dev/null
+From b2128d3e80174fa319ebcd57e3fbd4000895e28d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:09:09 +0100
+Subject: ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on
+ failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+
+[ Upstream commit 622363757b2286dd2c2984b0d80255cbb35a0495 ]
+
+ep93xx_i2s_enable() calls clk_prepare_enable() on three clocks in
+sequence (mclk, sclk, lrclk) without checking the return value of any
+of them. If an intermediate enable fails, the clocks that were already
+enabled are never rolled back, leaking them until the next disable cycle
+— which may never come if the stream never started cleanly.
+
+Change ep93xx_i2s_enable() from void to int. Add error checking after
+each clk_prepare_enable() call and unwind already-enabled clocks on
+failure. Propagate the error through ep93xx_i2s_startup() and
+ep93xx_i2s_resume(), both of which already return int.
+
+Signed-off-by: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+Fixes: f4ff6b56bc8a ("ASoC: cirrus: i2s: Prepare clock before using it")
+Link: https://patch.msgid.link/20260324210909.45494-1-jihed.chaibi.dev@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/cirrus/ep93xx-i2s.c | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
+index cca01c03f0486..5dba741594fab 100644
+--- a/sound/soc/cirrus/ep93xx-i2s.c
++++ b/sound/soc/cirrus/ep93xx-i2s.c
+@@ -91,16 +91,28 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ return __raw_readl(info->regs + reg);
+ }
+
+-static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
++static int ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ {
+ unsigned base_reg;
++ int err;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+- clk_prepare_enable(info->mclk);
+- clk_prepare_enable(info->sclk);
+- clk_prepare_enable(info->lrclk);
++ err = clk_prepare_enable(info->mclk);
++ if (err)
++ return err;
++ err = clk_prepare_enable(info->sclk);
++ if (err) {
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
++ err = clk_prepare_enable(info->lrclk);
++ if (err) {
++ clk_disable_unprepare(info->sclk);
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+@@ -119,6 +131,8 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
+ EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
+ EP93XX_I2S_TXCTRL_TXUFIE);
++
++ return 0;
+ }
+
+ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+@@ -195,9 +209,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ {
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+- ep93xx_i2s_enable(info, substream->stream);
+-
+- return 0;
++ return ep93xx_i2s_enable(info, substream->stream);
+ }
+
+ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+@@ -373,14 +385,16 @@ static int ep93xx_i2s_suspend(struct snd_soc_component *component)
+ static int ep93xx_i2s_resume(struct snd_soc_component *component)
+ {
+ struct ep93xx_i2s_info *info = snd_soc_component_get_drvdata(component);
++ int err;
+
+ if (!snd_soc_component_active(component))
+ return 0;
+
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
++ err = ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
++ if (err)
++ return err;
+
+- return 0;
++ return ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ #else
+ #define ep93xx_i2s_suspend NULL
+--
+2.53.0
+
--- /dev/null
+From 5e000583da64b1e5774f34392bc1db3f026bad6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:15:21 +0000
+Subject: ASoC: Intel: boards: fix unmet dependency on PINCTRL
+
+From: Julian Braha <julianbraha@gmail.com>
+
+[ Upstream commit e920c36f2073d533bdf19ba6ab690432c8173b63 ]
+
+This reverts commit c073f0757663 ("ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43")
+
+Currently, SND_SOC_INTEL_SOUNDWIRE_SOF_MACH selects PINCTRL_CS42L43
+without also selecting or depending on PINCTRL, despite PINCTRL_CS42L43
+depending on PINCTRL.
+
+See the following Kbuild warning:
+
+WARNING: unmet direct dependencies detected for PINCTRL_CS42L43
+ Depends on [n]: PINCTRL [=n] && MFD_CS42L43 [=m]
+ Selected by [m]:
+ - SND_SOC_INTEL_SOUNDWIRE_SOF_MACH [=m] && SOUND [=y] && SND [=m] && SND_SOC [=m] && SND_SOC_INTEL_MACH [=y] && (SND_SOC_SOF_INTEL_COMMON [=m] || !SND_SOC_SOF_INTEL_COMMON [=m]) && SND_SOC_SOF_INTEL_SOUNDWIRE [=m] && I2C [=y] && SPI_MASTER [=y] && ACPI [=y] && (MFD_INTEL_LPSS [=n] || COMPILE_TEST [=y]) && (SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES [=n] || COMPILE_TEST [=y]) && SOUNDWIRE [=m]
+
+In response to v1 of this patch [1], Arnd pointed out that there is
+no compile-time dependency sof_sdw and the PINCTRL_CS42L43 driver.
+After testing, I can confirm that the kernel compiled with
+SND_SOC_INTEL_SOUNDWIRE_SOF_MACH enabled and PINCTRL_CS42L43 disabled.
+
+This unmet dependency was detected by kconfirm, a static analysis
+tool for Kconfig.
+
+Link: https://lore.kernel.org/all/b8aecc71-1fed-4f52-9f6c-263fbe56d493@app.fastmail.com/ [1]
+Fixes: c073f0757663 ("ASoC: Intel: sof_sdw: select PINCTRL_CS42L43 and SPI_CS42L43")
+Signed-off-by: Julian Braha <julianbraha@gmail.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://patch.msgid.link/20260325001522.1727678-1-julianbraha@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/Kconfig | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
+index c23fdb6aad4ca..1031d6497f55e 100644
+--- a/sound/soc/intel/boards/Kconfig
++++ b/sound/soc/intel/boards/Kconfig
+@@ -525,8 +525,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
+ select SND_SOC_CS42L43_SDW
+ select MFD_CS42L43
+ select MFD_CS42L43_SDW
+- select PINCTRL_CS42L43
+- select SPI_CS42L43
+ select SND_SOC_CS35L56_SPI
+ select SND_SOC_CS35L56_SDW
+ select SND_SOC_DMIC
+--
+2.53.0
+
--- /dev/null
+From 86441742dcd9d8b35a1c3d8c484f39ab69794c67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index c39dc5d367979..b6f764e524f7c 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From 04326786268467a9e8a61b97a0f233696c80966c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:01 +0300
+Subject: Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a2639a7f0f5bf7d73f337f8f077c19415c62ed2c ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+set_cig_params_sync, otherwise it's possible it is freed concurrently.
+
+Take hdev lock to prevent hci_conn from being deleted or modified
+concurrently. Just RCU lock is not suitable here, as we also want to
+avoid "tearing" in the configuration.
+
+Fixes: a091289218202 ("Bluetooth: hci_conn: Fix hci_le_set_cig_params")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_conn.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index 48aaccd35954a..a966d36d0e798 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -1843,9 +1843,13 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+ u8 aux_num_cis = 0;
+ u8 cis_id;
+
++ hci_dev_lock(hdev);
++
+ conn = hci_conn_hash_lookup_cig(hdev, cig_id);
+- if (!conn)
++ if (!conn) {
++ hci_dev_unlock(hdev);
+ return 0;
++ }
+
+ qos = &conn->iso_qos;
+ pdu->cig_id = cig_id;
+@@ -1884,6 +1888,8 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
+ }
+ pdu->num_cis = aux_num_cis;
+
++ hci_dev_unlock(hdev);
++
+ if (!pdu->num_cis)
+ return 0;
+
+--
+2.53.0
+
--- /dev/null
+From ae5f76c635037053215b88b0d95c2aa3af4f96da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:02 +0300
+Subject: Bluetooth: hci_event: fix potential UAF in
+ hci_le_remote_conn_param_req_evt
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit b255531b27da336571411248c2a72a350662bd09 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_le_remote_conn_param_req_evt, otherwise it's possible it is freed
+concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage.
+
+Fixes: 95118dd4edfec ("Bluetooth: hci_event: Use of a function table to handle LE subevents")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 33 ++++++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 467710a42d453..3869ff3b8bea6 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -6767,25 +6767,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ latency = le16_to_cpu(ev->latency);
+ timeout = le16_to_cpu(ev->timeout);
+
++ hci_dev_lock(hdev);
++
+ hcon = hci_conn_hash_lookup_handle(hdev, handle);
+- if (!hcon || hcon->state != BT_CONNECTED)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_UNKNOWN_CONN_ID);
++ if (!hcon || hcon->state != BT_CONNECTED) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_UNKNOWN_CONN_ID);
++ goto unlock;
++ }
+
+- if (max > hcon->le_conn_max_interval)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (max > hcon->le_conn_max_interval) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+- if (hci_check_conn_params(min, max, latency, timeout))
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (hci_check_conn_params(min, max, latency, timeout)) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+ if (hcon->role == HCI_ROLE_MASTER) {
+ struct hci_conn_params *params;
+ u8 store_hint;
+
+- hci_dev_lock(hdev);
+-
+ params = hci_conn_params_lookup(hdev, &hcon->dst,
+ hcon->dst_type);
+ if (params) {
+@@ -6798,8 +6804,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ store_hint = 0x00;
+ }
+
+- hci_dev_unlock(hdev);
+-
+ mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
+ store_hint, min, max, latency, timeout);
+ }
+@@ -6813,6 +6817,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ cp.max_ce_len = 0;
+
+ hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
+--
+2.53.0
+
--- /dev/null
+From 67197c54197b2f1a495333ba60f6b79b8fd6bd17 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 11:47:21 +0100
+Subject: Bluetooth: hci_h4: Fix race during initialization
+
+From: Jonathan Rissanen <jonathan.rissanen@axis.com>
+
+[ Upstream commit 0ffac654e95c1bdfe2d4edf28fb18d6ba1f103e6 ]
+
+Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during
+initialization") fixed a race for hci commands sent during initialization.
+However, there is still a race that happens if an hci event from one of
+these commands is received before HCI_UART_REGISTERED has been set at
+the end of hci_uart_register_dev(). The event will be ignored which
+causes the command to fail with a timeout in the log:
+
+"Bluetooth: hci0: command 0x1003 tx timeout"
+
+This is because the hci event receive path (hci_uart_tty_receive ->
+h4_recv) requires HCI_UART_REGISTERED to be set in h4_recv(), while the
+hci command transmit path (hci_uart_send_frame -> h4_enqueue) only
+requires HCI_UART_PROTO_INIT to be set in hci_uart_send_frame().
+
+The check for HCI_UART_REGISTERED was originally added in commit
+c2578202919a ("Bluetooth: Fix H4 crash from incoming UART packets")
+to fix a crash caused by hu->hdev being null dereferenced. That can no
+longer happen: once HCI_UART_PROTO_INIT is set in hci_uart_register_dev()
+all pointers (hu, hu->priv and hu->hdev) are valid, and
+hci_uart_tty_receive() already calls h4_recv() on HCI_UART_PROTO_INIT
+or HCI_UART_PROTO_READY.
+
+Remove the check for HCI_UART_REGISTERED in h4_recv() to fix the race
+condition.
+
+Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization")
+Signed-off-by: Jonathan Rissanen <jonathan.rissanen@axis.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/hci_h4.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
+index ec017df8572c8..1e9e2cad9ddf6 100644
+--- a/drivers/bluetooth/hci_h4.c
++++ b/drivers/bluetooth/hci_h4.c
+@@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
+ {
+ struct h4_struct *h4 = hu->priv;
+
+- if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+- return -EUNATCH;
+-
+ h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
+ h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
+ if (IS_ERR(h4->rx_skb)) {
+--
+2.53.0
+
--- /dev/null
+From 775e2e0ce2fe4c0361991b5fc6e24183a276f6ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 21:07:46 +0200
+Subject: Bluetooth: hci_sync: call destroy in hci_cmd_sync_run if immediate
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a834a0b66ec6fb743377201a0f4229bb2503f4ce ]
+
+hci_cmd_sync_run() may run the work immediately if called from existing
+sync work (otherwise it queues a new sync work). In this case it fails
+to call the destroy() function.
+
+On immediate run, make it behave same way as if item was queued
+successfully: call destroy, and return 0.
+
+The only callsite is hci_abort_conn() via hci_cmd_sync_run_once(), and
+this changes its return value. However, its return value is not used
+except as the return value for hci_disconnect(), and nothing uses the
+return value of hci_disconnect(). Hence there should be no behavior
+change anywhere.
+
+Fixes: c898f6d7b093b ("Bluetooth: hci_sync: Introduce hci_cmd_sync_run/hci_cmd_sync_run_once")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index 43b36581e336d..a7fc43273815c 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -801,8 +801,15 @@ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+ return -ENETDOWN;
+
+ /* If on cmd_sync_work then run immediately otherwise queue */
+- if (current_work() == &hdev->cmd_sync_work)
+- return func(hdev, data);
++ if (current_work() == &hdev->cmd_sync_work) {
++ int err;
++
++ err = func(hdev, data);
++ if (destroy)
++ destroy(hdev, data, err);
++
++ return 0;
++ }
+
+ return hci_cmd_sync_submit(hdev, func, data, destroy);
+ }
+--
+2.53.0
+
--- /dev/null
+From d5091f5f9f898930ceefb6317ff5fbd56454823b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 21:07:44 +0200
+Subject: Bluetooth: hci_sync: fix leaks when hci_cmd_sync_queue_once fails
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit aca377208e7f7322bf4e107cdec6e7d7e8aa7a88 ]
+
+When hci_cmd_sync_queue_once() returns with error, the destroy callback
+will not be called.
+
+Fix leaking references / memory on these failures.
+
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: 035c25007c9e ("Bluetooth: hci_sync: Fix UAF in le_read_features_complete")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index b501f89caf619..7dfd630d38f05 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -7429,13 +7429,16 @@ int hci_le_read_remote_features(struct hci_conn *conn)
+ * role is possible. Otherwise just transition into the
+ * connected state without requesting the remote features.
+ */
+- if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
++ if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
+ err = hci_cmd_sync_queue_once(hdev,
+ hci_le_read_remote_features_sync,
+ hci_conn_hold(conn),
+ le_read_features_complete);
+- else
++ if (err)
++ hci_conn_drop(conn);
++ } else {
+ err = -EOPNOTSUPP;
++ }
+
+ return (err == -EEXIST) ? 0 : err;
+ }
+@@ -7474,6 +7477,9 @@ int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
+
+ err = hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
+ pkt_type_changed);
++ if (err)
++ kfree(cp);
++
+ return (err == -EEXIST) ? 0 : err;
+ }
+
+@@ -7513,5 +7519,8 @@ int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
+
+ err = hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
+ le_phy_update_complete);
++ if (err)
++ kfree(cp);
++
+ return (err == -EEXIST) ? 0 : err;
+ }
+--
+2.53.0
+
--- /dev/null
+From 56b32254651a8110e864fd09098079d6ca06841b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 11:11:46 -0400
+Subject: Bluetooth: hci_sync: Fix UAF in le_read_features_complete
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 035c25007c9e698bef3826070ee34bb6d778020c ]
+
+This fixes the following backtrace caused by hci_conn being freed
+before le_read_features_complete but after
+hci_le_read_remote_features_sync so hci_conn_del -> hci_cmd_sync_dequeue
+is not able to prevent it:
+
+==================================================================
+BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:96 [inline]
+BUG: KASAN: slab-use-after-free in atomic_dec_and_test include/linux/atomic/atomic-instrumented.h:1383 [inline]
+BUG: KASAN: slab-use-after-free in hci_conn_drop include/net/bluetooth/hci_core.h:1688 [inline]
+BUG: KASAN: slab-use-after-free in le_read_features_complete+0x5b/0x340 net/bluetooth/hci_sync.c:7344
+Write of size 4 at addr ffff8880796b0010 by task kworker/u9:0/52
+
+CPU: 0 UID: 0 PID: 52 Comm: kworker/u9:0 Not tainted syzkaller #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025
+Workqueue: hci0 hci_cmd_sync_work
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:378 [inline]
+ print_report+0xcd/0x630 mm/kasan/report.c:482
+ kasan_report+0xe0/0x110 mm/kasan/report.c:595
+ check_region_inline mm/kasan/generic.c:194 [inline]
+ kasan_check_range+0x100/0x1b0 mm/kasan/generic.c:200
+ instrument_atomic_read_write include/linux/instrumented.h:96 [inline]
+ atomic_dec_and_test include/linux/atomic/atomic-instrumented.h:1383 [inline]
+ hci_conn_drop include/net/bluetooth/hci_core.h:1688 [inline]
+ le_read_features_complete+0x5b/0x340 net/bluetooth/hci_sync.c:7344
+ hci_cmd_sync_work+0x1ff/0x430 net/bluetooth/hci_sync.c:334
+ process_one_work+0x9ba/0x1b20 kernel/workqueue.c:3257
+ process_scheduled_works kernel/workqueue.c:3340 [inline]
+ worker_thread+0x6c8/0xf10 kernel/workqueue.c:3421
+ kthread+0x3c5/0x780 kernel/kthread.c:463
+ ret_from_fork+0x983/0xb10 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246
+ </TASK>
+
+Allocated by task 5932:
+ kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
+ kasan_save_track+0x14/0x30 mm/kasan/common.c:77
+ poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
+ __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:417
+ kmalloc_noprof include/linux/slab.h:957 [inline]
+ kzalloc_noprof include/linux/slab.h:1094 [inline]
+ __hci_conn_add+0xf8/0x1c70 net/bluetooth/hci_conn.c:963
+ hci_conn_add_unset+0x76/0x100 net/bluetooth/hci_conn.c:1084
+ le_conn_complete_evt+0x639/0x1f20 net/bluetooth/hci_event.c:5714
+ hci_le_enh_conn_complete_evt+0x23d/0x380 net/bluetooth/hci_event.c:5861
+ hci_le_meta_evt+0x357/0x5e0 net/bluetooth/hci_event.c:7408
+ hci_event_func net/bluetooth/hci_event.c:7716 [inline]
+ hci_event_packet+0x685/0x11c0 net/bluetooth/hci_event.c:7773
+ hci_rx_work+0x2c9/0xeb0 net/bluetooth/hci_core.c:4076
+ process_one_work+0x9ba/0x1b20 kernel/workqueue.c:3257
+ process_scheduled_works kernel/workqueue.c:3340 [inline]
+ worker_thread+0x6c8/0xf10 kernel/workqueue.c:3421
+ kthread+0x3c5/0x780 kernel/kthread.c:463
+ ret_from_fork+0x983/0xb10 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246
+
+Freed by task 5932:
+ kasan_save_stack+0x33/0x60 mm/kasan/common.c:56
+ kasan_save_track+0x14/0x30 mm/kasan/common.c:77
+ __kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:587
+ kasan_save_free_info mm/kasan/kasan.h:406 [inline]
+ poison_slab_object mm/kasan/common.c:252 [inline]
+ __kasan_slab_free+0x5f/0x80 mm/kasan/common.c:284
+ kasan_slab_free include/linux/kasan.h:234 [inline]
+ slab_free_hook mm/slub.c:2540 [inline]
+ slab_free mm/slub.c:6663 [inline]
+ kfree+0x2f8/0x6e0 mm/slub.c:6871
+ device_release+0xa4/0x240 drivers/base/core.c:2565
+ kobject_cleanup lib/kobject.c:689 [inline]
+ kobject_release lib/kobject.c:720 [inline]
+ kref_put include/linux/kref.h:65 [inline]
+ kobject_put+0x1e7/0x590 lib/kobject.c:737
+ put_device drivers/base/core.c:3797 [inline]
+ device_unregister+0x2f/0xc0 drivers/base/core.c:3920
+ hci_conn_del_sysfs+0xb4/0x180 net/bluetooth/hci_sysfs.c:79
+ hci_conn_cleanup net/bluetooth/hci_conn.c:173 [inline]
+ hci_conn_del+0x657/0x1180 net/bluetooth/hci_conn.c:1234
+ hci_disconn_complete_evt+0x410/0xa00 net/bluetooth/hci_event.c:3451
+ hci_event_func net/bluetooth/hci_event.c:7719 [inline]
+ hci_event_packet+0xa10/0x11c0 net/bluetooth/hci_event.c:7773
+ hci_rx_work+0x2c9/0xeb0 net/bluetooth/hci_core.c:4076
+ process_one_work+0x9ba/0x1b20 kernel/workqueue.c:3257
+ process_scheduled_works kernel/workqueue.c:3340 [inline]
+ worker_thread+0x6c8/0xf10 kernel/workqueue.c:3421
+ kthread+0x3c5/0x780 kernel/kthread.c:463
+ ret_from_fork+0x983/0xb10 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246
+
+The buggy address belongs to the object at ffff8880796b0000
+ which belongs to the cache kmalloc-8k of size 8192
+The buggy address is located 16 bytes inside of
+ freed 8192-byte region [ffff8880796b0000, ffff8880796b2000)
+
+The buggy address belongs to the physical page:
+page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x796b0
+head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
+anon flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff)
+page_type: f5(slab)
+raw: 00fff00000000040 ffff88813ff27280 0000000000000000 0000000000000001
+raw: 0000000000000000 0000000000020002 00000000f5000000 0000000000000000
+head: 00fff00000000040 ffff88813ff27280 0000000000000000 0000000000000001
+head: 0000000000000000 0000000000020002 00000000f5000000 0000000000000000
+head: 00fff00000000003 ffffea0001e5ac01 00000000ffffffff 00000000ffffffff
+head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
+page dumped because: kasan: bad access detected
+page_owner tracks the page as allocated
+page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd2040(__GFP_IO|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5657, tgid 5657 (dhcpcd-run-hook), ts 79819636908, free_ts 79814310558
+ set_page_owner include/linux/page_owner.h:32 [inline]
+ post_alloc_hook+0x1af/0x220 mm/page_alloc.c:1845
+ prep_new_page mm/page_alloc.c:1853 [inline]
+ get_page_from_freelist+0xd0b/0x31a0 mm/page_alloc.c:3879
+ __alloc_frozen_pages_noprof+0x25f/0x2440 mm/page_alloc.c:5183
+ alloc_pages_mpol+0x1fb/0x550 mm/mempolicy.c:2416
+ alloc_slab_page mm/slub.c:3075 [inline]
+ allocate_slab mm/slub.c:3248 [inline]
+ new_slab+0x2c3/0x430 mm/slub.c:3302
+ ___slab_alloc+0xe18/0x1c90 mm/slub.c:4651
+ __slab_alloc.constprop.0+0x63/0x110 mm/slub.c:4774
+ __slab_alloc_node mm/slub.c:4850 [inline]
+ slab_alloc_node mm/slub.c:5246 [inline]
+ __kmalloc_cache_noprof+0x477/0x800 mm/slub.c:5766
+ kmalloc_noprof include/linux/slab.h:957 [inline]
+ kzalloc_noprof include/linux/slab.h:1094 [inline]
+ tomoyo_print_bprm security/tomoyo/audit.c:26 [inline]
+ tomoyo_init_log+0xc8a/0x2140 security/tomoyo/audit.c:264
+ tomoyo_supervisor+0x302/0x13b0 security/tomoyo/common.c:2198
+ tomoyo_audit_env_log security/tomoyo/environ.c:36 [inline]
+ tomoyo_env_perm+0x191/0x200 security/tomoyo/environ.c:63
+ tomoyo_environ security/tomoyo/domain.c:672 [inline]
+ tomoyo_find_next_domain+0xec1/0x20b0 security/tomoyo/domain.c:888
+ tomoyo_bprm_check_security security/tomoyo/tomoyo.c:102 [inline]
+ tomoyo_bprm_check_security+0x12d/0x1d0 security/tomoyo/tomoyo.c:92
+ security_bprm_check+0x1b9/0x1e0 security/security.c:794
+ search_binary_handler fs/exec.c:1659 [inline]
+ exec_binprm fs/exec.c:1701 [inline]
+ bprm_execve fs/exec.c:1753 [inline]
+ bprm_execve+0x81e/0x1620 fs/exec.c:1729
+ do_execveat_common.isra.0+0x4a5/0x610 fs/exec.c:1859
+page last free pid 5657 tgid 5657 stack trace:
+ reset_page_owner include/linux/page_owner.h:25 [inline]
+ free_pages_prepare mm/page_alloc.c:1394 [inline]
+ __free_frozen_pages+0x7df/0x1160 mm/page_alloc.c:2901
+ discard_slab mm/slub.c:3346 [inline]
+ __put_partials+0x130/0x170 mm/slub.c:3886
+ qlink_free mm/kasan/quarantine.c:163 [inline]
+ qlist_free_all+0x4c/0xf0 mm/kasan/quarantine.c:179
+ kasan_quarantine_reduce+0x195/0x1e0 mm/kasan/quarantine.c:286
+ __kasan_slab_alloc+0x69/0x90 mm/kasan/common.c:352
+ kasan_slab_alloc include/linux/kasan.h:252 [inline]
+ slab_post_alloc_hook mm/slub.c:4948 [inline]
+ slab_alloc_node mm/slub.c:5258 [inline]
+ __kmalloc_cache_noprof+0x274/0x800 mm/slub.c:5766
+ kmalloc_noprof include/linux/slab.h:957 [inline]
+ tomoyo_print_header security/tomoyo/audit.c:156 [inline]
+ tomoyo_init_log+0x197/0x2140 security/tomoyo/audit.c:255
+ tomoyo_supervisor+0x302/0x13b0 security/tomoyo/common.c:2198
+ tomoyo_audit_env_log security/tomoyo/environ.c:36 [inline]
+ tomoyo_env_perm+0x191/0x200 security/tomoyo/environ.c:63
+ tomoyo_environ security/tomoyo/domain.c:672 [inline]
+ tomoyo_find_next_domain+0xec1/0x20b0 security/tomoyo/domain.c:888
+ tomoyo_bprm_check_security security/tomoyo/tomoyo.c:102 [inline]
+ tomoyo_bprm_check_security+0x12d/0x1d0 security/tomoyo/tomoyo.c:92
+ security_bprm_check+0x1b9/0x1e0 security/security.c:794
+ search_binary_handler fs/exec.c:1659 [inline]
+ exec_binprm fs/exec.c:1701 [inline]
+ bprm_execve fs/exec.c:1753 [inline]
+ bprm_execve+0x81e/0x1620 fs/exec.c:1729
+ do_execveat_common.isra.0+0x4a5/0x610 fs/exec.c:1859
+ do_execve fs/exec.c:1933 [inline]
+ __do_sys_execve fs/exec.c:2009 [inline]
+ __se_sys_execve fs/exec.c:2004 [inline]
+ __x64_sys_execve+0x8e/0xb0 fs/exec.c:2004
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0xcd/0xf80 arch/x86/entry/syscall_64.c:94
+
+Memory state around the buggy address:
+ ffff8880796aff00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff8880796aff80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+>ffff8880796b0000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+ ^
+ ffff8880796b0080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+ ffff8880796b0100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+==================================================================
+
+Fixes: a106e50be74b ("Bluetooth: HCI: Add support for LL Extended Feature Set")
+Reported-by: syzbot+87badbb9094e008e0685@syzkaller.appspotmail.com
+Tested-by: syzbot+87badbb9094e008e0685@syzkaller.appspotmail.com
+Closes: https://syzbot.org/bug?extid=87badbb9094e008e0685
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index 7dfd630d38f05..312526a5a1efb 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -7359,10 +7359,8 @@ static void le_read_features_complete(struct hci_dev *hdev, void *data, int err)
+
+ bt_dev_dbg(hdev, "err %d", err);
+
+- if (err == -ECANCELED)
+- return;
+-
+ hci_conn_drop(conn);
++ hci_conn_put(conn);
+ }
+
+ static int hci_le_read_all_remote_features_sync(struct hci_dev *hdev,
+@@ -7432,10 +7430,12 @@ int hci_le_read_remote_features(struct hci_conn *conn)
+ if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
+ err = hci_cmd_sync_queue_once(hdev,
+ hci_le_read_remote_features_sync,
+- hci_conn_hold(conn),
++ hci_conn_hold(hci_conn_get(conn)),
+ le_read_features_complete);
+- if (err)
++ if (err) {
+ hci_conn_drop(conn);
++ hci_conn_put(conn);
++ }
+ } else {
+ err = -EOPNOTSUPP;
+ }
+--
+2.53.0
+
--- /dev/null
+From 878ef2da9ac705157c7b86abd366e952946962b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 21:07:43 +0200
+Subject: Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if
+ exists
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit 2969554bcfccb5c609f6b6cd4a014933f3a66dd0 ]
+
+hci_cmd_sync_queue_once() needs to indicate whether a queue item was
+added, so caller can know if callbacks are called, so it can avoid
+leaking resources.
+
+Change the function to return -EEXIST if queue item already exists.
+
+Modify all callsites to handle that.
+
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: 035c25007c9e ("Bluetooth: hci_sync: Fix UAF in le_read_features_complete")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 53 +++++++++++++++++++++++++++-------------
+ 1 file changed, 36 insertions(+), 17 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index b4b5789ef3ab0..b501f89caf619 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -780,7 +780,7 @@ int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+ void *data, hci_cmd_sync_work_destroy_t destroy)
+ {
+ if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
+- return 0;
++ return -EEXIST;
+
+ return hci_cmd_sync_queue(hdev, func, data, destroy);
+ }
+@@ -3262,6 +3262,8 @@ static int update_passive_scan_sync(struct hci_dev *hdev, void *data)
+
+ int hci_update_passive_scan(struct hci_dev *hdev)
+ {
++ int err;
++
+ /* Only queue if it would have any effect */
+ if (!test_bit(HCI_UP, &hdev->flags) ||
+ test_bit(HCI_INIT, &hdev->flags) ||
+@@ -3271,8 +3273,9 @@ int hci_update_passive_scan(struct hci_dev *hdev)
+ hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ return 0;
+
+- return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
+- NULL);
++ err = hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
++ NULL);
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val)
+@@ -6934,8 +6937,11 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
+
+ int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
+ {
+- return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
+- NULL);
++ int err;
++
++ err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
++ NULL);
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
+@@ -6971,8 +6977,11 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
+
+ int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
+ {
+- return hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
+- create_le_conn_complete);
++ int err;
++
++ err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
++ create_le_conn_complete);
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
+@@ -7179,8 +7188,11 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
+
+ int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn)
+ {
+- return hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
+- create_pa_complete);
++ int err;
++
++ err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
++ create_pa_complete);
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
+@@ -7242,8 +7254,11 @@ static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
+
+ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
+ {
+- return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
+- create_big_complete);
++ int err;
++
++ err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
++ create_big_complete);
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ struct past_data {
+@@ -7335,7 +7350,7 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)
+ if (err)
+ kfree(data);
+
+- return err;
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ static void le_read_features_complete(struct hci_dev *hdev, void *data, int err)
+@@ -7422,7 +7437,7 @@ int hci_le_read_remote_features(struct hci_conn *conn)
+ else
+ err = -EOPNOTSUPP;
+
+- return err;
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ static void pkt_type_changed(struct hci_dev *hdev, void *data, int err)
+@@ -7448,6 +7463,7 @@ int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
+ {
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_change_conn_ptype *cp;
++ int err;
+
+ cp = kmalloc(sizeof(*cp), GFP_KERNEL);
+ if (!cp)
+@@ -7456,8 +7472,9 @@ int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
+ cp->handle = cpu_to_le16(conn->handle);
+ cp->pkt_type = cpu_to_le16(pkt_type);
+
+- return hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
+- pkt_type_changed);
++ err = hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
++ pkt_type_changed);
++ return (err == -EEXIST) ? 0 : err;
+ }
+
+ static void le_phy_update_complete(struct hci_dev *hdev, void *data, int err)
+@@ -7483,6 +7500,7 @@ int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
+ {
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_le_set_phy *cp;
++ int err;
+
+ cp = kmalloc(sizeof(*cp), GFP_KERNEL);
+ if (!cp)
+@@ -7493,6 +7511,7 @@ int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
+ cp->tx_phys = tx_phys;
+ cp->rx_phys = rx_phys;
+
+- return hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
+- le_phy_update_complete);
++ err = hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
++ le_phy_update_complete);
++ return (err == -EEXIST) ? 0 : err;
+ }
+--
+2.53.0
+
--- /dev/null
+From a894b49a3d50dcb45e6e01684fa51504e215bf18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Dec 2025 10:50:51 -0500
+Subject: Bluetooth: L2CAP: Add support for setting BT_PHY
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 132c0779d4a2d08541519cf04783bca52c6ec85c ]
+
+This enables client to use setsockopt(BT_PHY) to set the connection
+packet type/PHY:
+
+Example setting BT_PHY_BR_1M_1SLOT:
+
+< HCI Command: Change Conne.. (0x01|0x000f) plen 4
+ Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation)
+ Packet type: 0x331e
+ 2-DH1 may not be used
+ 3-DH1 may not be used
+ DM1 may be used
+ DH1 may be used
+ 2-DH3 may not be used
+ 3-DH3 may not be used
+ 2-DH5 may not be used
+ 3-DH5 may not be used
+> HCI Event: Command Status (0x0f) plen 4
+ Change Connection Packet Type (0x01|0x000f) ncmd 1
+ Status: Success (0x00)
+> HCI Event: Connection Packet Typ.. (0x1d) plen 5
+ Status: Success (0x00)
+ Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation)
+ Packet type: 0x331e
+ 2-DH1 may not be used
+ 3-DH1 may not be used
+ DM1 may be used
+ DH1 may be used
+ 2-DH3 may not be used
+ 3-DH3 may not be used
+ 2-DH5 may not be used
+
+Example setting BT_PHY_LE_1M_TX and BT_PHY_LE_1M_RX:
+
+< HCI Command: LE Set PHY (0x08|0x0032) plen 7
+ Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation)
+ All PHYs preference: 0x00
+ TX PHYs preference: 0x01
+ LE 1M
+ RX PHYs preference: 0x01
+ LE 1M
+ PHY options preference: Reserved (0x0000)
+> HCI Event: Command Status (0x0f) plen 4
+ LE Set PHY (0x08|0x0032) ncmd 1
+ Status: Success (0x00)
+> HCI Event: LE Meta Event (0x3e) plen 6
+ LE PHY Update Complete (0x0c)
+ Status: Success (0x00)
+ Handle: 1 Address: 00:AA:01:01:00:00 (Intel Corporation)
+ TX PHY: LE 1M (0x01)
+ RX PHY: LE 1M (0x01)
+
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: 035c25007c9e ("Bluetooth: hci_sync: Fix UAF in le_read_features_complete")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/bluetooth/bluetooth.h | 39 ++++++-----
+ include/net/bluetooth/hci.h | 9 +++
+ include/net/bluetooth/hci_core.h | 1 +
+ include/net/bluetooth/hci_sync.h | 3 +
+ net/bluetooth/hci_conn.c | 105 ++++++++++++++++++++++++++++++
+ net/bluetooth/hci_event.c | 26 ++++++++
+ net/bluetooth/hci_sync.c | 72 ++++++++++++++++++++
+ net/bluetooth/l2cap_sock.c | 20 +++++-
+ 8 files changed, 259 insertions(+), 16 deletions(-)
+
+diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
+index d46ed9011ee5d..89a60919050b0 100644
+--- a/include/net/bluetooth/bluetooth.h
++++ b/include/net/bluetooth/bluetooth.h
+@@ -130,21 +130,30 @@ struct bt_voice {
+ #define BT_RCVMTU 13
+ #define BT_PHY 14
+
+-#define BT_PHY_BR_1M_1SLOT 0x00000001
+-#define BT_PHY_BR_1M_3SLOT 0x00000002
+-#define BT_PHY_BR_1M_5SLOT 0x00000004
+-#define BT_PHY_EDR_2M_1SLOT 0x00000008
+-#define BT_PHY_EDR_2M_3SLOT 0x00000010
+-#define BT_PHY_EDR_2M_5SLOT 0x00000020
+-#define BT_PHY_EDR_3M_1SLOT 0x00000040
+-#define BT_PHY_EDR_3M_3SLOT 0x00000080
+-#define BT_PHY_EDR_3M_5SLOT 0x00000100
+-#define BT_PHY_LE_1M_TX 0x00000200
+-#define BT_PHY_LE_1M_RX 0x00000400
+-#define BT_PHY_LE_2M_TX 0x00000800
+-#define BT_PHY_LE_2M_RX 0x00001000
+-#define BT_PHY_LE_CODED_TX 0x00002000
+-#define BT_PHY_LE_CODED_RX 0x00004000
++#define BT_PHY_BR_1M_1SLOT BIT(0)
++#define BT_PHY_BR_1M_3SLOT BIT(1)
++#define BT_PHY_BR_1M_5SLOT BIT(2)
++#define BT_PHY_EDR_2M_1SLOT BIT(3)
++#define BT_PHY_EDR_2M_3SLOT BIT(4)
++#define BT_PHY_EDR_2M_5SLOT BIT(5)
++#define BT_PHY_EDR_3M_1SLOT BIT(6)
++#define BT_PHY_EDR_3M_3SLOT BIT(7)
++#define BT_PHY_EDR_3M_5SLOT BIT(8)
++#define BT_PHY_LE_1M_TX BIT(9)
++#define BT_PHY_LE_1M_RX BIT(10)
++#define BT_PHY_LE_2M_TX BIT(11)
++#define BT_PHY_LE_2M_RX BIT(12)
++#define BT_PHY_LE_CODED_TX BIT(13)
++#define BT_PHY_LE_CODED_RX BIT(14)
++
++#define BT_PHY_BREDR_MASK (BT_PHY_BR_1M_1SLOT | BT_PHY_BR_1M_3SLOT | \
++ BT_PHY_BR_1M_5SLOT | BT_PHY_EDR_2M_1SLOT | \
++ BT_PHY_EDR_2M_3SLOT | BT_PHY_EDR_2M_5SLOT | \
++ BT_PHY_EDR_3M_1SLOT | BT_PHY_EDR_3M_3SLOT | \
++ BT_PHY_EDR_3M_5SLOT)
++#define BT_PHY_LE_MASK (BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX | \
++ BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX | \
++ BT_PHY_LE_CODED_TX | BT_PHY_LE_CODED_RX)
+
+ #define BT_MODE 15
+
+diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
+index a27cd3626b872..a2beda3b0071d 100644
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -1883,6 +1883,15 @@ struct hci_cp_le_set_default_phy {
+ #define HCI_LE_SET_PHY_2M 0x02
+ #define HCI_LE_SET_PHY_CODED 0x04
+
++#define HCI_OP_LE_SET_PHY 0x2032
++struct hci_cp_le_set_phy {
++ __le16 handle;
++ __u8 all_phys;
++ __u8 tx_phys;
++ __u8 rx_phys;
++ __le16 phy_opts;
++} __packed;
++
+ #define HCI_OP_LE_SET_EXT_SCAN_PARAMS 0x2041
+ struct hci_cp_le_set_ext_scan_params {
+ __u8 own_addr_type;
+diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
+index 8aadf4cdead2b..71bbaa7dc790b 100644
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -2336,6 +2336,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
+ void *hci_recv_event_data(struct hci_dev *hdev, __u8 event);
+
+ u32 hci_conn_get_phy(struct hci_conn *conn);
++int hci_conn_set_phy(struct hci_conn *conn, u32 phys);
+
+ /* ----- HCI Sockets ----- */
+ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
+index 56076bbc981d9..73e494b2591de 100644
+--- a/include/net/bluetooth/hci_sync.h
++++ b/include/net/bluetooth/hci_sync.h
+@@ -191,3 +191,6 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn);
+ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le);
+
+ int hci_le_read_remote_features(struct hci_conn *conn);
++
++int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type);
++int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys);
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index 0f512c2c2fd3c..48aaccd35954a 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -2958,6 +2958,111 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
+ return phys;
+ }
+
++static u16 bt_phy_pkt_type(struct hci_conn *conn, u32 phys)
++{
++ u16 pkt_type = conn->pkt_type;
++
++ if (phys & BT_PHY_BR_1M_3SLOT)
++ pkt_type |= HCI_DM3 | HCI_DH3;
++ else
++ pkt_type &= ~(HCI_DM3 | HCI_DH3);
++
++ if (phys & BT_PHY_BR_1M_5SLOT)
++ pkt_type |= HCI_DM5 | HCI_DH5;
++ else
++ pkt_type &= ~(HCI_DM5 | HCI_DH5);
++
++ if (phys & BT_PHY_EDR_2M_1SLOT)
++ pkt_type &= ~HCI_2DH1;
++ else
++ pkt_type |= HCI_2DH1;
++
++ if (phys & BT_PHY_EDR_2M_3SLOT)
++ pkt_type &= ~HCI_2DH3;
++ else
++ pkt_type |= HCI_2DH3;
++
++ if (phys & BT_PHY_EDR_2M_5SLOT)
++ pkt_type &= ~HCI_2DH5;
++ else
++ pkt_type |= HCI_2DH5;
++
++ if (phys & BT_PHY_EDR_3M_1SLOT)
++ pkt_type &= ~HCI_3DH1;
++ else
++ pkt_type |= HCI_3DH1;
++
++ if (phys & BT_PHY_EDR_3M_3SLOT)
++ pkt_type &= ~HCI_3DH3;
++ else
++ pkt_type |= HCI_3DH3;
++
++ if (phys & BT_PHY_EDR_3M_5SLOT)
++ pkt_type &= ~HCI_3DH5;
++ else
++ pkt_type |= HCI_3DH5;
++
++ return pkt_type;
++}
++
++static int bt_phy_le_phy(u32 phys, u8 *tx_phys, u8 *rx_phys)
++{
++ if (!tx_phys || !rx_phys)
++ return -EINVAL;
++
++ *tx_phys = 0;
++ *rx_phys = 0;
++
++ if (phys & BT_PHY_LE_1M_TX)
++ *tx_phys |= HCI_LE_SET_PHY_1M;
++
++ if (phys & BT_PHY_LE_1M_RX)
++ *rx_phys |= HCI_LE_SET_PHY_1M;
++
++ if (phys & BT_PHY_LE_2M_TX)
++ *tx_phys |= HCI_LE_SET_PHY_2M;
++
++ if (phys & BT_PHY_LE_2M_RX)
++ *rx_phys |= HCI_LE_SET_PHY_2M;
++
++ if (phys & BT_PHY_LE_CODED_TX)
++ *tx_phys |= HCI_LE_SET_PHY_CODED;
++
++ if (phys & BT_PHY_LE_CODED_RX)
++ *rx_phys |= HCI_LE_SET_PHY_CODED;
++
++ return 0;
++}
++
++int hci_conn_set_phy(struct hci_conn *conn, u32 phys)
++{
++ u8 tx_phys, rx_phys;
++
++ switch (conn->type) {
++ case SCO_LINK:
++ case ESCO_LINK:
++ return -EINVAL;
++ case ACL_LINK:
++ /* Only allow setting BR/EDR PHYs if link type is ACL */
++ if (phys & ~BT_PHY_BREDR_MASK)
++ return -EINVAL;
++
++ return hci_acl_change_pkt_type(conn,
++ bt_phy_pkt_type(conn, phys));
++ case LE_LINK:
++ /* Only allow setting LE PHYs if link type is LE */
++ if (phys & ~BT_PHY_LE_MASK)
++ return -EINVAL;
++
++ if (bt_phy_le_phy(phys, &tx_phys, &rx_phys))
++ return -EINVAL;
++
++ return hci_le_set_phy(conn, tx_phys, rx_phys);
++ default:
++ return -EINVAL;
++ }
++}
++
+ static int abort_conn_sync(struct hci_dev *hdev, void *data)
+ {
+ struct hci_conn *conn = data;
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 58075bf720554..467710a42d453 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -2869,6 +2869,31 @@ static void hci_cs_le_ext_create_conn(struct hci_dev *hdev, u8 status)
+ hci_dev_unlock(hdev);
+ }
+
++static void hci_cs_le_set_phy(struct hci_dev *hdev, u8 status)
++{
++ struct hci_cp_le_set_phy *cp;
++ struct hci_conn *conn;
++
++ bt_dev_dbg(hdev, "status 0x%2.2x", status);
++
++ if (status)
++ return;
++
++ cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_PHY);
++ if (!cp)
++ return;
++
++ hci_dev_lock(hdev);
++
++ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
++ if (conn) {
++ conn->le_tx_def_phys = cp->tx_phys;
++ conn->le_rx_def_phys = cp->rx_phys;
++ }
++
++ hci_dev_unlock(hdev);
++}
++
+ static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
+ {
+ struct hci_cp_le_read_remote_features *cp;
+@@ -4359,6 +4384,7 @@ static const struct hci_cs {
+ HCI_CS(HCI_OP_LE_CREATE_CONN, hci_cs_le_create_conn),
+ HCI_CS(HCI_OP_LE_READ_REMOTE_FEATURES, hci_cs_le_read_remote_features),
+ HCI_CS(HCI_OP_LE_START_ENC, hci_cs_le_start_enc),
++ HCI_CS(HCI_OP_LE_SET_PHY, hci_cs_le_set_phy),
+ HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn),
+ HCI_CS(HCI_OP_LE_CREATE_CIS, hci_cs_le_create_cis),
+ HCI_CS(HCI_OP_LE_CREATE_BIG, hci_cs_le_create_big),
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index a7fc43273815c..b4b5789ef3ab0 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -7424,3 +7424,75 @@ int hci_le_read_remote_features(struct hci_conn *conn)
+
+ return err;
+ }
++
++static void pkt_type_changed(struct hci_dev *hdev, void *data, int err)
++{
++ struct hci_cp_change_conn_ptype *cp = data;
++
++ bt_dev_dbg(hdev, "err %d", err);
++
++ kfree(cp);
++}
++
++static int hci_change_conn_ptype_sync(struct hci_dev *hdev, void *data)
++{
++ struct hci_cp_change_conn_ptype *cp = data;
++
++ return __hci_cmd_sync_status_sk(hdev, HCI_OP_CHANGE_CONN_PTYPE,
++ sizeof(*cp), cp,
++ HCI_EV_PKT_TYPE_CHANGE,
++ HCI_CMD_TIMEOUT, NULL);
++}
++
++int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
++{
++ struct hci_dev *hdev = conn->hdev;
++ struct hci_cp_change_conn_ptype *cp;
++
++ cp = kmalloc(sizeof(*cp), GFP_KERNEL);
++ if (!cp)
++ return -ENOMEM;
++
++ cp->handle = cpu_to_le16(conn->handle);
++ cp->pkt_type = cpu_to_le16(pkt_type);
++
++ return hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
++ pkt_type_changed);
++}
++
++static void le_phy_update_complete(struct hci_dev *hdev, void *data, int err)
++{
++ struct hci_cp_le_set_phy *cp = data;
++
++ bt_dev_dbg(hdev, "err %d", err);
++
++ kfree(cp);
++}
++
++static int hci_le_set_phy_sync(struct hci_dev *hdev, void *data)
++{
++ struct hci_cp_le_set_phy *cp = data;
++
++ return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_SET_PHY,
++ sizeof(*cp), cp,
++ HCI_EV_LE_PHY_UPDATE_COMPLETE,
++ HCI_CMD_TIMEOUT, NULL);
++}
++
++int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
++{
++ struct hci_dev *hdev = conn->hdev;
++ struct hci_cp_le_set_phy *cp;
++
++ cp = kmalloc(sizeof(*cp), GFP_KERNEL);
++ if (!cp)
++ return -ENOMEM;
++
++ memset(cp, 0, sizeof(*cp));
++ cp->handle = cpu_to_le16(conn->handle);
++ cp->tx_phys = tx_phys;
++ cp->rx_phys = rx_phys;
++
++ return hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
++ le_phy_update_complete);
++}
+diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
+index f1131e4415c95..e8106d09f2a42 100644
+--- a/net/bluetooth/l2cap_sock.c
++++ b/net/bluetooth/l2cap_sock.c
+@@ -885,7 +885,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
+ struct bt_power pwr;
+ struct l2cap_conn *conn;
+ int err = 0;
+- u32 opt;
++ u32 opt, phys;
+ u16 mtu;
+ u8 mode;
+
+@@ -1066,6 +1066,24 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
+
+ break;
+
++ case BT_PHY:
++ if (sk->sk_state != BT_CONNECTED) {
++ err = -ENOTCONN;
++ break;
++ }
++
++ err = copy_safe_from_sockptr(&phys, sizeof(phys), optval,
++ optlen);
++ if (err)
++ break;
++
++ if (!chan->conn)
++ break;
++
++ conn = chan->conn;
++ err = hci_conn_set_phy(conn->hcon, phys);
++ break;
++
+ case BT_MODE:
+ if (!enable_ecred) {
+ err = -ENOPROTOOPT;
+--
+2.53.0
+
--- /dev/null
+From bd36a8a6680ee8bc7acd824cadbbf8916b918ffb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index f3da1bc38a551..996cef033e48e 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -7248,6 +7248,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From c939d5b69b2519421ca62cce3f9279c1c9faa6c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 22:25:26 +0800
+Subject: Bluetooth: MGMT: validate mesh send advertising payload length
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit bda93eec78cdbfe5cda00785cefebd443e56b88b ]
+
+mesh_send() currently bounds MGMT_OP_MESH_SEND by total command
+length, but it never verifies that the bytes supplied for the
+flexible adv_data[] array actually match the embedded adv_data_len
+field. MGMT_MESH_SEND_SIZE only covers the fixed header, so a
+truncated command can still pass the existing 20..50 byte range
+check and later drive the async mesh send path past the end of the
+queued command buffer.
+
+Keep rejecting zero-length and oversized advertising payloads, but
+validate adv_data_len explicitly and require the command length to
+exactly match the flexible array size before queueing the request.
+
+Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index 996cef033e48e..86fd2009de0d2 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -2478,6 +2478,7 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ struct mgmt_mesh_tx *mesh_tx;
+ struct mgmt_cp_mesh_send *send = data;
+ struct mgmt_rp_mesh_read_features rp;
++ u16 expected_len;
+ bool sending;
+ int err = 0;
+
+@@ -2485,12 +2486,19 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ !hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_NOT_SUPPORTED);
+- if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
+- len <= MGMT_MESH_SEND_SIZE ||
+- len > (MGMT_MESH_SEND_SIZE + 31))
++ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_REJECTED);
++
++ if (!send->adv_data_len || send->adv_data_len > 31)
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_REJECTED);
+
++ expected_len = struct_size(send, adv_data, send->adv_data_len);
++ if (expected_len != len)
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_INVALID_PARAMS);
++
+ hci_dev_lock(hdev);
+
+ memset(&rp, 0, sizeof(rp));
+--
+2.53.0
+
--- /dev/null
+From 6e9f35aa4a53672a4d7ac4c8917b23ad4dd859c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 23:16:45 +0800
+Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect()
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit 8a5b0135d4a5d9683203a3d9a12a711ccec5936b ]
+
+sco_sock_connect() checks sk_state and sk_type without holding
+the socket lock. Two concurrent connect() syscalls on the same
+socket can both pass the check and enter sco_connect(), leading
+to use-after-free.
+
+The buggy scenario involves three participants and was confirmed
+with additional logging instrumentation:
+
+ Thread A (connect): HCI disconnect: Thread B (connect):
+
+ sco_sock_connect(sk) sco_sock_connect(sk)
+ sk_state==BT_OPEN sk_state==BT_OPEN
+ (pass, no lock) (pass, no lock)
+ sco_connect(sk): sco_connect(sk):
+ hci_dev_lock hci_dev_lock
+ hci_connect_sco <- blocked
+ -> hcon1
+ sco_conn_add->conn1
+ lock_sock(sk)
+ sco_chan_add:
+ conn1->sk = sk
+ sk->conn = conn1
+ sk_state=BT_CONNECT
+ release_sock
+ hci_dev_unlock
+ hci_dev_lock
+ sco_conn_del:
+ lock_sock(sk)
+ sco_chan_del:
+ sk->conn=NULL
+ conn1->sk=NULL
+ sk_state=
+ BT_CLOSED
+ SOCK_ZAPPED
+ release_sock
+ hci_dev_unlock
+ (unblocked)
+ hci_connect_sco
+ -> hcon2
+ sco_conn_add
+ -> conn2
+ lock_sock(sk)
+ sco_chan_add:
+ sk->conn=conn2
+ sk_state=
+ BT_CONNECT
+ // zombie sk!
+ release_sock
+ hci_dev_unlock
+
+Thread B revives a BT_CLOSED + SOCK_ZAPPED socket back to
+BT_CONNECT. Subsequent cleanup triggers double sock_put() and
+use-after-free. Meanwhile conn1 is leaked as it was orphaned
+when sco_conn_del() cleared the association.
+
+Fix this by:
+- Moving lock_sock() before the sk_state/sk_type checks in
+ sco_sock_connect() to serialize concurrent connect attempts
+- Fixing the sk_type != SOCK_SEQPACKET check to actually
+ return the error instead of just assigning it
+- Adding a state re-check in sco_connect() after lock_sock()
+ to catch state changes during the window between the locks
+- Adding sco_pi(sk)->conn check in sco_chan_add() to prevent
+ double-attach of a socket to multiple connections
+- Adding hci_conn_drop() on sco_chan_add failure to prevent
+ HCI connection leaks
+
+Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm")
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/sco.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 6741b067d28b5..a446844354a18 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -298,7 +298,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+ int err = 0;
+
+ sco_conn_lock(conn);
+- if (conn->sk)
++ if (conn->sk || sco_pi(sk)->conn)
+ err = -EBUSY;
+ else
+ __sco_chan_add(conn, sk, parent);
+@@ -353,9 +353,20 @@ static int sco_connect(struct sock *sk)
+
+ lock_sock(sk);
+
++ /* Recheck state after reacquiring the socket lock, as another
++ * thread may have changed it (e.g., closed the socket).
++ */
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
++ hci_conn_drop(hcon);
++ err = -EBADFD;
++ goto unlock;
++ }
++
+ err = sco_chan_add(conn, sk, NULL);
+ if (err) {
+ release_sock(sk);
++ hci_conn_drop(hcon);
+ goto unlock;
+ }
+
+@@ -656,13 +667,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
+ addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
+- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
++ lock_sock(sk);
++
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
+ return -EBADFD;
++ }
+
+- if (sk->sk_type != SOCK_SEQPACKET)
+- err = -EINVAL;
++ if (sk->sk_type != SOCK_SEQPACKET) {
++ release_sock(sk);
++ return -EINVAL;
++ }
+
+- lock_sock(sk);
+ /* Set destination address and psm */
+ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
+ release_sock(sk);
+--
+2.53.0
+
--- /dev/null
+From 5472d3ac318b140d77bc756eecac952ed97851fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 23:51:37 -0700
+Subject: bnxt_en: Don't assume XDP is never enabled in
+ bnxt_init_dflt_ring_mode()
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit e4bf81dcad0a6fff2bbe5331d2c7fb30d45a788c ]
+
+The original code made the assumption that when we set up the initial
+default ring mode, we must be just loading the driver and XDP cannot
+be enabled yet. This is not true when the FW goes through a resource
+or capability change. Resource reservations will be cancelled and
+reinitialized with XDP already enabled. devlink reload with XDP enabled
+will also have the same issue. This scenario will cause the ring
+arithmetic to be all wrong in the bnxt_init_dflt_ring_mode() path
+causing failure:
+
+bnxt_en 0000:a1:00.0 ens2f0np0: bnxt_setup_int_mode err: ffffffea
+bnxt_en 0000:a1:00.0 ens2f0np0: bnxt_request_irq err: ffffffea
+bnxt_en 0000:a1:00.0 ens2f0np0: nic open fail (rc: ffffffea)
+
+Fix it by properly accounting for XDP in the bnxt_init_dflt_ring_mode()
+path by using the refactored helper functions in the previous patch.
+
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Fixes: ec5d31e3c15d ("bnxt_en: Handle firmware reset status during IF_UP.")
+Fixes: 228ea8c187d8 ("bnxt_en: implement devlink dev reload driver_reinit")
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260331065138.948205-3-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index bf888be2c54ed..b4ad85e183390 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -16443,6 +16443,10 @@ static void bnxt_adj_dflt_rings(struct bnxt *bp, bool sh)
+ else
+ bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
+ bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
++ if (sh && READ_ONCE(bp->xdp_prog)) {
++ bnxt_set_xdp_tx_rings(bp);
++ bnxt_set_cp_rings(bp, true);
++ }
+ }
+
+ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
+@@ -16484,16 +16488,17 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
+ rc = __bnxt_reserve_rings(bp);
+ if (rc && rc != -ENODEV)
+ netdev_warn(bp->dev, "Unable to reserve tx rings\n");
+- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
++
++ bnxt_adj_tx_rings(bp);
+ if (sh)
+- bnxt_trim_dflt_sh_rings(bp);
++ bnxt_adj_dflt_rings(bp, true);
+
+ /* Rings may have been trimmed, re-reserve the trimmed rings. */
+ if (bnxt_need_reserve_rings(bp)) {
+ rc = __bnxt_reserve_rings(bp);
+ if (rc && rc != -ENODEV)
+ netdev_warn(bp->dev, "2nd rings reservation failed.\n");
+- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
++ bnxt_adj_tx_rings(bp);
+ }
+ if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
+ bp->rx_nr_rings++;
+@@ -16527,7 +16532,7 @@ static int bnxt_init_dflt_ring_mode(struct bnxt *bp)
+ if (rc)
+ goto init_dflt_ring_err;
+
+- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
++ bnxt_adj_tx_rings(bp);
+
+ bnxt_set_dflt_rfs(bp);
+
+--
+2.53.0
+
--- /dev/null
+From 8927ad8fe9bb538d5b2a1aa960ce561d26adb9d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 23:51:36 -0700
+Subject: bnxt_en: Refactor some basic ring setup and adjustment logic
+
+From: Michael Chan <michael.chan@broadcom.com>
+
+[ Upstream commit ceee35e5674aa84cf9e504c2a9dae4587511556c ]
+
+Refactor out the basic code that trims the default rings, sets up and
+adjusts XDP TX rings and CP rings. There is no change in behavior.
+This is to prepare for the next bug fix patch.
+
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260331065138.948205-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: e4bf81dcad0a ("bnxt_en: Don't assume XDP is never enabled in bnxt_init_dflt_ring_mode()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 53 +++++++++++++------
+ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
+ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 5 +-
+ drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 5 +-
+ 4 files changed, 41 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 300324ea1e8aa..bf888be2c54ed 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -12917,6 +12917,21 @@ static int bnxt_tx_nr_rings_per_tc(struct bnxt *bp)
+ return bp->num_tc ? bp->tx_nr_rings / bp->num_tc : bp->tx_nr_rings;
+ }
+
++static void bnxt_set_xdp_tx_rings(struct bnxt *bp)
++{
++ bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc;
++ bp->tx_nr_rings += bp->tx_nr_rings_xdp;
++}
++
++static void bnxt_adj_tx_rings(struct bnxt *bp)
++{
++ /* Make adjustments if reserved TX rings are less than requested */
++ bp->tx_nr_rings -= bp->tx_nr_rings_xdp;
++ bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
++ if (bp->tx_nr_rings_xdp)
++ bnxt_set_xdp_tx_rings(bp);
++}
++
+ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
+ {
+ int rc = 0;
+@@ -12934,13 +12949,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
+ if (rc)
+ return rc;
+
+- /* Make adjustments if reserved TX rings are less than requested */
+- bp->tx_nr_rings -= bp->tx_nr_rings_xdp;
+- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+- if (bp->tx_nr_rings_xdp) {
+- bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc;
+- bp->tx_nr_rings += bp->tx_nr_rings_xdp;
+- }
++ bnxt_adj_tx_rings(bp);
+ rc = bnxt_alloc_mem(bp, irq_re_init);
+ if (rc) {
+ netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
+@@ -15377,11 +15386,19 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu)
+ return 0;
+ }
+
++void bnxt_set_cp_rings(struct bnxt *bp, bool sh)
++{
++ int tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
++
++ bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
++ tx_cp + bp->rx_nr_rings;
++}
++
+ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
+ {
+ struct bnxt *bp = netdev_priv(dev);
+ bool sh = false;
+- int rc, tx_cp;
++ int rc;
+
+ if (tc > bp->max_tc) {
+ netdev_err(dev, "Too many traffic classes requested: %d. Max supported is %d.\n",
+@@ -15414,9 +15431,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
+ bp->num_tc = 0;
+ }
+ bp->tx_nr_rings += bp->tx_nr_rings_xdp;
+- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+- bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
+- tx_cp + bp->rx_nr_rings;
++ bnxt_set_cp_rings(bp, sh);
+
+ if (netif_running(bp->dev))
+ return bnxt_open_nic(bp, true, false);
+@@ -16421,6 +16436,15 @@ static void bnxt_trim_dflt_sh_rings(struct bnxt *bp)
+ bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
+ }
+
++static void bnxt_adj_dflt_rings(struct bnxt *bp, bool sh)
++{
++ if (sh)
++ bnxt_trim_dflt_sh_rings(bp);
++ else
++ bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
++ bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
++}
++
+ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
+ {
+ int dflt_rings, max_rx_rings, max_tx_rings, rc;
+@@ -16446,11 +16470,8 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
+ return rc;
+ bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings);
+ bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings);
+- if (sh)
+- bnxt_trim_dflt_sh_rings(bp);
+- else
+- bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
+- bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
++
++ bnxt_adj_dflt_rings(bp, sh);
+
+ avail_msix = bnxt_get_max_func_irqs(bp) - bp->cp_nr_rings;
+ if (avail_msix >= BNXT_MIN_ROCE_CP_RINGS) {
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 4d94bacf9f012..9413818788c4e 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -2971,6 +2971,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
+ int tx_xdp);
+ int bnxt_fw_init_one(struct bnxt *bp);
+ bool bnxt_hwrm_reset_permitted(struct bnxt *bp);
++void bnxt_set_cp_rings(struct bnxt *bp, bool sh);
+ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
+ struct bnxt_ntuple_filter *bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr, u32 idx);
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+index fa452d6272e0f..34d9264d51950 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+@@ -945,7 +945,6 @@ static int bnxt_set_channels(struct net_device *dev,
+ bool sh = false;
+ int tx_xdp = 0;
+ int rc = 0;
+- int tx_cp;
+
+ if (channel->other_count)
+ return -EINVAL;
+@@ -1013,9 +1012,7 @@ static int bnxt_set_channels(struct net_device *dev,
+ if (tcs > 1)
+ bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
+
+- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+- bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
+- tx_cp + bp->rx_nr_rings;
++ bnxt_set_cp_rings(bp, sh);
+
+ /* After changing number of rx channels, update NTUPLE feature. */
+ netdev_update_features(dev);
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+index c94a391b1ba5b..06f35a61c1774 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+@@ -384,7 +384,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
+ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
+ {
+ struct net_device *dev = bp->dev;
+- int tx_xdp = 0, tx_cp, rc, tc;
++ int tx_xdp = 0, rc, tc;
+ struct bpf_prog *old;
+
+ netdev_assert_locked(dev);
+@@ -431,8 +431,7 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
+ }
+ bp->tx_nr_rings_xdp = tx_xdp;
+ bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
+- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+- bp->cp_nr_rings = max_t(int, tx_cp, bp->rx_nr_rings);
++ bnxt_set_cp_rings(bp, true);
+ bnxt_set_tpa_flags(bp);
+ bnxt_set_ring_params(bp);
+
+--
+2.53.0
+
--- /dev/null
+From 0ae3037ab8608aed10166d96e65ffcfd6b373abc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 23:51:38 -0700
+Subject: bnxt_en: Restore default stat ctxs for ULP when resource is available
+
+From: Pavan Chebbi <pavan.chebbi@broadcom.com>
+
+[ Upstream commit 071dbfa304e85a6b04a593e950d18fa170997288 ]
+
+During resource reservation, if the L2 driver does not have enough
+MSIX vectors to provide to the RoCE driver, it sets the stat ctxs for
+ULP also to 0 so that we don't have to reserve it unnecessarily.
+
+However, subsequently the user may reduce L2 rings thereby freeing up
+some resources that the L2 driver can now earmark for RoCE. In this
+case, the driver should restore the default ULP stat ctxs to make
+sure that all RoCE resources are ready for use.
+
+The RoCE driver may fail to initialize in this scenario without this
+fix.
+
+Fixes: d630624ebd70 ("bnxt_en: Utilize ulp client resources if RoCE is not registered")
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260331065138.948205-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index b4ad85e183390..d8c42349ded18 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -8002,6 +8002,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
+ ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
+ if (!ulp_msix)
+ bnxt_set_ulp_stat_ctxs(bp, 0);
++ else
++ bnxt_set_dflt_ulp_stat_ctxs(bp);
+
+ if (ulp_msix > bp->ulp_num_msix_want)
+ ulp_msix = bp->ulp_num_msix_want;
+--
+2.53.0
+
--- /dev/null
+From 6cb8d3bc5ef2546209dfa3c960f8f492b93d80b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 07:43:56 +0800
+Subject: bnxt_en: set backing store type from query type
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 4ee937107d52f9e5c350e4b5e629760e328b3d9f ]
+
+bnxt_hwrm_func_backing_store_qcaps_v2() stores resp->type from the
+firmware response in ctxm->type and later uses that value to index
+fixed backing-store metadata arrays such as ctx_arr[] and
+bnxt_bstore_to_trace[].
+
+ctxm->type is fixed by the current backing-store query type and matches
+the array index of ctx->ctx_arr. Set ctxm->type from the current loop
+variable instead of depending on resp->type.
+
+Also update the loop to advance type from next_valid_type in the for
+statement, which keeps the control flow simpler for non-valid and
+unchanged entries.
+
+Fixes: 6a4d0774f02d ("bnxt_en: Add support for new backing store query firmware API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Tested-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 2dadc7c668587..300324ea1e8aa 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -8623,7 +8623,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ struct hwrm_func_backing_store_qcaps_v2_output *resp;
+ struct hwrm_func_backing_store_qcaps_v2_input *req;
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+- u16 type;
++ u16 type, next_type = 0;
+ int rc;
+
+ rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2);
+@@ -8639,7 +8639,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+
+ resp = hwrm_req_hold(bp, req);
+
+- for (type = 0; type < BNXT_CTX_V2_MAX; ) {
++ for (type = 0; type < BNXT_CTX_V2_MAX; type = next_type) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ u8 init_val, init_off, i;
+ u32 max_entries;
+@@ -8652,7 +8652,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ if (rc)
+ goto ctx_done;
+ flags = le32_to_cpu(resp->flags);
+- type = le16_to_cpu(resp->next_valid_type);
++ next_type = le16_to_cpu(resp->next_valid_type);
+ if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) {
+ bnxt_free_one_ctx_mem(bp, ctxm, true);
+ continue;
+@@ -8667,7 +8667,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+ else
+ continue;
+ }
+- ctxm->type = le16_to_cpu(resp->type);
++ ctxm->type = type;
+ ctxm->entry_size = entry_size;
+ ctxm->flags = flags;
+ ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
+--
+2.53.0
+
--- /dev/null
+From 25d9f7d112a884d112a0a13b24e7dd605ebccb2c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 00:20:19 +0200
+Subject: bpf: Fix incorrect pruning due to atomic fetch precision tracking
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+[ Upstream commit 179ee84a89114b854ac2dd1d293633a7f6c8dac1 ]
+
+When backtrack_insn encounters a BPF_STX instruction with BPF_ATOMIC
+and BPF_FETCH, the src register (or r0 for BPF_CMPXCHG) also acts as
+a destination, thus receiving the old value from the memory location.
+
+The current backtracking logic does not account for this. It treats
+atomic fetch operations the same as regular stores where the src
+register is only an input. This leads the backtrack_insn to fail to
+propagate precision to the stack location, which is then not marked
+as precise!
+
+Later, the verifier's path pruning can incorrectly consider two states
+equivalent when they differ in terms of stack state. Meaning, two
+branches can be treated as equivalent and thus get pruned when they
+should not be seen as such.
+
+Fix it as follows: Extend the BPF_LDX handling in backtrack_insn to
+also cover atomic fetch operations via is_atomic_fetch_insn() helper.
+When the fetch dst register is being tracked for precision, clear it,
+and propagate precision over to the stack slot. For non-stack memory,
+the precision walk stops at the atomic instruction, same as regular
+BPF_LDX. This covers all fetch variants.
+
+Before:
+
+ 0: (b7) r1 = 8 ; R1=8
+ 1: (7b) *(u64 *)(r10 -8) = r1 ; R1=8 R10=fp0 fp-8=8
+ 2: (b7) r2 = 0 ; R2=0
+ 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2) ; R2=8 R10=fp0 fp-8=mmmmmmmm
+ 4: (bf) r3 = r10 ; R3=fp0 R10=fp0
+ 5: (0f) r3 += r2
+ mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1
+ mark_precise: frame0: regs=r2 stack= before 4: (bf) r3 = r10
+ mark_precise: frame0: regs=r2 stack= before 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2)
+ mark_precise: frame0: regs=r2 stack= before 2: (b7) r2 = 0
+ 6: R2=8 R3=fp8
+ 6: (b7) r0 = 0 ; R0=0
+ 7: (95) exit
+
+After:
+
+ 0: (b7) r1 = 8 ; R1=8
+ 1: (7b) *(u64 *)(r10 -8) = r1 ; R1=8 R10=fp0 fp-8=8
+ 2: (b7) r2 = 0 ; R2=0
+ 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2) ; R2=8 R10=fp0 fp-8=mmmmmmmm
+ 4: (bf) r3 = r10 ; R3=fp0 R10=fp0
+ 5: (0f) r3 += r2
+ mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1
+ mark_precise: frame0: regs=r2 stack= before 4: (bf) r3 = r10
+ mark_precise: frame0: regs=r2 stack= before 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2)
+ mark_precise: frame0: regs= stack=-8 before 2: (b7) r2 = 0
+ mark_precise: frame0: regs= stack=-8 before 1: (7b) *(u64 *)(r10 -8) = r1
+ mark_precise: frame0: regs=r1 stack= before 0: (b7) r1 = 8
+ 6: R2=8 R3=fp8
+ 6: (b7) r0 = 0 ; R0=0
+ 7: (95) exit
+
+Fixes: 5ffa25502b5a ("bpf: Add instructions for atomic_[cmp]xchg")
+Fixes: 5ca419f2864a ("bpf: Add BPF_FETCH field / create atomic_fetch_add instruction")
+Reported-by: STAR Labs SG <info@starlabs.sg>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/r/20260331222020.401848-1-daniel@iogearbox.net
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 0aea870b87a6c..d1394e16d108c 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -608,6 +608,13 @@ static bool is_atomic_load_insn(const struct bpf_insn *insn)
+ insn->imm == BPF_LOAD_ACQ;
+ }
+
++static bool is_atomic_fetch_insn(const struct bpf_insn *insn)
++{
++ return BPF_CLASS(insn->code) == BPF_STX &&
++ BPF_MODE(insn->code) == BPF_ATOMIC &&
++ (insn->imm & BPF_FETCH);
++}
++
+ static int __get_spi(s32 off)
+ {
+ return (-off - 1) / BPF_REG_SIZE;
+@@ -4356,10 +4363,24 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
+ * dreg still needs precision before this insn
+ */
+ }
+- } else if (class == BPF_LDX || is_atomic_load_insn(insn)) {
+- if (!bt_is_reg_set(bt, dreg))
++ } else if (class == BPF_LDX ||
++ is_atomic_load_insn(insn) ||
++ is_atomic_fetch_insn(insn)) {
++ u32 load_reg = dreg;
++
++ /*
++ * Atomic fetch operation writes the old value into
++ * a register (sreg or r0) and if it was tracked for
++ * precision, propagate to the stack slot like we do
++ * in regular ldx.
++ */
++ if (is_atomic_fetch_insn(insn))
++ load_reg = insn->imm == BPF_CMPXCHG ?
++ BPF_REG_0 : sreg;
++
++ if (!bt_is_reg_set(bt, load_reg))
+ return 0;
+- bt_clear_reg(bt, dreg);
++ bt_clear_reg(bt, load_reg);
+
+ /* scalars can only be spilled into stack w/o losing precision.
+ * Load from any other memory can be zero extended.
+--
+2.53.0
+
--- /dev/null
+From cbe7166e28f37b9b7225d532727b0d23bc4846d6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 9032c6d4dbbcc..11fe83d6109d7 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -19343,8 +19343,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From b1481b721e9a4f0f77389cae9f168a8b394bdc1f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 17:29:22 +0800
+Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit b0db1accbc7395657c2b79db59fa9fae0d6656f3 ]
+
+check_mem_access() matches PTR_TO_BUF via base_type() which strips
+PTR_MAYBE_NULL, allowing direct dereference without a null check.
+
+Map iterator ctx->key and ctx->value are PTR_TO_BUF | PTR_MAYBE_NULL.
+On stop callbacks these are NULL, causing a kernel NULL dereference.
+
+Add a type_may_be_null() guard to the PTR_TO_BUF branch, matching the
+existing PTR_TO_BTF_ID pattern.
+
+Fixes: 20b2aff4bc15 ("bpf: Introduce MEM_RDONLY flag")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 11fe83d6109d7..0aea870b87a6c 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -7806,7 +7806,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ } else if (reg->type == CONST_PTR_TO_MAP) {
+ err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+ value_regno);
+- } else if (base_type(reg->type) == PTR_TO_BUF) {
++ } else if (base_type(reg->type) == PTR_TO_BUF &&
++ !type_may_be_null(reg->type)) {
+ bool rdonly_mem = type_is_rdonly_mem(reg->type);
+ u32 *max_access;
+
+--
+2.53.0
+
--- /dev/null
+From 80bebbb45adf12c8b7a260ccec4f1c12281b03ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 00:41:25 +0530
+Subject: bpf: Reject sleepable kprobe_multi programs at attach time
+
+From: Varun R Mallya <varunrmallya@gmail.com>
+
+[ Upstream commit eb7024bfcc5f68ed11ed9dd4891a3073c15f04a8 ]
+
+kprobe.multi programs run in atomic/RCU context and cannot sleep.
+However, bpf_kprobe_multi_link_attach() did not validate whether the
+program being attached had the sleepable flag set, allowing sleepable
+helpers such as bpf_copy_from_user() to be invoked from a non-sleepable
+context.
+
+This causes a "sleeping function called from invalid context" splat:
+
+ BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:169
+ in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1787, name: sudo
+ preempt_count: 1, expected: 0
+ RCU nest depth: 2, expected: 0
+
+Fix this by rejecting sleepable programs early in
+bpf_kprobe_multi_link_attach(), before any further processing.
+
+Fixes: 0dcac2725406 ("bpf: Add multi kprobe link")
+Signed-off-by: Varun R Mallya <varunrmallya@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Acked-by: Leon Hwang <leon.hwang@linux.dev>
+Acked-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20260401191126.440683-1-varunrmallya@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/bpf_trace.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
+index e448a2553f7ce..42734975a06bc 100644
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2739,6 +2739,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
+ if (!is_kprobe_multi(prog))
+ return -EINVAL;
+
++ /* kprobe_multi is not allowed to be sleepable. */
++ if (prog->sleepable)
++ return -EINVAL;
++
+ /* Writing to context is not allowed for kprobes. */
+ if (prog->aux->kprobe_write_ctx)
+ return -EINVAL;
+--
+2.53.0
+
--- /dev/null
+From 7d33bb28b9a088fc7ec083f66bd91098ca4a78f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 00:54:15 +0000
+Subject: bpf: sockmap: Fix use-after-free of sk->sk_socket in
+ sk_psock_verdict_data_ready().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit ad8391d37f334ee73ba91926f8b4e4cf6d31ea04 ]
+
+syzbot reported use-after-free of AF_UNIX socket's sk->sk_socket
+in sk_psock_verdict_data_ready(). [0]
+
+In unix_stream_sendmsg(), the peer socket's ->sk_data_ready() is
+called after dropping its unix_state_lock().
+
+Although the sender socket holds the peer's refcount, it does not
+prevent the peer's sock_orphan(), and the peer's sk_socket might
+be freed after one RCU grace period.
+
+Let's fetch the peer's sk->sk_socket and sk->sk_socket->ops under
+RCU in sk_psock_verdict_data_ready().
+
+[0]:
+BUG: KASAN: slab-use-after-free in sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+Read of size 8 at addr ffff8880594da860 by task syz.4.1842/11013
+
+CPU: 1 UID: 0 PID: 11013 Comm: syz.4.1842 Not tainted syzkaller #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:378 [inline]
+ print_report+0xba/0x230 mm/kasan/report.c:482
+ kasan_report+0x117/0x150 mm/kasan/report.c:595
+ sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+ unix_stream_sendmsg+0x8a3/0xe80 net/unix/af_unix.c:2482
+ sock_sendmsg_nosec net/socket.c:721 [inline]
+ __sock_sendmsg net/socket.c:736 [inline]
+ ____sys_sendmsg+0x972/0x9f0 net/socket.c:2585
+ ___sys_sendmsg+0x2a5/0x360 net/socket.c:2639
+ __sys_sendmsg net/socket.c:2671 [inline]
+ __do_sys_sendmsg net/socket.c:2676 [inline]
+ __se_sys_sendmsg net/socket.c:2674 [inline]
+ __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2674
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7facf899c819
+Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007facf9827028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007facf8c15fa0 RCX: 00007facf899c819
+RDX: 0000000000000000 RSI: 0000200000000500 RDI: 0000000000000004
+RBP: 00007facf8a32c91 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 00007facf8c16038 R14: 00007facf8c15fa0 R15: 00007ffd41b01c78
+ </TASK>
+
+Allocated by task 11013:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ unpoison_slab_object mm/kasan/common.c:340 [inline]
+ __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:366
+ kasan_slab_alloc include/linux/kasan.h:253 [inline]
+ slab_post_alloc_hook mm/slub.c:4538 [inline]
+ slab_alloc_node mm/slub.c:4866 [inline]
+ kmem_cache_alloc_lru_noprof+0x2b8/0x640 mm/slub.c:4885
+ sock_alloc_inode+0x28/0xc0 net/socket.c:316
+ alloc_inode+0x6a/0x1b0 fs/inode.c:347
+ new_inode_pseudo include/linux/fs.h:3003 [inline]
+ sock_alloc net/socket.c:631 [inline]
+ __sock_create+0x12d/0x9d0 net/socket.c:1562
+ sock_create net/socket.c:1656 [inline]
+ __sys_socketpair+0x1c4/0x560 net/socket.c:1803
+ __do_sys_socketpair net/socket.c:1856 [inline]
+ __se_sys_socketpair net/socket.c:1853 [inline]
+ __x64_sys_socketpair+0x9b/0xb0 net/socket.c:1853
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 15:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
+ poison_slab_object mm/kasan/common.c:253 [inline]
+ __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
+ kasan_slab_free include/linux/kasan.h:235 [inline]
+ slab_free_hook mm/slub.c:2685 [inline]
+ slab_free mm/slub.c:6165 [inline]
+ kmem_cache_free+0x187/0x630 mm/slub.c:6295
+ rcu_do_batch kernel/rcu/tree.c:2617 [inline]
+ rcu_core+0x7cd/0x1070 kernel/rcu/tree.c:2869
+ handle_softirqs+0x22a/0x870 kernel/softirq.c:622
+ run_ksoftirqd+0x36/0x60 kernel/softirq.c:1063
+ smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160
+ kthread+0x388/0x470 kernel/kthread.c:436
+ ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
+
+Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()")
+Closes: https://lore.kernel.org/bpf/69cc6b9f.a70a0220.128fd0.004b.GAE@google.com/
+Reported-by: syzbot+2184232f07e3677fbaef@syzkaller.appspotmail.com
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/skmsg.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/skmsg.c b/net/core/skmsg.c
+index 12fbb0545c712..35a6acbf9a579 100644
+--- a/net/core/skmsg.c
++++ b/net/core/skmsg.c
+@@ -1267,17 +1267,20 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)
+
+ static void sk_psock_verdict_data_ready(struct sock *sk)
+ {
+- struct socket *sock = sk->sk_socket;
+- const struct proto_ops *ops;
++ const struct proto_ops *ops = NULL;
++ struct socket *sock;
+ int copied;
+
+ trace_sk_data_ready(sk);
+
+- if (unlikely(!sock))
+- return;
+- ops = READ_ONCE(sock->ops);
++ rcu_read_lock();
++ sock = READ_ONCE(sk->sk_socket);
++ if (likely(sock))
++ ops = READ_ONCE(sock->ops);
++ rcu_read_unlock();
+ if (!ops || !ops->read_skb)
+ return;
++
+ copied = ops->read_skb(sk, sk_psock_verdict_recv);
+ if (copied >= 0) {
+ struct sk_psock *psock;
+--
+2.53.0
+
--- /dev/null
+From 4dd397cba2471c5c4b6b12159bb3905acdac34a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index 1e2b51769eec8..af3d1e33f50b8 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -251,12 +251,12 @@ struct nd_msg *br_is_nd_neigh_msg(const struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -264,7 +264,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -281,6 +281,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -472,9 +474,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 9590e2f5a09d753eec62fefe1706130ae667ff2c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 23:30:00 -0700
+Subject: bridge: mrp: reject zero test interval to avoid OOM panic
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit fa6e24963342de4370e3a3c9af41e38277b74cf3 ]
+
+br_mrp_start_test() and br_mrp_start_in_test() accept the user-supplied
+interval value from netlink without validation. When interval is 0,
+usecs_to_jiffies(0) yields 0, causing the delayed work
+(br_mrp_test_work_expired / br_mrp_in_test_work_expired) to reschedule
+itself with zero delay. This creates a tight loop on system_percpu_wq
+that allocates and transmits MRP test frames at maximum rate, exhausting
+all system memory and causing a kernel panic via OOM deadlock.
+
+The same zero-interval issue applies to br_mrp_start_in_test_parse()
+for interconnect test frames.
+
+Use NLA_POLICY_MIN(NLA_U32, 1) in the nla_policy tables for both
+IFLA_BRIDGE_MRP_START_TEST_INTERVAL and
+IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, so zero is rejected at the
+netlink attribute parsing layer before the value ever reaches the
+workqueue scheduling code. This is consistent with how other bridge
+subsystems (br_fdb, br_mst) enforce range constraints on netlink
+attributes.
+
+Fixes: 20f6a05ef635 ("bridge: mrp: Rework the MRP netlink interface")
+Fixes: 7ab1748e4ce6 ("bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260328063000.1845376-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_mrp_netlink.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c
+index ce6f63c77cc0a..86f0e75d6e345 100644
+--- a/net/bridge/br_mrp_netlink.c
++++ b/net/bridge/br_mrp_netlink.c
+@@ -196,7 +196,7 @@ static const struct nla_policy
+ br_mrp_start_test_policy[IFLA_BRIDGE_MRP_START_TEST_MAX + 1] = {
+ [IFLA_BRIDGE_MRP_START_TEST_UNSPEC] = { .type = NLA_REJECT },
+ [IFLA_BRIDGE_MRP_START_TEST_RING_ID] = { .type = NLA_U32 },
+- [IFLA_BRIDGE_MRP_START_TEST_INTERVAL] = { .type = NLA_U32 },
++ [IFLA_BRIDGE_MRP_START_TEST_INTERVAL] = NLA_POLICY_MIN(NLA_U32, 1),
+ [IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] = { .type = NLA_U32 },
+ [IFLA_BRIDGE_MRP_START_TEST_PERIOD] = { .type = NLA_U32 },
+ [IFLA_BRIDGE_MRP_START_TEST_MONITOR] = { .type = NLA_U32 },
+@@ -316,7 +316,7 @@ static const struct nla_policy
+ br_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = {
+ [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT },
+ [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 },
+- [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] = { .type = NLA_U32 },
++ [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] = NLA_POLICY_MIN(NLA_U32, 1),
+ [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS] = { .type = NLA_U32 },
+ [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 },
+ };
+--
+2.53.0
+
--- /dev/null
+From 225f673d588566a243721c7d0a176f619e1c6c0d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 11:53:46 +0100
+Subject: btrfs: don't take device_list_mutex when querying zone info
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 77603ab10429fe713a03345553ca8dbbfb1d91c6 ]
+
+Shin'ichiro reported sporadic hangs when running generic/013 in our CI
+system. When enabling lockdep, there is a lockdep splat when calling
+btrfs_get_dev_zone_info_all_devices() in the mount path that can be
+triggered by i.e. generic/013:
+
+ ======================================================
+ WARNING: possible circular locking dependency detected
+ 7.0.0-rc1+ #355 Not tainted
+ ------------------------------------------------------
+ mount/1043 is trying to acquire lock:
+ ffff8881020b5470 (&vblk->vdev_mutex){+.+.}-{4:4}, at: virtblk_report_zones+0xda/0x430
+
+ but task is already holding lock:
+ ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #4 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
+ __mutex_lock+0xa3/0x1360
+ btrfs_create_pending_block_groups+0x1f4/0x9d0
+ __btrfs_end_transaction+0x3e/0x2e0
+ btrfs_zoned_reserve_data_reloc_bg+0x2f8/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #3 (btrfs_trans_num_extwriters){++++}-{0:0}:
+ join_transaction+0xc2/0x5c0
+ start_transaction+0x17c/0xbc0
+ btrfs_zoned_reserve_data_reloc_bg+0x2b4/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #2 (btrfs_trans_num_writers){++++}-{0:0}:
+ lock_release+0x163/0x4b0
+ __btrfs_end_transaction+0x1c7/0x2e0
+ btrfs_dirty_inode+0x6f/0xd0
+ touch_atime+0xe5/0x2c0
+ btrfs_file_mmap_prepare+0x65/0x90
+ __mmap_region+0x4b9/0xf00
+ mmap_region+0xf7/0x120
+ do_mmap+0x43d/0x610
+ vm_mmap_pgoff+0xd6/0x190
+ ksys_mmap_pgoff+0x7e/0xc0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #1 (&mm->mmap_lock){++++}-{4:4}:
+ __might_fault+0x68/0xa0
+ _copy_to_user+0x22/0x70
+ blkdev_copy_zone_to_user+0x22/0x40
+ virtblk_report_zones+0x282/0x430
+ blkdev_report_zones_ioctl+0xfd/0x130
+ blkdev_ioctl+0x20f/0x2c0
+ __x64_sys_ioctl+0x86/0xd0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #0 (&vblk->vdev_mutex){+.+.}-{4:4}:
+ __lock_acquire+0x1522/0x2680
+ lock_acquire+0xd5/0x2f0
+ __mutex_lock+0xa3/0x1360
+ virtblk_report_zones+0xda/0x430
+ blkdev_report_zones_cached+0x162/0x190
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ other info that might help us debug this:
+
+ Chain exists of:
+ &vblk->vdev_mutex --> btrfs_trans_num_extwriters --> &fs_devs->device_list_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&fs_devs->device_list_mutex);
+ lock(btrfs_trans_num_extwriters);
+ lock(&fs_devs->device_list_mutex);
+ lock(&vblk->vdev_mutex);
+
+ *** DEADLOCK ***
+
+ 3 locks held by mount/1043:
+ #0: ffff88811063e878 (&fc->uapi_mutex){+.+.}-{4:4}, at: __do_sys_fsconfig+0x2ae/0x680
+ #1: ffff88810cb9f0e8 (&type->s_umount_key#31/1){+.+.}-{4:4}, at: alloc_super+0xc0/0x3e0
+ #2: ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 1043 Comm: mount Not tainted 7.0.0-rc1+ #355 PREEMPT(full)
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x80
+ print_circular_bug.cold+0x18d/0x1d8
+ check_noncircular+0x10d/0x130
+ __lock_acquire+0x1522/0x2680
+ ? vmap_small_pages_range_noflush+0x3ef/0x820
+ lock_acquire+0xd5/0x2f0
+ ? virtblk_report_zones+0xda/0x430
+ ? lock_is_held_type+0xcd/0x130
+ __mutex_lock+0xa3/0x1360
+ ? virtblk_report_zones+0xda/0x430
+ ? virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ ? virtblk_report_zones+0xda/0x430
+ virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ blkdev_report_zones_cached+0x162/0x190
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ ? rcu_is_watching+0x18/0x50
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ RIP: 0033:0x7f615e27a40e
+ RSP: 002b:00007fff11b18fb8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ RAX: ffffffffffffffda RBX: 000055572e92ab10 RCX: 00007f615e27a40e
+ RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ RBP: 00007fff11b19100 R08: 0000000000000000 R09: 0000000000000000
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055572e92bc40 R14: 00007f615e3faa60 R15: 000055572e92bd08
+ </TASK>
+
+Don't hold the device_list_mutex while calling into
+btrfs_get_dev_zone_info() in btrfs_get_dev_zone_info_all_devices() to
+mitigate the issue. This is safe, as no other thread can touch the device
+list at the moment of execution.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 392e6ad874cc7..ab7cc30212702 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -337,7 +337,10 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (!btrfs_fs_incompat(fs_info, ZONED))
+ return 0;
+
+- mutex_lock(&fs_devices->device_list_mutex);
++ /*
++ * No need to take the device_list mutex here, we're still in the mount
++ * path and devices cannot be added to or removed from the list yet.
++ */
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ /* We can skip reading of zone info for missing devices */
+ if (!device->bdev)
+@@ -347,7 +350,6 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (ret)
+ break;
+ }
+- mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
+ }
+--
+2.53.0
+
--- /dev/null
+From 44b43649a8717f0ac78d6dd2ff95f8b1a46cf15e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Mar 2026 08:14:43 +0800
+Subject: btrfs: reject root items with drop_progress and zero drop_level
+
+From: ZhengYuan Huang <gality369@gmail.com>
+
+[ Upstream commit b17b79ff896305fd74980a5f72afec370ee88ca4 ]
+
+[BUG]
+When recovering relocation at mount time, merge_reloc_root() and
+btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
+an impossible state: a non-zero drop_progress combined with a zero
+drop_level in a root_item, which can be triggered:
+
+------------[ cut here ]------------
+kernel BUG at fs/btrfs/relocation.c:1545!
+Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
+CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
+Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
+RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
+Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
+Call Trace:
+ merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
+ btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
+ btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
+ open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
+ btrfs_fill_super fs/btrfs/super.c:987 [inline]
+ btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
+ btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
+ btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
+ vfs_get_tree+0x9a/0x370 fs/super.c:1758
+ fc_mount fs/namespace.c:1199 [inline]
+ do_new_mount_fc fs/namespace.c:3642 [inline]
+ do_new_mount fs/namespace.c:3718 [inline]
+ path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
+ do_mount fs/namespace.c:4041 [inline]
+ __do_sys_mount fs/namespace.c:4229 [inline]
+ __se_sys_mount fs/namespace.c:4206 [inline]
+ __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
+ ...
+RIP: 0033:0x7f969c9a8fde
+Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
+---[ end trace 0000000000000000 ]---
+
+The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
+metadata fuzzing tool that corrupts btrfs metadata at runtime.
+
+[CAUSE]
+A non-zero drop_progress.objectid means an interrupted
+btrfs_drop_snapshot() left a resume point on disk, and in that case
+drop_level must be greater than 0 because the checkpoint is only
+saved at internal node levels.
+
+Although this invariant is enforced when the kernel writes the root
+item, it is not validated when the root item is read back from disk.
+That allows on-disk corruption to provide an invalid state with
+drop_progress.objectid != 0 and drop_level == 0.
+
+When relocation recovery later processes such a root item,
+merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
+same invalid metadata can also trigger the corresponding BUG_ON() in
+btrfs_drop_snapshot().
+
+[FIX]
+Fix this by validating the root_item invariant in tree-checker when
+reading root items from disk: if drop_progress.objectid is non-zero,
+drop_level must also be non-zero. Reject such malformed metadata with
+-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
+and triggers the BUG_ON.
+
+After the fix, the same corruption is correctly rejected by tree-checker
+and the BUG_ON is no longer triggered.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 59794d726fd27..1c8f61cbbbe5b 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -1260,6 +1260,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
+ btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
+ return -EUCLEAN;
+ }
++ /*
++ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
++ * interrupted and the resume point was recorded in drop_progress and
++ * drop_level. In that case drop_level must be >= 1: level 0 is the
++ * leaf level and drop_snapshot never saves a checkpoint there (it
++ * only records checkpoints at internal node levels in DROP_REFERENCE
++ * stage). A zero drop_level combined with a non-zero drop_progress
++ * objectid indicates on-disk corruption and would cause a BUG_ON in
++ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
++ */
++ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
++ btrfs_root_drop_level(&ri) == 0)) {
++ generic_err(leaf, slot,
++ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
++ btrfs_disk_key_objectid(&ri.drop_progress));
++ return -EUCLEAN;
++ }
+
+ /* Flags check */
+ if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
+--
+2.53.0
+
--- /dev/null
+From 14376f1c7ba834dc0c2767b281bc80022b9fcce8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Feb 2026 16:08:53 +0000
+Subject: btrfs: reserve enough transaction items for qgroup ioctls
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit f9a4e3015db1aeafbef407650eb8555445ca943e ]
+
+Currently our qgroup ioctls don't reserve any space, they just do a
+transaction join, which does not reserve any space, neither for the quota
+tree updates nor for the delayed refs generated when updating the quota
+tree. The quota root uses the global block reserve, which is fine most of
+the time since we don't expect a lot of updates to the quota root, or to
+be too close to -ENOSPC such that other critical metadata updates need to
+resort to the global reserve.
+
+However this is not optimal, as not reserving proper space may result in a
+transaction abort due to not reserving space for delayed refs and then
+abusing the use of the global block reserve.
+
+For example, the following reproducer (which is unlikely to model any
+real world use case, but just to illustrate the problem), triggers such a
+transaction abort due to -ENOSPC when running delayed refs:
+
+ $ cat test.sh
+ #!/bin/bash
+
+ DEV=/dev/nullb0
+ MNT=/mnt/nullb0
+
+ umount $DEV &> /dev/null
+ # Limit device to 1G so that it's much faster to reproduce the issue.
+ mkfs.btrfs -f -b 1G $DEV
+ mount -o commit=600 $DEV $MNT
+
+ fallocate -l 800M $MNT/filler
+ btrfs quota enable $MNT
+
+ for ((i = 1; i <= 400000; i++)); do
+ btrfs qgroup create 1/$i $MNT
+ done
+
+ umount $MNT
+
+When running this, we can see in dmesg/syslog that a transaction abort
+happened:
+
+ [436.490] BTRFS error (device nullb0): failed to run delayed ref for logical 30408704 num_bytes 16384 type 176 action 1 ref_mod 1: -28
+ [436.493] ------------[ cut here ]------------
+ [436.494] BTRFS: Transaction aborted (error -28)
+ [436.495] WARNING: fs/btrfs/extent-tree.c:2247 at btrfs_run_delayed_refs+0xd9/0x110 [btrfs], CPU#4: umount/2495372
+ [436.497] Modules linked in: btrfs loop (...)
+ [436.508] CPU: 4 UID: 0 PID: 2495372 Comm: umount Tainted: G W 6.19.0-rc8-btrfs-next-225+ #1 PREEMPT(full)
+ [436.510] Tainted: [W]=WARN
+ [436.511] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
+ [436.513] RIP: 0010:btrfs_run_delayed_refs+0xdf/0x110 [btrfs]
+ [436.514] Code: 0f 82 ea (...)
+ [436.518] RSP: 0018:ffffd511850b7d78 EFLAGS: 00010292
+ [436.519] RAX: 00000000ffffffe4 RBX: ffff8f120dad37e0 RCX: 0000000002040001
+ [436.520] RDX: 0000000000000002 RSI: 00000000ffffffe4 RDI: ffffffffc090fd80
+ [436.522] RBP: 0000000000000000 R08: 0000000000000001 R09: ffffffffc04d1867
+ [436.523] R10: ffff8f18dc1fffa8 R11: 0000000000000003 R12: ffff8f173aa89400
+ [436.524] R13: 0000000000000000 R14: ffff8f173aa89400 R15: 0000000000000000
+ [436.526] FS: 00007fe59045d840(0000) GS:ffff8f192e22e000(0000) knlGS:0000000000000000
+ [436.527] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ [436.528] CR2: 00007fe5905ff2b0 CR3: 000000060710a002 CR4: 0000000000370ef0
+ [436.530] Call Trace:
+ [436.530] <TASK>
+ [436.530] btrfs_commit_transaction+0x73/0xc00 [btrfs]
+ [436.531] ? btrfs_attach_transaction_barrier+0x1e/0x70 [btrfs]
+ [436.532] sync_filesystem+0x7a/0x90
+ [436.533] generic_shutdown_super+0x28/0x180
+ [436.533] kill_anon_super+0x12/0x40
+ [436.534] btrfs_kill_super+0x12/0x20 [btrfs]
+ [436.534] deactivate_locked_super+0x2f/0xb0
+ [436.534] cleanup_mnt+0xea/0x180
+ [436.535] task_work_run+0x58/0xa0
+ [436.535] exit_to_user_mode_loop+0xed/0x480
+ [436.536] ? __x64_sys_umount+0x68/0x80
+ [436.536] do_syscall_64+0x2a5/0xf20
+ [436.537] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ [436.537] RIP: 0033:0x7fe5906b6217
+ [436.538] Code: 0d 00 f7 (...)
+ [436.540] RSP: 002b:00007ffcd87a61f8 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+ [436.541] RAX: 0000000000000000 RBX: 00005618b9ecadc8 RCX: 00007fe5906b6217
+ [436.541] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00005618b9ecb100
+ [436.542] RBP: 0000000000000000 R08: 00007ffcd87a4fe0 R09: 00000000ffffffff
+ [436.544] R10: 0000000000000103 R11: 0000000000000246 R12: 00007fe59081626c
+ [436.544] R13: 00005618b9ecb100 R14: 0000000000000000 R15: 00005618b9ecacc0
+ [436.545] </TASK>
+ [436.545] ---[ end trace 0000000000000000 ]---
+
+Fix this by changing the qgroup ioctls to use start transaction instead of
+joining so that proper space is reserved for the delayed refs generated
+for the updates to the quota root. This way we don't get any transaction
+abort.
+
+Reviewed-by: Boris Burkov <boris@bur.io>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ioctl.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index b78998815ce72..16c9b242e917f 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3697,7 +3697,8 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
+ }
+ }
+
+- trans = btrfs_join_transaction(root);
++ /* 2 BTRFS_QGROUP_RELATION_KEY items. */
++ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+@@ -3769,7 +3770,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
+ goto out;
+ }
+
+- trans = btrfs_join_transaction(root);
++ /*
++ * 1 BTRFS_QGROUP_INFO_KEY item.
++ * 1 BTRFS_QGROUP_LIMIT_KEY item.
++ */
++ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+@@ -3818,7 +3823,8 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
+ goto drop_write;
+ }
+
+- trans = btrfs_join_transaction(root);
++ /* 1 BTRFS_QGROUP_LIMIT_KEY item. */
++ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out;
+--
+2.53.0
+
--- /dev/null
+From a2d199376b86beb5bceaf0a873ea4183b8007a43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 07:23:48 -1000
+Subject: cgroup: Fix cgroup_drain_dying() testing the wrong condition
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 4c56a8ac6869855866de0bb368a4189739e1d24f ]
+
+cgroup_drain_dying() was using cgroup_is_populated() to test whether there are
+dying tasks to wait for. cgroup_is_populated() tests nr_populated_csets,
+nr_populated_domain_children and nr_populated_threaded_children, but
+cgroup_drain_dying() only needs to care about this cgroup's own tasks - whether
+there are children is cgroup_destroy_locked()'s concern.
+
+This caused hangs during shutdown. When systemd tried to rmdir a cgroup that had
+no direct tasks but had a populated child, cgroup_drain_dying() would enter its
+wait loop because cgroup_is_populated() was true from
+nr_populated_domain_children. The task iterator found nothing to wait for, yet
+the populated state never cleared because it was driven by live tasks in the
+child cgroup.
+
+Fix it by using cgroup_has_tasks() which only tests nr_populated_csets.
+
+v3: Fix cgroup_is_populated() -> cgroup_has_tasks() (Sebastian).
+
+v2: https://lore.kernel.org/r/20260323200205.1063629-1-tj@kernel.org
+
+Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Fixes: 1b164b876c36 ("cgroup: Wait for dying tasks to leave on rmdir")
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/cgroup.c | 42 ++++++++++++++++++++++--------------------
+ 1 file changed, 22 insertions(+), 20 deletions(-)
+
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index 257d1ddea1ada..9370100764904 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -6229,20 +6229,22 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
+ * cgroup_drain_dying - wait for dying tasks to leave before rmdir
+ * @cgrp: the cgroup being removed
+ *
+- * The PF_EXITING filter in css_task_iter_advance() hides exiting tasks from
+- * cgroup.procs so that userspace (e.g. systemd) doesn't see tasks that have
+- * already been reaped via waitpid(). However, the populated counter
+- * (nr_populated_csets) is only decremented when the task later passes through
++ * cgroup.procs and cgroup.threads use css_task_iter which filters out
++ * PF_EXITING tasks so that userspace doesn't see tasks that have already been
++ * reaped via waitpid(). However, cgroup_has_tasks() - which tests whether the
++ * cgroup has non-empty css_sets - is only updated when dying tasks pass through
+ * cgroup_task_dead() in finish_task_switch(). This creates a window where
+- * cgroup.procs appears empty but cgroup_is_populated() is still true, causing
+- * rmdir to fail with -EBUSY.
++ * cgroup.procs reads empty but cgroup_has_tasks() is still true, making rmdir
++ * fail with -EBUSY from cgroup_destroy_locked() even though userspace sees no
++ * tasks.
++ *
++ * This function aligns cgroup_has_tasks() with what userspace can observe. If
++ * cgroup_has_tasks() but the task iterator sees nothing (all remaining tasks are
++ * PF_EXITING), we wait for cgroup_task_dead() to finish processing them. As the
++ * window between PF_EXITING and cgroup_task_dead() is short, the wait is brief.
+ *
+- * This function bridges that gap. If the cgroup is populated but all remaining
+- * tasks have PF_EXITING set, we wait for cgroup_task_dead() to process them.
+- * Tasks are removed from the cgroup's css_set in cgroup_task_dead() called from
+- * finish_task_switch(). As the window between PF_EXITING and cgroup_task_dead()
+- * is short, the number of PF_EXITING tasks on the list is small and the wait
+- * is brief.
++ * This function only concerns itself with this cgroup's own dying tasks.
++ * Whether the cgroup has children is cgroup_destroy_locked()'s problem.
+ *
+ * Each cgroup_task_dead() kicks the waitqueue via cset->cgrp_links, and we
+ * retry the full check from scratch.
+@@ -6258,7 +6260,7 @@ static int cgroup_drain_dying(struct cgroup *cgrp)
+
+ lockdep_assert_held(&cgroup_mutex);
+ retry:
+- if (!cgroup_is_populated(cgrp))
++ if (!cgroup_has_tasks(cgrp))
+ return 0;
+
+ /* Same iterator as cgroup.threads - if any task is visible, it's busy */
+@@ -6273,15 +6275,15 @@ static int cgroup_drain_dying(struct cgroup *cgrp)
+ * All remaining tasks are PF_EXITING and will pass through
+ * cgroup_task_dead() shortly. Wait for a kick and retry.
+ *
+- * cgroup_is_populated() can't transition from false to true while
+- * we're holding cgroup_mutex, but the true to false transition
+- * happens under css_set_lock (via cgroup_task_dead()). We must
+- * retest and prepare_to_wait() under css_set_lock. Otherwise, the
+- * transition can happen between our first test and
+- * prepare_to_wait(), and we sleep with no one to wake us.
++ * cgroup_has_tasks() can't transition from false to true while we're
++ * holding cgroup_mutex, but the true to false transition happens
++ * under css_set_lock (via cgroup_task_dead()). We must retest and
++ * prepare_to_wait() under css_set_lock. Otherwise, the transition
++ * can happen between our first test and prepare_to_wait(), and we
++ * sleep with no one to wake us.
+ */
+ spin_lock_irq(&css_set_lock);
+- if (!cgroup_is_populated(cgrp)) {
++ if (!cgroup_has_tasks(cgrp)) {
+ spin_unlock_irq(&css_set_lock);
+ return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From ca1e97763a2046abc85e068fd62033172a70b346 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 10:21:25 -1000
+Subject: cgroup: Wait for dying tasks to leave on rmdir
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 1b164b876c36c3eb5561dd9b37702b04401b0166 ]
+
+a72f73c4dd9b ("cgroup: Don't expose dead tasks in cgroup") hid PF_EXITING
+tasks from cgroup.procs so that systemd doesn't see tasks that have already
+been reaped via waitpid(). However, the populated counter (nr_populated_csets)
+is only decremented when the task later passes through cgroup_task_dead() in
+finish_task_switch(). This means cgroup.procs can appear empty while the
+cgroup is still populated, causing rmdir to fail with -EBUSY.
+
+Fix this by making cgroup_rmdir() wait for dying tasks to fully leave. If the
+cgroup is populated but all remaining tasks have PF_EXITING set (the task
+iterator returns none due to the existing filter), wait for a kick from
+cgroup_task_dead() and retry. The wait is brief as tasks are removed from the
+cgroup's css_set between PF_EXITING assertion in do_exit() and
+cgroup_task_dead() in finish_task_switch().
+
+v2: cgroup_is_populated() true to false transition happens under css_set_lock
+ not cgroup_mutex, so retest under css_set_lock before sleeping to avoid
+ missed wakeups (Sebastian).
+
+Fixes: a72f73c4dd9b ("cgroup: Don't expose dead tasks in cgroup")
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202603222104.2c81684e-lkp@intel.com
+Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Cc: Bert Karwatzki <spasswolf@web.de>
+Cc: Michal Koutny <mkoutny@suse.com>
+Cc: cgroups@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/cgroup-defs.h | 3 ++
+ kernel/cgroup/cgroup.c | 86 +++++++++++++++++++++++++++++++++++--
+ 2 files changed, 86 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
+index f7cc60de00583..2bff3e2be0d3b 100644
+--- a/include/linux/cgroup-defs.h
++++ b/include/linux/cgroup-defs.h
+@@ -609,6 +609,9 @@ struct cgroup {
+ /* used to wait for offlining of csses */
+ wait_queue_head_t offline_waitq;
+
++ /* used by cgroup_rmdir() to wait for dying tasks to leave */
++ wait_queue_head_t dying_populated_waitq;
++
+ /* used to schedule release agent */
+ struct work_struct release_agent_work;
+
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index 3f9e4bcd71988..257d1ddea1ada 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -2126,6 +2126,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
+ #endif
+
+ init_waitqueue_head(&cgrp->offline_waitq);
++ init_waitqueue_head(&cgrp->dying_populated_waitq);
+ INIT_WORK(&cgrp->release_agent_work, cgroup1_release_agent);
+ }
+
+@@ -6224,6 +6225,76 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
+ return 0;
+ };
+
++/**
++ * cgroup_drain_dying - wait for dying tasks to leave before rmdir
++ * @cgrp: the cgroup being removed
++ *
++ * The PF_EXITING filter in css_task_iter_advance() hides exiting tasks from
++ * cgroup.procs so that userspace (e.g. systemd) doesn't see tasks that have
++ * already been reaped via waitpid(). However, the populated counter
++ * (nr_populated_csets) is only decremented when the task later passes through
++ * cgroup_task_dead() in finish_task_switch(). This creates a window where
++ * cgroup.procs appears empty but cgroup_is_populated() is still true, causing
++ * rmdir to fail with -EBUSY.
++ *
++ * This function bridges that gap. If the cgroup is populated but all remaining
++ * tasks have PF_EXITING set, we wait for cgroup_task_dead() to process them.
++ * Tasks are removed from the cgroup's css_set in cgroup_task_dead() called from
++ * finish_task_switch(). As the window between PF_EXITING and cgroup_task_dead()
++ * is short, the number of PF_EXITING tasks on the list is small and the wait
++ * is brief.
++ *
++ * Each cgroup_task_dead() kicks the waitqueue via cset->cgrp_links, and we
++ * retry the full check from scratch.
++ *
++ * Must be called with cgroup_mutex held.
++ */
++static int cgroup_drain_dying(struct cgroup *cgrp)
++ __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
++{
++ struct css_task_iter it;
++ struct task_struct *task;
++ DEFINE_WAIT(wait);
++
++ lockdep_assert_held(&cgroup_mutex);
++retry:
++ if (!cgroup_is_populated(cgrp))
++ return 0;
++
++ /* Same iterator as cgroup.threads - if any task is visible, it's busy */
++ css_task_iter_start(&cgrp->self, 0, &it);
++ task = css_task_iter_next(&it);
++ css_task_iter_end(&it);
++
++ if (task)
++ return -EBUSY;
++
++ /*
++ * All remaining tasks are PF_EXITING and will pass through
++ * cgroup_task_dead() shortly. Wait for a kick and retry.
++ *
++ * cgroup_is_populated() can't transition from false to true while
++ * we're holding cgroup_mutex, but the true to false transition
++ * happens under css_set_lock (via cgroup_task_dead()). We must
++ * retest and prepare_to_wait() under css_set_lock. Otherwise, the
++ * transition can happen between our first test and
++ * prepare_to_wait(), and we sleep with no one to wake us.
++ */
++ spin_lock_irq(&css_set_lock);
++ if (!cgroup_is_populated(cgrp)) {
++ spin_unlock_irq(&css_set_lock);
++ return 0;
++ }
++ prepare_to_wait(&cgrp->dying_populated_waitq, &wait,
++ TASK_UNINTERRUPTIBLE);
++ spin_unlock_irq(&css_set_lock);
++ mutex_unlock(&cgroup_mutex);
++ schedule();
++ finish_wait(&cgrp->dying_populated_waitq, &wait);
++ mutex_lock(&cgroup_mutex);
++ goto retry;
++}
++
+ int cgroup_rmdir(struct kernfs_node *kn)
+ {
+ struct cgroup *cgrp;
+@@ -6233,9 +6304,12 @@ int cgroup_rmdir(struct kernfs_node *kn)
+ if (!cgrp)
+ return 0;
+
+- ret = cgroup_destroy_locked(cgrp);
+- if (!ret)
+- TRACE_CGROUP_PATH(rmdir, cgrp);
++ ret = cgroup_drain_dying(cgrp);
++ if (!ret) {
++ ret = cgroup_destroy_locked(cgrp);
++ if (!ret)
++ TRACE_CGROUP_PATH(rmdir, cgrp);
++ }
+
+ cgroup_kn_unlock(kn);
+ return ret;
+@@ -6995,6 +7069,7 @@ void cgroup_task_exit(struct task_struct *tsk)
+
+ static void do_cgroup_task_dead(struct task_struct *tsk)
+ {
++ struct cgrp_cset_link *link;
+ struct css_set *cset;
+ unsigned long flags;
+
+@@ -7008,6 +7083,11 @@ static void do_cgroup_task_dead(struct task_struct *tsk)
+ if (thread_group_leader(tsk) && atomic_read(&tsk->signal->live))
+ list_add_tail(&tsk->cg_list, &cset->dying_tasks);
+
++ /* kick cgroup_drain_dying() waiters, see cgroup_rmdir() */
++ list_for_each_entry(link, &cset->cgrp_links, cgrp_link)
++ if (waitqueue_active(&link->cgrp->dying_populated_waitq))
++ wake_up(&link->cgrp->dying_populated_waitq);
++
+ if (dl_task(tsk))
+ dec_dl_tasks_cs(tsk);
+
+--
+2.53.0
+
--- /dev/null
+From d9f386e5932437f8afc7ce730e7debed24b1b502 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index e468714f539df..ace8a4dc8e976 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -623,8 +623,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From cc561b4dbe8abd568e4432790cfb37c93bbe9209 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:30:20 +0900
+Subject: crypto: algif_aead - Revert to operating out-of-place
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 ]
+
+This mostly reverts commit 72548b093ee3 except for the copying of
+the associated data.
+
+There is no benefit in operating in-place in algif_aead since the
+source and destination come from different mappings. Get rid of
+all the complexity added for in-place operation and just copy the
+AD directly.
+
+Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst")
+Reported-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 49 ++++----------------
+ crypto/algif_aead.c | 100 ++++++++--------------------------------
+ crypto/algif_skcipher.c | 6 +--
+ include/crypto/if_alg.h | 5 +-
+ 4 files changed, 34 insertions(+), 126 deletions(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index ace8a4dc8e976..bc78c915eabc4 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -637,15 +637,13 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ /**
+ * af_alg_count_tsgl - Count number of TX SG entries
+ *
+- * The counting starts from the beginning of the SGL to @bytes. If
+- * an @offset is provided, the counting of the SG entries starts at the @offset.
++ * The counting starts from the beginning of the SGL to @bytes.
+ *
+ * @sk: socket of connection to user space
+ * @bytes: Count the number of SG entries holding given number of bytes.
+- * @offset: Start the counting of SG entries from the given offset.
+ * Return: Number of TX SG entries found given the constraints
+ */
+-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset)
++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes)
+ {
+ const struct alg_sock *ask = alg_sk(sk);
+ const struct af_alg_ctx *ctx = ask->private;
+@@ -660,25 +658,11 @@ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset)
+ const struct scatterlist *sg = sgl->sg;
+
+ for (i = 0; i < sgl->cur; i++) {
+- size_t bytes_count;
+-
+- /* Skip offset */
+- if (offset >= sg[i].length) {
+- offset -= sg[i].length;
+- bytes -= sg[i].length;
+- continue;
+- }
+-
+- bytes_count = sg[i].length - offset;
+-
+- offset = 0;
+ sgl_count++;
+-
+- /* If we have seen requested number of bytes, stop */
+- if (bytes_count >= bytes)
++ if (sg[i].length >= bytes)
+ return sgl_count;
+
+- bytes -= bytes_count;
++ bytes -= sg[i].length;
+ }
+ }
+
+@@ -690,19 +674,14 @@ EXPORT_SYMBOL_GPL(af_alg_count_tsgl);
+ * af_alg_pull_tsgl - Release the specified buffers from TX SGL
+ *
+ * If @dst is non-null, reassign the pages to @dst. The caller must release
+- * the pages. If @dst_offset is given only reassign the pages to @dst starting
+- * at the @dst_offset (byte). The caller must ensure that @dst is large
+- * enough (e.g. by using af_alg_count_tsgl with the same offset).
++ * the pages.
+ *
+ * @sk: socket of connection to user space
+ * @used: Number of bytes to pull from TX SGL
+ * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The
+ * caller must release the buffers in dst.
+- * @dst_offset: Reassign the TX SGL from given offset. All buffers before
+- * reaching the offset is released.
+ */
+-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
+- size_t dst_offset)
++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst)
+ {
+ struct alg_sock *ask = alg_sk(sk);
+ struct af_alg_ctx *ctx = ask->private;
+@@ -727,18 +706,10 @@ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
+ * SG entries in dst.
+ */
+ if (dst) {
+- if (dst_offset >= plen) {
+- /* discard page before offset */
+- dst_offset -= plen;
+- } else {
+- /* reassign page to dst after offset */
+- get_page(page);
+- sg_set_page(dst + j, page,
+- plen - dst_offset,
+- sg[i].offset + dst_offset);
+- dst_offset = 0;
+- j++;
+- }
++ /* reassign page to dst after offset */
++ get_page(page);
++ sg_set_page(dst + j, page, plen, sg[i].offset);
++ j++;
+ }
+
+ sg[i].length -= plen;
+diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
+index 79b016a899a1e..dda15bb05e892 100644
+--- a/crypto/algif_aead.c
++++ b/crypto/algif_aead.c
+@@ -26,7 +26,6 @@
+ #include <crypto/internal/aead.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/if_alg.h>
+-#include <crypto/skcipher.h>
+ #include <linux/init.h>
+ #include <linux/list.h>
+ #include <linux/kernel.h>
+@@ -72,9 +71,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
+ struct alg_sock *pask = alg_sk(psk);
+ struct af_alg_ctx *ctx = ask->private;
+ struct crypto_aead *tfm = pask->private;
+- unsigned int i, as = crypto_aead_authsize(tfm);
++ unsigned int as = crypto_aead_authsize(tfm);
+ struct af_alg_async_req *areq;
+- struct af_alg_tsgl *tsgl, *tmp;
+ struct scatterlist *rsgl_src, *tsgl_src = NULL;
+ int err = 0;
+ size_t used = 0; /* [in] TX bufs to be en/decrypted */
+@@ -154,23 +152,24 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
+ outlen -= less;
+ }
+
++ /*
++ * Create a per request TX SGL for this request which tracks the
++ * SG entries from the global TX SGL.
++ */
+ processed = used + ctx->aead_assoclen;
+- list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) {
+- for (i = 0; i < tsgl->cur; i++) {
+- struct scatterlist *process_sg = tsgl->sg + i;
+-
+- if (!(process_sg->length) || !sg_page(process_sg))
+- continue;
+- tsgl_src = process_sg;
+- break;
+- }
+- if (tsgl_src)
+- break;
+- }
+- if (processed && !tsgl_src) {
+- err = -EFAULT;
++ areq->tsgl_entries = af_alg_count_tsgl(sk, processed);
++ if (!areq->tsgl_entries)
++ areq->tsgl_entries = 1;
++ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
++ areq->tsgl_entries),
++ GFP_KERNEL);
++ if (!areq->tsgl) {
++ err = -ENOMEM;
+ goto free;
+ }
++ sg_init_table(areq->tsgl, areq->tsgl_entries);
++ af_alg_pull_tsgl(sk, processed, areq->tsgl);
++ tsgl_src = areq->tsgl;
+
+ /*
+ * Copy of AAD from source to destination
+@@ -179,76 +178,15 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
+ * when user space uses an in-place cipher operation, the kernel
+ * will copy the data as it does not see whether such in-place operation
+ * is initiated.
+- *
+- * To ensure efficiency, the following implementation ensure that the
+- * ciphers are invoked to perform a crypto operation in-place. This
+- * is achieved by memory management specified as follows.
+ */
+
+ /* Use the RX SGL as source (and destination) for crypto op. */
+ rsgl_src = areq->first_rsgl.sgl.sgt.sgl;
+
+- if (ctx->enc) {
+- /*
+- * Encryption operation - The in-place cipher operation is
+- * achieved by the following operation:
+- *
+- * TX SGL: AAD || PT
+- * | |
+- * | copy |
+- * v v
+- * RX SGL: AAD || PT || Tag
+- */
+- memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src,
+- processed);
+- af_alg_pull_tsgl(sk, processed, NULL, 0);
+- } else {
+- /*
+- * Decryption operation - To achieve an in-place cipher
+- * operation, the following SGL structure is used:
+- *
+- * TX SGL: AAD || CT || Tag
+- * | | ^
+- * | copy | | Create SGL link.
+- * v v |
+- * RX SGL: AAD || CT ----+
+- */
+-
+- /* Copy AAD || CT to RX SGL buffer for in-place operation. */
+- memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src, outlen);
+-
+- /* Create TX SGL for tag and chain it to RX SGL. */
+- areq->tsgl_entries = af_alg_count_tsgl(sk, processed,
+- processed - as);
+- if (!areq->tsgl_entries)
+- areq->tsgl_entries = 1;
+- areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
+- areq->tsgl_entries),
+- GFP_KERNEL);
+- if (!areq->tsgl) {
+- err = -ENOMEM;
+- goto free;
+- }
+- sg_init_table(areq->tsgl, areq->tsgl_entries);
+-
+- /* Release TX SGL, except for tag data and reassign tag data. */
+- af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as);
+-
+- /* chain the areq TX SGL holding the tag with RX SGL */
+- if (usedpages) {
+- /* RX SGL present */
+- struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl;
+- struct scatterlist *sg = sgl_prev->sgt.sgl;
+-
+- sg_unmark_end(sg + sgl_prev->sgt.nents - 1);
+- sg_chain(sg, sgl_prev->sgt.nents + 1, areq->tsgl);
+- } else
+- /* no RX SGL present (e.g. authentication only) */
+- rsgl_src = areq->tsgl;
+- }
++ memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen);
+
+ /* Initialize the crypto operation */
+- aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src,
++ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src,
+ areq->first_rsgl.sgl.sgt.sgl, used, ctx->iv);
+ aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen);
+ aead_request_set_tfm(&areq->cra_u.aead_req, tfm);
+@@ -450,7 +388,7 @@ static void aead_sock_destruct(struct sock *sk)
+ struct crypto_aead *tfm = pask->private;
+ unsigned int ivlen = crypto_aead_ivsize(tfm);
+
+- af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
++ af_alg_pull_tsgl(sk, ctx->used, NULL);
+ sock_kzfree_s(sk, ctx->iv, ivlen);
+ sock_kfree_s(sk, ctx, ctx->len);
+ af_alg_release_parent(sk);
+diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
+index 125d395c5e009..82735e51be108 100644
+--- a/crypto/algif_skcipher.c
++++ b/crypto/algif_skcipher.c
+@@ -138,7 +138,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ * Create a per request TX SGL for this request which tracks the
+ * SG entries from the global TX SGL.
+ */
+- areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0);
++ areq->tsgl_entries = af_alg_count_tsgl(sk, len);
+ if (!areq->tsgl_entries)
+ areq->tsgl_entries = 1;
+ areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
+@@ -149,7 +149,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ goto free;
+ }
+ sg_init_table(areq->tsgl, areq->tsgl_entries);
+- af_alg_pull_tsgl(sk, len, areq->tsgl, 0);
++ af_alg_pull_tsgl(sk, len, areq->tsgl);
+
+ /* Initialize the crypto operation */
+ skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm);
+@@ -363,7 +363,7 @@ static void skcipher_sock_destruct(struct sock *sk)
+ struct alg_sock *pask = alg_sk(psk);
+ struct crypto_skcipher *tfm = pask->private;
+
+- af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
++ af_alg_pull_tsgl(sk, ctx->used, NULL);
+ sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
+ if (ctx->state)
+ sock_kzfree_s(sk, ctx->state, crypto_skcipher_statesize(tfm));
+diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
+index 107b797c33ecf..0cc8fa749f68d 100644
+--- a/include/crypto/if_alg.h
++++ b/include/crypto/if_alg.h
+@@ -230,9 +230,8 @@ static inline bool af_alg_readable(struct sock *sk)
+ return PAGE_SIZE <= af_alg_rcvbuf(sk);
+ }
+
+-unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset);
+-void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
+- size_t dst_offset);
++unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes);
++void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst);
+ void af_alg_wmem_wakeup(struct sock *sk);
+ int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min);
+ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
+--
+2.53.0
+
--- /dev/null
+From 7c725251959f8ade1ff4bb31087b2381d03ca84c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 15:04:17 +0900
+Subject: crypto: authencesn - Do not place hiseq at end of dst for
+ out-of-place decryption
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit e02494114ebf7c8b42777c6cd6982f113bfdbec7 ]
+
+When decrypting data that is not in-place (src != dst), there is
+no need to save the high-order sequence bits in dst as it could
+simply be re-copied from the source.
+
+However, the data to be hashed need to be rearranged accordingly.
+
+Reported-by: Taeyang Lee <0wn@theori.io>
+Fixes: 104880a6b470 ("crypto: authencesn - Convert to new AEAD interface")
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+
+Thanks,
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/authencesn.c | 48 +++++++++++++++++++++++++++------------------
+ 1 file changed, 29 insertions(+), 19 deletions(-)
+
+diff --git a/crypto/authencesn.c b/crypto/authencesn.c
+index 542a978663b9e..c0a01d738d9bc 100644
+--- a/crypto/authencesn.c
++++ b/crypto/authencesn.c
+@@ -207,6 +207,7 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
+ u8 *ohash = areq_ctx->tail;
+ unsigned int cryptlen = req->cryptlen - authsize;
+ unsigned int assoclen = req->assoclen;
++ struct scatterlist *src = req->src;
+ struct scatterlist *dst = req->dst;
+ u8 *ihash = ohash + crypto_ahash_digestsize(auth);
+ u32 tmp[2];
+@@ -214,23 +215,27 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
+ if (!authsize)
+ goto decrypt;
+
+- /* Move high-order bits of sequence number back. */
+- scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
+- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
+- scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
++ if (src == dst) {
++ /* Move high-order bits of sequence number back. */
++ scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
++ scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
++ } else
++ memcpy_sglist(dst, src, assoclen);
+
+ if (crypto_memneq(ihash, ohash, authsize))
+ return -EBADMSG;
+
+ decrypt:
+
+- sg_init_table(areq_ctx->dst, 2);
++ if (src != dst)
++ src = scatterwalk_ffwd(areq_ctx->src, src, assoclen);
+ dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
+
+ skcipher_request_set_tfm(skreq, ctx->enc);
+ skcipher_request_set_callback(skreq, flags,
+ req->base.complete, req->base.data);
+- skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv);
++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
+
+ return crypto_skcipher_decrypt(skreq);
+ }
+@@ -255,6 +260,7 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req)
+ unsigned int assoclen = req->assoclen;
+ unsigned int cryptlen = req->cryptlen;
+ u8 *ihash = ohash + crypto_ahash_digestsize(auth);
++ struct scatterlist *src = req->src;
+ struct scatterlist *dst = req->dst;
+ u32 tmp[2];
+ int err;
+@@ -262,24 +268,28 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req)
+ if (assoclen < 8)
+ return -EINVAL;
+
+- cryptlen -= authsize;
+-
+- if (req->src != dst)
+- memcpy_sglist(dst, req->src, assoclen + cryptlen);
++ if (!authsize)
++ goto tail;
+
++ cryptlen -= authsize;
+ scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
+ authsize, 0);
+
+- if (!authsize)
+- goto tail;
+-
+ /* Move high-order bits of sequence number to the end. */
+- scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
+- scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
+- scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
+-
+- sg_init_table(areq_ctx->dst, 2);
+- dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
++ scatterwalk_map_and_copy(tmp, src, 0, 8, 0);
++ if (src == dst) {
++ scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
++ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
++ } else {
++ scatterwalk_map_and_copy(tmp, dst, 0, 4, 1);
++ scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1);
++
++ src = scatterwalk_ffwd(areq_ctx->src, src, 8);
++ dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
++ memcpy_sglist(dst, src, assoclen + cryptlen - 8);
++ dst = req->dst;
++ }
+
+ ahash_request_set_tfm(ahreq, auth);
+ ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen);
+--
+2.53.0
+
--- /dev/null
+From 2822bd8a349bc93a3db4bc825ac3efb1f4a06d51 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:13 +0200
+Subject: crypto: caam - fix DMA corruption on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 5ddfdcbe10dc5f97afc4e46ca22be2be717e8caf ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The rounding was performed, but never actually used for the allocation.
+Fix this by replacing kmemdup with kmalloc for a larger buffer,
+followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Reported-by: Paul Bunyan <pbunyan@redhat.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamhash.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
+index 25c02e2672585..053af748be86d 100644
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -441,9 +441,10 @@ static int ahash_setkey(struct crypto_ahash *ahash,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, keylen, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From a1c590e3e5cb8abfa41f0fc221a834fc0b2269cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:14 +0200
+Subject: crypto: caam - fix overflow on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 80688afb9c35b3934ce2d6be9973758915e2e0ef ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The copying is performed using kmemdup, however this leads to an overflow:
+reading more bytes (aligned_len - keylen) from the keylen source buffer.
+Fix this by replacing kmemdup with kmalloc, followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamalg_qi2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
+index c6117c23eb25b..07665494c8758 100644
+--- a/drivers/crypto/caam/caamalg_qi2.c
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -3326,9 +3326,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, aligned_len, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From d8372a209f835b90d0c56a0f7752d47c27a0bd1c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 16:31:38 +0100
+Subject: crypto: deflate - fix spurious -ENOSPC
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+[ Upstream commit 6d89f743e57cb34e233a8217b394c7ee09abf225 ]
+
+The code in deflate_decompress_one may erroneously return -ENOSPC even if
+it didn't run out of output space. The error happens under this
+condition:
+
+- Suppose that there are two input pages, the compressed data fits into
+ the first page and the zlib checksum is placed in the second page.
+
+- The code iterates over the first page, decompresses the data and fully
+ fills the destination buffer, zlib_inflate returns Z_OK becuse zlib
+ hasn't seen the checksum yet.
+
+- The outer do-while loop is iterated again, acomp_walk_next_src sets the
+ input parameters to the second page containing the checksum.
+
+- We go into the inner do-while loop, execute "dcur =
+ acomp_walk_next_dst(&walk);". "dcur" is zero, so we break out of the
+ loop and return -ENOSPC, despite the fact that the decompressed data
+ fit into the destination buffer.
+
+In order to fix this bug, this commit changes the logic when to report
+the -ENOSPC error. We report the error if the destination buffer is empty
+*and* if zlib_inflate didn't make any progress consuming the input
+buffer. If zlib_inflate consumes the trailing checksum, we see that it
+made progress and we will not return -ENOSPC.
+
+Fixes: 08cabc7d3c86 ("crypto: deflate - Convert to acomp")
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/deflate.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/crypto/deflate.c b/crypto/deflate.c
+index a3e1fff55661b..8df17e7880c9b 100644
+--- a/crypto/deflate.c
++++ b/crypto/deflate.c
+@@ -164,18 +164,21 @@ static int deflate_decompress_one(struct acomp_req *req,
+
+ do {
+ unsigned int dcur;
++ unsigned long avail_in;
+
+ dcur = acomp_walk_next_dst(&walk);
+- if (!dcur) {
+- out_of_space = true;
+- break;
+- }
+
+ stream->avail_out = dcur;
+ stream->next_out = walk.dst.virt.addr;
++ avail_in = stream->avail_in;
+
+ ret = zlib_inflate(stream, Z_NO_FLUSH);
+
++ if (!dcur && avail_in == stream->avail_in) {
++ out_of_space = true;
++ break;
++ }
++
+ dcur -= stream->avail_out;
+ acomp_walk_done_dst(&walk, dcur);
+ } while (ret == Z_OK && stream->avail_in);
+--
+2.53.0
+
--- /dev/null
+From 6b787e360f7c95601ad09f54cc476b920dc5b70b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Mar 2026 15:18:37 -0600
+Subject: drm/amd/display: Fix gamma 2.2 colorop TFs
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit b49814033cb5224c818cfb04dccb3260da10cc4f ]
+
+Use GAMMA22 for degamma/blend and GAMMA22_INV for shaper so
+curves match the color pipeline.
+
+Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/5016
+Tested-by: Xaver Hugl <xaver.hugl@kde.org>
+Reviewed-by: Melissa Wen <mwen@igalia.com>
+Reviewed-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit d8f9f42effd767ffa7bbcd7e05fbd6b20737e468)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+index cc124ab6aa7f7..212c13b745d0c 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+@@ -37,19 +37,19 @@ const u64 amdgpu_dm_supported_degam_tfs =
+ BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
+ BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
+ BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
+- BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
++ BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
+
+ const u64 amdgpu_dm_supported_shaper_tfs =
+ BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
+ BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) |
+ BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF) |
+- BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
++ BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
+
+ const u64 amdgpu_dm_supported_blnd_tfs =
+ BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
+ BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
+ BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
+- BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
++ BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
+
+ #define MAX_COLOR_PIPELINE_OPS 10
+
+--
+2.53.0
+
--- /dev/null
+From c1f5824cfc8c3e5ebf434923acc3d793ecc2f6a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Mar 2026 16:59:55 -0500
+Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix
+ common property warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 398c0c8bbc8f5a9d2f43863275a427a9d3720b6f ]
+
+Change additionalProperties to unevaluatedProperties because it refs to
+/schemas/input/matrix-keymap.yaml.
+
+Fix below CHECK_DTBS warnings:
+arch/arm/boot/dts/nxp/imx/imx6dl-victgo.dtb: keypad@70 (holtek,ht16k33): 'keypad,num-columns', 'keypad,num-rows' do not match any of the regexes: '^pinctrl-[0-9]+$'
+ from schema $id: http://devicetree.org/schemas/auxdisplay/holtek,ht16k33.yaml#
+
+Fixes: f12b457c6b25c ("dt-bindings: auxdisplay: ht16k33: Convert to json-schema")
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../devicetree/bindings/auxdisplay/holtek,ht16k33.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+index b90eec2077b4b..fe1272e86467e 100644
+--- a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++++ b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+@@ -66,7 +66,7 @@ then:
+ required:
+ - refresh-rate-hz
+
+-additionalProperties: false
++unevaluatedProperties: false
+
+ examples:
+ - |
+--
+2.53.0
+
--- /dev/null
+From ea78969febacceda8b1aca6c4d04054d14542abd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 12:51:22 -0700
+Subject: eth: fbnic: Account for page fragments when updating BDQ tail
+
+From: Dimitri Daskalakis <daskald@meta.com>
+
+[ Upstream commit b38c55320bf85a84a4f04803c57b261fc87e9b4b ]
+
+FBNIC supports fixed size buffers of 4K. When PAGE_SIZE > 4K, we
+fragment the page across multiple descriptors (FBNIC_BD_FRAG_COUNT).
+When refilling the BDQ, the correct number of entries are populated,
+but tail was only incremented by one. So on a system with 64K pages,
+HW would get one descriptor refilled for every 16 we populate.
+
+Additionally, we program the ring size in the HW when enabling the BDQ.
+This was not accounting for page fragments, so on systems with 64K pages,
+the HW used 1/16th of the ring.
+
+Fixes: 0cb4c0a13723 ("eth: fbnic: Implement Rx queue alloc/start/stop/free")
+Signed-off-by: Dimitri Daskalakis <daskald@meta.com>
+Link: https://patch.msgid.link/20260324195123.3486219-2-dimitri.daskalakis1@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+index e119526fce14c..cb0be88427f88 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+@@ -927,7 +927,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq)
+ /* Force DMA writes to flush before writing to tail */
+ dma_wmb();
+
+- writel(i, bdq->doorbell);
++ writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell);
+ }
+ }
+
+@@ -2548,7 +2548,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
+ hpq->tail = 0;
+ hpq->head = 0;
+
+- log_size = fls(hpq->size_mask);
++ log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+
+ /* Store descriptor ring address and size */
+ fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma));
+@@ -2560,7 +2560,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
+ if (!ppq->size_mask)
+ goto write_ctl;
+
+- log_size = fls(ppq->size_mask);
++ log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
+
+ /* Add enabling of PPQ to BDQ control */
+ bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;
+--
+2.53.0
+
--- /dev/null
+From 1ead5dc269c5fb52b91ff8f3c70c660852171bb8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 09:28:48 -0700
+Subject: eth: fbnic: Increase FBNIC_QUEUE_SIZE_MIN to 64
+
+From: Dimitri Daskalakis <daskald@meta.com>
+
+[ Upstream commit ec7067e661193403a7a00980bda8612db5954142 ]
+
+On systems with 64K pages, RX queues will be wedged if users set the
+descriptor count to the current minimum (16). Fbnic fragments large
+pages into 4K chunks, and scales down the ring size accordingly. With
+64K pages and 16 descriptors, the ring size mask is 0 and will never
+be filled.
+
+32 descriptors is another special case that wedges the RX rings.
+Internally, the rings track pages for the head/tail pointers, not page
+fragments. So with 32 descriptors, there's only 1 usable page as one
+ring slot is kept empty to disambiguate between an empty/full ring.
+As a result, the head pointer never advances and the HW stalls after
+consuming 16 page fragments.
+
+Fixes: 0cb4c0a13723 ("eth: fbnic: Implement Rx queue alloc/start/stop/free")
+Signed-off-by: Dimitri Daskalakis <daskald@meta.com>
+Link: https://patch.msgid.link/20260401162848.2335350-1-dimitri.daskalakis1@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+index 51a98f27d5d91..f2ee2cbf3486b 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+@@ -38,7 +38,7 @@ struct fbnic_net;
+ #define FBNIC_MAX_XDPQS 128u
+
+ /* These apply to TWQs, TCQ, RCQ */
+-#define FBNIC_QUEUE_SIZE_MIN 16u
++#define FBNIC_QUEUE_SIZE_MIN 64u
+ #define FBNIC_QUEUE_SIZE_MAX SZ_64K
+
+ #define FBNIC_TXQ_SIZE_DEFAULT 1024
+--
+2.53.0
+
--- /dev/null
+From 210260a33eec4ea5f22df208263c453a4e03baf5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 14:59:29 +0000
+Subject: HID: core: Mitigate potential OOB by removing bogus memset()
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit 0a3fe972a7cb1404f693d6f1711f32bc1d244b1c ]
+
+The memset() in hid_report_raw_event() has the good intention of
+clearing out bogus data by zeroing the area from the end of the incoming
+data string to the assumed end of the buffer. However, as we have
+previously seen, doing so can easily result in OOB reads and writes in
+the subsequent thread of execution.
+
+The current suggestion from one of the HID maintainers is to remove the
+memset() and simply return if the incoming event buffer size is not
+large enough to fill the associated report.
+
+Suggested-by Benjamin Tissoires <bentiss@kernel.org>
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+[bentiss: changed the return value]
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index a5b3a8ca2fcbc..f5587b786f875 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -2057,9 +2057,10 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
+ rsize = max_buffer_size;
+
+ if (csize < rsize) {
+- dbg_hid("report %d is too short, (%d < %d)\n", report->id,
+- csize, rsize);
+- memset(cdata + csize, 0, rsize - csize);
++ hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
++ report->id, rsize, csize);
++ ret = -EINVAL;
++ goto out;
+ }
+
+ if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
+--
+2.53.0
+
--- /dev/null
+From 94d242731653cb0dde4b43c48dc4e762f103adb5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Mar 2026 20:19:33 +0100
+Subject: HID: logitech-hidpp: Enable MX Master 4 over bluetooth
+
+From: Adrian Freund <adrian@freund.io>
+
+[ Upstream commit 70031e70ca15ede6a39db4d978e53a6cc720d454 ]
+
+The Logitech MX Master 4 can be connected over bluetooth or through a
+Logitech Bolt receiver. This change adds support for non-standard HID
+features, such as high resolution scrolling when the mouse is connected
+over bluetooth.
+Because no Logitech Bolt receiver driver exists yet those features
+won't be available when the mouse is connected through the receiver.
+
+Signed-off-by: Adrian Freund <adrian@freund.io>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-hidpp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
+index 02d83c3bd73d4..c3d53250a7604 100644
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4668,6 +4668,8 @@ static const struct hid_device_id hidpp_devices[] = {
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
+ { /* Slim Solar+ K980 Keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
++ { /* MX Master 4 mouse over Bluetooth */
++ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb042) },
+ {}
+ };
+
+--
+2.53.0
+
--- /dev/null
+From 7ab56fdef4f286bc61113d05b95551837b6d6517 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 10:09:38 +0000
+Subject: HID: logitech-hidpp: Prevent use-after-free on force feedback
+ initialisation failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit f7a4c78bfeb320299c1b641500fe7761eadbd101 ]
+
+Presently, if the force feedback initialisation fails when probing the
+Logitech G920 Driving Force Racing Wheel for Xbox One, an error number
+will be returned and propagated before the userspace infrastructure
+(sysfs and /dev/input) has been torn down. If userspace ignores the
+errors and continues to use its references to these dangling entities, a
+UAF will promptly follow.
+
+We have 2 options; continue to return the error, but ensure that all of
+the infrastructure is torn down accordingly or continue to treat this
+condition as a warning by emitting the message but returning success.
+It is thought that the original author's intention was to emit the
+warning but keep the device functional, less the force feedback feature,
+so let's go with that.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Reviewed-by: Günther Noack <gnoack@google.com>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-hidpp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
+index c3d53250a7604..65bfad405ac5b 100644
+--- a/drivers/hid/hid-logitech-hidpp.c
++++ b/drivers/hid/hid-logitech-hidpp.c
+@@ -4487,10 +4487,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ if (!ret)
+ ret = hidpp_ff_init(hidpp, &data);
+
+- if (ret)
++ if (ret) {
+ hid_warn(hidpp->hid_dev,
+ "Unable to initialize force feedback support, errno %d\n",
+ ret);
++ ret = 0;
++ }
+ }
+
+ /*
+--
+2.53.0
+
--- /dev/null
+From a287dc5f2793b1e7d27aa81c711a4f7f8ae3a1f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index b8a748bbf0fd8..e82a3c4e5b44e 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -526,12 +526,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e8e6381cbb94b244ec547f9cfe7670cd7661cb83 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 9b2c710f8da18..da1f0ea85625d 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1208,10 +1208,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From 9c1434f39305436595babf24cdfe0bffa9049e6b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:32:11 +0900
+Subject: i2c: tegra: Don't mark devices with pins as IRQ safe
+
+From: Mikko Perttunen <mperttunen@nvidia.com>
+
+[ Upstream commit ec69c9e88315c4be70c283f18c2ff130da6320b5 ]
+
+I2C devices with associated pinctrl states (DPAUX I2C controllers)
+will change pinctrl state during runtime PM. This requires taking
+a mutex, so these devices cannot be marked as IRQ safe.
+
+Add PINCTRL as dependency to avoid build errors.
+
+Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
+Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/Kconfig | 2 ++
+ drivers/i2c/busses/i2c-tegra.c | 5 ++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 09ba55bae1fac..7d0afdc7d8862 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -1220,6 +1220,8 @@ config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
+ # COMPILE_TEST needs architectures with readsX()/writesX() primitives
++ depends on PINCTRL
++ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
+index e533460bccc39..a9aed411e3190 100644
+--- a/drivers/i2c/busses/i2c-tegra.c
++++ b/drivers/i2c/busses/i2c-tegra.c
+@@ -1837,8 +1837,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
+ *
+ * VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
+ * be used for atomic transfers. ACPI device is not IRQ safe also.
++ *
++ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
++ * state transitions during runtime PM require mutexes.
+ */
+- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
++ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
+ pm_runtime_irq_safe(i2c_dev->dev);
+
+ pm_runtime_enable(i2c_dev->dev);
+--
+2.53.0
+
--- /dev/null
+From 0bf736eb0be37f12934da976809f566706583f56 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 09:17:19 -0700
+Subject: iommupt/amdv1: mark amdv1pt_install_leaf_entry as __always_inline
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Sherry Yang <sherry.yang@oracle.com>
+
+[ Upstream commit 8b72aa5704c77380742346d4ac755b074b7f9eaa ]
+
+After enabling CONFIG_GCOV_KERNEL and CONFIG_GCOV_PROFILE_ALL, following
+build failure is observed under GCC 14.2.1:
+
+In function 'amdv1pt_install_leaf_entry',
+ inlined from '__do_map_single_page' at drivers/iommu/generic_pt/fmt/../iommu_pt.h:650:3,
+ inlined from '__map_single_page0' at drivers/iommu/generic_pt/fmt/../iommu_pt.h:661:1,
+ inlined from 'pt_descend' at drivers/iommu/generic_pt/fmt/../pt_iter.h:391:9,
+ inlined from '__do_map_single_page' at drivers/iommu/generic_pt/fmt/../iommu_pt.h:657:10,
+ inlined from '__map_single_page1.constprop' at drivers/iommu/generic_pt/fmt/../iommu_pt.h:661:1:
+././include/linux/compiler_types.h:706:45: error: call to '__compiletime_assert_71' declared with attribute error: FIELD_PREP: value too large for the field
+ 706 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
+ |
+
+......
+
+drivers/iommu/generic_pt/fmt/amdv1.h:220:26: note: in expansion of macro 'FIELD_PREP'
+ 220 | FIELD_PREP(AMDV1PT_FMT_OA,
+ | ^~~~~~~~~~
+
+In the path '__do_map_single_page()', level 0 always invokes
+'pt_install_leaf_entry(&pts, map->oa, PAGE_SHIFT, …)'. At runtime that
+lands in the 'if (oasz_lg2 == isz_lg2)' arm of 'amdv1pt_install_leaf_entry()';
+the contiguous-only 'else' block is unreachable for 4 KiB pages.
+
+With CONFIG_GCOV_KERNEL + CONFIG_GCOV_PROFILE_ALL, the extra
+instrumentation changes GCC's inlining so that the "dead" 'else' branch
+still gets instantiated. The compiler constant-folds the contiguous OA
+expression, runs the 'FIELD_PREP()' compile-time check, and produces:
+
+ FIELD_PREP: value too large for the field
+
+gcov-enabled builds therefore fail even though the code path never executes.
+
+Fix this by marking amdv1pt_install_leaf_entry as __always_inline.
+
+Fixes: dcd6a011a8d5 ("iommupt: Add map_pages op")
+Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Sherry Yang <sherry.yang@oracle.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/generic_pt/fmt/amdv1.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h
+index 3b2c41d9654d7..8d11b08291d73 100644
+--- a/drivers/iommu/generic_pt/fmt/amdv1.h
++++ b/drivers/iommu/generic_pt/fmt/amdv1.h
+@@ -191,7 +191,7 @@ static inline enum pt_entry_type amdv1pt_load_entry_raw(struct pt_state *pts)
+ }
+ #define pt_load_entry_raw amdv1pt_load_entry_raw
+
+-static inline void
++static __always_inline void
+ amdv1pt_install_leaf_entry(struct pt_state *pts, pt_oaddr_t oa,
+ unsigned int oasz_lg2,
+ const struct pt_write_attrs *attrs)
+--
+2.53.0
+
--- /dev/null
+From 60fa8ad71a5b3db3d3c9ebd2bad8418786f0d55a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index c1f39735a2367..9e2449db0bdf2 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From 754bfbe798fae88c2eb37bc8f4bbf1d1454c4cdb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 83e03176819ce..022069c7d6edc 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -762,6 +762,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -923,9 +924,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -968,12 +973,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From 1d914e3e30dae71e9347c7d5802dc4a11eb35b62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index 0f41ca6f3d83e..9844758252718 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -871,6 +871,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From 4d9057acaf13b7a6c7443ea254a904958ec4bf3a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 3dcfa4b3094a8..272dd1a0acd0e 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3621,12 +3621,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 93c3733b966af16f61f7e1d9633e760f0c8318b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 00:25:57 +0100
+Subject: mpls: add seqcount to protect the platform_label{,s} pair
+
+From: Sabrina Dubroca <sd@queasysnail.net>
+
+[ Upstream commit 629ec78ef8608d955ce217880cdc3e1873af3a15 ]
+
+The RCU-protected codepaths (mpls_forward, mpls_dump_routes) can have
+an inconsistent view of platform_labels vs platform_label in case of a
+concurrent resize (resize_platform_label_table, under
+platform_mutex). This can lead to OOB accesses.
+
+This patch adds a seqcount, so that we get a consistent snapshot.
+
+Note that mpls_label_ok is also susceptible to this, so the check
+against RTA_DST in rtm_to_route_config, done outside platform_mutex,
+is not sufficient. This value gets passed to mpls_label_ok once more
+in both mpls_route_add and mpls_route_del, so there is no issue, but
+that additional check must not be removed.
+
+Reported-by: Yuan Tan <tanyuan98@outlook.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Fixes: 7720c01f3f590 ("mpls: Add a sysctl to control the size of the mpls label table")
+Fixes: dde1b38e873c ("mpls: Convert mpls_dump_routes() to RCU.")
+Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
+Link: https://patch.msgid.link/cd8fca15e3eb7e212b094064cd83652e20fd9d31.1774284088.git.sd@queasysnail.net
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netns/mpls.h | 1 +
+ net/mpls/af_mpls.c | 29 +++++++++++++++++++++++++----
+ 2 files changed, 26 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/netns/mpls.h b/include/net/netns/mpls.h
+index 6682e51513efa..2073cbac2afb5 100644
+--- a/include/net/netns/mpls.h
++++ b/include/net/netns/mpls.h
+@@ -17,6 +17,7 @@ struct netns_mpls {
+ size_t platform_labels;
+ struct mpls_route __rcu * __rcu *platform_label;
+ struct mutex platform_mutex;
++ seqcount_mutex_t platform_label_seq;
+
+ struct ctl_table_header *ctl;
+ };
+diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
+index c57f10e2ef269..d77bbe4969886 100644
+--- a/net/mpls/af_mpls.c
++++ b/net/mpls/af_mpls.c
+@@ -83,14 +83,30 @@ static struct mpls_route *mpls_route_input(struct net *net, unsigned int index)
+ return mpls_dereference(net, platform_label[index]);
+ }
+
++static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net, size_t *platform_labels)
++{
++ struct mpls_route __rcu **platform_label;
++ unsigned int sequence;
++
++ do {
++ sequence = read_seqcount_begin(&net->mpls.platform_label_seq);
++ platform_label = rcu_dereference(net->mpls.platform_label);
++ *platform_labels = net->mpls.platform_labels;
++ } while (read_seqcount_retry(&net->mpls.platform_label_seq, sequence));
++
++ return platform_label;
++}
++
+ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
+ {
+ struct mpls_route __rcu **platform_label;
++ size_t platform_labels;
++
++ platform_label = mpls_platform_label_rcu(net, &platform_labels);
+
+- if (index >= net->mpls.platform_labels)
++ if (index >= platform_labels)
+ return NULL;
+
+- platform_label = rcu_dereference(net->mpls.platform_label);
+ return rcu_dereference(platform_label[index]);
+ }
+
+@@ -2240,8 +2256,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
+ if (index < MPLS_LABEL_FIRST_UNRESERVED)
+ index = MPLS_LABEL_FIRST_UNRESERVED;
+
+- platform_label = rcu_dereference(net->mpls.platform_label);
+- platform_labels = net->mpls.platform_labels;
++ platform_label = mpls_platform_label_rcu(net, &platform_labels);
+
+ if (filter.filter_set)
+ flags |= NLM_F_DUMP_FILTERED;
+@@ -2645,8 +2660,12 @@ static int resize_platform_label_table(struct net *net, size_t limit)
+ }
+
+ /* Update the global pointers */
++ local_bh_disable();
++ write_seqcount_begin(&net->mpls.platform_label_seq);
+ net->mpls.platform_labels = limit;
+ rcu_assign_pointer(net->mpls.platform_label, labels);
++ write_seqcount_end(&net->mpls.platform_label_seq);
++ local_bh_enable();
+
+ mutex_unlock(&net->mpls.platform_mutex);
+
+@@ -2728,6 +2747,8 @@ static __net_init int mpls_net_init(struct net *net)
+ int i;
+
+ mutex_init(&net->mpls.platform_mutex);
++ seqcount_mutex_init(&net->mpls.platform_label_seq, &net->mpls.platform_mutex);
++
+ net->mpls.platform_labels = 0;
+ net->mpls.platform_label = NULL;
+ net->mpls.ip_ttl_propagate = 1;
+--
+2.53.0
+
--- /dev/null
+From e8de53113901733a13e9d50ba9235d7423ff709c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Jan 2026 20:24:24 +0100
+Subject: mptcp: add eat_recv_skb helper
+
+From: Geliang Tang <tanggeliang@kylinos.cn>
+
+[ Upstream commit 436510df0cafb1bc36f12e92e0e76599be28d8f4 ]
+
+This patch extracts the free skb related code in __mptcp_recvmsg_mskq()
+into a new helper mptcp_eat_recv_skb().
+
+This new helper will be used in the next patch.
+
+Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260130-net-next-mptcp-splice-v2-1-31332ba70d7f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index bad9fc0f27d9c..a29f959b123a4 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -1989,6 +1989,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+
+ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);
+
++static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
++{
++ /* avoid the indirect call, we know the destructor is sock_rfree */
++ skb->destructor = NULL;
++ skb->sk = NULL;
++ atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
++ sk_mem_uncharge(sk, skb->truesize);
++ __skb_unlink(skb, &sk->sk_receive_queue);
++ skb_attempt_defer_free(skb);
++}
++
+ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ size_t len, int flags, int copied_total,
+ struct scm_timestamping_internal *tss,
+@@ -2043,13 +2054,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ break;
+ }
+
+- /* avoid the indirect call, we know the destructor is sock_rfree */
+- skb->destructor = NULL;
+- skb->sk = NULL;
+- atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
+- sk_mem_uncharge(sk, skb->truesize);
+- __skb_unlink(skb, &sk->sk_receive_queue);
+- skb_attempt_defer_free(skb);
++ mptcp_eat_recv_skb(sk, skb);
+ }
+
+ if (copied >= len)
+--
+2.53.0
+
--- /dev/null
+From b7109a8b73bfd2b44e470bde0e166647a2e81199 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 20:03:35 +0800
+Subject: mptcp: fix soft lockup in mptcp_recvmsg()
+
+From: Li Xiasong <lixiasong1@huawei.com>
+
+[ Upstream commit 5dd8025a49c268ab6b94d978532af3ad341132a7 ]
+
+syzbot reported a soft lockup in mptcp_recvmsg() [0].
+
+When receiving data with MSG_PEEK | MSG_WAITALL flags, the skb is not
+removed from the sk_receive_queue. This causes sk_wait_data() to always
+find available data and never perform actual waiting, leading to a soft
+lockup.
+
+Fix this by adding a 'last' parameter to track the last peeked skb.
+This allows sk_wait_data() to make informed waiting decisions and prevent
+infinite loops when MSG_PEEK is used.
+
+[0]:
+watchdog: BUG: soft lockup - CPU#2 stuck for 156s! [server:1963]
+Modules linked in:
+CPU: 2 UID: 0 PID: 1963 Comm: server Not tainted 6.19.0-rc8 #61 PREEMPT(none)
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
+RIP: 0010:sk_wait_data+0x15/0x190
+Code: 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 41 56 41 55 41 54 49 89 f4 55 48 89 d5 53 48 89 fb <48> 83 ec 30 65 48 8b 05 17 a4 6b 01 48 89 44 24 28 31 c0 65 48 8b
+RSP: 0018:ffffc90000603ca0 EFLAGS: 00000246
+RAX: 0000000000000000 RBX: ffff888102bf0800 RCX: 0000000000000001
+RDX: 0000000000000000 RSI: ffffc90000603d18 RDI: ffff888102bf0800
+RBP: 0000000000000000 R08: 0000000000000002 R09: 0000000000000101
+R10: 0000000000000000 R11: 0000000000000075 R12: ffffc90000603d18
+R13: ffff888102bf0800 R14: ffff888102bf0800 R15: 0000000000000000
+FS: 00007f6e38b8c4c0(0000) GS:ffff8881b877e000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 000055aa7bff1680 CR3: 0000000105cbe000 CR4: 00000000000006f0
+Call Trace:
+ <TASK>
+ mptcp_recvmsg+0x547/0x8c0 net/mptcp/protocol.c:2329
+ inet_recvmsg+0x11f/0x130 net/ipv4/af_inet.c:891
+ sock_recvmsg+0x94/0xc0 net/socket.c:1100
+ __sys_recvfrom+0xb2/0x130 net/socket.c:2256
+ __x64_sys_recvfrom+0x1f/0x30 net/socket.c:2267
+ do_syscall_64+0x59/0x2d0 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e arch/x86/entry/entry_64.S:131
+RIP: 0033:0x7f6e386a4a1d
+Code: 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8d 05 f1 de 2c 00 41 89 ca 8b 00 85 c0 75 20 45 31 c9 45 31 c0 b8 2d 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 6b f3 c3 66 0f 1f 84 00 00 00 00 00 41 56 41
+RSP: 002b:00007ffc3c4bb078 EFLAGS: 00000246 ORIG_RAX: 000000000000002d
+RAX: ffffffffffffffda RBX: 000000000000861e RCX: 00007f6e386a4a1d
+RDX: 00000000000003ff RSI: 00007ffc3c4bb150 RDI: 0000000000000004
+RBP: 00007ffc3c4bb570 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000103 R11: 0000000000000246 R12: 00005605dbc00be0
+R13: 00007ffc3c4bb650 R14: 0000000000000000 R15: 0000000000000000
+ </TASK>
+
+Fixes: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
+Signed-off-by: Li Xiasong <lixiasong1@huawei.com>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260330120335.659027-1-lixiasong1@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index a29f959b123a4..f1fa35cb8c000 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -2003,7 +2003,7 @@ static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
+ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ size_t len, int flags, int copied_total,
+ struct scm_timestamping_internal *tss,
+- int *cmsg_flags)
++ int *cmsg_flags, struct sk_buff **last)
+ {
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ struct sk_buff *skb, *tmp;
+@@ -2020,6 +2020,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ /* skip already peeked skbs */
+ if (total_data_len + data_len <= copied_total) {
+ total_data_len += data_len;
++ *last = skb;
+ continue;
+ }
+
+@@ -2055,6 +2056,8 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg,
+ }
+
+ mptcp_eat_recv_skb(sk, skb);
++ } else {
++ *last = skb;
+ }
+
+ if (copied >= len)
+@@ -2269,10 +2272,12 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
+ cmsg_flags = MPTCP_CMSG_INQ;
+
+ while (copied < len) {
++ struct sk_buff *last = NULL;
+ int err, bytes_read;
+
+ bytes_read = __mptcp_recvmsg_mskq(sk, msg, len - copied, flags,
+- copied, &tss, &cmsg_flags);
++ copied, &tss, &cmsg_flags,
++ &last);
+ if (unlikely(bytes_read < 0)) {
+ if (!copied)
+ copied = bytes_read;
+@@ -2324,7 +2329,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
+
+ pr_debug("block timeout %ld\n", timeo);
+ mptcp_cleanup_rbuf(msk, copied);
+- err = sk_wait_data(sk, &timeo, NULL);
++ err = sk_wait_data(sk, &timeo, last);
+ if (err < 0) {
+ err = copied ? : err;
+ goto out_err;
+--
+2.53.0
+
--- /dev/null
+From 6c085c4e0a7b39ad6c4cf7e8702c039abe2f6360 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 15:04:55 +0000
+Subject: mshv: Fix error handling in mshv_region_pin
+
+From: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
+
+[ Upstream commit c0e296f257671ba10249630fe58026f29e4804d9 ]
+
+The current error handling has two issues:
+
+First, pin_user_pages_fast() can return a short pin count (less than
+requested but greater than zero) when it cannot pin all requested pages.
+This is treated as success, leading to partially pinned regions being
+used, which causes memory corruption.
+
+Second, when an error occurs mid-loop, already pinned pages from the
+current batch are not properly accounted for before calling
+mshv_region_invalidate_pages(), causing a page reference leak.
+
+Treat short pins as errors and fix partial batch accounting before
+cleanup.
+
+Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hv/mshv_regions.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
+index adba3564d9f1a..baa864cac375a 100644
+--- a/drivers/hv/mshv_regions.c
++++ b/drivers/hv/mshv_regions.c
+@@ -314,15 +314,17 @@ int mshv_region_pin(struct mshv_mem_region *region)
+ ret = pin_user_pages_fast(userspace_addr, nr_pages,
+ FOLL_WRITE | FOLL_LONGTERM,
+ pages);
+- if (ret < 0)
++ if (ret != nr_pages)
+ goto release_pages;
+ }
+
+ return 0;
+
+ release_pages:
++ if (ret > 0)
++ done_count += ret;
+ mshv_region_invalidate_pages(region, 0, done_count);
+- return ret;
++ return ret < 0 ? ret : -ENOMEM;
+ }
+
+ static int mshv_region_chunk_unmap(struct mshv_mem_region *region,
+--
+2.53.0
+
--- /dev/null
+From c54bcb55b35632d52f18f6d43e5c3d02d4bd9dfd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:48:21 +0100
+Subject: net: airoha: Add missing cleanup bits in
+ airoha_qdma_cleanup_rx_queue()
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit 514aac3599879a7ed48b7dc19e31145beb6958ac ]
+
+In order to properly cleanup hw rx QDMA queues and bring the device to
+the initial state, reset rx DMA queue head/tail index. Moreover, reset
+queued DMA descriptor fields.
+
+Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
+Tested-by: Madhur Agrawal <Madhur.Agrawal@airoha.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://patch.msgid.link/20260327-airoha_qdma_cleanup_rx_queue-fix-v1-1-369d6ab1511a@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_eth.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
+index c37a1b86180f3..454d7dcf198d9 100644
+--- a/drivers/net/ethernet/airoha/airoha_eth.c
++++ b/drivers/net/ethernet/airoha/airoha_eth.c
+@@ -794,18 +794,34 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
+
+ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
+ {
+- struct airoha_eth *eth = q->qdma->eth;
++ struct airoha_qdma *qdma = q->qdma;
++ struct airoha_eth *eth = qdma->eth;
++ int qid = q - &qdma->q_rx[0];
+
+ while (q->queued) {
+ struct airoha_queue_entry *e = &q->entry[q->tail];
++ struct airoha_qdma_desc *desc = &q->desc[q->tail];
+ struct page *page = virt_to_head_page(e->buf);
+
+ dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
+ page_pool_get_dma_dir(q->page_pool));
+ page_pool_put_full_page(q->page_pool, page, false);
++ /* Reset DMA descriptor */
++ WRITE_ONCE(desc->ctrl, 0);
++ WRITE_ONCE(desc->addr, 0);
++ WRITE_ONCE(desc->data, 0);
++ WRITE_ONCE(desc->msg0, 0);
++ WRITE_ONCE(desc->msg1, 0);
++ WRITE_ONCE(desc->msg2, 0);
++ WRITE_ONCE(desc->msg3, 0);
++
+ q->tail = (q->tail + 1) % q->ndesc;
+ q->queued--;
+ }
++
++ q->head = q->tail;
++ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
++ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
+ }
+
+ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
+--
+2.53.0
+
--- /dev/null
+From 470b2d4fdb198e51187115e4486944512dcd26f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:55:53 -0700
+Subject: net: bonding: fix use-after-free in bond_xmit_broadcast()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 2884bf72fb8f03409e423397319205de48adca16 ]
+
+bond_xmit_broadcast() reuses the original skb for the last slave
+(determined by bond_is_last_slave()) and clones it for others.
+Concurrent slave enslave/release can mutate the slave list during
+RCU-protected iteration, changing which slave is "last" mid-loop.
+This causes the original skb to be double-consumed (double-freed).
+
+Replace the racy bond_is_last_slave() check with a simple index
+comparison (i + 1 == slaves_count) against the pre-snapshot slave
+count taken via READ_ONCE() before the loop. This preserves the
+zero-copy optimization for the last slave while making the "last"
+determination stable against concurrent list mutations.
+
+The UAF can trigger the following crash:
+
+==================================================================
+BUG: KASAN: slab-use-after-free in skb_clone
+Read of size 8 at addr ffff888100ef8d40 by task exploit/147
+
+CPU: 1 UID: 0 PID: 147 Comm: exploit Not tainted 7.0.0-rc3+ #4 PREEMPTLAZY
+Call Trace:
+ <TASK>
+ dump_stack_lvl (lib/dump_stack.c:123)
+ print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
+ kasan_report (mm/kasan/report.c:597)
+ skb_clone (include/linux/skbuff.h:1724 include/linux/skbuff.h:1792 include/linux/skbuff.h:3396 net/core/skbuff.c:2108)
+ bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5334)
+ bond_start_xmit (drivers/net/bonding/bond_main.c:5567 drivers/net/bonding/bond_main.c:5593)
+ dev_hard_start_xmit (include/linux/netdevice.h:5325 include/linux/netdevice.h:5334 net/core/dev.c:3871 net/core/dev.c:3887)
+ __dev_queue_xmit (include/linux/netdevice.h:3601 net/core/dev.c:4838)
+ ip6_finish_output2 (include/net/neighbour.h:540 include/net/neighbour.h:554 net/ipv6/ip6_output.c:136)
+ ip6_finish_output (net/ipv6/ip6_output.c:208 net/ipv6/ip6_output.c:219)
+ ip6_output (net/ipv6/ip6_output.c:250)
+ ip6_send_skb (net/ipv6/ip6_output.c:1985)
+ udp_v6_send_skb (net/ipv6/udp.c:1442)
+ udpv6_sendmsg (net/ipv6/udp.c:1733)
+ __sys_sendto (net/socket.c:730 net/socket.c:742 net/socket.c:2206)
+ __x64_sys_sendto (net/socket.c:2209)
+ 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:130)
+ </TASK>
+
+Allocated by task 147:
+
+Freed by task 147:
+
+The buggy address belongs to the object at ffff888100ef8c80
+ which belongs to the cache skbuff_head_cache of size 224
+The buggy address is located 192 bytes inside of
+ freed 224-byte region [ffff888100ef8c80, ffff888100ef8d60)
+
+Memory state around the buggy address:
+ ffff888100ef8c00: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff888100ef8c80: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+>ffff888100ef8d00: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
+ ^
+ ffff888100ef8d80: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
+ ffff888100ef8e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+==================================================================
+
+Fixes: 4e5bd03ae346 ("net: bonding: fix bond_xmit_broadcast return value error bug")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/bonding/bond_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 106cfe732a15e..1d84e348f2cc7 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -5300,7 +5300,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb,
+ if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
+ continue;
+
+- if (bond_is_last_slave(bond, slave)) {
++ if (i + 1 == slaves_count) {
+ skb2 = skb;
+ skb_used = true;
+ } else {
+--
+2.53.0
+
--- /dev/null
+From acf09541fa3d50e21627fff4d60d450750ecc56d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:21:20 +0800
+Subject: net: enetc: add graceful stop to safely reinitialize the TX Ring
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit 2725d84efe2582c0a4b907e74a689d26b2dbd382 ]
+
+For ENETC v4, the PIR and CIR will be reset if they are not equal when
+reinitializing the TX BD ring. However, resetting the PIR and CIR alone
+is insufficient. When a link-down event occurs while the TX BD ring is
+transmitting frames, subsequent reinitialization of the TX BD ring may
+cause it to malfunction. For example, the below steps can reproduce the
+problem.
+
+1. Unplug the cable when the TX BD ring is busy transmitting frames.
+2. Disable the network interface (ifconfig eth0 down).
+3. Re-enable the network interface (ifconfig eth0 up).
+4. Plug in the cable, the TX BD ring may fail to transmit packets.
+
+When the link-down event occurs, enetc4_pl_mac_link_down() only clears
+PMa_COMMAND_CONFIG[TX_EN] to disable MAC transmit data path. It doesn't
+set PORT[TXDIS] to 1 to flush the TX BD ring. Therefore, reinitializing
+the TX BD ring at this point is unsafe. To safely reinitialize the TX BD
+ring after a link-down event, we checked with the NETC IP team, a proper
+Ethernet MAC graceful stop is necessary. Therefore, add the Ethernet MAC
+graceful stop to the link-down event handler enetc4_pl_mac_link_down().
+
+Fixes: 99100d0d9922 ("net: enetc: add preliminary support for i.MX95 ENETC PF")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324062121.2745033-3-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/freescale/enetc/enetc4_hw.h | 11 ++
+ .../net/ethernet/freescale/enetc/enetc4_pf.c | 111 +++++++++++++++---
+ 2 files changed, 108 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+index 3ed0f7a027679..719c88ceb801a 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+@@ -134,6 +134,12 @@
+
+ /* Port operational register */
+ #define ENETC4_POR 0x4100
++#define POR_TXDIS BIT(0)
++#define POR_RXDIS BIT(1)
++
++/* Port status register */
++#define ENETC4_PSR 0x4104
++#define PSR_RX_BUSY BIT(1)
+
+ /* Port traffic class a transmit maximum SDU register */
+ #define ENETC4_PTCTMSDUR(a) ((a) * 0x20 + 0x4208)
+@@ -173,6 +179,11 @@
+ /* Port internal MDIO base address, use to access PCS */
+ #define ENETC4_PM_IMDIO_BASE 0x5030
+
++/* Port MAC 0/1 Interrupt Event Register */
++#define ENETC4_PM_IEVENT(mac) (0x5040 + (mac) * 0x400)
++#define PM_IEVENT_TX_EMPTY BIT(5)
++#define PM_IEVENT_RX_EMPTY BIT(6)
++
+ /* Port MAC 0/1 Pause Quanta Register */
+ #define ENETC4_PM_PAUSE_QUANTA(mac) (0x5054 + (mac) * 0x400)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+index 5850540634b0c..6a334f2848448 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+@@ -444,20 +444,11 @@ static void enetc4_set_trx_frame_size(struct enetc_pf *pf)
+ enetc4_pf_reset_tc_msdu(&si->hw);
+ }
+
+-static void enetc4_enable_trx(struct enetc_pf *pf)
+-{
+- struct enetc_hw *hw = &pf->si->hw;
+-
+- /* Enable port transmit/receive */
+- enetc_port_wr(hw, ENETC4_POR, 0);
+-}
+-
+ static void enetc4_configure_port(struct enetc_pf *pf)
+ {
+ enetc4_configure_port_si(pf);
+ enetc4_set_trx_frame_size(pf);
+ enetc_set_default_rss_key(pf);
+- enetc4_enable_trx(pf);
+ }
+
+ static int enetc4_init_ntmp_user(struct enetc_si *si)
+@@ -801,15 +792,105 @@ static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_paus
+ enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh);
+ }
+
+-static void enetc4_enable_mac(struct enetc_pf *pf, bool en)
++static void enetc4_mac_wait_tx_empty(struct enetc_si *si, int mac)
++{
++ u32 val;
++
++ if (read_poll_timeout(enetc_port_rd, val,
++ val & PM_IEVENT_TX_EMPTY,
++ 100, 10000, false, &si->hw,
++ ENETC4_PM_IEVENT(mac)))
++ dev_warn(&si->pdev->dev,
++ "MAC %d TX is not empty\n", mac);
++}
++
++static void enetc4_mac_tx_graceful_stop(struct enetc_pf *pf)
++{
++ struct enetc_hw *hw = &pf->si->hw;
++ struct enetc_si *si = pf->si;
++ u32 val;
++
++ val = enetc_port_rd(hw, ENETC4_POR);
++ val |= POR_TXDIS;
++ enetc_port_wr(hw, ENETC4_POR, val);
++
++ enetc4_mac_wait_tx_empty(si, 0);
++ if (si->hw_features & ENETC_SI_F_QBU)
++ enetc4_mac_wait_tx_empty(si, 1);
++
++ val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
++ val &= ~PM_CMD_CFG_TX_EN;
++ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
++}
++
++static void enetc4_mac_tx_enable(struct enetc_pf *pf)
+ {
++ struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+- val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN);
+- val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0;
++ val |= PM_CMD_CFG_TX_EN;
++ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
++
++ val = enetc_port_rd(hw, ENETC4_POR);
++ val &= ~POR_TXDIS;
++ enetc_port_wr(hw, ENETC4_POR, val);
++}
++
++static void enetc4_mac_wait_rx_empty(struct enetc_si *si, int mac)
++{
++ u32 val;
++
++ if (read_poll_timeout(enetc_port_rd, val,
++ val & PM_IEVENT_RX_EMPTY,
++ 100, 10000, false, &si->hw,
++ ENETC4_PM_IEVENT(mac)))
++ dev_warn(&si->pdev->dev,
++ "MAC %d RX is not empty\n", mac);
++}
++
++static void enetc4_mac_rx_graceful_stop(struct enetc_pf *pf)
++{
++ struct enetc_hw *hw = &pf->si->hw;
++ struct enetc_si *si = pf->si;
++ u32 val;
++
++ if (si->hw_features & ENETC_SI_F_QBU) {
++ val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(1));
++ val &= ~PM_CMD_CFG_RX_EN;
++ enetc_port_wr(hw, ENETC4_PM_CMD_CFG(1), val);
++ enetc4_mac_wait_rx_empty(si, 1);
++ }
++
++ val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(0));
++ val &= ~PM_CMD_CFG_RX_EN;
++ enetc_port_wr(hw, ENETC4_PM_CMD_CFG(0), val);
++ enetc4_mac_wait_rx_empty(si, 0);
++
++ if (read_poll_timeout(enetc_port_rd, val,
++ !(val & PSR_RX_BUSY),
++ 100, 10000, false, hw,
++ ENETC4_PSR))
++ dev_warn(&si->pdev->dev, "Port RX busy\n");
++
++ val = enetc_port_rd(hw, ENETC4_POR);
++ val |= POR_RXDIS;
++ enetc_port_wr(hw, ENETC4_POR, val);
++}
++
++static void enetc4_mac_rx_enable(struct enetc_pf *pf)
++{
++ struct enetc_hw *hw = &pf->si->hw;
++ struct enetc_si *si = pf->si;
++ u32 val;
++
++ val = enetc_port_rd(hw, ENETC4_POR);
++ val &= ~POR_RXDIS;
++ enetc_port_wr(hw, ENETC4_POR, val);
+
++ val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
++ val |= PM_CMD_CFG_RX_EN;
+ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+ }
+
+@@ -853,7 +934,8 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,
+ enetc4_set_hd_flow_control(pf, hd_fc);
+ enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause);
+ enetc4_set_rx_pause(pf, rx_pause);
+- enetc4_enable_mac(pf, true);
++ enetc4_mac_tx_enable(pf);
++ enetc4_mac_rx_enable(pf);
+ }
+
+ static void enetc4_pl_mac_link_down(struct phylink_config *config,
+@@ -862,7 +944,8 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config,
+ {
+ struct enetc_pf *pf = phylink_to_enetc_pf(config);
+
+- enetc4_enable_mac(pf, false);
++ enetc4_mac_rx_graceful_stop(pf);
++ enetc4_mac_tx_graceful_stop(pf);
+ }
+
+ static const struct phylink_mac_ops enetc_pl_mac_ops = {
+--
+2.53.0
+
--- /dev/null
+From 3bc93b860ed92c074bdbc91ea4545ec7c4660468 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:52:32 +0800
+Subject: net: enetc: check whether the RSS algorithm is Toeplitz
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit d389954a6cae7bf76b7b082ac3511d177b77ef2d ]
+
+Both ENETC v1 and v4 only provide Toeplitz RSS support. This patch adds
+a validation check to reject attempts to configure other RSS algorithms,
+avoiding misleading configuration options for users.
+
+Fixes: d382563f541b ("enetc: Add RFS and RSS support")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Link: https://patch.msgid.link/20260326075233.3628047-2-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+index 2fe140ddebb23..a393647e6062c 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -795,6 +795,10 @@ static int enetc_set_rxfh(struct net_device *ndev,
+ struct enetc_si *si = priv->si;
+ int err = 0;
+
++ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
++ rxfh->hfunc != ETH_RSS_HASH_TOP)
++ return -EOPNOTSUPP;
++
+ /* set hash key, if PF */
+ if (rxfh->key && enetc_si_is_pf(si))
+ enetc_set_rss_key(si, rxfh->key);
+--
+2.53.0
+
--- /dev/null
+From 16b6b8fd6642fd47f46478284da82cf74000d69b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:21:21 +0800
+Subject: net: enetc: do not access non-existent registers on pseudo MAC
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit f2df9567b123145a07ee4ea7440e233f5d0232cc ]
+
+The ENETC4_PM_IEVENT and ENETC4_PM_CMD_CFG registers do not exist on the
+ENETC pseudo MAC, so the driver should prevent from accessing them.
+
+Fixes: 5175c1e4adca ("net: enetc: add basic support for the ENETC with pseudo MAC for i.MX94")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Tested-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324062121.2745033-4-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc4_pf.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+index 6a334f2848448..993c27e342266 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+@@ -814,6 +814,9 @@ static void enetc4_mac_tx_graceful_stop(struct enetc_pf *pf)
+ val |= POR_TXDIS;
+ enetc_port_wr(hw, ENETC4_POR, val);
+
++ if (enetc_is_pseudo_mac(si))
++ return;
++
+ enetc4_mac_wait_tx_empty(si, 0);
+ if (si->hw_features & ENETC_SI_F_QBU)
+ enetc4_mac_wait_tx_empty(si, 1);
+@@ -856,6 +859,9 @@ static void enetc4_mac_rx_graceful_stop(struct enetc_pf *pf)
+ struct enetc_si *si = pf->si;
+ u32 val;
+
++ if (enetc_is_pseudo_mac(si))
++ goto check_rx_busy;
++
+ if (si->hw_features & ENETC_SI_F_QBU) {
+ val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(1));
+ val &= ~PM_CMD_CFG_RX_EN;
+@@ -868,6 +874,7 @@ static void enetc4_mac_rx_graceful_stop(struct enetc_pf *pf)
+ enetc_port_wr(hw, ENETC4_PM_CMD_CFG(0), val);
+ enetc4_mac_wait_rx_empty(si, 0);
+
++check_rx_busy:
+ if (read_poll_timeout(enetc_port_rd, val,
+ !(val & PSR_RX_BUSY),
+ 100, 10000, false, hw,
+--
+2.53.0
+
--- /dev/null
+From 9af4dfcd4656e90d0a33d2670690da77ccb4c711 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:52:33 +0800
+Subject: net: enetc: do not allow VF to configure the RSS key
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit a142d139168cce8d5776245b5494c7f7f5d7fb7d ]
+
+VFs do not have privilege to configure the RSS key because the registers
+are owned by the PF. Currently, if VF attempts to configure the RSS key,
+enetc_set_rxfh() simply skips the configuration and does not generate a
+warning, which may mislead users into thinking the feature is supported.
+To improve this situation, add a check to reject RSS key configuration
+on VFs.
+
+Fixes: d382563f541b ("enetc: Add RFS and RSS support")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Clark Wang <xiaoning.wang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Link: https://patch.msgid.link/20260326075233.3628047-3-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+index a393647e6062c..7c17acaf7a380 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+@@ -800,8 +800,12 @@ static int enetc_set_rxfh(struct net_device *ndev,
+ return -EOPNOTSUPP;
+
+ /* set hash key, if PF */
+- if (rxfh->key && enetc_si_is_pf(si))
++ if (rxfh->key) {
++ if (!enetc_si_is_pf(si))
++ return -EOPNOTSUPP;
++
+ enetc_set_rss_key(si, rxfh->key);
++ }
+
+ /* set RSS table */
+ if (rxfh->indir)
+--
+2.53.0
+
--- /dev/null
+From 199e2ae1cc0fa124d853231ddb690c1781fdaa4b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:21:19 +0800
+Subject: net: enetc: reset PIR and CIR if they are not equal when initializing
+ TX ring
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit 0239fd701d33475a39428daa3dc627407cd417a6 ]
+
+Currently the driver does not reset the producer index register (PIR) and
+consumer index register (CIR) when initializing a TX BD ring. The driver
+only reads the PIR and CIR and initializes the software indexes. If the
+TX BD ring is reinitialized when it still contains unsent frames, its PIR
+and CIR will not be equal after the reinitialization. However, the BDs
+between CIR and PIR have been freed and become invalid and this can lead
+to a hardware malfunction, causing the TX BD ring will not work properly.
+
+For ENETC v4, it supports software to set the PIR and CIR, so the driver
+can reset these two registers if they are not equal when reinitializing
+the TX BD ring. Therefore, add this solution for ENETC v4. Note that this
+patch does not work for ENETC v1 because it does not support software to
+set the PIR and CIR.
+
+Fixes: 99100d0d9922 ("net: enetc: add preliminary support for i.MX95 ENETC PF")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324062121.2745033-2-wei.fang@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
+index 9fdd448e602f1..8ec96f39e1263 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -2579,6 +2579,7 @@ EXPORT_SYMBOL_GPL(enetc_free_si_resources);
+
+ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
+ {
++ struct enetc_si *si = container_of(hw, struct enetc_si, hw);
+ int idx = tx_ring->index;
+ u32 tbmr;
+
+@@ -2592,10 +2593,20 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
+ enetc_txbdr_wr(hw, idx, ENETC_TBLENR,
+ ENETC_RTBLENR_LEN(tx_ring->bd_count));
+
+- /* clearing PI/CI registers for Tx not supported, adjust sw indexes */
++ /* For ENETC v1, clearing PI/CI registers for Tx not supported,
++ * adjust sw indexes
++ */
+ tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR);
+ tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR);
+
++ if (tx_ring->next_to_use != tx_ring->next_to_clean &&
++ !is_enetc_rev1(si)) {
++ tx_ring->next_to_use = 0;
++ tx_ring->next_to_clean = 0;
++ enetc_txbdr_wr(hw, idx, ENETC_TBPIR, 0);
++ enetc_txbdr_wr(hw, idx, ENETC_TBCIR, 0);
++ }
++
+ /* enable Tx ints by setting pkt thr to 1 */
+ enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1);
+
+--
+2.53.0
+
--- /dev/null
+From bfda6df93a394b9ebf988da44c642bbd8ec3c189 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:32:30 +0100
+Subject: net: fec: fix the PTP periodic output sysfs interface
+
+From: Buday Csaba <buday.csaba@prolan.hu>
+
+[ Upstream commit e8e44c98f789dee45cfd24ffb9d4936e0606d7c6 ]
+
+When the PPS channel configuration was implemented, the channel
+index for the periodic outputs was configured as the hardware
+channel number.
+
+The sysfs interface uses a logical channel index, and rejects numbers
+greater than `n_per_out` (see period_store() in ptp_sysfs.c).
+That property was left at 1, since the driver implements channel
+selection, not simultaneous operation of multiple PTP hardware timer
+channels.
+
+A second check in fec_ptp_enable() returns -EOPNOTSUPP when the two
+channel numbers disagree, making channels 1..3 unusable from sysfs.
+
+Fix by removing this redundant check in the FEC PTP driver.
+
+Fixes: 566c2d83887f ("net: fec: make PPS channel configurable")
+Signed-off-by: Buday Csaba <buday.csaba@prolan.hu>
+Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/fec_ptp.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
+index 4b7bad9a485df..56801c2009d59 100644
+--- a/drivers/net/ethernet/freescale/fec_ptp.c
++++ b/drivers/net/ethernet/freescale/fec_ptp.c
+@@ -545,9 +545,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
+ if (rq->perout.flags)
+ return -EOPNOTSUPP;
+
+- if (rq->perout.index != fep->pps_channel)
+- return -EOPNOTSUPP;
+-
+ period.tv_sec = rq->perout.period.sec;
+ period.tv_nsec = rq->perout.period.nsec;
+ period_ns = timespec64_to_ns(&period);
+--
+2.53.0
+
--- /dev/null
+From 188ee5de04343f2e059b063cf33cb1153358e74c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 11:22:43 +0200
+Subject: net: hsr: fix VLAN add unwind on slave errors
+
+From: Luka Gejak <luka.gejak@linux.dev>
+
+[ Upstream commit 2e3514e63bfb0e972b1f19668547a455d0129e88 ]
+
+When vlan_vid_add() fails for a secondary slave, the error path calls
+vlan_vid_del() on the failing port instead of the peer slave that had
+already succeeded. This results in asymmetric VLAN state across the HSR
+pair.
+
+Fix this by switching to a centralized unwind path that removes the VID
+from any slave device that was already programmed.
+
+Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
+Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
+Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index d1bfc49b5f017..fd2fea25eff0d 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -532,8 +532,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+ {
+- bool is_slave_a_added = false;
+- bool is_slave_b_added = false;
++ struct net_device *slave_a_dev = NULL;
++ struct net_device *slave_b_dev = NULL;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+@@ -549,33 +549,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+- /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+- if (is_slave_b_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_a_added = true;
++ slave_a_dev = port->dev;
+ break;
+-
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+- /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+- if (is_slave_a_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_b_added = true;
++ slave_b_dev = port->dev;
+ break;
+ default:
++ if (ret)
++ goto unwind;
+ break;
+ }
+ }
+
+ return 0;
++
++unwind:
++ if (slave_a_dev)
++ vlan_vid_del(slave_a_dev, proto, vid);
++
++ if (slave_b_dev)
++ vlan_vid_del(slave_b_dev, proto, vid);
++
++ return ret;
+ }
+
+ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+--
+2.53.0
+
--- /dev/null
+From dc7f820a49b671493cb743d81d995ccd5eecf2f8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Jan 2026 17:11:27 +0100
+Subject: net: introduce mangleid_features
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit 31c5a71d982b57df75858974634c2f0a338f2fc6 ]
+
+Some/most devices implementing gso_partial need to disable the GSO partial
+features when the IP ID can't be mangled; to that extend each of them
+implements something alike the following[1]:
+
+ if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID))
+ features &= ~NETIF_F_TSO;
+
+in the ndo_features_check() op, which leads to a bit of duplicate code.
+
+Later patch in the series will implement GSO partial support for virtual
+devices, and the current status quo will require more duplicate code and
+a new indirect call in the TX path for them.
+
+Introduce the mangleid_features mask, allowing the core to disable NIC
+features based on/requiring MANGLEID, without any further intervention
+from the driver.
+
+The same functionality could be alternatively implemented adding a single
+boolean flag to the struct net_device, but would require an additional
+checks in ndo_features_check().
+
+Also note that [1] is incorrect if the NIC additionally implements
+NETIF_F_GSO_UDP_L4, mangleid_features transparently handle even such a
+case.
+
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/5a7cdaeea40b0a29b88e525b6c942d73ed3b8ce7.1769011015.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: ddc748a391dd ("net: use skb_header_pointer() for TCPv4 GSO frag_off check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netdevice.h | 3 +++
+ net/core/dev.c | 5 ++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 1216f050f0699..846afec74703b 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1833,6 +1833,8 @@ enum netdev_reg_state {
+ *
+ * @mpls_features: Mask of features inheritable by MPLS
+ * @gso_partial_features: value(s) from NETIF_F_GSO\*
++ * @mangleid_features: Mask of features requiring MANGLEID, will be
++ * disabled together with the latter.
+ *
+ * @ifindex: interface index
+ * @group: The group the device belongs to
+@@ -2222,6 +2224,7 @@ struct net_device {
+ netdev_features_t vlan_features;
+ netdev_features_t hw_enc_features;
+ netdev_features_t mpls_features;
++ netdev_features_t mangleid_features;
+
+ unsigned int min_mtu;
+ unsigned int max_mtu;
+diff --git a/net/core/dev.c b/net/core/dev.c
+index b5f0d5c4d5412..8439bac371b7d 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3819,7 +3819,7 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
+ inner_ip_hdr(skb) : ip_hdr(skb);
+
+ if (!(iph->frag_off & htons(IP_DF)))
+- features &= ~NETIF_F_TSO_MANGLEID;
++ features &= ~dev->mangleid_features;
+ }
+
+ /* NETIF_F_IPV6_CSUM does not support IPv6 extension headers,
+@@ -11411,6 +11411,9 @@ int register_netdevice(struct net_device *dev)
+ if (dev->hw_enc_features & NETIF_F_TSO)
+ dev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
+
++ /* TSO_MANGLEID belongs in mangleid_features by definition */
++ dev->mangleid_features |= NETIF_F_TSO_MANGLEID;
++
+ /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
+ */
+ dev->vlan_features |= NETIF_F_HIGHDMA;
+--
+2.53.0
+
--- /dev/null
+From e5282baa914c29440a006d2a6d3f8e0403574192 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index 60d0be47a9f31..8aa29b3d3daca 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From b5c13036206c02cc966fff53f498ab5fd9e3e24c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 15:41:52 +0800
+Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 5e67ba9bb531e1ec6599a82a065dea9040b9ce50 ]
+
+ioam6_fill_trace_data() stores the schema contribution to the trace
+length in a u8. With bit 22 enabled and the largest schema payload,
+sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
+remaining-space check. __ioam6_fill_trace_data() then positions the
+write cursor without reserving the schema area but still copies the
+4-byte schema header and the full schema payload, overrunning the trace
+buffer.
+
+Keep sclen in an unsigned int so the remaining-space check and the write
+cursor calculation both see the full schema length.
+
+Fixes: 8c6f6fa67726 ("ipv6: ioam: IOAM Generic Netlink API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ioam6.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
+index 08b7ac8c99b7e..8db7f965696aa 100644
+--- a/net/ipv6/ioam6.c
++++ b/net/ipv6/ioam6.c
+@@ -708,7 +708,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
+ struct ioam6_namespace *ns,
+ struct ioam6_trace_hdr *trace,
+ struct ioam6_schema *sc,
+- u8 sclen, bool is_input)
++ unsigned int sclen, bool is_input)
+ {
+ struct net_device *dev = skb_dst_dev(skb);
+ struct timespec64 ts;
+@@ -939,7 +939,7 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
+ bool is_input)
+ {
+ struct ioam6_schema *sc;
+- u8 sclen = 0;
++ unsigned int sclen = 0;
+
+ /* Skip if Overflow flag is set
+ */
+--
+2.53.0
+
--- /dev/null
+From f073c0613a75037cee1374c2b31c4ed9fce28b27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index f6a5d8c73af97..186e60c792145 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1209,6 +1209,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From d953c6d7f8ef8cf0ffcf9eabfd8aed4f2d118a48 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index fc4f5aee6ab3f..0ce5b736ea438 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -109,10 +109,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From c30bcd5c64971799437f651e12f9197f760c0776 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 0ce5b736ea438..b79dec17e6b09 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -96,10 +96,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -113,8 +113,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 85bfb080480e631b88759d74eedcaff7755dea2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:14:28 -0700
+Subject: net: mana: Fix RX skb truesize accounting
+
+From: Dipayaan Roy <dipayanroy@linux.microsoft.com>
+
+[ Upstream commit f73896b4197ed53cf0894657c899265ef7c86b7a ]
+
+MANA passes rxq->alloc_size to napi_build_skb() for all RX buffers.
+It is correct for fragment-backed RX buffers, where alloc_size matches
+the actual backing allocation used for each packet buffer. However, in
+the non-fragment RX path mana allocates a full page, or a higher-order
+page, per RX buffer. In that case alloc_size only reflects the usable
+packet area and not the actual backing memory.
+
+This causes napi_build_skb() to underestimate the skb backing allocation
+in the single-buffer RX path, so skb->truesize is derived from a value
+smaller than the real RX buffer allocation.
+
+Fix this by updating alloc_size in the non-fragment RX path to the
+actual backing allocation size before it is passed to napi_build_skb().
+
+Fixes: 730ff06d3f5c ("net: mana: Use page pool fragments for RX buffers instead of full pages to improve memory efficiency.")
+Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
+Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
+Link: https://patch.msgid.link/acLUhLpLum6qrD/N@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/microsoft/mana/mana_en.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
+index 14f44b71daded..215ce3443adea 100644
+--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
+@@ -737,6 +737,13 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
+ }
+
+ *frag_count = 1;
++
++ /* In the single-buffer path, napi_build_skb() must see the
++ * actual backing allocation size so skb->truesize reflects
++ * the full page (or higher-order page), not just the usable
++ * packet area.
++ */
++ *alloc_size = PAGE_SIZE << get_order(*alloc_size);
+ return;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f61f3dc4a4daf1e41b7f2350cd52b7f0b98851dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index ea77fbd98396a..055ee020c56f4 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -107,9 +107,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index eeb4437975f20..c1f220e5fe185 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -822,48 +822,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index f2d74382fb85d..c048839f07d6d 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -392,8 +392,8 @@ int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ #ifdef CONFIG_MLX5_CORE_EN
+ int mlx5e_init(void);
+--
+2.53.0
+
--- /dev/null
+From 171ca0174affcd6c7264cdf15a403885698026c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:15 +0300
+Subject: net/mlx5: Fix switchdev mode rollback in case of failure
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 403186400a1a6166efe7031edc549c15fee4723f ]
+
+If for some internal reason switchdev mode fails, we rollback to legacy
+mode, before this patch, rollback will unregister the uplink netdev and
+leave it unregistered causing the below kernel bug.
+
+To fix this, we need to avoid netdev unregister by setting the proper
+rollback flag 'MLX5_PRIV_FLAGS_SWITCH_LEGACY' to indicate legacy mode.
+
+devlink (431) used greatest stack depth: 11048 bytes left
+mlx5_core 0000:00:03.0: E-Switch: Disable: mode(LEGACY), nvfs(0), \
+ necvfs(0), active vports(0)
+mlx5_core 0000:00:03.0: E-Switch: Supported tc chains and prios offload
+mlx5_core 0000:00:03.0: Loading uplink representor for vport 65535
+mlx5_core 0000:00:03.0: mlx5_cmd_out_err:816:(pid 456): \
+ QUERY_HCA_CAP(0x100) op_mod(0x0) failed, \
+ status bad parameter(0x3), syndrome (0x3a3846), err(-22)
+mlx5_core 0000:00:03.0 enp0s3np0 (unregistered): Unloading uplink \
+ representor for vport 65535
+ ------------[ cut here ]------------
+kernel BUG at net/core/dev.c:12070!
+Oops: invalid opcode: 0000 [#1] SMP NOPTI
+CPU: 2 UID: 0 PID: 456 Comm: devlink Not tainted 6.16.0-rc3+ \
+ #9 PREEMPT(voluntary)
+RIP: 0010:unregister_netdevice_many_notify+0x123/0xae0
+...
+Call Trace:
+[ 90.923094] unregister_netdevice_queue+0xad/0xf0
+[ 90.923323] unregister_netdev+0x1c/0x40
+[ 90.923522] mlx5e_vport_rep_unload+0x61/0xc6
+[ 90.923736] esw_offloads_enable+0x8e6/0x920
+[ 90.923947] mlx5_eswitch_enable_locked+0x349/0x430
+[ 90.924182] ? is_mp_supported+0x57/0xb0
+[ 90.924376] mlx5_devlink_eswitch_mode_set+0x167/0x350
+[ 90.924628] devlink_nl_eswitch_set_doit+0x6f/0xf0
+[ 90.924862] genl_family_rcv_msg_doit+0xe8/0x140
+[ 90.925088] genl_rcv_msg+0x18b/0x290
+[ 90.925269] ? __pfx_devlink_nl_pre_doit+0x10/0x10
+[ 90.925506] ? __pfx_devlink_nl_eswitch_set_doit+0x10/0x10
+[ 90.925766] ? __pfx_devlink_nl_post_doit+0x10/0x10
+[ 90.926001] ? __pfx_genl_rcv_msg+0x10/0x10
+[ 90.926206] netlink_rcv_skb+0x52/0x100
+[ 90.926393] genl_rcv+0x28/0x40
+[ 90.926557] netlink_unicast+0x27d/0x3d0
+[ 90.926749] netlink_sendmsg+0x1f7/0x430
+[ 90.926942] __sys_sendto+0x213/0x220
+[ 90.927127] ? __sys_recvmsg+0x6a/0xd0
+[ 90.927312] __x64_sys_sendto+0x24/0x30
+[ 90.927504] do_syscall_64+0x50/0x1c0
+[ 90.927687] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+[ 90.927929] RIP: 0033:0x7f7d0363e047
+
+Fixes: 2a4f56fbcc47 ("net/mlx5e: Keep netdev when leave switchdev for devlink set legacy only")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Jianbo Liu <jianbol@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-4-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+index 166a88988904e..31e4eb6bd685b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+@@ -3761,6 +3761,8 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
+ return 0;
+
+ err_vports:
++ /* rollback to legacy, indicates don't unregister the uplink netdev */
++ esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY;
+ mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK);
+ err_uplink:
+ esw_offloads_steering_cleanup(esw);
+--
+2.53.0
+
--- /dev/null
+From 00921ac14e6ec324c2894657d77b37ae0f67136c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:13 +0300
+Subject: net/mlx5: lag: Check for LAG device before creating debugfs
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit bf16bca6653679d8a514d6c1c5a2c67065033f14 ]
+
+__mlx5_lag_dev_add_mdev() may return 0 (success) even when an error
+occurs that is handled gracefully. Consequently, the initialization
+flow proceeds to call mlx5_ldev_add_debugfs() even when there is no
+valid LAG context.
+
+mlx5_ldev_add_debugfs() blindly created the debugfs directory and
+attributes. This exposed interfaces (like the members file) that rely on
+a valid ldev pointer, leading to potential NULL pointer dereferences if
+accessed when ldev is NULL.
+
+Add a check to verify that mlx5_lag_dev(dev) returns a valid pointer
+before attempting to create the debugfs entries.
+
+Fixes: 7f46a0b7327a ("net/mlx5: Lag, add debugfs to query hardware lag state")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Mark Bloch <mbloch@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+index 62b6faa4276aa..b8d5f6a44d26a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+@@ -160,8 +160,11 @@ DEFINE_SHOW_ATTRIBUTE(members);
+
+ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
+ {
++ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+ struct dentry *dbg;
+
++ if (!ldev)
++ return;
+ dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
+ dev->priv.dbg.lag_debugfs = dbg;
+
+--
+2.53.0
+
--- /dev/null
+From 79cc77e315c4c56ebffebcb740d5b54ee781f957 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index dab839f61ee93..26609feff4f80 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -118,7 +118,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -129,7 +129,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -172,6 +172,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -189,11 +190,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -228,9 +227,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -269,12 +266,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -326,9 +324,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -599,7 +595,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -627,6 +623,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -649,10 +646,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From 0209052ee1ee2a7f48bd23d065a029c2b906f206 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 8c72faf3314dd..9edaff15052f3 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2969,6 +2969,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From f2994b70cfe095e57e4dfdae18bfe89ac4fbf257 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 5693b41b093f3..edf1252c1fde7 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -503,8 +503,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From 8e0b548a8d5e761298adb89c103f1e2e1e91e9e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index cdddc86952284..83a7372ea15c2 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -247,8 +247,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From f51e36323691e5b32a2c307daceb5079b74d693c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index d8fd35da32a7c..57221522fe56d 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -555,7 +555,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -598,7 +598,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From e23b1347ff48fd750180e3d098bd84cd91876176 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:00:21 +0800
+Subject: net/sched: sch_netem: fix out-of-bounds access in packet corruption
+
+From: Yucheng Lu <kanolyc@gmail.com>
+
+[ Upstream commit d64cb81dcbd54927515a7f65e5e24affdc73c14b ]
+
+In netem_enqueue(), the packet corruption logic uses
+get_random_u32_below(skb_headlen(skb)) to select an index for
+modifying skb->data. When an AF_PACKET TX_RING sends fully non-linear
+packets over an IPIP tunnel, skb_headlen(skb) evaluates to 0.
+
+Passing 0 to get_random_u32_below() takes the variable-ceil slow path
+which returns an unconstrained 32-bit random integer. Using this
+unconstrained value as an offset into skb->data results in an
+out-of-bounds memory access.
+
+Fix this by verifying skb_headlen(skb) is non-zero before attempting
+to corrupt the linear data area. Fully non-linear packets will silently
+bypass the corruption logic.
+
+Fixes: c865e5d99e25 ("[PKT_SCHED] netem: packet corruption option")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yuhang Zheng <z1652074432@gmail.com>
+Signed-off-by: Yucheng Lu <kanolyc@gmail.com>
+Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
+Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_netem.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
+index 32a5f33040461..3356d62ad0548 100644
+--- a/net/sched/sch_netem.c
++++ b/net/sched/sch_netem.c
+@@ -519,8 +519,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+ goto finish_segs;
+ }
+
+- skb->data[get_random_u32_below(skb_headlen(skb))] ^=
+- 1<<get_random_u32_below(8);
++ if (skb_headlen(skb))
++ skb->data[get_random_u32_below(skb_headlen(skb))] ^=
++ 1 << get_random_u32_below(8);
+ }
+
+ if (unlikely(q->t_len >= sch->limit)) {
+--
+2.53.0
+
--- /dev/null
+From 6e99346c2eb8955d6d19965f3ad054b4dd1dcf98 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:20:38 +0100
+Subject: net: sfp: Fix Ubiquiti U-Fiber Instant SFP module on mvneta
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marek Behún <kabel@kernel.org>
+
+[ Upstream commit eeee5a710f26ce57807024ef330fe5a850eaecd8 ]
+
+In commit 8110633db49d7de2 ("net: sfp-bus: allow SFP quirks to override
+Autoneg and pause bits") we moved the setting of Autoneg and pause bits
+before the call to SFP quirk when parsing SFP module support.
+
+Since the quirk for Ubiquiti U-Fiber Instant SFP module zeroes the
+support bits and sets 1000baseX_Full only, the above mentioned commit
+changed the overall computed support from
+ 1000baseX_Full, Autoneg, Pause, Asym_Pause
+to just
+ 1000baseX_Full.
+
+This broke the SFP module for mvneta, which requires Autoneg for
+1000baseX since commit c762b7fac1b249a9 ("net: mvneta: deny disabling
+autoneg for 802.3z modes").
+
+Fix this by setting back the Autoneg, Pause and Asym_Pause bits in the
+quirk.
+
+Fixes: 8110633db49d7de2 ("net: sfp-bus: allow SFP quirks to override Autoneg and pause bits")
+Signed-off-by: Marek Behún <kabel@kernel.org>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://patch.msgid.link/20260326122038.2489589-1-kabel@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/sfp.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
+index ca09925335725..7a85b758fb1e6 100644
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -480,11 +480,16 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
+ {
+ /* Ubiquiti U-Fiber Instant module claims that support all transceiver
+ * types including 10G Ethernet which is not truth. So clear all claimed
+- * modes and set only one mode which module supports: 1000baseX_Full.
++ * modes and set only one mode which module supports: 1000baseX_Full,
++ * along with the Autoneg and pause bits.
+ */
+ linkmode_zero(caps->link_modes);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+ caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, caps->link_modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, caps->link_modes);
++
+ phy_interface_zero(caps->interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, caps->interfaces);
+ }
+--
+2.53.0
+
--- /dev/null
+From f51b994cc3f1b5ae5ac2dfc7db89b7ee08a9b090 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 09:55:51 +0100
+Subject: net: stmmac: skip VLAN restore when VLAN hash ops are missing
+
+From: Michal Piekos <michal.piekos@mmpsystems.pl>
+
+[ Upstream commit 48b3cd69265f346f64b93064723492da46206e9b ]
+
+stmmac_vlan_restore() unconditionally calls stmmac_vlan_update() when
+NETIF_F_VLAN_FEATURES is set. On platforms where priv->hw->vlan (or
+->update_vlan_hash) is not provided, stmmac_update_vlan_hash() returns
+-EINVAL via stmmac_do_void_callback(), resulting in a spurious
+"Failed to restore VLANs" error even when no VLAN filtering is in use.
+
+Remove not needed comment.
+Remove not used return value from stmmac_vlan_restore().
+
+Tested on Orange Pi Zero 3.
+
+Fixes: bd7ad51253a7 ("net: stmmac: Fix VLAN HW state restore")
+Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
+Link: https://patch.msgid.link/20260328-vlan-restore-error-v4-1-f88624c530dc@mmpsystems.pl
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 01ede5148163e..cfe47a8e2c6d5 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -140,7 +140,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
+ static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
+ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
+ u32 rxmode, u32 chan);
+-static int stmmac_vlan_restore(struct stmmac_priv *priv);
++static void stmmac_vlan_restore(struct stmmac_priv *priv);
+
+ #ifdef CONFIG_DEBUG_FS
+ static const struct net_device_ops stmmac_netdev_ops;
+@@ -6811,21 +6811,15 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
+ return ret;
+ }
+
+-static int stmmac_vlan_restore(struct stmmac_priv *priv)
++static void stmmac_vlan_restore(struct stmmac_priv *priv)
+ {
+- int ret;
+-
+ if (!(priv->dev->features & NETIF_F_VLAN_FEATURES))
+- return 0;
++ return;
+
+ if (priv->hw->num_vlan)
+ stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw);
+
+- ret = stmmac_vlan_update(priv, priv->num_double_vlans);
+- if (ret)
+- netdev_err(priv->dev, "Failed to restore VLANs\n");
+-
+- return ret;
++ stmmac_vlan_update(priv, priv->num_double_vlans);
+ }
+
+ static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
+--
+2.53.0
+
--- /dev/null
+From add287e5df9d306fc357522b85e1627ba4a478b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:51:30 +0000
+Subject: net: ti: icssg-prueth: fix missing data copy and wrong recycle in ZC
+ RX dispatch
+
+From: David Carlier <devnexen@gmail.com>
+
+[ Upstream commit 5597dd284ff8c556c0b00f6a34473677426e3f81 ]
+
+emac_dispatch_skb_zc() allocates a new skb via napi_alloc_skb() but
+never copies the packet data from the XDP buffer into it. The skb is
+passed up the stack containing uninitialized heap memory instead of
+the actual received packet, leaking kernel heap contents to userspace.
+
+Copy the received packet data from the XDP buffer into the skb using
+skb_copy_to_linear_data().
+
+Additionally, remove the skb_mark_for_recycle() call since the skb is
+backed by the NAPI page frag allocator, not page_pool. Marking a
+non-page_pool skb for recycle causes the free path to return pages to
+a page_pool that does not own them, corrupting page_pool state.
+
+The non-ZC path (emac_rx_packet) does not have these issues because it
+uses napi_build_skb() to wrap the existing page_pool page directly,
+requiring no copy, and correctly marks for recycle since the page comes
+from page_pool_dev_alloc_pages().
+
+Fixes: 7a64bb388df3 ("net: ti: icssg-prueth: Add AF_XDP zero copy for RX")
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/ti/icssg/icssg_common.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
+index 11d5b23a61bad..a74a41ad59c82 100644
+--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
++++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
+@@ -902,6 +902,7 @@ static void emac_dispatch_skb_zc(struct prueth_emac *emac, struct xdp_buff *xdp,
+
+ skb_reserve(skb, headroom);
+ skb_put(skb, pkt_len);
++ skb_copy_to_linear_data(skb, xdp->data, pkt_len);
+ skb->dev = ndev;
+
+ /* RX HW timestamp */
+@@ -912,7 +913,6 @@ static void emac_dispatch_skb_zc(struct prueth_emac *emac, struct xdp_buff *xdp,
+ skb->offload_fwd_mark = emac->offload_fwd_mark;
+ skb->protocol = eth_type_trans(skb, ndev);
+
+- skb_mark_for_recycle(skb);
+ napi_gro_receive(&emac->napi_rx, skb);
+ ndev->stats.rx_bytes += pkt_len;
+ ndev->stats.rx_packets++;
+--
+2.53.0
+
--- /dev/null
+From b8435bc097b09f5905cf4f27df6b2548c28d89d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 23:35:07 +0800
+Subject: net: use skb_header_pointer() for TCPv4 GSO frag_off check
+
+From: Guoyu Su <yss2813483011xxl@gmail.com>
+
+[ Upstream commit ddc748a391dd8642ba6b2e4fe22e7f2ddf84b7f0 ]
+
+Syzbot reported a KMSAN uninit-value warning in gso_features_check()
+called from netif_skb_features() [1].
+
+gso_features_check() reads iph->frag_off to decide whether to clear
+mangleid_features. Accessing the IPv4 header via ip_hdr()/inner_ip_hdr()
+can rely on skb header offsets that are not always safe for direct
+dereference on packets injected from PF_PACKET paths.
+
+Use skb_header_pointer() for the TCPv4 frag_off check so the header read
+is robust whether data is already linear or needs copying.
+
+[1] https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
+
+Link: https://lore.kernel.org/netdev/willemdebruijn.kernel.1a9f35039caab@gmail.com/
+Fixes: cbc53e08a793 ("GSO: Add GSO type for fixed IPv4 ID")
+Reported-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=1543a7d954d9c6d00407
+Tested-by: syzbot+1543a7d954d9c6d00407@syzkaller.appspotmail.com
+Signed-off-by: Guoyu Su <yss2813483011xxl@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20260327153507.39742-1-yss2813483011xxl@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/dev.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 8439bac371b7d..384250c3a519c 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3815,10 +3815,15 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
+ * segmentation-offloads.rst).
+ */
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
+- struct iphdr *iph = skb->encapsulation ?
+- inner_ip_hdr(skb) : ip_hdr(skb);
++ const struct iphdr *iph;
++ struct iphdr _iph;
++ int nhoff = skb->encapsulation ?
++ skb_inner_network_offset(skb) :
++ skb_network_offset(skb);
+
+- if (!(iph->frag_off & htons(IP_DF)))
++ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
++
++ if (!iph || !(iph->frag_off & htons(IP_DF)))
+ features &= ~dev->mangleid_features;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 84ec2a0c40350fa9361b5ad3c3de3d5cd3d3c43f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 0dbc73efab1cb..e47ebd8acd21b 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 6bda358f99f7e0ae83d42aaae23d220c5a367ba3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index b981a4828d08c..0dbc73efab1cb 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From c93d61675895246e8d58185bb9bde6f7d27a42b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index 5ff742103beb9..fcd3aaef27fc3 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -105,7 +105,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -130,7 +130,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From be80886c3aa2e3f68effb34a7530b24d5effd46a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:38 +0530
+Subject: net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit d1978d03e86785872871bff9c2623174b10740de ]
+
+When a TX packet spans multiple buffer descriptors (scatter-gather),
+axienet_free_tx_chain sums the per-BD actual length from descriptor
+status into a caller-provided accumulator. That sum is reset on each
+NAPI poll. If the BDs for a single packet complete across different
+polls, the earlier bytes are lost and never credited to BQL. This
+causes BQL to think bytes are permanently in-flight, eventually
+stalling the TX queue.
+
+The SKB pointer is stored only on the last BD of a packet. When that
+BD completes, use skb->len for the byte count instead of summing
+per-BD status lengths. This matches netdev_sent_queue(), which debits
+skb->len, and naturally survives across polls because no partial
+packet contributes to the accumulator.
+
+Fixes: c900e49d58eb ("net: xilinx: axienet: Implement BQL")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-3-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+index 284031fb2e2c7..eefe54ce66852 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+@@ -770,8 +770,8 @@ static int axienet_device_reset(struct net_device *ndev)
+ * @first_bd: Index of first descriptor to clean up
+ * @nr_bds: Max number of descriptors to clean up
+ * @force: Whether to clean descriptors even if not complete
+- * @sizep: Pointer to a u32 filled with the total sum of all bytes
+- * in all cleaned-up descriptors. Ignored if NULL.
++ * @sizep: Pointer to a u32 accumulating the total byte count of
++ * completed packets (using skb->len). Ignored if NULL.
+ * @budget: NAPI budget (use 0 when not called from NAPI poll)
+ *
+ * Would either be called after a successful transmit operation, or after
+@@ -805,6 +805,8 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
+ DMA_TO_DEVICE);
+
+ if (cur_p->skb && (status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
++ if (sizep)
++ *sizep += cur_p->skb->len;
+ napi_consume_skb(cur_p->skb, budget);
+ packets++;
+ }
+@@ -818,9 +820,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
+ wmb();
+ cur_p->cntrl = 0;
+ cur_p->status = 0;
+-
+- if (sizep)
+- *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
+ }
+
+ if (!force) {
+--
+2.53.0
+
--- /dev/null
+From 21be7cf00fb388a24b2b0a2205f8a2e03f0be3e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:08:56 +0800
+Subject: netdevsim: fix build if SKB_EXTENSIONS=n
+
+From: Qingfang Deng <dqfext@gmail.com>
+
+[ Upstream commit 57a04a13aac1f247d171c3f3aef93efc69e6979e ]
+
+__skb_ext_put() is not declared if SKB_EXTENSIONS is not enabled, which
+causes a build error:
+
+drivers/net/netdevsim/netdev.c: In function 'nsim_forward_skb':
+drivers/net/netdevsim/netdev.c:114:25: error: implicit declaration of function '__skb_ext_put'; did you mean 'skb_ext_put'? [-Werror=implicit-function-declaration]
+ 114 | __skb_ext_put(psp_ext);
+ | ^~~~~~~~~~~~~
+ | skb_ext_put
+cc1: some warnings being treated as errors
+
+Add a stub to fix the build.
+
+Fixes: 7d9351435ebb ("netdevsim: drop PSP ext ref on forward failure")
+Signed-off-by: Qingfang Deng <dqfext@gmail.com>
+Link: https://patch.msgid.link/20260324140857.783-1-dqfext@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/skbuff.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 112e48970338f..13c6eca3bbc69 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -5093,6 +5093,7 @@ static inline bool skb_has_extensions(struct sk_buff *skb)
+ return unlikely(skb->active_extensions);
+ }
+ #else
++static inline void __skb_ext_put(struct skb_ext *ext) {}
+ static inline void skb_ext_put(struct sk_buff *skb) {}
+ static inline void skb_ext_reset(struct sk_buff *skb) {}
+ static inline void skb_ext_del(struct sk_buff *skb, int unused) {}
+--
+2.53.0
+
--- /dev/null
+From 030c73c1963f97037de10042dae0d63bac5c8f0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 11:26:22 +0200
+Subject: netfilter: ctnetlink: ignore explicit helper on new expectations
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 917b61fa2042f11e2af4c428e43f08199586633a ]
+
+Use the existing master conntrack helper, anything else is not really
+supported and it just makes validation more complicated, so just ignore
+what helper userspace suggests for this expectation.
+
+This was uncovered when validating CTA_EXPECT_CLASS via different helper
+provided by userspace than the existing master conntrack helper:
+
+ BUG: KASAN: slab-out-of-bounds in nf_ct_expect_related_report+0x2479/0x27c0
+ Read of size 4 at addr ffff8880043fe408 by task poc/102
+ Call Trace:
+ nf_ct_expect_related_report+0x2479/0x27c0
+ ctnetlink_create_expect+0x22b/0x3b0
+ ctnetlink_new_expect+0x4bd/0x5c0
+ nfnetlink_rcv_msg+0x67a/0x950
+ netlink_rcv_skb+0x120/0x350
+
+Allowing to read kernel memory bytes off the expectation boundary.
+
+CTA_EXPECT_HELP_NAME is still used to offer the helper name to userspace
+via netlink dump.
+
+Fixes: bd0779370588 ("netfilter: nfnetlink_queue: allow to attach expectations to conntracks")
+Reported-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 54 +++++-----------------------
+ 1 file changed, 9 insertions(+), 45 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index f5db3c6c485ae..2bb9eb2d25fb0 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2635,7 +2635,6 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask);
+
+@@ -2864,7 +2863,6 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ {
+ struct nlattr *cda[CTA_EXPECT_MAX+1];
+ struct nf_conntrack_tuple tuple, mask;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ int err;
+
+@@ -2878,17 +2876,8 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ if (err < 0)
+ return err;
+
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+- nf_ct_protonum(ct));
+- if (helper == NULL)
+- return -EOPNOTSUPP;
+- }
+-
+ exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
+- helper, &tuple, &mask);
++ &tuple, &mask);
+ if (IS_ERR(exp))
+ return PTR_ERR(exp);
+
+@@ -3517,11 +3506,11 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+ struct net *net = read_pnet(&ct->ct_net);
++ struct nf_conntrack_helper *helper;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3531,7 +3520,11 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ if (!help)
+ return ERR_PTR(-EOPNOTSUPP);
+
+- if (cda[CTA_EXPECT_CLASS] && helper) {
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return ERR_PTR(-EOPNOTSUPP);
++
++ if (cda[CTA_EXPECT_CLASS]) {
+ class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
+ if (class > helper->expect_class_max)
+ return ERR_PTR(-EINVAL);
+@@ -3565,8 +3558,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+ exp->zone = ct->zone;
+ #endif
+- if (!helper)
+- helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+@@ -3598,7 +3589,6 @@ ctnetlink_create_expect(struct net *net,
+ {
+ struct nf_conntrack_tuple tuple, mask, master_tuple;
+ struct nf_conntrack_tuple_hash *h = NULL;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn *ct;
+ int err;
+@@ -3624,33 +3614,7 @@ ctnetlink_create_expect(struct net *net,
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ rcu_read_lock();
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper == NULL) {
+- rcu_read_unlock();
+-#ifdef CONFIG_MODULES
+- if (request_module("nfct-helper-%s", helpname) < 0) {
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- rcu_read_lock();
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper) {
+- err = -EAGAIN;
+- goto err_rcu;
+- }
+- rcu_read_unlock();
+-#endif
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- }
+-
+- exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
++ exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask);
+ if (IS_ERR(exp)) {
+ err = PTR_ERR(exp);
+ goto err_rcu;
+@@ -3660,8 +3624,8 @@ ctnetlink_create_expect(struct net *net,
+ nf_ct_expect_put(exp);
+ err_rcu:
+ rcu_read_unlock();
+-err_ct:
+ nf_ct_put(ct);
++
+ return err;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 9f9f9b8d6e9249bbf774187379c6292492f0a19c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index fea750653e967..3b5da5e7e9d27 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3576,6 +3576,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From 9ac5645986ecaa033b63c3e8aec743bed5c23f40 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:17:09 +0100
+Subject: netfilter: flowtable: strictly check for maximum number of actions
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 76522fcdbc3a02b568f5d957f7e66fc194abb893 ]
+
+The maximum number of flowtable hardware offload actions in IPv6 is:
+
+* ethernet mangling (4 payload actions, 2 for each ethernet address)
+* SNAT (4 payload actions)
+* DNAT (4 payload actions)
+* Double VLAN (4 vlan actions, 2 for popping vlan, and 2 for pushing)
+ for QinQ.
+* Redirect (1 action)
+
+Which makes 17, while the maximum is 16. But act_ct supports for tunnels
+actions too. Note that payload action operates at 32-bit word level, so
+mangling an IPv6 address takes 4 payload actions.
+
+Update flow_action_entry_next() calls to check for the maximum number of
+supported actions.
+
+While at it, rise the maximum number of actions per flow from 16 to 24
+so this works fine with IPv6 setups.
+
+Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_offload.c | 196 +++++++++++++++++---------
+ 1 file changed, 130 insertions(+), 66 deletions(-)
+
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index d8f7bfd60ac66..77e46eae2025d 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -13,6 +13,8 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
+
++#define NF_FLOW_RULE_ACTION_MAX 24
++
+ static struct workqueue_struct *nf_flow_offload_add_wq;
+ static struct workqueue_struct *nf_flow_offload_del_wq;
+ static struct workqueue_struct *nf_flow_offload_stats_wq;
+@@ -215,7 +217,12 @@ static void flow_offload_mangle(struct flow_action_entry *entry,
+ static inline struct flow_action_entry *
+ flow_action_entry_next(struct nf_flow_rule *flow_rule)
+ {
+- int i = flow_rule->rule->action.num_entries++;
++ int i;
++
++ if (unlikely(flow_rule->rule->action.num_entries >= NF_FLOW_RULE_ACTION_MAX))
++ return NULL;
++
++ i = flow_rule->rule->action.num_entries++;
+
+ return &flow_rule->rule->action.entries[i];
+ }
+@@ -233,6 +240,9 @@ static int flow_offload_eth_src(struct net *net,
+ u32 mask, val;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -283,6 +293,9 @@ static int flow_offload_eth_dst(struct net *net,
+ u8 nud_state;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -324,16 +337,19 @@ static int flow_offload_eth_dst(struct net *net,
+ return 0;
+ }
+
+-static void flow_offload_ipv4_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
+@@ -344,23 +360,27 @@ static void flow_offload_ipv4_snat(struct net *net,
+ offset = offsetof(struct iphdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
+@@ -371,14 +391,15 @@ static void flow_offload_ipv4_dnat(struct net *net,
+ offset = offsetof(struct iphdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
++static int flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+ unsigned int offset,
+ const __be32 *addr, const __be32 *mask)
+ {
+@@ -387,15 +408,20 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+
+ for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i++) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
++
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
+ offset + i * sizeof(u32), &addr[i], mask);
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_ipv6_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -411,16 +437,16 @@ static void flow_offload_ipv6_snat(struct net *net,
+ offset = offsetof(struct ipv6hdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+-static void flow_offload_ipv6_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -436,10 +462,10 @@ static void flow_offload_ipv6_dnat(struct net *net,
+ offset = offsetof(struct ipv6hdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+ static int flow_offload_l4proto(const struct flow_offload *flow)
+@@ -461,15 +487,18 @@ static int flow_offload_l4proto(const struct flow_offload *flow)
+ return type;
+ }
+
+-static void flow_offload_port_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
+@@ -484,22 +513,26 @@ static void flow_offload_port_snat(struct net *net,
+ mask = ~htonl(0xffff);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_port_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port);
+@@ -514,20 +547,24 @@ static void flow_offload_port_dnat(struct net *net,
+ mask = ~htonl(0xffff0000);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_checksum(struct net *net,
+- const struct flow_offload *flow,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_checksum(struct net *net,
++ const struct flow_offload *flow,
++ struct nf_flow_rule *flow_rule)
+ {
+ u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+
++ if (!entry)
++ return -E2BIG;
++
+ entry->id = FLOW_ACTION_CSUM;
+ entry->csum_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+@@ -539,12 +576,14 @@ static void flow_offload_ipv4_checksum(struct net *net,
+ entry->csum_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+ break;
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_redirect(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_redirect(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple, *other_tuple;
+ struct flow_action_entry *entry;
+@@ -562,21 +601,28 @@ static void flow_offload_redirect(struct net *net,
+ ifindex = other_tuple->iifidx;
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ dev = dev_get_by_index(net, ifindex);
+ if (!dev)
+- return;
++ return -ENODEV;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry) {
++ dev_put(dev);
++ return -E2BIG;
++ }
++
+ entry->id = FLOW_ACTION_REDIRECT;
+ entry->dev = dev;
++
++ return 0;
+ }
+
+-static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_encap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple;
+ struct flow_action_entry *entry;
+@@ -584,7 +630,7 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+
+ this_tuple = &flow->tuplehash[dir].tuple;
+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = this_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -593,15 +639,19 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+ entry->tunnel = tun_info;
+ }
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_decap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *other_tuple;
+ struct flow_action_entry *entry;
+@@ -609,7 +659,7 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+
+ other_tuple = &flow->tuplehash[!dir].tuple;
+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = other_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -618,9 +668,13 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_DECAP;
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -632,8 +686,9 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ const struct flow_offload_tuple *tuple;
+ int i;
+
+- flow_offload_decap_tunnel(flow, dir, flow_rule);
+- flow_offload_encap_tunnel(flow, dir, flow_rule);
++ if (flow_offload_decap_tunnel(flow, dir, flow_rule) < 0 ||
++ flow_offload_encap_tunnel(flow, dir, flow_rule) < 0)
++ return -1;
+
+ if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
+ flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
+@@ -649,6 +704,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+
+ if (tuple->encap[i].proto == htons(ETH_P_8021Q)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+ entry->id = FLOW_ACTION_VLAN_POP;
+ }
+ }
+@@ -662,6 +719,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ continue;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+
+ switch (other_tuple->encap[i].proto) {
+ case htons(ETH_P_PPP_SES):
+@@ -687,18 +746,22 @@ int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv4_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_SNAT, &flow->flags) ||
+ test_bit(NF_FLOW_DNAT, &flow->flags))
+- flow_offload_ipv4_checksum(net, flow, flow_rule);
++ if (flow_offload_ipv4_checksum(net, flow, flow_rule) < 0)
++ return -1;
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+@@ -712,22 +775,23 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv6_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
+
+-#define NF_FLOW_RULE_ACTION_MAX 16
+-
+ static struct nf_flow_rule *
+ nf_flow_offload_rule_alloc(struct net *net,
+ const struct flow_offload_work *offload,
+--
+2.53.0
+
--- /dev/null
+From 6dc15e0d5e7d0da8c278c407803eb1697167d457 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index e9f4f845d760a..b98331572ad29 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -309,7 +309,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index cc20e6d56807c..a4e1d7951b2c6 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -821,7 +821,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -830,7 +830,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 13c7a08aa868c..34bb84d7b174c 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From a7f464726fa548135140ab6c13f72535ac0f10db Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:02 +0100
+Subject: netfilter: nf_conntrack_expect: honor expectation helper field
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 9c42bc9db90a154bc61ae337a070465f3393485a ]
+
+The expectation helper field is mostly unused. As a result, the
+netfilter codebase relies on accessing the helper through exp->master.
+
+Always set on the expectation helper field so it can be used to reach
+the helper.
+
+nf_ct_expect_init() is called from packet path where the skb owns
+the ct object, therefore accessing exp->master for the newly created
+expectation is safe. This saves a lot of updates in all callsites
+to pass the ct object as parameter to nf_ct_expect_init().
+
+This is a preparation patches for follow up fixes.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 2 +-
+ net/netfilter/nf_conntrack_broadcast.c | 2 +-
+ net/netfilter/nf_conntrack_expect.c | 14 +++++++++++++-
+ net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------
+ net/netfilter/nf_conntrack_helper.c | 7 ++++++-
+ net/netfilter/nf_conntrack_netlink.c | 2 +-
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 7 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 165e7a03b8e9d..1b01400b10bdb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -40,7 +40,7 @@ struct nf_conntrack_expect {
+ struct nf_conntrack_expect *this);
+
+ /* Helper to assign to new connection */
+- struct nf_conntrack_helper *helper;
++ struct nf_conntrack_helper __rcu *helper;
+
+ /* The conntrack of the master connection */
+ struct nf_conn *master;
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index a7552a46d6acf..1964c596c6468 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -70,7 +70,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->expectfn = NULL;
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+- exp->helper = NULL;
++ rcu_assign_pointer(exp->helper, helper);
+
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 227fb5dc39e27..6739b48c644fc 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -309,12 +309,19 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
+
++/* This function can only be used from packet path, where accessing
++ * master's helper is safe, because the packet holds a reference on
++ * the conntrack object. Never use it from control plane.
++ */
+ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ u_int8_t family,
+ const union nf_inet_addr *saddr,
+ const union nf_inet_addr *daddr,
+ u_int8_t proto, const __be16 *src, const __be16 *dst)
+ {
++ struct nf_conntrack_helper *helper = NULL;
++ struct nf_conn *ct = exp->master;
++ struct nf_conn_help *help;
+ int len;
+
+ if (family == AF_INET)
+@@ -325,7 +332,12 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ exp->flags = 0;
+ exp->class = class;
+ exp->expectfn = NULL;
+- exp->helper = NULL;
++
++ help = nfct_help(ct);
++ if (help)
++ helper = rcu_dereference(help->helper);
++
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
+index e35814d68ce30..bd7e9e13e4f68 100644
+--- a/net/netfilter/nf_conntrack_h323_main.c
++++ b/net/netfilter/nf_conntrack_h323_main.c
+@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = &nf_conntrack_helper_h245;
++ rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3 : NULL,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+ exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_UDP, NULL, &port);
+- exp->helper = nf_conntrack_helper_ras;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect RAS ");
+@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 9d7d36ac83083..a21c976701f79 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -399,7 +399,7 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (exp->helper == me)
++ if (rcu_access_pointer(exp->helper) == me)
+ return true;
+
+ this = rcu_dereference_protected(help->helper,
+@@ -421,6 +421,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
++
++ /* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
++ * last step, this ensures rcu readers of exp->helper are done.
++ * No need for another synchronize_rcu() here.
++ */
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 3b5da5e7e9d27..b67ab92d65bab 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3566,7 +3566,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+ exp->mask.src.u.all = mask->src.u.all;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 17af0ff4ea7ab..5bddee342e122 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -1303,7 +1303,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
+ nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
+ saddr, &daddr, proto, NULL, &port);
+ exp->timeout.expires = sip_timeout * HZ;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
+
+ hooks = rcu_dereference(nf_nat_sip_hooks);
+--
+2.53.0
+
--- /dev/null
+From 82b9b3fa17d3f5a78ab8990a31b1f75d850ef76d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 22:39:55 +0100
+Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 02a3231b6d82efe750da6554ebf280e4a6f78756 ]
+
+__nf_ct_expect_find() and nf_ct_expect_find_get() are called under
+rcu_read_lock() but they dereference the master conntrack via
+exp->master.
+
+Since the expectation does not hold a reference on the master conntrack,
+this could be dying conntrack or different recycled conntrack than the
+real master due to SLAB_TYPESAFE_RCU.
+
+Store the netns, the master_tuple and the zone in struct
+nf_conntrack_expect as a safety measure.
+
+This patch is required by the follow up fix not to dump expectations
+that do not belong to this netns.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++++++++++-
+ net/netfilter/nf_conntrack_broadcast.c | 6 +++++-
+ net/netfilter/nf_conntrack_expect.c | 9 +++++++--
+ net/netfilter/nf_conntrack_netlink.c | 5 +++++
+ 4 files changed, 34 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 1b01400b10bdb..e9a8350e7ccfb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
+ /* Hash member */
+ struct hlist_node hnode;
+
++ /* Network namespace */
++ possible_net_t net;
++
+ /* We expect this tuple, with the following mask */
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
+
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ struct nf_conntrack_zone zone;
++#endif
+ /* Usage count. */
+ refcount_t use;
+
+@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
+
+ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
+ {
+- return nf_ct_net(exp->master);
++ return read_pnet(&exp->net);
++}
++
++static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
++ const struct nf_conntrack_zone *b)
++{
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ return a->zone.id == b->id;
++#else
++ return true;
++#endif
+ }
+
+ #define NF_CT_EXP_POLICY_NAME_LEN 16
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 1964c596c6468..4f39bf7c843f2 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ unsigned int timeout)
+ {
+ const struct nf_conntrack_helper *helper;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = skb_rtable(skb);
+@@ -71,7 +72,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+ rcu_assign_pointer(exp->helper, helper);
+-
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index b37ff73efb3e2..2234c444a320e 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -112,8 +112,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
+ const struct net *net)
+ {
+ return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+- net_eq(net, nf_ct_net(i->master)) &&
+- nf_ct_zone_equal_any(i->master, zone);
++ net_eq(net, read_pnet(&i->net)) &&
++ nf_ct_exp_zone_equal_any(i, zone);
+ }
+
+ bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
+@@ -321,6 +321,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ {
+ struct nf_conntrack_helper *helper = NULL;
+ struct nf_conn *ct = exp->master;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conn_help *help;
+ int len;
+
+@@ -338,6 +339,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ helper = rcu_dereference(help->helper);
+
+ rcu_assign_pointer(exp->helper, helper);
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 66a87b0ed46c4..f5db3c6c485ae 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3521,6 +3521,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3560,6 +3561,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ if (!helper)
+ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+--
+2.53.0
+
--- /dev/null
+From 95fca6bbc526a868d45bee52dee24990ddae8132 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:03 +0100
+Subject: netfilter: nf_conntrack_expect: use expect->helper
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit f01794106042ee27e54af6fdf5b319a2fe3df94d ]
+
+Use expect->helper in ctnetlink and /proc to dump the helper name.
+Using nfct_help() without holding a reference to the master conntrack
+is unsafe.
+
+Use exp->master->helper in ctnetlink path if userspace does not provide
+an explicit helper when creating an expectation to retain the existing
+behaviour. The ctnetlink expectation path holds the reference on the
+master conntrack and nf_conntrack_expect lock and the nfnetlink glue
+path refers to the master ct that is attached to the skb.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_expect.c | 2 +-
+ net/netfilter/nf_conntrack_helper.c | 6 +-----
+ net/netfilter/nf_conntrack_netlink.c | 24 ++++++++++--------------
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 4 files changed, 13 insertions(+), 21 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 6739b48c644fc..b37ff73efb3e2 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -670,7 +670,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
+ if (expect->flags & NF_CT_EXPECT_USERSPACE)
+ seq_printf(s, "%sUSERSPACE", delim);
+
+- helper = rcu_dereference(nfct_help(expect->master)->helper);
++ helper = rcu_dereference(expect->helper);
+ if (helper) {
+ seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
+ if (helper->expect_policy[expect->class].name[0])
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index a21c976701f79..a715304a53d8c 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -395,14 +395,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
+
+ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ {
+- struct nf_conn_help *help = nfct_help(exp->master);
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (rcu_access_pointer(exp->helper) == me)
+- return true;
+-
+- this = rcu_dereference_protected(help->helper,
++ this = rcu_dereference_protected(exp->helper,
+ lockdep_is_held(&nf_conntrack_expect_lock));
+ return this == me;
+ }
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index b67ab92d65bab..66a87b0ed46c4 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3005,7 +3005,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ {
+ struct nf_conn *master = exp->master;
+ long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
+- struct nf_conn_help *help;
++ struct nf_conntrack_helper *helper;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+ struct nlattr *nest_parms;
+ struct nf_conntrack_tuple nat_tuple = {};
+@@ -3050,15 +3050,12 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
+ goto nla_put_failure;
+- help = nfct_help(master);
+- if (help) {
+- struct nf_conntrack_helper *helper;
+
+- helper = rcu_dereference(help->helper);
+- if (helper &&
+- nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
+- goto nla_put_failure;
+- }
++ helper = rcu_dereference(exp->helper);
++ if (helper &&
++ nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
++ goto nla_put_failure;
++
+ expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
+ if (expfn != NULL &&
+ nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
+@@ -3387,12 +3384,9 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
+ static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
+ {
+ struct nf_conntrack_helper *helper;
+- const struct nf_conn_help *m_help;
+ const char *name = data;
+
+- m_help = nfct_help(exp->master);
+-
+- helper = rcu_dereference(m_help->helper);
++ helper = rcu_dereference(exp->helper);
+ if (!helper)
+ return false;
+
+@@ -3527,9 +3521,9 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+- u_int32_t class = 0;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
++ u32 class = 0;
+ int err;
+
+ help = nfct_help(ct);
+@@ -3566,6 +3560,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ if (!helper)
++ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 5bddee342e122..939502ff7c871 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -924,7 +924,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
+
+ if (!exp || exp->master == ct ||
+- nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
++ exp->helper != nfct_help(ct)->helper ||
+ exp->class != class)
+ break;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+--
+2.53.0
+
--- /dev/null
+From 9e09c207378402ee54fdc50f2e2d48f31c0f08e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index ceb48c3ca0a43..9d7d36ac83083 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -419,7 +419,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+--
+2.53.0
+
--- /dev/null
+From 2888a637513ba66658545c08788c394c73be595b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index fdbb1e20499bd..0349787e18465 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -11667,8 +11667,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -11703,6 +11701,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 0fb502798d297582784bde1094bb7ba1f1fe1029 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index 27dd35224e629..dcd2493a9a404 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -726,7 +726,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From 0614b2c1600315323be5a276fc8b94afb4388706 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c437fbd59ec13..43d2ae2be628d 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -65,6 +65,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -102,6 +105,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 95c69190eb63387d12a81e0f892c3f719d6c8a5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index 48105ea3df152..1ca4fa9d249b8 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -501,6 +501,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -1016,6 +1027,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From f0c393d8a05809a2675f6249dc913c9e8f4b9ede Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index a081bce61c29f..49c399a571750 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
+
+ timer_delete(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From 044dbaa81ce9213e7c6f19e94a7a255b56d33a5e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 30609aed5d37e..2f63f938d0890 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -2144,12 +2144,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From aca4a5152909020e287ce4750a80df9f2578772b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Mar 2026 16:37:41 -0400
+Subject: objtool/klp: fix mkstemp() failure with long paths
+
+From: Joe Lawrence <joe.lawrence@redhat.com>
+
+[ Upstream commit 28e367a969b0c54c87ca655ec180715fe469fd14 ]
+
+The elf_create_file() function fails with EINVAL when the build directory
+path is long enough to truncate the "XXXXXX" suffix in the 256-byte
+tmp_name buffer.
+
+Simplify the code to remove the unnecessary dirname()/basename() split
+and concatenation. Instead, allocate the exact number of bytes needed for
+the path.
+
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
+Link: https://patch.msgid.link/20260310203751.1479229-3-joe.lawrence@redhat.com
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/elf.c | 23 +++--------------------
+ 1 file changed, 3 insertions(+), 20 deletions(-)
+
+diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
+index 3da90686350d7..2ffe3ebfbe37c 100644
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -16,7 +16,6 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <errno.h>
+-#include <libgen.h>
+ #include <ctype.h>
+ #include <linux/align.h>
+ #include <linux/kernel.h>
+@@ -1189,7 +1188,7 @@ struct elf *elf_open_read(const char *name, int flags)
+ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name)
+ {
+ struct section *null, *symtab, *strtab, *shstrtab;
+- char *dir, *base, *tmp_name;
++ char *tmp_name;
+ struct symbol *sym;
+ struct elf *elf;
+
+@@ -1203,29 +1202,13 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name)
+
+ INIT_LIST_HEAD(&elf->sections);
+
+- dir = strdup(name);
+- if (!dir) {
+- ERROR_GLIBC("strdup");
+- return NULL;
+- }
+-
+- dir = dirname(dir);
+-
+- base = strdup(name);
+- if (!base) {
+- ERROR_GLIBC("strdup");
+- return NULL;
+- }
+-
+- base = basename(base);
+-
+- tmp_name = malloc(256);
++ tmp_name = malloc(strlen(name) + 8);
+ if (!tmp_name) {
+ ERROR_GLIBC("malloc");
+ return NULL;
+ }
+
+- snprintf(tmp_name, 256, "%s/%s.XXXXXX", dir, base);
++ sprintf(tmp_name, "%s.XXXXXX", name);
+
+ elf->fd = mkstemp(tmp_name);
+ if (elf->fd == -1) {
+--
+2.53.0
+
--- /dev/null
+From ada5dad3ed6a8ff4ccd46a7c8b9f0f70ec209b15 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 6585164c70595..dd08ccc4246da 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -604,8 +604,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
--- /dev/null
+From 36b3d83078ee2247969c454c7dc82ab1bbbc10c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 10:21:47 -1000
+Subject: selftests/cgroup: Don't require synchronous populated update on task
+ exit
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 6680c162b4850976ee52b57372eddc4450c1d074 ]
+
+test_cgcore_populated (test_core) and test_cgkill_{simple,tree,forkbomb}
+(test_kill) check cgroup.events "populated 0" immediately after reaping
+child tasks with waitpid(). This used to work because cgroup_task_exit() in
+do_exit() unlinked tasks from css_sets before exit_notify() woke up
+waitpid().
+
+d245698d727a ("cgroup: Defer task cgroup unlink until after the task is done
+switching out") moved the unlink to cgroup_task_dead() in
+finish_task_switch(), which runs after exit_notify(). The populated counter
+is now decremented after the parent's waitpid() can return, so there is no
+longer a synchronous ordering guarantee. On PREEMPT_RT, where
+cgroup_task_dead() is further deferred through lazy irq_work, the race
+window is even larger.
+
+The synchronous populated transition was never part of the cgroup interface
+contract - it was an implementation artifact. Use cg_read_strcmp_wait() which
+retries for up to 1 second, matching what these tests actually need to
+verify: that the cgroup eventually becomes unpopulated after all tasks exit.
+
+Fixes: d245698d727a ("cgroup: Defer task cgroup unlink until after the task is done switching out")
+Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: cgroups@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/cgroup/lib/cgroup_util.c | 15 +++++++++++++++
+ .../selftests/cgroup/lib/include/cgroup_util.h | 2 ++
+ tools/testing/selftests/cgroup/test_core.c | 3 ++-
+ tools/testing/selftests/cgroup/test_kill.c | 7 ++++---
+ 4 files changed, 23 insertions(+), 4 deletions(-)
+
+diff --git a/tools/testing/selftests/cgroup/lib/cgroup_util.c b/tools/testing/selftests/cgroup/lib/cgroup_util.c
+index 44c52f620fda1..4b0f2c46d4322 100644
+--- a/tools/testing/selftests/cgroup/lib/cgroup_util.c
++++ b/tools/testing/selftests/cgroup/lib/cgroup_util.c
+@@ -123,6 +123,21 @@ int cg_read_strcmp(const char *cgroup, const char *control,
+ return ret;
+ }
+
++int cg_read_strcmp_wait(const char *cgroup, const char *control,
++ const char *expected)
++{
++ int i, ret;
++
++ for (i = 0; i < 100; i++) {
++ ret = cg_read_strcmp(cgroup, control, expected);
++ if (!ret)
++ return ret;
++ usleep(10000);
++ }
++
++ return ret;
++}
++
+ int cg_read_strstr(const char *cgroup, const char *control, const char *needle)
+ {
+ char buf[PAGE_SIZE];
+diff --git a/tools/testing/selftests/cgroup/lib/include/cgroup_util.h b/tools/testing/selftests/cgroup/lib/include/cgroup_util.h
+index 7ab2824ed7b54..1cbe3b0ac6f73 100644
+--- a/tools/testing/selftests/cgroup/lib/include/cgroup_util.h
++++ b/tools/testing/selftests/cgroup/lib/include/cgroup_util.h
+@@ -59,6 +59,8 @@ extern int cg_read(const char *cgroup, const char *control,
+ char *buf, size_t len);
+ extern int cg_read_strcmp(const char *cgroup, const char *control,
+ const char *expected);
++extern int cg_read_strcmp_wait(const char *cgroup, const char *control,
++ const char *expected);
+ extern int cg_read_strstr(const char *cgroup, const char *control,
+ const char *needle);
+ extern long cg_read_long(const char *cgroup, const char *control);
+diff --git a/tools/testing/selftests/cgroup/test_core.c b/tools/testing/selftests/cgroup/test_core.c
+index 102262555a599..7b83c7e7c9d4f 100644
+--- a/tools/testing/selftests/cgroup/test_core.c
++++ b/tools/testing/selftests/cgroup/test_core.c
+@@ -233,7 +233,8 @@ static int test_cgcore_populated(const char *root)
+ if (err)
+ goto cleanup;
+
+- if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n"))
++ if (cg_read_strcmp_wait(cg_test_d, "cgroup.events",
++ "populated 0\n"))
+ goto cleanup;
+
+ /* Remove cgroup. */
+diff --git a/tools/testing/selftests/cgroup/test_kill.c b/tools/testing/selftests/cgroup/test_kill.c
+index c8c9d306925b6..f6cd23a8ecc71 100644
+--- a/tools/testing/selftests/cgroup/test_kill.c
++++ b/tools/testing/selftests/cgroup/test_kill.c
+@@ -86,7 +86,7 @@ static int test_cgkill_simple(const char *root)
+ wait_for_pid(pids[i]);
+
+ if (ret == KSFT_PASS &&
+- cg_read_strcmp(cgroup, "cgroup.events", "populated 0\n"))
++ cg_read_strcmp_wait(cgroup, "cgroup.events", "populated 0\n"))
+ ret = KSFT_FAIL;
+
+ if (cgroup)
+@@ -190,7 +190,8 @@ static int test_cgkill_tree(const char *root)
+ wait_for_pid(pids[i]);
+
+ if (ret == KSFT_PASS &&
+- cg_read_strcmp(cgroup[0], "cgroup.events", "populated 0\n"))
++ cg_read_strcmp_wait(cgroup[0], "cgroup.events",
++ "populated 0\n"))
+ ret = KSFT_FAIL;
+
+ for (i = 9; i >= 0 && cgroup[i]; i--) {
+@@ -251,7 +252,7 @@ static int test_cgkill_forkbomb(const char *root)
+ wait_for_pid(pid);
+
+ if (ret == KSFT_PASS &&
+- cg_read_strcmp(cgroup, "cgroup.events", "populated 0\n"))
++ cg_read_strcmp_wait(cgroup, "cgroup.events", "populated 0\n"))
+ ret = KSFT_FAIL;
+
+ if (cgroup)
+--
+2.53.0
+
xfs-factor-out-xfs_attr3_node_entry_remove.patch
xfs-factor-out-xfs_attr3_leaf_init.patch
xfs-close-crash-window-in-attr-dabtree-inactivation.patch
+arm64-scs-fix-handling-of-advance_loc4.patch
+hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch
+wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+btrfs-don-t-take-device_list_mutex-when-querying-zon.patch
+tg3-replace-placeholder-mac-address-with-device-prop.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch
+hid-core-mitigate-potential-oob-by-removing-bogus-me.patch
+objtool-klp-fix-mkstemp-failure-with-long-paths.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+btrfs-reserve-enough-transaction-items-for-qgroup-io.patch
+i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch
+btrfs-reject-root-items-with-drop_progress-and-zero-.patch
+drm-amd-display-fix-gamma-2.2-colorop-tfs.patch
+smb-client-fix-generic-694-due-to-wrong-i_blocks.patch
+spi-geni-qcom-check-dma-interrupts-early-in-isr.patch
+mshv-fix-error-handling-in-mshv_region_pin.patch
+dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch
+wifi-iwlwifi-mld-fix-mlo-scan-timing.patch
+wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch
+wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch
+wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch
+cgroup-wait-for-dying-tasks-to-leave-on-rmdir.patch
+selftests-cgroup-don-t-require-synchronous-populated.patch
+cgroup-fix-cgroup_drain_dying-testing-the-wrong-cond.patch
+crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch
+crypto-caam-fix-overflow-on-long-hmac-keys.patch
+crypto-deflate-fix-spurious-enospc.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+mpls-add-seqcount-to-protect-the-platform_label-s-pa.patch
+net-mana-fix-rx-skb-truesize-accounting.patch
+netdevsim-fix-build-if-skb_extensions-n.patch
+net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch
+net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch
+net-enetc-add-graceful-stop-to-safely-reinitialize-t.patch
+net-enetc-do-not-access-non-existent-registers-on-ps.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+iommupt-amdv1-mark-amdv1pt_install_leaf_entry-as-__a.patch
+net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+net-ti-icssg-prueth-fix-missing-data-copy-and-wrong-.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+eth-fbnic-account-for-page-fragments-when-updating-b.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch
+net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch
+net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch
+alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch
+asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch
+net-introduce-mangleid_features.patch
+net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+bnxt_en-set-backing-store-type-from-query-type.patch
+crypto-algif_aead-revert-to-operating-out-of-place.patch
+crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch
+net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch
+asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch
+bridge-mrp-reject-zero-test-interval-to-avoid-oom-pa.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+mptcp-add-eat_recv_skb-helper.patch
+mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch
+net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch
+alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch
+netfilter-flowtable-strictly-check-for-maximum-numbe.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-nf_conntrack_expect-honor-expectation-help.patch
+netfilter-nf_conntrack_expect-use-expect-helper.patch
+netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch
+netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch
+bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch
+bluetooth-l2cap-add-support-for-setting-bt_phy.patch
+bluetooth-hci_sync-hci_cmd_sync_queue_once-return-ee.patch
+bluetooth-hci_sync-fix-leaks-when-hci_cmd_sync_queue.patch
+bluetooth-hci_sync-fix-uaf-in-le_read_features_compl.patch
+bluetooth-hci_h4-fix-race-during-initialization.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch
+bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch
+bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch
+net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-lag-check-for-lag-device-before-creating-de.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch
+bnxt_en-refactor-some-basic-ring-setup-and-adjustmen.patch
+bnxt_en-don-t-assume-xdp-is-never-enabled-in-bnxt_in.patch
+bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+net-hsr-fix-vlan-add-unwind-on-slave-errors.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
+eth-fbnic-increase-fbnic_queue_size_min-to-64.patch
+bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch
+bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch
+bpf-fix-incorrect-pruning-due-to-atomic-fetch-precis.patch
--- /dev/null
+From d01b97ed1977923b7ca008b94df01fee15a63a4d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Mar 2026 21:43:51 -0300
+Subject: smb: client: fix generic/694 due to wrong ->i_blocks
+
+From: Paulo Alcantara <pc@manguebit.org>
+
+[ Upstream commit 23b5df09c27aec13962b30d32a4167ebdd043f8e ]
+
+When updating ->i_size, make sure to always update ->i_blocks as well
+until we query new allocation size from the server.
+
+generic/694 was failing because smb3_simple_falloc() was missing the
+update of ->i_blocks after calling cifs_setsize(). So, fix this by
+updating ->i_blocks directly in cifs_setsize(), so all places that
+call it doesn't need to worry about updating ->i_blocks later.
+
+Reported-by: Shyam Prasad N <sprasad@microsoft.com>
+Closes: https://lore.kernel.org/r/CANT5p=rqgRwaADB=b_PhJkqXjtfq3SFv41SSTXSVEHnuh871pA@mail.gmail.com
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
+Cc: David Howells <dhowells@redhat.com>
+Cc: linux-cifs@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsglob.h | 6 ++++++
+ fs/smb/client/file.c | 1 -
+ fs/smb/client/inode.c | 21 ++++++---------------
+ fs/smb/client/smb2ops.c | 20 ++++----------------
+ 4 files changed, 16 insertions(+), 32 deletions(-)
+
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index 0c3d2bbef938e..474d7b2aa2ef5 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -2324,4 +2324,10 @@ static inline int cifs_open_create_options(unsigned int oflags, int opts)
+ return opts;
+ }
+
++/*
++ * The number of blocks is not related to (i_size / i_blksize), but instead
++ * 512 byte (2**9) size is required for calculating num blocks.
++ */
++#define CIFS_INO_BLOCKS(size) DIV_ROUND_UP_ULL((u64)(size), 512)
++
+ #endif /* _CIFS_GLOB_H */
+diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
+index c27a38843aa64..9d703a2474509 100644
+--- a/fs/smb/client/file.c
++++ b/fs/smb/client/file.c
+@@ -994,7 +994,6 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
+ if (!rc) {
+ netfs_resize_file(&cinode->netfs, 0, true);
+ cifs_setsize(inode, 0);
+- inode->i_blocks = 0;
+ }
+ }
+ if (cfile)
+diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
+index f9ee95953fa4a..c5d89ddc87c00 100644
+--- a/fs/smb/client/inode.c
++++ b/fs/smb/client/inode.c
+@@ -219,13 +219,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
+ */
+ if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) {
+ i_size_write(inode, fattr->cf_eof);
+-
+- /*
+- * i_blocks is not related to (i_size / i_blksize),
+- * but instead 512 byte (2**9) size is required for
+- * calculating num blocks.
+- */
+- inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
++ inode->i_blocks = CIFS_INO_BLOCKS(fattr->cf_bytes);
+ }
+
+ if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) {
+@@ -3009,6 +3003,11 @@ void cifs_setsize(struct inode *inode, loff_t offset)
+ {
+ spin_lock(&inode->i_lock);
+ i_size_write(inode, offset);
++ /*
++ * Until we can query the server for actual allocation size,
++ * this is best estimate we have for blocks allocated for a file.
++ */
++ inode->i_blocks = CIFS_INO_BLOCKS(offset);
+ spin_unlock(&inode->i_lock);
+ inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ truncate_pagecache(inode, offset);
+@@ -3081,14 +3080,6 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
+ if (rc == 0) {
+ netfs_resize_file(&cifsInode->netfs, size, true);
+ cifs_setsize(inode, size);
+- /*
+- * i_blocks is not related to (i_size / i_blksize), but instead
+- * 512 byte (2**9) size is required for calculating num blocks.
+- * Until we can query the server for actual allocation size,
+- * this is best estimate we have for blocks allocated for a file
+- * Number of blocks must be rounded up so size 1 is not 0 blocks
+- */
+- inode->i_blocks = (512 - 1 + size) >> 9;
+ }
+
+ return rc;
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 9bfd3711030b4..067e313283291 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -1493,6 +1493,7 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+ {
+ struct smb2_file_network_open_info file_inf;
+ struct inode *inode;
++ u64 asize;
+ int rc;
+
+ rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
+@@ -1516,14 +1517,9 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+ inode_set_atime_to_ts(inode,
+ cifs_NTtimeToUnix(file_inf.LastAccessTime));
+
+- /*
+- * i_blocks is not related to (i_size / i_blksize),
+- * but instead 512 byte (2**9) size is required for
+- * calculating num blocks.
+- */
+- if (le64_to_cpu(file_inf.AllocationSize) > 4096)
+- inode->i_blocks =
+- (512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
++ asize = le64_to_cpu(file_inf.AllocationSize);
++ if (asize > 4096)
++ inode->i_blocks = CIFS_INO_BLOCKS(asize);
+
+ /* End of file and Attributes should not have to be updated on close */
+ spin_unlock(&inode->i_lock);
+@@ -2197,14 +2193,6 @@ smb2_duplicate_extents(const unsigned int xid,
+ rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
+ if (rc)
+ goto duplicate_extents_out;
+-
+- /*
+- * Although also could set plausible allocation size (i_blocks)
+- * here in addition to setting the file size, in reflink
+- * it is likely that the target file is sparse. Its allocation
+- * size will be queried on next revalidate, but it is important
+- * to make sure that file's cached size is updated immediately
+- */
+ netfs_resize_file(netfs_inode(inode), dest_off + len, true);
+ cifs_setsize(inode, dest_off + len);
+ }
+--
+2.53.0
+
--- /dev/null
+From f32cec81b2dfa2a25a93ae0dea04bf7b06fae9d0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 21:49:01 +0530
+Subject: spi: geni-qcom: Check DMA interrupts early in ISR
+
+From: Praveen Talari <praveen.talari@oss.qualcomm.com>
+
+[ Upstream commit 8c89a077ca796a2fe248c584e9d7e66cff0388c8 ]
+
+The current interrupt handler only checks the GENI main IRQ status
+(m_irq) before deciding to return IRQ_NONE. This can lead to spurious
+IRQ_NONE returns when DMA interrupts are pending but m_irq is zero.
+
+Move the DMA TX/RX status register reads to the beginning of the ISR,
+right after reading m_irq. Update the early return condition to check
+all three status registers (m_irq, dma_tx_status, dma_rx_status) before
+returning IRQ_NONE.
+
+Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-geni-qcom.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
+index acfcf870efd84..736120107184f 100644
+--- a/drivers/spi/spi-geni-qcom.c
++++ b/drivers/spi/spi-geni-qcom.c
+@@ -958,10 +958,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ struct spi_controller *spi = data;
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+- u32 m_irq;
++ u32 m_irq, dma_tx_status, dma_rx_status;
+
+ m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
+- if (!m_irq)
++ dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
++ dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
++
++ if (!m_irq && !dma_tx_status && !dma_rx_status)
+ return IRQ_NONE;
+
+ if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
+@@ -1009,8 +1012,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ }
+ } else if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ const struct spi_transfer *xfer = mas->cur_xfer;
+- u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+- u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (dma_tx_status)
+ writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
+--
+2.53.0
+
--- /dev/null
+From c5c2e6c3be61f35288e3b1526d0b3c8d3f7650e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index a80f27e66ab52..1a59a2e53d865 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12300,7 +12300,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From 4a9611568624aa78c8cfce17732618288eedabbf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Mar 2026 03:24:30 +0530
+Subject: tg3: replace placeholder MAC address with device property
+
+From: Paul SAGE <paul.sage@42.fr>
+
+[ Upstream commit e4c00ba7274b613e3ab19e27eb009f0ec2e28379 ]
+
+On some systems (e.g. iMac 20,1 with BCM57766), the tg3 driver reads
+a default placeholder mac address (00:10:18:00:00:00) from the
+mailbox. The correct value on those systems are stored in the
+'local-mac-address' property.
+
+This patch, detect the default value and tries to retrieve
+the correct address from the device_get_mac_address
+function instead.
+
+The patch has been tested on two different systems:
+- iMac 20,1 (BCM57766) model which use the local-mac-address property
+- iMac 13,2 (BCM57766) model which can use the mailbox,
+ NVRAM or MAC control registers
+
+Tested-by: Rishon Jonathan R <mithicalaviator85@gmail.com>
+
+Co-developed-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Paul SAGE <paul.sage@42.fr>
+Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index 75f66587983d7..a80f27e66ab52 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -17030,6 +17030,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
+ return err;
+ }
+
++static int tg3_is_default_mac_address(u8 *addr)
++{
++ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
++
++ return ether_addr_equal(default_mac_address, addr);
++}
++
+ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+ {
+ u32 hi, lo, mac_offset;
+@@ -17103,6 +17110,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+
+ if (!is_valid_ether_addr(addr))
+ return -EINVAL;
++
++ if (tg3_is_default_mac_address(addr))
++ return device_get_mac_address(&tp->pdev->dev, addr);
++
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From b4df7e86c286f2a710d62b63180f17c83d00e692 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Mar 2026 12:26:08 +0530
+Subject: wifi: ath11k: Pass the correct value of each TID during a stop AMPDU
+ session
+
+From: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+
+[ Upstream commit e225b36f83d7926c1f2035923bb0359d851fdb73 ]
+
+During ongoing traffic, a request to stop an AMPDU session
+for one TID could incorrectly affect other active sessions.
+This can happen because an incorrect TID reference would be
+passed when updating the BA session state, causing the wrong
+session to be stopped. As a result, the affected session would
+be reduced to a minimal BA size, leading to a noticeable
+throughput degradation.
+
+Fix this issue by passing the correct argument from
+ath11k_dp_rx_ampdu_stop() to ath11k_peer_rx_tid_reo_update()
+during a stop AMPDU session. Instead of passing peer->tx_tid, which
+is the base address of the array, corresponding to TID 0; pass
+the value of &peer->rx_tid[params->tid], where the different TID numbers
+are accounted for.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1
+
+Fixes: d5c65159f2895 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
+Signed-off-by: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index b9e976ddcbbf6..44eea682c297b 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_peer *peer;
+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
++ struct dp_rx_tid *rx_tid;
+ int vdev_id = arsta->arvif->vdev_id;
+- dma_addr_t paddr;
+- bool active;
+ int ret;
+
+ spin_lock_bh(&ab->base_lock);
+@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ return -ENOENT;
+ }
+
+- paddr = peer->rx_tid[params->tid].paddr;
+- active = peer->rx_tid[params->tid].active;
++ rx_tid = &peer->rx_tid[params->tid];
+
+- if (!active) {
++ if (!rx_tid->active) {
+ spin_unlock_bh(&ab->base_lock);
+ return 0;
+ }
+
+- ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
++ ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
+ spin_unlock_bh(&ab->base_lock);
+ if (ret) {
+ ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
+@@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ }
+
+ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
+- params->sta->addr, paddr,
++ params->sta->addr,
++ rx_tid->paddr,
+ params->tid, 1, 1);
+ if (ret)
+ ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
+--
+2.53.0
+
--- /dev/null
+From 6e5ac9ee8f6b003c304c1fd420bc263ae460991d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:33:26 +0200
+Subject: wifi: iwlwifi: mld: correctly set wifi generation data
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 687a95d204e72e52f2e6bc7a994cc82f76b2678f ]
+
+In each MAC context, the firmware expects the wifi generation
+data, i.e. whether or not HE/EHT (and in the future UHR) is
+enabled on that MAC.
+
+However, this is currently handled wrong in two ways:
+ - EHT is only enabled when the interface is also an MLD, but
+ we currently allow (despite the spec) connecting with EHT
+ but without MLO.
+ - when HE or EHT are used by TDLS peers, the firmware needs
+ to have them enabled regardless of the AP
+
+Fix this by iterating setting up the data depending on the
+interface type:
+ - for AP, just set it according to the BSS configuration
+ - for monitor, set it according to HW capabilities
+ - otherwise, particularly for client, iterate all stations
+ and then their links on the interface in question and set
+ according to their capabilities, this handles the AP and
+ TDLS peers. Re-calculate this whenever a TDLS station is
+ marked associated or removed so that it's kept updated,
+ for the AP it's already updated on assoc/disassoc.
+
+Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20260319110722.404713b22177.Ic972b5e557d011a5438f8f97c1e793cc829e2ea9@changeid
+Link: https://patch.msgid.link/20260324093333.2953495-1-miriam.rachel.korenblit@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/mld/iface.c | 101 ++++++++++++------
+ .../net/wireless/intel/iwlwifi/mld/mac80211.c | 19 ++++
+ 2 files changed, 88 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+index f15d1f5d1bf59..a770ee5e0e73a 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+@@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
+ IEEE80211_HE_MAC_CAP2_ACK_EN);
+ }
+
+-static void iwl_mld_set_he_support(struct iwl_mld *mld,
+- struct ieee80211_vif *vif,
+- struct iwl_mac_config_cmd *cmd)
++struct iwl_mld_mac_wifi_gen_sta_iter_data {
++ struct ieee80211_vif *vif;
++ struct iwl_mac_wifi_gen_support *support;
++};
++
++static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
++ struct ieee80211_sta *sta)
+ {
+- if (vif->type == NL80211_IFTYPE_AP)
+- cmd->wifi_gen.he_ap_support = 1;
+- else
+- cmd->wifi_gen.he_support = 1;
++ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
++ struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
++ struct ieee80211_link_sta *link_sta;
++ unsigned int link_id;
++
++ if (mld_sta->vif != data->vif)
++ return;
++
++ for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
++ if (link_sta->he_cap.has_he)
++ data->support->he_support = 1;
++ if (link_sta->eht_cap.has_eht)
++ data->support->eht_support = 1;
++ }
++}
++
++static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
++ struct ieee80211_vif *vif,
++ struct iwl_mac_wifi_gen_support *support)
++{
++ struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
++ .vif = vif,
++ .support = support,
++ };
++ struct ieee80211_bss_conf *link_conf;
++ unsigned int link_id;
++
++ switch (vif->type) {
++ case NL80211_IFTYPE_MONITOR:
++ /* for sniffer, set to HW capabilities */
++ support->he_support = 1;
++ support->eht_support = mld->trans->cfg->eht_supported;
++ break;
++ case NL80211_IFTYPE_AP:
++ /* for AP set according to the link configs */
++ for_each_vif_active_link(vif, link_conf, link_id) {
++ support->he_ap_support |= link_conf->he_support;
++ support->eht_support |= link_conf->eht_support;
++ }
++ break;
++ default:
++ /*
++ * If we have MLO enabled, then the firmware needs to enable
++ * address translation for the station(s) we add. That depends
++ * on having EHT enabled in firmware, which in turn depends on
++ * mac80211 in the iteration below.
++ * However, mac80211 doesn't enable capabilities on the AP STA
++ * until it has parsed the association response successfully,
++ * so set EHT (and HE as a pre-requisite for EHT) when the vif
++ * is an MLD.
++ */
++ if (ieee80211_vif_is_mld(vif)) {
++ support->he_support = 1;
++ support->eht_support = 1;
++ }
++
++ ieee80211_iterate_stations_mtx(mld->hw,
++ iwl_mld_mac_wifi_gen_sta_iter,
++ &sta_iter_data);
++ break;
++ }
+ }
+
+ /* fill the common part for all interface types */
+@@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
+ u32 action)
+ {
+ struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+- struct ieee80211_bss_conf *link_conf;
+- unsigned int link_id;
+
+ lockdep_assert_wiphy(mld->wiphy);
+
+@@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
+ cmd->nic_not_ack_enabled =
+ cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
+
+- /* If we have MLO enabled, then the firmware needs to enable
+- * address translation for the station(s) we add. That depends
+- * on having EHT enabled in firmware, which in turn depends on
+- * mac80211 in the code below.
+- * However, mac80211 doesn't enable HE/EHT until it has parsed
+- * the association response successfully, so just skip all that
+- * and enable both when we have MLO.
+- */
+- if (ieee80211_vif_is_mld(vif)) {
+- iwl_mld_set_he_support(mld, vif, cmd);
+- cmd->wifi_gen.eht_support = 1;
+- return;
+- }
+-
+- for_each_vif_active_link(vif, link_conf, link_id) {
+- if (!link_conf->he_support)
+- continue;
+-
+- iwl_mld_set_he_support(mld, vif, cmd);
+-
+- /* EHT, if supported, was already set above */
+- break;
+- }
++ iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
+ }
+
+ static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+index 3a1b5bfb9ed66..77793da147b73 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+@@ -1690,6 +1690,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ iwl_mld_link_set_2mhz_block(mld, vif, sta);
++
++ if (sta->tdls) {
++ /*
++ * update MAC since wifi generation flags may change,
++ * we also update MAC on association to the AP via the
++ * vif assoc change
++ */
++ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
++ }
++
+ /* Now the link_sta's capabilities are set, update the FW */
+ iwl_mld_config_tlc(mld, vif, sta);
+
+@@ -1799,6 +1809,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,
+ /* just removed last TDLS STA, so enable PM */
+ iwl_mld_update_mac_power(mld, vif, false);
+ }
++
++ if (sta->tdls) {
++ /*
++ * update MAC since wifi generation flags may change,
++ * we also update MAC on disassociation to the AP via
++ * the vif assoc change
++ */
++ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
++ }
+ } else {
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 399ba6c08e364814c0385e523f702eb914466253 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:33:24 +0200
+Subject: wifi: iwlwifi: mld: Fix MLO scan timing
+
+From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+
+[ Upstream commit ec66ec6a5a8f53e7c70085749e8d68f4431c630f ]
+
+Calculate MLO scan start time based on actual
+scan start notification from firmware instead of recording
+time when scan command is sent.
+
+Currently, MLO scan start time was captured immediately
+after sending the scan command to firmware. However, the
+actual scan start time may differ due to the FW being busy
+with a previous scan.
+
+In that case, the link selection code will think that the MLO
+scan is too old, and will warn.
+
+To fix it, Implement start scan notification handling to
+capture the precise moment when firmware begins the scan
+operation.
+
+Fixes: 9324731b9985 ("wifi: iwlwifi: mld: avoid selecting bad links")
+Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20260324113316.4c56b8bac533.I6e656d8cc30bb82c96aabadedd62bd67f4c46bf9@changeid
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../wireless/intel/iwlwifi/fw/api/commands.h | 5 ++++
+ .../net/wireless/intel/iwlwifi/fw/api/scan.h | 10 +++++++
+ drivers/net/wireless/intel/iwlwifi/mld/mld.c | 1 +
+ drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 4 +--
+ .../net/wireless/intel/iwlwifi/mld/notif.c | 5 ++++
+ drivers/net/wireless/intel/iwlwifi/mld/scan.c | 30 +++++++++++++++++--
+ drivers/net/wireless/intel/iwlwifi/mld/scan.h | 9 ++++--
+ 7 files changed, 56 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+index 8d64a271bb945..36159a7699167 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+@@ -296,6 +296,11 @@ enum iwl_legacy_cmds {
+ */
+ SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
+
++ /**
++ * @SCAN_START_NOTIFICATION_UMAC: uses &struct iwl_umac_scan_start
++ */
++ SCAN_START_NOTIFICATION_UMAC = 0xb2,
++
+ /**
+ * @MATCH_FOUND_NOTIFICATION: scan match found
+ */
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+index 60f0a4924ddfb..46fcc32608e34 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+@@ -1156,6 +1156,16 @@ enum iwl_umac_scan_abort_status {
+ IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
+ };
+
++/**
++ * struct iwl_umac_scan_start - scan start notification
++ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
++ * @reserved: for future use
++ */
++struct iwl_umac_scan_start {
++ __le32 uid;
++ __le32 reserved;
++} __packed; /* SCAN_START_UMAC_API_S_VER_1 */
++
+ /**
+ * struct iwl_umac_scan_complete - scan complete notification
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+index 8a4c96385640b..18691871bdacc 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+@@ -171,6 +171,7 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = {
+ HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
+ HCMD_NAME(MAC_PM_POWER_TABLE),
+ HCMD_NAME(MFUART_LOAD_NOTIFICATION),
++ HCMD_NAME(SCAN_START_NOTIFICATION_UMAC),
+ HCMD_NAME(RSS_CONFIG_CMD),
+ HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
+ HCMD_NAME(REPLY_RX_MPDU_CMD),
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+index 1efefc737248f..47d36f0149efb 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+@@ -725,7 +725,7 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld,
+
+ /* Ignore any BSS that was not seen in the last MLO scan */
+ if (ktime_before(link_conf->bss->ts_boottime,
+- mld->scan.last_mlo_scan_time))
++ mld->scan.last_mlo_scan_start_time))
+ continue;
+
+ data[n_data].link_id = link_id;
+@@ -931,7 +931,7 @@ static void _iwl_mld_select_links(struct iwl_mld *mld,
+ if (!mld_vif->authorized || hweight16(usable_links) <= 1)
+ return;
+
+- if (WARN(ktime_before(mld->scan.last_mlo_scan_time,
++ if (WARN(ktime_before(mld->scan.last_mlo_scan_start_time,
+ ktime_sub_ns(ktime_get_boottime_ns(),
+ 5ULL * NSEC_PER_SEC)),
+ "Last MLO scan was too long ago, can't select links\n"))
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+index 4cf3920b005fe..ca90a2f905262 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+@@ -284,6 +284,8 @@ static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld,
+ * at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
+ */
+
++CMD_VERSIONS(scan_start_notif,
++ CMD_VER_ENTRY(1, iwl_umac_scan_start))
+ CMD_VERSIONS(scan_complete_notif,
+ CMD_VER_ENTRY(1, iwl_umac_scan_complete))
+ CMD_VERSIONS(scan_iter_complete_notif,
+@@ -355,6 +357,7 @@ DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif,
+ link_id)
+ DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity)
+ DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid)
++DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid)
+ DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif,
+ mac_id)
+ DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif,
+@@ -397,6 +400,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
+ RX_HANDLER_SYNC)
+ RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif,
+ RX_HANDLER_SYNC)
++ RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC,
++ scan_start_notif)
+ RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC,
+ scan_complete_notif)
+ RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC,
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+index fd1022ddc9122..76ac6fd5f9ff3 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
++++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+@@ -473,6 +473,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld,
+ params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN;
+
++ if (scan_status == IWL_MLD_SCAN_INT_MLO)
++ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START;
++
+ if (params->enable_6ghz_passive)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN;
+
+@@ -1817,9 +1820,6 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,
+ ret = _iwl_mld_single_scan_start(mld, vif, req, &ies,
+ IWL_MLD_SCAN_INT_MLO);
+
+- if (!ret)
+- mld->scan.last_mlo_scan_time = ktime_get_boottime_ns();
+-
+ IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);
+ }
+
+@@ -1904,6 +1904,30 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
+ ieee80211_sched_scan_results(mld->hw);
+ }
+
++void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
++ struct iwl_rx_packet *pkt)
++{
++ struct iwl_umac_scan_complete *notif = (void *)pkt->data;
++ u32 uid = le32_to_cpu(notif->uid);
++
++ if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),
++ "FW reports out-of-range scan UID %d\n", uid))
++ return;
++
++ if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status),
++ "FW reports scan UID %d we didn't trigger\n", uid))
++ return;
++
++ IWL_DEBUG_SCAN(mld, "Scan started: uid=%u type=%u\n", uid,
++ mld->scan.uid_status[uid]);
++ if (IWL_FW_CHECK(mld, mld->scan.uid_status[uid] != IWL_MLD_SCAN_INT_MLO,
++ "FW reports scan start notification %d we didn't trigger\n",
++ mld->scan.uid_status[uid]))
++ return;
++
++ mld->scan.last_mlo_scan_start_time = ktime_get_boottime_ns();
++}
++
+ void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt)
+ {
+diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+index 69110f0cfc8e2..de5620e7f463b 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+@@ -27,6 +27,9 @@ int iwl_mld_sched_scan_start(struct iwl_mld *mld,
+ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt);
+
++void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
++ struct iwl_rx_packet *pkt);
++
+ void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt);
+
+@@ -114,8 +117,8 @@ enum iwl_mld_traffic_load {
+ * in jiffies.
+ * @last_start_time_jiffies: stores the last start time in jiffies
+ * (interface up/reset/resume).
+- * @last_mlo_scan_time: start time of the last MLO scan in nanoseconds since
+- * boot.
++ * @last_mlo_scan_start_time: start time of the last MLO scan in nanoseconds
++ * since boot.
+ */
+ struct iwl_mld_scan {
+ /* Add here fields that need clean up on restart */
+@@ -136,7 +139,7 @@ struct iwl_mld_scan {
+ void *cmd;
+ unsigned long last_6ghz_passive_jiffies;
+ unsigned long last_start_time_jiffies;
+- u64 last_mlo_scan_time;
++ u64 last_mlo_scan_start_time;
+ };
+
+ /**
+--
+2.53.0
+
--- /dev/null
+From 51f723acb0b89de4b2d1bdfa8bda859ebe5051fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 11:33:25 +0200
+Subject: wifi: iwlwifi: mvm: don't send a 6E related command when not
+ supported
+
+From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+
+[ Upstream commit 323156c3541e23da7e582008a7ac30cd51b60acd ]
+
+MCC_ALLOWED_AP_TYPE_CMD is related to 6E support. Do not send it if the
+device doesn't support 6E.
+Apparently, the firmware is mistakenly advertising support for this
+command even on AX201 which does not support 6E and then the firmware
+crashes.
+
+Fixes: 0d2fc8821a7d ("wifi: iwlwifi: nvm: parse the VLP/AFC bit from regulatory")
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220804
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20260324113316.e171f0163f2a.I0c444d1f82d1773054e7ffc391ad49697d58f44e@changeid
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+index edae13755ee61..b9c9ee30272ec 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+@@ -470,7 +470,8 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
+ .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+ };
+
+- if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
++ if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210 ||
++ !mvm->trans->cfg->uhb_supported) {
+ IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");
+ return;
+ }
+--
+2.53.0
+
--- /dev/null
+From ab6c8c0ad696b3510db923867be712ac6fc55dc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 14:54:17 +0530
+Subject: wifi: mac80211: check tdls flag in ieee80211_tdls_oper
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 7d73872d949c488a1d7c308031d6a9d89b5e0a8b ]
+
+When NL80211_TDLS_ENABLE_LINK is called, the code only checks if the
+station exists but not whether it is actually a TDLS station. This
+allows the operation to proceed for non-TDLS stations, causing
+unintended side effects like modifying channel context and HT
+protection before failing.
+
+Add a check for sta->sta.tdls early in the ENABLE_LINK case, before
+any side effects occur, to ensure the operation is only allowed for
+actual TDLS peers.
+
+Reported-by: syzbot+56b6a844a4ea74487b7b@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=56b6a844a4ea74487b7b
+Tested-by: syzbot+56b6a844a4ea74487b7b@syzkaller.appspotmail.com
+Suggested-by: Johannes Berg <johannes@sipsolutions.net>
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Link: https://patch.msgid.link/20260313092417.520807-1-kartikey406@gmail.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/tdls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
+index dbbfe2d6842fb..1dca2fae05a52 100644
+--- a/net/mac80211/tdls.c
++++ b/net/mac80211/tdls.c
+@@ -1449,7 +1449,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ }
+
+ sta = sta_info_get(sdata, peer);
+- if (!sta)
++ if (!sta || !sta->sta.tdls)
+ return -ENOLINK;
+
+ iee80211_tdls_recalc_chanctx(sdata, sta);
+--
+2.53.0
+
--- /dev/null
+From 0636bb6d097f824e07bbea60a930186ca5daa73b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Mar 2026 14:44:28 +0100
+Subject: arm64/scs: Fix handling of advance_loc4
+
+From: Pepper Gray <hello@peppergray.xyz>
+
+[ Upstream commit d499e9627d70b1269020d59b95ed3e18bee6b8cd ]
+
+DW_CFA_advance_loc4 is defined but no handler is implemented. Its
+CFA opcode defaults to EDYNSCS_INVALID_CFA_OPCODE triggering an
+error which wrongfully prevents modules from loading.
+
+Link: https://bugs.gentoo.org/971060
+Signed-off-by: Pepper Gray <hello@peppergray.xyz>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/patch-scs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm64/kernel/patch-scs.c b/arch/arm64/kernel/patch-scs.c
+index a1fe4b4ff5917..6d656179ea03b 100644
+--- a/arch/arm64/kernel/patch-scs.c
++++ b/arch/arm64/kernel/patch-scs.c
+@@ -171,6 +171,14 @@ static int noinstr scs_handle_fde_frame(const struct eh_frame *frame,
+ size -= 2;
+ break;
+
++ case DW_CFA_advance_loc4:
++ loc += *opcode++ * code_alignment_factor;
++ loc += (*opcode++ << 8) * code_alignment_factor;
++ loc += (*opcode++ << 16) * code_alignment_factor;
++ loc += (*opcode++ << 24) * code_alignment_factor;
++ size -= 4;
++ break;
++
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended:
+ size = skip_xleb128(&opcode, size);
+--
+2.53.0
+
--- /dev/null
+From 379cefa0aca002daaf89b0cc65f06c430038150f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 22:09:09 +0100
+Subject: ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on
+ failure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+
+[ Upstream commit 622363757b2286dd2c2984b0d80255cbb35a0495 ]
+
+ep93xx_i2s_enable() calls clk_prepare_enable() on three clocks in
+sequence (mclk, sclk, lrclk) without checking the return value of any
+of them. If an intermediate enable fails, the clocks that were already
+enabled are never rolled back, leaking them until the next disable cycle
+— which may never come if the stream never started cleanly.
+
+Change ep93xx_i2s_enable() from void to int. Add error checking after
+each clk_prepare_enable() call and unwind already-enabled clocks on
+failure. Propagate the error through ep93xx_i2s_startup() and
+ep93xx_i2s_resume(), both of which already return int.
+
+Signed-off-by: Jihed Chaibi <jihed.chaibi.dev@gmail.com>
+Fixes: f4ff6b56bc8a ("ASoC: cirrus: i2s: Prepare clock before using it")
+Link: https://patch.msgid.link/20260324210909.45494-1-jihed.chaibi.dev@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/cirrus/ep93xx-i2s.c | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
+index 522de4b802939..a13fb1243379e 100644
+--- a/sound/soc/cirrus/ep93xx-i2s.c
++++ b/sound/soc/cirrus/ep93xx-i2s.c
+@@ -105,16 +105,28 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ return __raw_readl(info->regs + reg);
+ }
+
+-static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
++static int ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ {
+ unsigned base_reg;
++ int err;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+- clk_prepare_enable(info->mclk);
+- clk_prepare_enable(info->sclk);
+- clk_prepare_enable(info->lrclk);
++ err = clk_prepare_enable(info->mclk);
++ if (err)
++ return err;
++ err = clk_prepare_enable(info->sclk);
++ if (err) {
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
++ err = clk_prepare_enable(info->lrclk);
++ if (err) {
++ clk_disable_unprepare(info->sclk);
++ clk_disable_unprepare(info->mclk);
++ return err;
++ }
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+@@ -133,6 +145,8 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
+ EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
+ EP93XX_I2S_TXCTRL_TXUFIE);
++
++ return 0;
+ }
+
+ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+@@ -214,9 +228,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ {
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+- ep93xx_i2s_enable(info, substream->stream);
+-
+- return 0;
++ return ep93xx_i2s_enable(info, substream->stream);
+ }
+
+ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+@@ -392,14 +404,16 @@ static int ep93xx_i2s_suspend(struct snd_soc_component *component)
+ static int ep93xx_i2s_resume(struct snd_soc_component *component)
+ {
+ struct ep93xx_i2s_info *info = snd_soc_component_get_drvdata(component);
++ int err;
+
+ if (!snd_soc_component_active(component))
+ return 0;
+
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+- ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
++ err = ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
++ if (err)
++ return err;
+
+- return 0;
++ return ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ #else
+ #define ep93xx_i2s_suspend NULL
+--
+2.53.0
+
--- /dev/null
+From 79b95c78493197e842873bfa1cf6344461fe3351 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 21:29:08 +0530
+Subject: atm: lec: fix use-after-free in sock_def_readable()
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit 922814879542c2e397b0e9641fd36b8202a8e555 ]
+
+A race condition exists between lec_atm_close() setting priv->lecd
+to NULL and concurrent access to priv->lecd in send_to_lecd(),
+lec_handle_bridge(), and lec_atm_send(). When the socket is freed
+via RCU while another thread is still using it, a use-after-free
+occurs in sock_def_readable() when accessing the socket's wait queue.
+
+The root cause is that lec_atm_close() clears priv->lecd without
+any synchronization, while callers dereference priv->lecd without
+any protection against concurrent teardown.
+
+Fix this by converting priv->lecd to an RCU-protected pointer:
+- Mark priv->lecd as __rcu in lec.h
+- Use rcu_assign_pointer() in lec_atm_close() and lecd_attach()
+ for safe pointer assignment
+- Use rcu_access_pointer() for NULL checks that do not dereference
+ the pointer in lec_start_xmit(), lec_push(), send_to_lecd() and
+ lecd_attach()
+- Use rcu_read_lock/rcu_dereference/rcu_read_unlock in send_to_lecd(),
+ lec_handle_bridge() and lec_atm_send() to safely access lecd
+- Use rcu_assign_pointer() followed by synchronize_rcu() in
+ lec_atm_close() to ensure all readers have completed before
+ proceeding. This is safe since lec_atm_close() is called from
+ vcc_release() which holds lock_sock(), a sleeping lock.
+- Remove the manual sk_receive_queue drain from lec_atm_close()
+ since vcc_destroy_socket() already drains it after lec_atm_close()
+ returns.
+
+v2: Switch from spinlock + sock_hold/put approach to RCU to properly
+ fix the race. The v1 spinlock approach had two issues pointed out
+ by Eric Dumazet:
+ 1. priv->lecd was still accessed directly after releasing the
+ lock instead of using a local copy.
+ 2. The spinlock did not prevent packets being queued after
+ lec_atm_close() drains sk_receive_queue since timer and
+ workqueue paths bypass netif_stop_queue().
+
+Note: Syzbot patch testing was attempted but the test VM terminated
+ unexpectedly with "Connection to localhost closed by remote host",
+ likely due to a QEMU AHCI emulation issue unrelated to this fix.
+ Compile testing with "make W=1 net/atm/lec.o" passes cleanly.
+
+Reported-by: syzbot+f50072212ab792c86925@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f50072212ab792c86925
+Link: https://lore.kernel.org/all/20260309093614.502094-1-kartikey406@gmail.com/T/ [v1]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 72 +++++++++++++++++++++++++++++++++------------------
+ net/atm/lec.h | 2 +-
+ 2 files changed, 48 insertions(+), 26 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index 0d4b8e5936dcf..d8ab969625790 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+ /* 0x01 is topology change */
+
+ priv = netdev_priv(dev);
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
+ int is_rdesc;
+
+ pr_debug("called\n");
+- if (!priv->lecd) {
++ if (!rcu_access_pointer(priv->lecd)) {
+ pr_info("%s:No lecd attached\n", dev->name);
+ dev->stats.tx_errors++;
+ netif_stop_queue(dev);
+@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+ break;
+ skb2->len = sizeof(struct atmlec_msg);
+ skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+- atm_force_charge(priv->lecd, skb2->truesize);
+- sk = sk_atm(priv->lecd);
+- skb_queue_tail(&sk->sk_receive_queue, skb2);
+- sk->sk_data_ready(sk);
++ struct atm_vcc *vcc;
++
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (vcc) {
++ atm_force_charge(vcc, skb2->truesize);
++ sk = sk_atm(vcc);
++ skb_queue_tail(&sk->sk_receive_queue, skb2);
++ sk->sk_data_ready(sk);
++ } else {
++ dev_kfree_skb(skb2);
++ }
++ rcu_read_unlock();
+ }
+ }
+ #endif /* IS_ENABLED(CONFIG_BRIDGE) */
+@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ static void lec_atm_close(struct atm_vcc *vcc)
+ {
+- struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = netdev_priv(dev);
+
+- priv->lecd = NULL;
++ rcu_assign_pointer(priv->lecd, NULL);
++ synchronize_rcu();
+ /* Do something needful? */
+
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
+
+- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+- pr_info("%s closing with messages pending\n", dev->name);
+- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
+- atm_return(vcc, skb->truesize);
+- dev_kfree_skb(skb);
+- }
+-
+ pr_info("%s: Shut down!\n", dev->name);
+ module_put(THIS_MODULE);
+ }
+@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ const unsigned char *mac_addr, const unsigned char *atm_addr,
+ struct sk_buff *data)
+ {
++ struct atm_vcc *vcc;
+ struct sock *sk;
+ struct sk_buff *skb;
+ struct atmlec_msg *mesg;
+
+- if (!priv || !priv->lecd)
++ if (!priv || !rcu_access_pointer(priv->lecd))
+ return -1;
++
+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (!skb)
+ return -1;
+@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ if (atm_addr)
+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
+
+- atm_force_charge(priv->lecd, skb->truesize);
+- sk = sk_atm(priv->lecd);
++ rcu_read_lock();
++ vcc = rcu_dereference(priv->lecd);
++ if (!vcc) {
++ rcu_read_unlock();
++ kfree_skb(skb);
++ return -1;
++ }
++
++ atm_force_charge(vcc, skb->truesize);
++ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk);
+
+ if (data != NULL) {
+ pr_debug("about to send %d bytes of data\n", data->len);
+- atm_force_charge(priv->lecd, data->truesize);
++ atm_force_charge(vcc, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk);
+ }
+
++ rcu_read_unlock();
+ return 0;
+ }
+
+@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+
+ atm_return(vcc, skb->truesize);
+ if (*(__be16 *) skb->data == htons(priv->lecid) ||
+- !priv->lecd || !(dev->flags & IFF_UP)) {
++ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+ priv = netdev_priv(dev_lec[i]);
+ } else {
+ priv = netdev_priv(dev_lec[i]);
+- if (priv->lecd)
++ if (rcu_access_pointer(priv->lecd))
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+- priv->lecd = vcc;
++ rcu_assign_pointer(priv->lecd, vcc);
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+diff --git a/net/atm/lec.h b/net/atm/lec.h
+index be0e2667bd8c3..ec85709bf8185 100644
+--- a/net/atm/lec.h
++++ b/net/atm/lec.h
+@@ -91,7 +91,7 @@ struct lec_priv {
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+- struct atm_vcc *lecd;
++ struct atm_vcc __rcu *lecd;
+ struct delayed_work lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+--
+2.53.0
+
--- /dev/null
+From 83bf0c05a76d75faf050dc2257f6b9f53b812d9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 16:43:02 +0300
+Subject: Bluetooth: hci_event: fix potential UAF in
+ hci_le_remote_conn_param_req_evt
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit b255531b27da336571411248c2a72a350662bd09 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_le_remote_conn_param_req_evt, otherwise it's possible it is freed
+concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage.
+
+Fixes: 95118dd4edfec ("Bluetooth: hci_event: Use of a function table to handle LE subevents")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 33 ++++++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 4aa445e7f56bc..8b184839b013a 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -6555,25 +6555,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ latency = le16_to_cpu(ev->latency);
+ timeout = le16_to_cpu(ev->timeout);
+
++ hci_dev_lock(hdev);
++
+ hcon = hci_conn_hash_lookup_handle(hdev, handle);
+- if (!hcon || hcon->state != BT_CONNECTED)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_UNKNOWN_CONN_ID);
++ if (!hcon || hcon->state != BT_CONNECTED) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_UNKNOWN_CONN_ID);
++ goto unlock;
++ }
+
+- if (max > hcon->le_conn_max_interval)
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (max > hcon->le_conn_max_interval) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+- if (hci_check_conn_params(min, max, latency, timeout))
+- return send_conn_param_neg_reply(hdev, handle,
+- HCI_ERROR_INVALID_LL_PARAMS);
++ if (hci_check_conn_params(min, max, latency, timeout)) {
++ send_conn_param_neg_reply(hdev, handle,
++ HCI_ERROR_INVALID_LL_PARAMS);
++ goto unlock;
++ }
+
+ if (hcon->role == HCI_ROLE_MASTER) {
+ struct hci_conn_params *params;
+ u8 store_hint;
+
+- hci_dev_lock(hdev);
+-
+ params = hci_conn_params_lookup(hdev, &hcon->dst,
+ hcon->dst_type);
+ if (params) {
+@@ -6586,8 +6592,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ store_hint = 0x00;
+ }
+
+- hci_dev_unlock(hdev);
+-
+ mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
+ store_hint, min, max, latency, timeout);
+ }
+@@ -6601,6 +6605,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
+ cp.max_ce_len = 0;
+
+ hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
+--
+2.53.0
+
--- /dev/null
+From 0128ada87dc3ef55222776cc4d2340a712740b9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 21:07:46 +0200
+Subject: Bluetooth: hci_sync: call destroy in hci_cmd_sync_run if immediate
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit a834a0b66ec6fb743377201a0f4229bb2503f4ce ]
+
+hci_cmd_sync_run() may run the work immediately if called from existing
+sync work (otherwise it queues a new sync work). In this case it fails
+to call the destroy() function.
+
+On immediate run, make it behave same way as if item was queued
+successfully: call destroy, and return 0.
+
+The only callsite is hci_abort_conn() via hci_cmd_sync_run_once(), and
+this changes its return value. However, its return value is not used
+except as the return value for hci_disconnect(), and nothing uses the
+return value of hci_disconnect(). Hence there should be no behavior
+change anywhere.
+
+Fixes: c898f6d7b093b ("Bluetooth: hci_sync: Introduce hci_cmd_sync_run/hci_cmd_sync_run_once")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_sync.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index c1c9d82faa658..a41cfc76e98bf 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -825,8 +825,15 @@ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+ return -ENETDOWN;
+
+ /* If on cmd_sync_work then run immediately otherwise queue */
+- if (current_work() == &hdev->cmd_sync_work)
+- return func(hdev, data);
++ if (current_work() == &hdev->cmd_sync_work) {
++ int err;
++
++ err = func(hdev, data);
++ if (destroy)
++ destroy(hdev, data, err);
++
++ return 0;
++ }
+
+ return hci_cmd_sync_submit(hdev, func, data, destroy);
+ }
+--
+2.53.0
+
--- /dev/null
+From 2874133aee909d8c5a6a1c58f8e5e5e761c9d41e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Mar 2026 16:46:47 +0800
+Subject: Bluetooth: MGMT: validate LTK enc_size on load
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit b8dbe9648d69059cfe3a28917bfbf7e61efd7f15 ]
+
+Load Long Term Keys stores the user-provided enc_size and later uses
+it to size fixed-size stack operations when replying to LE LTK
+requests. An enc_size larger than the 16-byte key buffer can therefore
+overflow the reply stack buffer.
+
+Reject oversized enc_size values while validating the management LTK
+record so invalid keys never reach the stored key state.
+
+Fixes: 346af67b8d11 ("Bluetooth: Add MGMT handlers for dealing with SMP LTK's")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index 7de0a0d752629..81651f8ed03d0 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -7145,6 +7145,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
+ if (key->initiator != 0x00 && key->initiator != 0x01)
+ return false;
+
++ if (key->enc_size > sizeof(key->val))
++ return false;
++
+ switch (key->addr.type) {
+ case BDADDR_LE_PUBLIC:
+ return true;
+--
+2.53.0
+
--- /dev/null
+From 682c7654bcbc20450599aab073923b921fee7414 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 22:25:26 +0800
+Subject: Bluetooth: MGMT: validate mesh send advertising payload length
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit bda93eec78cdbfe5cda00785cefebd443e56b88b ]
+
+mesh_send() currently bounds MGMT_OP_MESH_SEND by total command
+length, but it never verifies that the bytes supplied for the
+flexible adv_data[] array actually match the embedded adv_data_len
+field. MGMT_MESH_SEND_SIZE only covers the fixed header, so a
+truncated command can still pass the existing 20..50 byte range
+check and later drive the async mesh send path past the end of the
+queued command buffer.
+
+Keep rejecting zero-length and oversized advertising payloads, but
+validate adv_data_len explicitly and require the command length to
+exactly match the flexible array size before queueing the request.
+
+Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/mgmt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index 81651f8ed03d0..51a6ad6a36c8d 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -2388,6 +2388,7 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ struct mgmt_mesh_tx *mesh_tx;
+ struct mgmt_cp_mesh_send *send = data;
+ struct mgmt_rp_mesh_read_features rp;
++ u16 expected_len;
+ bool sending;
+ int err = 0;
+
+@@ -2395,12 +2396,19 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+ !hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_NOT_SUPPORTED);
+- if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
+- len <= MGMT_MESH_SEND_SIZE ||
+- len > (MGMT_MESH_SEND_SIZE + 31))
++ if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_REJECTED);
++
++ if (!send->adv_data_len || send->adv_data_len > 31)
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+ MGMT_STATUS_REJECTED);
+
++ expected_len = struct_size(send, adv_data, send->adv_data_len);
++ if (expected_len != len)
++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
++ MGMT_STATUS_INVALID_PARAMS);
++
+ hci_dev_lock(hdev);
+
+ memset(&rp, 0, sizeof(rp));
+--
+2.53.0
+
--- /dev/null
+From 63c9ece260e4223abe518933bedbbb3266be5dea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 23:16:45 +0800
+Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect()
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit 8a5b0135d4a5d9683203a3d9a12a711ccec5936b ]
+
+sco_sock_connect() checks sk_state and sk_type without holding
+the socket lock. Two concurrent connect() syscalls on the same
+socket can both pass the check and enter sco_connect(), leading
+to use-after-free.
+
+The buggy scenario involves three participants and was confirmed
+with additional logging instrumentation:
+
+ Thread A (connect): HCI disconnect: Thread B (connect):
+
+ sco_sock_connect(sk) sco_sock_connect(sk)
+ sk_state==BT_OPEN sk_state==BT_OPEN
+ (pass, no lock) (pass, no lock)
+ sco_connect(sk): sco_connect(sk):
+ hci_dev_lock hci_dev_lock
+ hci_connect_sco <- blocked
+ -> hcon1
+ sco_conn_add->conn1
+ lock_sock(sk)
+ sco_chan_add:
+ conn1->sk = sk
+ sk->conn = conn1
+ sk_state=BT_CONNECT
+ release_sock
+ hci_dev_unlock
+ hci_dev_lock
+ sco_conn_del:
+ lock_sock(sk)
+ sco_chan_del:
+ sk->conn=NULL
+ conn1->sk=NULL
+ sk_state=
+ BT_CLOSED
+ SOCK_ZAPPED
+ release_sock
+ hci_dev_unlock
+ (unblocked)
+ hci_connect_sco
+ -> hcon2
+ sco_conn_add
+ -> conn2
+ lock_sock(sk)
+ sco_chan_add:
+ sk->conn=conn2
+ sk_state=
+ BT_CONNECT
+ // zombie sk!
+ release_sock
+ hci_dev_unlock
+
+Thread B revives a BT_CLOSED + SOCK_ZAPPED socket back to
+BT_CONNECT. Subsequent cleanup triggers double sock_put() and
+use-after-free. Meanwhile conn1 is leaked as it was orphaned
+when sco_conn_del() cleared the association.
+
+Fix this by:
+- Moving lock_sock() before the sk_state/sk_type checks in
+ sco_sock_connect() to serialize concurrent connect attempts
+- Fixing the sk_type != SOCK_SEQPACKET check to actually
+ return the error instead of just assigning it
+- Adding a state re-check in sco_connect() after lock_sock()
+ to catch state changes during the window between the locks
+- Adding sco_pi(sk)->conn check in sco_chan_add() to prevent
+ double-attach of a socket to multiple connections
+- Adding hci_conn_drop() on sco_chan_add failure to prevent
+ HCI connection leaks
+
+Fixes: 9a8ec9e8ebb5 ("Bluetooth: SCO: Fix possible circular locking dependency on sco_connect_cfm")
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/sco.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 56a146515df9e..1c9c54f35988b 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -238,7 +238,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+ int err = 0;
+
+ sco_conn_lock(conn);
+- if (conn->sk)
++ if (conn->sk || sco_pi(sk)->conn)
+ err = -EBUSY;
+ else
+ __sco_chan_add(conn, sk, parent);
+@@ -292,9 +292,20 @@ static int sco_connect(struct sock *sk)
+
+ lock_sock(sk);
+
++ /* Recheck state after reacquiring the socket lock, as another
++ * thread may have changed it (e.g., closed the socket).
++ */
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
++ hci_conn_drop(hcon);
++ err = -EBADFD;
++ goto unlock;
++ }
++
+ err = sco_chan_add(conn, sk, NULL);
+ if (err) {
+ release_sock(sk);
++ hci_conn_drop(hcon);
+ goto unlock;
+ }
+
+@@ -601,13 +612,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
+ addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
+- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
++ lock_sock(sk);
++
++ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
++ release_sock(sk);
+ return -EBADFD;
++ }
+
+- if (sk->sk_type != SOCK_SEQPACKET)
+- err = -EINVAL;
++ if (sk->sk_type != SOCK_SEQPACKET) {
++ release_sock(sk);
++ return -EINVAL;
++ }
+
+- lock_sock(sk);
+ /* Set destination address and psm */
+ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
+ release_sock(sk);
+--
+2.53.0
+
--- /dev/null
+From f07e1ea232d32f17776a991e7cf2fbea77f1eeca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 13:42:28 -0700
+Subject: bpf: Fix regsafe() for pointers to packet
+
+From: Alexei Starovoitov <ast@kernel.org>
+
+[ Upstream commit a8502a79e832b861e99218cbd2d8f4312d62e225 ]
+
+In case rold->reg->range == BEYOND_PKT_END && rcur->reg->range == N
+regsafe() may return true which may lead to current state with
+valid packet range not being explored. Fix the bug.
+
+Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 226f2cd338d67..e33cd755d6197 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -16148,8 +16148,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+ * since someone could have accessed through (ptr - k), or
+ * even done ptr -= k in a register, to get a safe access.
+ */
+- if (rold->range > rcur->range)
++ if (rold->range < 0 || rcur->range < 0) {
++ /* special case for [BEYOND|AT]_PKT_END */
++ if (rold->range != rcur->range)
++ return false;
++ } else if (rold->range > rcur->range) {
+ return false;
++ }
+ /* If the offsets don't match, we can't trust our alignment;
+ * nor can we be sure that we won't fall out of range.
+ */
+--
+2.53.0
+
--- /dev/null
+From 51b5480360cd3abbf5fc51b728d5aed4337d4a77 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Apr 2026 17:29:22 +0800
+Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit b0db1accbc7395657c2b79db59fa9fae0d6656f3 ]
+
+check_mem_access() matches PTR_TO_BUF via base_type() which strips
+PTR_MAYBE_NULL, allowing direct dereference without a null check.
+
+Map iterator ctx->key and ctx->value are PTR_TO_BUF | PTR_MAYBE_NULL.
+On stop callbacks these are NULL, causing a kernel NULL dereference.
+
+Add a type_may_be_null() guard to the PTR_TO_BUF branch, matching the
+existing PTR_TO_BTF_ID pattern.
+
+Fixes: 20b2aff4bc15 ("bpf: Introduce MEM_RDONLY flag")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index e33cd755d6197..45eb795c8c045 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -6912,7 +6912,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ } else if (reg->type == CONST_PTR_TO_MAP) {
+ err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+ value_regno);
+- } else if (base_type(reg->type) == PTR_TO_BUF) {
++ } else if (base_type(reg->type) == PTR_TO_BUF &&
++ !type_may_be_null(reg->type)) {
+ bool rdonly_mem = type_is_rdonly_mem(reg->type);
+ u32 *max_access;
+
+--
+2.53.0
+
--- /dev/null
+From 4d9702713c9e3f8a9824cb67fe2565cefdfe32b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 00:54:15 +0000
+Subject: bpf: sockmap: Fix use-after-free of sk->sk_socket in
+ sk_psock_verdict_data_ready().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit ad8391d37f334ee73ba91926f8b4e4cf6d31ea04 ]
+
+syzbot reported use-after-free of AF_UNIX socket's sk->sk_socket
+in sk_psock_verdict_data_ready(). [0]
+
+In unix_stream_sendmsg(), the peer socket's ->sk_data_ready() is
+called after dropping its unix_state_lock().
+
+Although the sender socket holds the peer's refcount, it does not
+prevent the peer's sock_orphan(), and the peer's sk_socket might
+be freed after one RCU grace period.
+
+Let's fetch the peer's sk->sk_socket and sk->sk_socket->ops under
+RCU in sk_psock_verdict_data_ready().
+
+[0]:
+BUG: KASAN: slab-use-after-free in sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+Read of size 8 at addr ffff8880594da860 by task syz.4.1842/11013
+
+CPU: 1 UID: 0 PID: 11013 Comm: syz.4.1842 Not tainted syzkaller #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:378 [inline]
+ print_report+0xba/0x230 mm/kasan/report.c:482
+ kasan_report+0x117/0x150 mm/kasan/report.c:595
+ sk_psock_verdict_data_ready+0xec/0x590 net/core/skmsg.c:1278
+ unix_stream_sendmsg+0x8a3/0xe80 net/unix/af_unix.c:2482
+ sock_sendmsg_nosec net/socket.c:721 [inline]
+ __sock_sendmsg net/socket.c:736 [inline]
+ ____sys_sendmsg+0x972/0x9f0 net/socket.c:2585
+ ___sys_sendmsg+0x2a5/0x360 net/socket.c:2639
+ __sys_sendmsg net/socket.c:2671 [inline]
+ __do_sys_sendmsg net/socket.c:2676 [inline]
+ __se_sys_sendmsg net/socket.c:2674 [inline]
+ __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2674
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7facf899c819
+Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007facf9827028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007facf8c15fa0 RCX: 00007facf899c819
+RDX: 0000000000000000 RSI: 0000200000000500 RDI: 0000000000000004
+RBP: 00007facf8a32c91 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 00007facf8c16038 R14: 00007facf8c15fa0 R15: 00007ffd41b01c78
+ </TASK>
+
+Allocated by task 11013:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ unpoison_slab_object mm/kasan/common.c:340 [inline]
+ __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:366
+ kasan_slab_alloc include/linux/kasan.h:253 [inline]
+ slab_post_alloc_hook mm/slub.c:4538 [inline]
+ slab_alloc_node mm/slub.c:4866 [inline]
+ kmem_cache_alloc_lru_noprof+0x2b8/0x640 mm/slub.c:4885
+ sock_alloc_inode+0x28/0xc0 net/socket.c:316
+ alloc_inode+0x6a/0x1b0 fs/inode.c:347
+ new_inode_pseudo include/linux/fs.h:3003 [inline]
+ sock_alloc net/socket.c:631 [inline]
+ __sock_create+0x12d/0x9d0 net/socket.c:1562
+ sock_create net/socket.c:1656 [inline]
+ __sys_socketpair+0x1c4/0x560 net/socket.c:1803
+ __do_sys_socketpair net/socket.c:1856 [inline]
+ __se_sys_socketpair net/socket.c:1853 [inline]
+ __x64_sys_socketpair+0x9b/0xb0 net/socket.c:1853
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 15:
+ kasan_save_stack mm/kasan/common.c:57 [inline]
+ kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
+ kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
+ poison_slab_object mm/kasan/common.c:253 [inline]
+ __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
+ kasan_slab_free include/linux/kasan.h:235 [inline]
+ slab_free_hook mm/slub.c:2685 [inline]
+ slab_free mm/slub.c:6165 [inline]
+ kmem_cache_free+0x187/0x630 mm/slub.c:6295
+ rcu_do_batch kernel/rcu/tree.c:2617 [inline]
+ rcu_core+0x7cd/0x1070 kernel/rcu/tree.c:2869
+ handle_softirqs+0x22a/0x870 kernel/softirq.c:622
+ run_ksoftirqd+0x36/0x60 kernel/softirq.c:1063
+ smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160
+ kthread+0x388/0x470 kernel/kthread.c:436
+ ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
+ ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
+
+Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()")
+Closes: https://lore.kernel.org/bpf/69cc6b9f.a70a0220.128fd0.004b.GAE@google.com/
+Reported-by: syzbot+2184232f07e3677fbaef@syzkaller.appspotmail.com
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
+Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/skmsg.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/skmsg.c b/net/core/skmsg.c
+index 5d557ba9c0cb4..e2bba1e86752e 100644
+--- a/net/core/skmsg.c
++++ b/net/core/skmsg.c
+@@ -1266,17 +1266,20 @@ static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb)
+
+ static void sk_psock_verdict_data_ready(struct sock *sk)
+ {
+- struct socket *sock = sk->sk_socket;
+- const struct proto_ops *ops;
++ const struct proto_ops *ops = NULL;
++ struct socket *sock;
+ int copied;
+
+ trace_sk_data_ready(sk);
+
+- if (unlikely(!sock))
+- return;
+- ops = READ_ONCE(sock->ops);
++ rcu_read_lock();
++ sock = READ_ONCE(sk->sk_socket);
++ if (likely(sock))
++ ops = READ_ONCE(sock->ops);
++ rcu_read_unlock();
+ if (!ops || !ops->read_skb)
+ return;
++
+ copied = ops->read_skb(sk, sk_psock_verdict_recv);
+ if (copied >= 0) {
+ struct sk_psock *psock;
+--
+2.53.0
+
--- /dev/null
+From a296d6211de05736e4e54a939bc8dc3ea538dddc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 03:44:39 +0000
+Subject: bridge: br_nd_send: linearize skb before parsing ND options
+
+From: Yang Yang <n05ec@lzu.edu.cn>
+
+[ Upstream commit a01aee7cafc575bb82f5529e8734e7052f9b16ea ]
+
+br_nd_send() parses neighbour discovery options from ns->opt[] and
+assumes that these options are in the linear part of request.
+
+Its callers only guarantee that the ICMPv6 header and target address
+are available, so the option area can still be non-linear. Parsing
+ns->opt[] in that case can access data past the linear buffer.
+
+Linearize request before option parsing and derive ns from the linear
+network header.
+
+Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Tested-by: Ao Zhou <n05ec@lzu.edu.cn>
+Co-developed-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
+index c7869a286df40..b8bfc336ff7a7 100644
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -248,12 +248,12 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
+
+ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ struct sk_buff *request, struct neighbour *n,
+- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
++ __be16 vlan_proto, u16 vlan_tci)
+ {
+ struct net_device *dev = request->dev;
+ struct net_bridge_vlan_group *vg;
++ struct nd_msg *na, *ns;
+ struct sk_buff *reply;
+- struct nd_msg *na;
+ struct ipv6hdr *pip6;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+@@ -261,7 +261,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ u8 *daddr;
+ u16 pvid;
+
+- if (!dev)
++ if (!dev || skb_linearize(request))
+ return;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+@@ -278,6 +278,8 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
+ skb_set_mac_header(reply, 0);
+
+ daddr = eth_hdr(request)->h_source;
++ ns = (struct nd_msg *)(skb_network_header(request) +
++ sizeof(struct ipv6hdr));
+
+ /* Do we need option processing ? */
+ ns_olen = request->len - (skb_network_offset(request) +
+@@ -465,9 +467,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+- skb_vlan_tag_get(skb), msg);
++ skb_vlan_tag_get(skb));
+ else
+- br_nd_send(br, p, skb, n, 0, 0, msg);
++ br_nd_send(br, p, skb, n, 0, 0);
+ replied = true;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e95a9aa0207f6e8e59a1de2853e94232b4b9347a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 11:53:46 +0100
+Subject: btrfs: don't take device_list_mutex when querying zone info
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 77603ab10429fe713a03345553ca8dbbfb1d91c6 ]
+
+Shin'ichiro reported sporadic hangs when running generic/013 in our CI
+system. When enabling lockdep, there is a lockdep splat when calling
+btrfs_get_dev_zone_info_all_devices() in the mount path that can be
+triggered by i.e. generic/013:
+
+ ======================================================
+ WARNING: possible circular locking dependency detected
+ 7.0.0-rc1+ #355 Not tainted
+ ------------------------------------------------------
+ mount/1043 is trying to acquire lock:
+ ffff8881020b5470 (&vblk->vdev_mutex){+.+.}-{4:4}, at: virtblk_report_zones+0xda/0x430
+
+ but task is already holding lock:
+ ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #4 (&fs_devs->device_list_mutex){+.+.}-{4:4}:
+ __mutex_lock+0xa3/0x1360
+ btrfs_create_pending_block_groups+0x1f4/0x9d0
+ __btrfs_end_transaction+0x3e/0x2e0
+ btrfs_zoned_reserve_data_reloc_bg+0x2f8/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #3 (btrfs_trans_num_extwriters){++++}-{0:0}:
+ join_transaction+0xc2/0x5c0
+ start_transaction+0x17c/0xbc0
+ btrfs_zoned_reserve_data_reloc_bg+0x2b4/0x390
+ open_ctree+0x1934/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #2 (btrfs_trans_num_writers){++++}-{0:0}:
+ lock_release+0x163/0x4b0
+ __btrfs_end_transaction+0x1c7/0x2e0
+ btrfs_dirty_inode+0x6f/0xd0
+ touch_atime+0xe5/0x2c0
+ btrfs_file_mmap_prepare+0x65/0x90
+ __mmap_region+0x4b9/0xf00
+ mmap_region+0xf7/0x120
+ do_mmap+0x43d/0x610
+ vm_mmap_pgoff+0xd6/0x190
+ ksys_mmap_pgoff+0x7e/0xc0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #1 (&mm->mmap_lock){++++}-{4:4}:
+ __might_fault+0x68/0xa0
+ _copy_to_user+0x22/0x70
+ blkdev_copy_zone_to_user+0x22/0x40
+ virtblk_report_zones+0x282/0x430
+ blkdev_report_zones_ioctl+0xfd/0x130
+ blkdev_ioctl+0x20f/0x2c0
+ __x64_sys_ioctl+0x86/0xd0
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ -> #0 (&vblk->vdev_mutex){+.+.}-{4:4}:
+ __lock_acquire+0x1522/0x2680
+ lock_acquire+0xd5/0x2f0
+ __mutex_lock+0xa3/0x1360
+ virtblk_report_zones+0xda/0x430
+ blkdev_report_zones_cached+0x162/0x190
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+ other info that might help us debug this:
+
+ Chain exists of:
+ &vblk->vdev_mutex --> btrfs_trans_num_extwriters --> &fs_devs->device_list_mutex
+
+ Possible unsafe locking scenario:
+
+ CPU0 CPU1
+ ---- ----
+ lock(&fs_devs->device_list_mutex);
+ lock(btrfs_trans_num_extwriters);
+ lock(&fs_devs->device_list_mutex);
+ lock(&vblk->vdev_mutex);
+
+ *** DEADLOCK ***
+
+ 3 locks held by mount/1043:
+ #0: ffff88811063e878 (&fc->uapi_mutex){+.+.}-{4:4}, at: __do_sys_fsconfig+0x2ae/0x680
+ #1: ffff88810cb9f0e8 (&type->s_umount_key#31/1){+.+.}-{4:4}, at: alloc_super+0xc0/0x3e0
+ #2: ffff888102a738e0 (&fs_devs->device_list_mutex){+.+.}-{4:4}, at: btrfs_get_dev_zone_info_all_devices+0x45/0x90
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 1043 Comm: mount Not tainted 7.0.0-rc1+ #355 PREEMPT(full)
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5b/0x80
+ print_circular_bug.cold+0x18d/0x1d8
+ check_noncircular+0x10d/0x130
+ __lock_acquire+0x1522/0x2680
+ ? vmap_small_pages_range_noflush+0x3ef/0x820
+ lock_acquire+0xd5/0x2f0
+ ? virtblk_report_zones+0xda/0x430
+ ? lock_is_held_type+0xcd/0x130
+ __mutex_lock+0xa3/0x1360
+ ? virtblk_report_zones+0xda/0x430
+ ? virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ ? virtblk_report_zones+0xda/0x430
+ virtblk_report_zones+0xda/0x430
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ blkdev_report_zones_cached+0x162/0x190
+ ? __pfx_copy_zone_info_cb+0x10/0x10
+ btrfs_get_dev_zones+0xdc/0x2e0
+ btrfs_get_dev_zone_info+0x219/0xe80
+ btrfs_get_dev_zone_info_all_devices+0x62/0x90
+ open_ctree+0x1200/0x23db
+ btrfs_get_tree.cold+0x105/0x26c
+ ? rcu_is_watching+0x18/0x50
+ vfs_get_tree+0x28/0xb0
+ __do_sys_fsconfig+0x324/0x680
+ do_syscall_64+0x92/0x4f0
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ RIP: 0033:0x7f615e27a40e
+ RSP: 002b:00007fff11b18fb8 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ RAX: ffffffffffffffda RBX: 000055572e92ab10 RCX: 00007f615e27a40e
+ RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ RBP: 00007fff11b19100 R08: 0000000000000000 R09: 0000000000000000
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055572e92bc40 R14: 00007f615e3faa60 R15: 000055572e92bd08
+ </TASK>
+
+Don't hold the device_list_mutex while calling into
+btrfs_get_dev_zone_info() in btrfs_get_dev_zone_info_all_devices() to
+mitigate the issue. This is safe, as no other thread can touch the device
+list at the moment of execution.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/zoned.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 6e8b8c46ba18f..dabbfc3b7d776 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -342,7 +342,10 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (!btrfs_fs_incompat(fs_info, ZONED))
+ return 0;
+
+- mutex_lock(&fs_devices->device_list_mutex);
++ /*
++ * No need to take the device_list mutex here, we're still in the mount
++ * path and devices cannot be added to or removed from the list yet.
++ */
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ /* We can skip reading of zone info for missing devices */
+ if (!device->bdev)
+@@ -352,7 +355,6 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
+ if (ret)
+ break;
+ }
+- mutex_unlock(&fs_devices->device_list_mutex);
+
+ return ret;
+ }
+--
+2.53.0
+
--- /dev/null
+From b003682f3172977a3d1cfe3ab87f265de4072098 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Mar 2026 08:14:43 +0800
+Subject: btrfs: reject root items with drop_progress and zero drop_level
+
+From: ZhengYuan Huang <gality369@gmail.com>
+
+[ Upstream commit b17b79ff896305fd74980a5f72afec370ee88ca4 ]
+
+[BUG]
+When recovering relocation at mount time, merge_reloc_root() and
+btrfs_drop_snapshot() both use BUG_ON(level == 0) to guard against
+an impossible state: a non-zero drop_progress combined with a zero
+drop_level in a root_item, which can be triggered:
+
+------------[ cut here ]------------
+kernel BUG at fs/btrfs/relocation.c:1545!
+Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
+CPU: 1 UID: 0 PID: 283 ... Tainted: 6.18.0+ #16 PREEMPT(voluntary)
+Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
+Hardware name: QEMU Ubuntu 24.04 PC v2, BIOS 1.16.3-debian-1.16.3-2
+RIP: 0010:merge_reloc_root+0x1266/0x1650 fs/btrfs/relocation.c:1545
+Code: ffff0000 00004589 d7e9acfa ffffe8a1 79bafebe 02000000
+Call Trace:
+ merge_reloc_roots+0x295/0x890 fs/btrfs/relocation.c:1861
+ btrfs_recover_relocation+0xd6e/0x11d0 fs/btrfs/relocation.c:4195
+ btrfs_start_pre_rw_mount+0xa4d/0x1810 fs/btrfs/disk-io.c:3130
+ open_ctree+0x5824/0x5fe0 fs/btrfs/disk-io.c:3640
+ btrfs_fill_super fs/btrfs/super.c:987 [inline]
+ btrfs_get_tree_super fs/btrfs/super.c:1951 [inline]
+ btrfs_get_tree_subvol fs/btrfs/super.c:2094 [inline]
+ btrfs_get_tree+0x111c/0x2190 fs/btrfs/super.c:2128
+ vfs_get_tree+0x9a/0x370 fs/super.c:1758
+ fc_mount fs/namespace.c:1199 [inline]
+ do_new_mount_fc fs/namespace.c:3642 [inline]
+ do_new_mount fs/namespace.c:3718 [inline]
+ path_mount+0x5b8/0x1ea0 fs/namespace.c:4028
+ do_mount fs/namespace.c:4041 [inline]
+ __do_sys_mount fs/namespace.c:4229 [inline]
+ __se_sys_mount fs/namespace.c:4206 [inline]
+ __x64_sys_mount+0x282/0x320 fs/namespace.c:4206
+ ...
+RIP: 0033:0x7f969c9a8fde
+Code: 0f1f4000 48c7c2b0 fffffff7 d8648902 b8ffffff ffc3660f
+---[ end trace 0000000000000000 ]---
+
+The bug is reproducible on 7.0.0-rc2-next-20260310 with our dynamic
+metadata fuzzing tool that corrupts btrfs metadata at runtime.
+
+[CAUSE]
+A non-zero drop_progress.objectid means an interrupted
+btrfs_drop_snapshot() left a resume point on disk, and in that case
+drop_level must be greater than 0 because the checkpoint is only
+saved at internal node levels.
+
+Although this invariant is enforced when the kernel writes the root
+item, it is not validated when the root item is read back from disk.
+That allows on-disk corruption to provide an invalid state with
+drop_progress.objectid != 0 and drop_level == 0.
+
+When relocation recovery later processes such a root item,
+merge_reloc_root() reads drop_level and hits BUG_ON(level == 0). The
+same invalid metadata can also trigger the corresponding BUG_ON() in
+btrfs_drop_snapshot().
+
+[FIX]
+Fix this by validating the root_item invariant in tree-checker when
+reading root items from disk: if drop_progress.objectid is non-zero,
+drop_level must also be non-zero. Reject such malformed metadata with
+-EUCLEAN before it reaches merge_reloc_root() or btrfs_drop_snapshot()
+and triggers the BUG_ON.
+
+After the fix, the same corruption is correctly rejected by tree-checker
+and the BUG_ON is no longer triggered.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index d2c36b765c83a..0689bd3832f8c 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -1224,6 +1224,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
+ btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
+ return -EUCLEAN;
+ }
++ /*
++ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
++ * interrupted and the resume point was recorded in drop_progress and
++ * drop_level. In that case drop_level must be >= 1: level 0 is the
++ * leaf level and drop_snapshot never saves a checkpoint there (it
++ * only records checkpoints at internal node levels in DROP_REFERENCE
++ * stage). A zero drop_level combined with a non-zero drop_progress
++ * objectid indicates on-disk corruption and would cause a BUG_ON in
++ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
++ */
++ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
++ btrfs_root_drop_level(&ri) == 0)) {
++ generic_err(leaf, slot,
++ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
++ btrfs_disk_key_objectid(&ri.drop_progress));
++ return -EUCLEAN;
++ }
+
+ /* Flags check */
+ if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
+--
+2.53.0
+
--- /dev/null
+From dadab559ee0f0ea028c133faf6e82375da920001 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 18:26:13 +0100
+Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk
+
+From: Norbert Szetei <norbert@doyensec.com>
+
+[ Upstream commit 62397b493e14107ae82d8b80938f293d95425bcb ]
+
+The AF_ALG interface fails to unmark the end of a Scatter/Gather List (SGL)
+when chaining a new af_alg_tsgl structure. If a sendmsg() fills an SGL
+exactly to MAX_SGL_ENTS, the last entry is marked as the end. A subsequent
+sendmsg() allocates a new SGL and chains it, but fails to clear the end
+marker on the previous SGL's last data entry.
+
+This causes the crypto scatterwalk to hit a premature end, returning NULL
+on sg_next() and leading to a kernel panic during dereference.
+
+Fix this by explicitly unmarking the end of the previous SGL when
+performing sg_chain() in af_alg_alloc_tsgl().
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Signed-off-by: Norbert Szetei <norbert@doyensec.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ crypto/af_alg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 3d0b7542f771c..24575ceae14bd 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -622,8 +622,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
+ sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
+ sgl->cur = 0;
+
+- if (sg)
++ if (sg) {
++ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
+ sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
++ }
+
+ list_add_tail(&sgl->list, &ctx->tsgl_list);
+ }
+--
+2.53.0
+
--- /dev/null
+From 8f78e4185a524594bdb514f464e8a307d075e43a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:13 +0200
+Subject: crypto: caam - fix DMA corruption on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 5ddfdcbe10dc5f97afc4e46ca22be2be717e8caf ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The rounding was performed, but never actually used for the allocation.
+Fix this by replacing kmemdup with kmalloc for a larger buffer,
+followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Reported-by: Paul Bunyan <pbunyan@redhat.com>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamhash.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
+index 65785dc5b73b2..30cc46c4c33af 100644
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -441,9 +441,10 @@ static int ahash_setkey(struct crypto_ahash *ahash,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, keylen, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From 6d694604fbe75496d91d77843a88c4f908c0cffa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2026 12:25:14 +0200
+Subject: crypto: caam - fix overflow on long hmac keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+[ Upstream commit 80688afb9c35b3934ce2d6be9973758915e2e0ef ]
+
+When a key longer than block size is supplied, it is copied and then
+hashed into the real key. The memory allocated for the copy needs to
+be rounded to DMA cache alignment, as otherwise the hashed key may
+corrupt neighbouring memory.
+
+The copying is performed using kmemdup, however this leads to an overflow:
+reading more bytes (aligned_len - keylen) from the keylen source buffer.
+Fix this by replacing kmemdup with kmalloc, followed by memcpy.
+
+Fixes: 199354d7fb6e ("crypto: caam - Remove GFP_DMA and add DMA alignment padding")
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/caam/caamalg_qi2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
+index a148ff1f0872c..06e0681fdbe15 100644
+--- a/drivers/crypto/caam/caamalg_qi2.c
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -3325,9 +3325,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
+ if (aligned_len < keylen)
+ return -EOVERFLOW;
+
+- hashed_key = kmemdup(key, aligned_len, GFP_KERNEL);
++ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
+ if (!hashed_key)
+ return -ENOMEM;
++ memcpy(hashed_key, key, keylen);
+ ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
+ if (ret)
+ goto bad_free_key;
+--
+2.53.0
+
--- /dev/null
+From b77cc2893443740726665f9fafb0328a0e9f591f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Mar 2026 16:59:55 -0500
+Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix
+ common property warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 398c0c8bbc8f5a9d2f43863275a427a9d3720b6f ]
+
+Change additionalProperties to unevaluatedProperties because it refs to
+/schemas/input/matrix-keymap.yaml.
+
+Fix below CHECK_DTBS warnings:
+arch/arm/boot/dts/nxp/imx/imx6dl-victgo.dtb: keypad@70 (holtek,ht16k33): 'keypad,num-columns', 'keypad,num-rows' do not match any of the regexes: '^pinctrl-[0-9]+$'
+ from schema $id: http://devicetree.org/schemas/auxdisplay/holtek,ht16k33.yaml#
+
+Fixes: f12b457c6b25c ("dt-bindings: auxdisplay: ht16k33: Convert to json-schema")
+Acked-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../devicetree/bindings/auxdisplay/holtek,ht16k33.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+index be95f6b97b41a..0c28292a5bb46 100644
+--- a/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
++++ b/Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
+@@ -66,7 +66,7 @@ then:
+ required:
+ - refresh-rate-hz
+
+-additionalProperties: false
++unevaluatedProperties: false
+
+ examples:
+ - |
+--
+2.53.0
+
--- /dev/null
+From e8ce74b4d0cab7cd9edde4d08c9f0182262cba3a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Feb 2026 16:30:25 +0000
+Subject: HID: multitouch: Check to ensure report responses match the request
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit e716edafedad4952fe3a4a273d2e039a84e8681a ]
+
+It is possible for a malicious (or clumsy) device to respond to a
+specific report's feature request using a completely different report
+ID. This can cause confusion in the HID core resulting in nasty
+side-effects such as OOB writes.
+
+Add a check to ensure that the report ID in the response, matches the
+one that was requested. If it doesn't, omit reporting the raw event and
+return early.
+
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-multitouch.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index b6c2cb7153fde..0039508943626 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -472,12 +472,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
+ dev_warn(&hdev->dev, "failed to fetch feature %d\n",
+ report->id);
+ } else {
++ /* The report ID in the request and the response should match */
++ if (report->id != buf[0]) {
++ hid_err(hdev, "Returned feature report did not match the request\n");
++ goto free;
++ }
++
+ ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
+ size, 0);
+ if (ret)
+ dev_warn(&hdev->dev, "failed to report feature\n");
+ }
+
++free:
+ kfree(buf);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 7ec01d1280368b9a7c0b34cfc30f018ed67c0e68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:58:28 +0000
+Subject: HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+[ Upstream commit 2f1763f62909ccb6386ac50350fa0abbf5bb16a9 ]
+
+The wacom_intuos_bt_irq() function processes Bluetooth HID reports
+without sufficient bounds checking. A maliciously crafted short report
+can trigger an out-of-bounds read when copying data into the wacom
+structure.
+
+Specifically, report 0x03 requires at least 22 bytes to safely read
+the processed data and battery status, while report 0x04 (which
+falls through to 0x03) requires 32 bytes.
+
+Add explicit length checks for these report IDs and log a warning if
+a short report is received.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/wacom_wac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
+index 42bc8f05e2635..859d0d9c5894e 100644
+--- a/drivers/hid/wacom_wac.c
++++ b/drivers/hid/wacom_wac.c
+@@ -1256,10 +1256,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+
+ switch (data[0]) {
+ case 0x04:
++ if (len < 32) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x04 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ fallthrough;
+ case 0x03:
++ if (i == 1 && len < 22) {
++ dev_warn(wacom->pen_input->dev.parent,
++ "Report 0x03 too short: %zu bytes\n", len);
++ break;
++ }
+ wacom_intuos_bt_process_data(wacom, data + i);
+ i += 10;
+ wacom_intuos_bt_process_data(wacom, data + i);
+--
+2.53.0
+
--- /dev/null
+From dac15ab7d1cc60478656f6577d8092f91fa0a717 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2026 13:32:11 +0900
+Subject: i2c: tegra: Don't mark devices with pins as IRQ safe
+
+From: Mikko Perttunen <mperttunen@nvidia.com>
+
+[ Upstream commit ec69c9e88315c4be70c283f18c2ff130da6320b5 ]
+
+I2C devices with associated pinctrl states (DPAUX I2C controllers)
+will change pinctrl state during runtime PM. This requires taking
+a mutex, so these devices cannot be marked as IRQ safe.
+
+Add PINCTRL as dependency to avoid build errors.
+
+Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
+Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/Kconfig | 2 ++
+ drivers/i2c/busses/i2c-tegra.c | 5 ++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 8d4270664ebd1..79ab924a4b2b9 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -1139,6 +1139,8 @@ config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
+ # COMPILE_TEST needs architectures with readsX()/writesX() primitives
++ depends on PINCTRL
++ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
+index 5766231b13cd1..a882f0f65d82a 100644
+--- a/drivers/i2c/busses/i2c-tegra.c
++++ b/drivers/i2c/busses/i2c-tegra.c
+@@ -1788,8 +1788,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
+ *
+ * VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
+ * be used for atomic transfers. ACPI device is not IRQ safe also.
++ *
++ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
++ * state transitions during runtime PM require mutexes.
+ */
+- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
++ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
+ pm_runtime_irq_safe(i2c_dev->dev);
+
+ pm_runtime_enable(i2c_dev->dev);
+--
+2.53.0
+
--- /dev/null
+From fc2dbaf3f42812ff1c5d7a6fd13f4ba4ea37c818 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 15:51:38 +0000
+Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 2edfa31769a4add828a7e604b21cb82aaaa05925 ]
+
+Oskar Kjos reported the following problem.
+
+ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written
+by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes
+IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region
+as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff
+at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr
+value. __ip_options_echo() then reads optlen from attacker-controlled
+packet data at sptr[rr+1] and copies that many bytes into dopt->__data,
+a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE).
+
+To fix this we clear skb2->cb[], as suggested by Oskar Kjos.
+
+Also add minimal IPv4 header validation (version == 4, ihl >= 5).
+
+Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
+Reported-by: Oskar Kjos <oskar.kjos@hotmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_tunnel.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 69cace90ece16..5a2583a82f974 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ if (!skb2)
+ return 0;
+
++ /* Remove debris left by IPv6 stack. */
++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
++
+ skb_dst_drop(skb2);
+
+ skb_pull(skb2, offset);
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
++ if (eiph->version != 4 || eiph->ihl < 5)
++ goto out;
+
+ /* Try to guess incoming interface */
+ rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+--
+2.53.0
+
--- /dev/null
+From 1b7178c02b4aef8ddd29ef736929499a75bb9f01 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 15:47:21 +0000
+Subject: ipv6: avoid overflows in ip6_datagram_send_ctl()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ]
+
+Yiming Qian reported :
+<quote>
+ I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
+ ancillary-data path that can panic the kernel via `skb_under_panic()`
+ (local DoS).
+
+ The core issue is a mismatch between:
+
+ - a 16-bit length accumulator (`struct ipv6_txoptions::opt_flen`, type
+ `__u16`) and
+ - a pointer to the *last* provided destination-options header (`opt->dst1opt`)
+
+ when multiple `IPV6_DSTOPTS` control messages (cmsgs) are provided.
+
+ - `include/net/ipv6.h`:
+ - `struct ipv6_txoptions::opt_flen` is `__u16` (wrap possible).
+ (lines 291-307, especially 298)
+ - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`:
+ - Accepts repeated `IPV6_DSTOPTS` and accumulates into `opt_flen`
+ without rejecting duplicates. (lines 909-933)
+ - `net/ipv6/ip6_output.c:__ip6_append_data()`:
+ - Uses `opt->opt_flen + opt->opt_nflen` to compute header
+ sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
+ - `net/ipv6/ip6_output.c:__ip6_make_skb()`:
+ - Calls `ipv6_push_frag_opts()` if `opt->opt_flen` is non-zero.
+ (lines 1930-1934)
+ - `net/ipv6/exthdrs.c:ipv6_push_frag_opts()` / `ipv6_push_exthdr()`:
+ - Push size comes from `ipv6_optlen(opt->dst1opt)` (based on the
+ pointed-to header). (lines 1179-1185 and 1206-1211)
+
+ 1. `opt_flen` is a 16-bit accumulator:
+
+ - `include/net/ipv6.h:298` defines `__u16 opt_flen; /* after fragment hdr */`.
+
+ 2. `ip6_datagram_send_ctl()` accepts *repeated* `IPV6_DSTOPTS` cmsgs
+ and increments `opt_flen` each time:
+
+ - In `net/ipv6/datagram.c:909-933`, for `IPV6_DSTOPTS`:
+ - It computes `len = ((hdr->hdrlen + 1) << 3);`
+ - It checks `CAP_NET_RAW` using `ns_capable(net->user_ns,
+ CAP_NET_RAW)`. (line 922)
+ - Then it does:
+ - `opt->opt_flen += len;` (line 927)
+ - `opt->dst1opt = hdr;` (line 928)
+
+ There is no duplicate rejection here (unlike the legacy
+ `IPV6_2292DSTOPTS` path which rejects duplicates at
+ `net/ipv6/datagram.c:901-904`).
+
+ If enough large `IPV6_DSTOPTS` cmsgs are provided, `opt_flen` wraps
+ while `dst1opt` still points to a large (2048-byte)
+ destination-options header.
+
+ In the attached PoC (`poc.c`):
+
+ - 32 cmsgs with `hdrlen=255` => `len = (255+1)*8 = 2048`
+ - 1 cmsg with `hdrlen=0` => `len = 8`
+ - Total increment: `32*2048 + 8 = 65544`, so `(__u16)opt_flen == 8`
+ - The last cmsg is 2048 bytes, so `dst1opt` points to a 2048-byte header.
+
+ 3. The transmit path sizes headers using the wrapped `opt_flen`:
+
+- In `net/ipv6/ip6_output.c:1463-1465`:
+ - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen +
+ opt->opt_nflen : 0) + ...;`
+
+ With wrapped `opt_flen`, `headersize`/headroom decisions underestimate
+ what will be pushed later.
+
+ 4. When building the final skb, the actual push length comes from
+ `dst1opt` and is not limited by wrapped `opt_flen`:
+
+ - In `net/ipv6/ip6_output.c:1930-1934`:
+ - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);`
+ - In `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()` pushes
+ `dst1opt` via `ipv6_push_exthdr()`.
+ - In `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()` does:
+ - `skb_push(skb, ipv6_optlen(opt));`
+ - `memcpy(h, opt, ipv6_optlen(opt));`
+
+ With insufficient headroom, `skb_push()` underflows and triggers
+ `skb_under_panic()` -> `BUG()`:
+
+ - `net/core/skbuff.c:2669-2675` (`skb_push()` calls `skb_under_panic()`)
+ - `net/core/skbuff.c:207-214` (`skb_panic()` ends in `BUG()`)
+
+ - The `IPV6_DSTOPTS` cmsg path requires `CAP_NET_RAW` in the target
+ netns user namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`).
+ - Root (or any task with `CAP_NET_RAW`) can trigger this without user
+ namespaces.
+ - An unprivileged `uid=1000` user can trigger this if unprivileged
+ user namespaces are enabled and it can create a userns+netns to obtain
+ namespaced `CAP_NET_RAW` (the attached PoC does this).
+
+ - Local denial of service: kernel BUG/panic (system crash).
+ - Reproducible with a small userspace PoC.
+</quote>
+
+This patch does not reject duplicated options, as this might break
+some user applications.
+
+Instead, it makes sure to adjust opt_flen and opt_nflen to correctly
+reflect the size of the current option headers, preventing the overflows
+and the potential for panics.
+
+This applies to IPV6_DSTOPTS, IPV6_HOPOPTS, and IPV6_RTHDR.
+
+Specifically:
+
+When a new IPV6_DSTOPTS is processed, the length of the old opt->dst1opt
+is subtracted from opt->opt_flen before adding the new length.
+
+When a new IPV6_HOPOPTS is processed, the length of the old opt->dst0opt
+is subtracted from opt->opt_nflen.
+
+When a new Routing Header (IPV6_RTHDR or IPV6_2292RTHDR) is processed,
+the length of the old opt->srcrt is subtracted from opt->opt_nflen.
+
+In the special case within IPV6_2292RTHDR handling where dst1opt is moved
+to dst0opt, the length of the old opt->dst0opt is subtracted from
+opt->opt_nflen before the new one is added.
+
+Fixes: 333fad5364d6 ("[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/datagram.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 41ebc4e574734..c1139f05a7942 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -763,6 +763,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ {
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
++ struct ipv6_rt_hdr *orthdr;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ struct ipv6_txoptions *opt = ipc6->opt;
+@@ -924,9 +925,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+ if (cmsg->cmsg_type == IPV6_DSTOPTS) {
++ if (opt->dst1opt)
++ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ } else {
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += len;
+ opt->dst0opt = hdr;
+ }
+@@ -969,12 +974,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+ goto exit_f;
+ }
+
++ orthdr = opt->srcrt;
++ if (orthdr)
++ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
++ if (opt->dst0opt)
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+--
+2.53.0
+
--- /dev/null
+From f8396d0c62320e07deedf6dbef7eb7976139f565 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 20:26:08 +0000
+Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 86ab3e55673a7a49a841838776f1ab18d23a67b5 ]
+
+Sashiko AI-review observed:
+
+ In ip6_err_gen_icmpv6_unreach(), the skb is an outer IPv4 ICMP error packet
+ where its cb contains an IPv4 inet_skb_parm. When skb is cloned into skb2
+ and passed to icmp6_send(), it uses IP6CB(skb2).
+
+ IP6CB interprets the IPv4 inet_skb_parm as an inet6_skb_parm. The cipso
+ offset in inet_skb_parm.opt directly overlaps with dsthao in inet6_skb_parm
+ at offset 18.
+
+ If an attacker sends a forged ICMPv4 error with a CIPSO IP option, dsthao
+ would be a non-zero offset. Inside icmp6_send(), mip6_addr_swap() is called
+ and uses ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO).
+
+ This would scan the inner, attacker-controlled IPv6 packet starting at that
+ offset, potentially returning a fake TLV without checking if the remaining
+ packet length can hold the full 18-byte struct ipv6_destopt_hao.
+
+ Could mip6_addr_swap() then perform a 16-byte swap that extends past the end
+ of the packet data into skb_shared_info?
+
+ Should the cb array also be cleared in ip6_err_gen_icmpv6_unreach() and
+ ip6ip6_err() to prevent this?
+
+This patch implements the first suggestion.
+
+I am not sure if ip6ip6_err() needs to be changed.
+A separate patch would be better anyway.
+
+Fixes: ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error")
+Reported-by: Ido Schimmel <idosch@nvidia.com>
+Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Oskar Kjos <oskar.kjos@hotmail.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/icmp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index 1d1c56e0e2460..0002fe04e0409 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -679,6 +679,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ if (!skb2)
+ return 1;
+
++ /* Remove debris left by IPv4 stack. */
++ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
++
+ skb_dst_drop(skb2);
+ skb_pull(skb2, nhs);
+ skb_reset_network_header(skb2);
+--
+2.53.0
+
--- /dev/null
+From 32325032c33431d4a80a39ebe856134c0cd4a5ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 10:52:57 +0100
+Subject: ipv6: prevent possible UaF in addrconf_permanent_addr()
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit fd63f185979b047fb22a0dfc6bd94d0cab6a6a70 ]
+
+The mentioned helper try to warn the user about an exceptional
+condition, but the message is delivered too late, accessing the ipv6
+after its possible deletion.
+
+Reorder the statement to avoid the possible UaF; while at it, place the
+warning outside the idev->lock as it needs no protection.
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Closes: https://sashiko.dev/#/patchset/8c8bfe2e1a324e501f0e15fef404a77443fd8caf.1774365668.git.pabeni%40redhat.com
+Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/addrconf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 7fcc68dcf144b..32fa6236dacdd 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -3611,12 +3611,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
+ if ((ifp->flags & IFA_F_PERMANENT) &&
+ fixup_permanent_addr(net, idev, ifp) < 0) {
+ write_unlock_bh(&idev->lock);
+- in6_ifa_hold(ifp);
+- ipv6_del_addr(ifp);
+- write_lock_bh(&idev->lock);
+
+ net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+ idev->dev->name, &ifp->addr);
++ in6_ifa_hold(ifp);
++ ipv6_del_addr(ifp);
++ write_lock_bh(&idev->lock);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 12765c79b4c5281001e977d602b50184ae86c848 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 14:32:30 +0100
+Subject: net: fec: fix the PTP periodic output sysfs interface
+
+From: Buday Csaba <buday.csaba@prolan.hu>
+
+[ Upstream commit e8e44c98f789dee45cfd24ffb9d4936e0606d7c6 ]
+
+When the PPS channel configuration was implemented, the channel
+index for the periodic outputs was configured as the hardware
+channel number.
+
+The sysfs interface uses a logical channel index, and rejects numbers
+greater than `n_per_out` (see period_store() in ptp_sysfs.c).
+That property was left at 1, since the driver implements channel
+selection, not simultaneous operation of multiple PTP hardware timer
+channels.
+
+A second check in fec_ptp_enable() returns -EOPNOTSUPP when the two
+channel numbers disagree, making channels 1..3 unusable from sysfs.
+
+Fix by removing this redundant check in the FEC PTP driver.
+
+Fixes: 566c2d83887f ("net: fec: make PPS channel configurable")
+Signed-off-by: Buday Csaba <buday.csaba@prolan.hu>
+Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/fec_ptp.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
+index 4bb894b5afcb9..778713c2fed40 100644
+--- a/drivers/net/ethernet/freescale/fec_ptp.c
++++ b/drivers/net/ethernet/freescale/fec_ptp.c
+@@ -546,9 +546,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
+ if (rq->perout.flags)
+ return -EOPNOTSUPP;
+
+- if (rq->perout.index != fep->pps_channel)
+- return -EOPNOTSUPP;
+-
+ period.tv_sec = rq->perout.period.sec;
+ period.tv_nsec = rq->perout.period.nsec;
+ period_ns = timespec64_to_ns(&period);
+--
+2.53.0
+
--- /dev/null
+From 23ab5fa68fc602f5b5a9e84671e2a6d98973f04b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Apr 2026 11:22:43 +0200
+Subject: net: hsr: fix VLAN add unwind on slave errors
+
+From: Luka Gejak <luka.gejak@linux.dev>
+
+[ Upstream commit 2e3514e63bfb0e972b1f19668547a455d0129e88 ]
+
+When vlan_vid_add() fails for a secondary slave, the error path calls
+vlan_vid_del() on the failing port instead of the peer slave that had
+already succeeded. This results in asymmetric VLAN state across the HSR
+pair.
+
+Fix this by switching to a centralized unwind path that removes the VID
+from any slave device that was already programmed.
+
+Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
+Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
+Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index 70e958caa956d..b34a9b680aab3 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -473,8 +473,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+ {
+- bool is_slave_a_added = false;
+- bool is_slave_b_added = false;
++ struct net_device *slave_a_dev = NULL;
++ struct net_device *slave_b_dev = NULL;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+@@ -490,33 +490,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+- /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+- if (is_slave_b_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_a_added = true;
++ slave_a_dev = port->dev;
+ break;
+-
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+- /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+- if (is_slave_a_added)
+- vlan_vid_del(port->dev, proto, vid);
+- return ret;
++ goto unwind;
+ }
+-
+- is_slave_b_added = true;
++ slave_b_dev = port->dev;
+ break;
+ default:
++ if (ret)
++ goto unwind;
+ break;
+ }
+ }
+
+ return 0;
++
++unwind:
++ if (slave_a_dev)
++ vlan_vid_del(slave_a_dev, proto, vid);
++
++ if (slave_b_dev)
++ vlan_vid_del(slave_b_dev, proto, vid);
++
++ return ret;
+ }
+
+ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+--
+2.53.0
+
--- /dev/null
+From 0ae4b7665722b3195040935b1e2578fdde376483 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 16:46:24 +0800
+Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit 9ca562bb8e66978b53028fa32b1a190708e6a091 ]
+
+`ip6fl_seq_show()` walks the global flowlabel hash under the seq-file
+RCU read-side lock and prints `fl->opt->opt_nflen` when an option block
+is present.
+
+Exclusive flowlabels currently free `fl->opt` as soon as `fl->users`
+drops to zero in `fl_release()`. However, the surrounding
+`struct ip6_flowlabel` remains visible in the global hash table until
+later garbage collection removes it and `fl_free_rcu()` finally tears it
+down.
+
+A concurrent `/proc/net/ip6_flowlabel` reader can therefore race that
+early `kfree()` and dereference freed option state, triggering a crash
+in `ip6fl_seq_show()`.
+
+Fix this by keeping `fl->opt` alive until `fl_free_rcu()`. That matches
+the lifetime already required for the enclosing flowlabel while readers
+can still reach it under RCU.
+
+Fixes: d3aedd5ebd4b ("ipv6 flowlabel: Convert hash list to RCU.")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ip6_flowlabel.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
+index b3ca4beb4405a..bf909fa69a977 100644
+--- a/net/ipv6/ip6_flowlabel.c
++++ b/net/ipv6/ip6_flowlabel.c
+@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
+ if (time_after(ttd, fl->expires))
+ fl->expires = ttd;
+ ttd = fl->expires;
+- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+- struct ipv6_txoptions *opt = fl->opt;
+- fl->opt = NULL;
+- kfree(opt);
+- }
+ if (!timer_pending(&ip6_fl_gc_timer) ||
+ time_after(ip6_fl_gc_timer.expires, ttd))
+ mod_timer(&ip6_fl_gc_timer, ttd);
+--
+2.53.0
+
--- /dev/null
+From 84e8275b4793bdb0fdcb9d5fa3da22b0f7cbfbd7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 15:41:52 +0800
+Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 5e67ba9bb531e1ec6599a82a065dea9040b9ce50 ]
+
+ioam6_fill_trace_data() stores the schema contribution to the trace
+length in a u8. With bit 22 enabled and the largest schema payload,
+sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
+remaining-space check. __ioam6_fill_trace_data() then positions the
+write cursor without reserving the schema area but still copies the
+4-byte schema header and the full schema payload, overrunning the trace
+buffer.
+
+Keep sclen in an unsigned int so the remaining-space check and the write
+cursor calculation both see the full schema length.
+
+Fixes: 8c6f6fa67726 ("ipv6: ioam: IOAM Generic Netlink API")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ioam6.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
+index a35b6fdbc93e9..a1953cf6131be 100644
+--- a/net/ipv6/ioam6.c
++++ b/net/ipv6/ioam6.c
+@@ -648,7 +648,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
+ struct ioam6_namespace *ns,
+ struct ioam6_trace_hdr *trace,
+ struct ioam6_schema *sc,
+- u8 sclen, bool is_input)
++ unsigned int sclen, bool is_input)
+ {
+ struct timespec64 ts;
+ ktime_t tstamp;
+@@ -878,7 +878,7 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
+ bool is_input)
+ {
+ struct ioam6_schema *sc;
+- u8 sclen = 0;
++ unsigned int sclen = 0;
+
+ /* Skip if Overflow flag is set
+ */
+--
+2.53.0
+
--- /dev/null
+From 762e31e3ede1487e1e74a939273e7eb43ca1fdc4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 00:49:25 +0200
+Subject: net: ipv6: ndisc: fix ndisc_ra_useropt to initialize nduseropt_padX
+ fields to zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit ae05340ccaa9d347fe85415609e075545bec589f ]
+
+When processing Router Advertisements with user options the kernel
+builds an RTM_NEWNDUSEROPT netlink message. The nduseroptmsg struct
+has three padding fields that are never zeroed and can leak kernel data
+
+The fix is simple, just zeroes the padding fields.
+
+Fixes: 31910575a9de ("[IPv6]: Export userland ND options through netlink (RDNSS support)")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/ndisc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 80ceb401ecf2d..652263e2f2d02 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1216,6 +1216,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
+ ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
+ ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
+ ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
++ ndmsg->nduseropt_pad1 = 0;
++ ndmsg->nduseropt_pad2 = 0;
++ ndmsg->nduseropt_pad3 = 0;
+
+ memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
+
+--
+2.53.0
+
--- /dev/null
+From 05bdf7cab0aeb359b881c3b0e5112a7a84a6e4ce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:40 +0300
+Subject: net: macb: fix clk handling on PCI glue driver removal
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit ce8fe5287b87e24e225c342f3b0ec04f0b3680fe ]
+
+platform_device_unregister() may still want to use the registered clks
+during runtime resume callback.
+
+Note that there is a commit d82d5303c4c5 ("net: macb: fix use after free
+on rmmod") that addressed the similar problem of clk vs platform device
+unregistration but just moved the bug to another place.
+
+Save the pointers to clks into local variables for reuse after platform
+device is unregistered.
+
+BUG: KASAN: use-after-free in clk_prepare+0x5a/0x60
+Read of size 8 at addr ffff888104f85e00 by task modprobe/597
+
+CPU: 2 PID: 597 Comm: modprobe Not tainted 6.1.164+ #114
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x8d/0xba
+ print_report+0x17f/0x496
+ kasan_report+0xd9/0x180
+ clk_prepare+0x5a/0x60
+ macb_runtime_resume+0x13d/0x410 [macb]
+ pm_generic_runtime_resume+0x97/0xd0
+ __rpm_callback+0xc8/0x4d0
+ rpm_callback+0xf6/0x230
+ rpm_resume+0xeeb/0x1a70
+ __pm_runtime_resume+0xb4/0x170
+ bus_remove_device+0x2e3/0x4b0
+ device_del+0x5b3/0xdc0
+ platform_device_del+0x4e/0x280
+ platform_device_unregister+0x11/0x50
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+ </TASK>
+
+Allocated by task 519:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ __kasan_kmalloc+0x8e/0x90
+ __clk_register+0x458/0x2890
+ clk_hw_register+0x1a/0x60
+ __clk_hw_register_fixed_rate+0x255/0x410
+ clk_register_fixed_rate+0x3c/0xa0
+ macb_probe+0x1d8/0x42e [macb_pci]
+ local_pci_probe+0xd7/0x190
+ pci_device_probe+0x252/0x600
+ really_probe+0x255/0x7f0
+ __driver_probe_device+0x1ee/0x330
+ driver_probe_device+0x4c/0x1f0
+ __driver_attach+0x1df/0x4e0
+ bus_for_each_dev+0x15d/0x1f0
+ bus_add_driver+0x486/0x5e0
+ driver_register+0x23a/0x3d0
+ do_one_initcall+0xfd/0x4d0
+ do_init_module+0x18b/0x5a0
+ load_module+0x5663/0x7950
+ __do_sys_finit_module+0x101/0x180
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Freed by task 597:
+ kasan_save_stack+0x2c/0x50
+ kasan_set_track+0x21/0x30
+ kasan_save_free_info+0x2a/0x50
+ __kasan_slab_free+0x106/0x180
+ __kmem_cache_free+0xbc/0x320
+ clk_unregister+0x6de/0x8d0
+ macb_remove+0x73/0xc0 [macb_pci]
+ pci_device_remove+0xae/0x210
+ device_remove+0xcb/0x180
+ device_release_driver_internal+0x529/0x770
+ driver_detach+0xd4/0x1a0
+ bus_remove_driver+0x135/0x260
+ driver_unregister+0x72/0xb0
+ pci_unregister_driver+0x26/0x220
+ __do_sys_delete_module+0x32e/0x550
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+
+Fixes: d82d5303c4c5 ("net: macb: fix use after free on rmmod")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index f66d22de5168d..4dd0cec2e5423 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -110,10 +110,12 @@ static void macb_remove(struct pci_dev *pdev)
+ {
+ struct platform_device *plat_dev = pci_get_drvdata(pdev);
+ struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
++ struct clk *pclk = plat_data->pclk;
++ struct clk *hclk = plat_data->hclk;
+
+- clk_unregister(plat_data->pclk);
+- clk_unregister(plat_data->hclk);
+ platform_device_unregister(plat_dev);
++ clk_unregister(pclk);
++ clk_unregister(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 44772290607ee1c7db98f6bb7e38c4f26ccf23f9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 21:45:41 +0300
+Subject: net: macb: properly unregister fixed rate clocks
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit f0f367a4f459cc8118aadc43c6bba53c60d93f8d ]
+
+The additional resources allocated with clk_register_fixed_rate() need
+to be released with clk_unregister_fixed_rate(), otherwise they are lost.
+
+Fixes: 83a77e9ec415 ("net: macb: Added PCI wrapper for Platform Driver.")
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb_pci.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
+index 4dd0cec2e5423..34e249e0e5860 100644
+--- a/drivers/net/ethernet/cadence/macb_pci.c
++++ b/drivers/net/ethernet/cadence/macb_pci.c
+@@ -97,10 +97,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return 0;
+
+ err_plat_dev_register:
+- clk_unregister(plat_data.hclk);
++ clk_unregister_fixed_rate(plat_data.hclk);
+
+ err_hclk_register:
+- clk_unregister(plat_data.pclk);
++ clk_unregister_fixed_rate(plat_data.pclk);
+
+ err_pclk_register:
+ return err;
+@@ -114,8 +114,8 @@ static void macb_remove(struct pci_dev *pdev)
+ struct clk *hclk = plat_data->hclk;
+
+ platform_device_unregister(plat_dev);
+- clk_unregister(pclk);
+- clk_unregister(hclk);
++ clk_unregister_fixed_rate(pclk);
++ clk_unregister_fixed_rate(hclk);
+ }
+
+ static const struct pci_device_id dev_id_table[] = {
+--
+2.53.0
+
--- /dev/null
+From 3a4a3cf6b346eee3b5ba22d3e474a2a833121e9a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:14 +0300
+Subject: net/mlx5: Avoid "No data available" when FW version queries fail
+
+From: Saeed Mahameed <saeedm@nvidia.com>
+
+[ Upstream commit 10dc35f6a443d488f219d1a1e3fb8f8dac422070 ]
+
+Avoid printing the misleading "kernel answers: No data available" devlink
+output when querying firmware or pending firmware version fails
+(e.g. MLX5 fw state errors / flash failures).
+
+FW can fail on loading the pending flash image and get its version due
+to various reasons, examples:
+
+mlxfw: Firmware flash failed: key not applicable, err (7)
+mlx5_fw_image_pending: can't read pending fw version while fw state is 1
+
+and the resulting:
+$ devlink dev info
+kernel answers: No data available
+
+Instead, just report 0 or 0xfff.. versions in case of failure to indicate
+a problem, and let other information be shown.
+
+after the fix:
+$ devlink dev info
+pci/0000:00:06.0:
+ driver mlx5_core
+ serial_number xxx...
+ board.serial_number MT2225300179
+ versions:
+ fixed:
+ fw.psid MT_0000000436
+ running:
+ fw.version 22.41.0188
+ fw 22.41.0188
+ stored:
+ fw.version 255.255.65535
+ fw 255.255.65535
+
+Fixes: 9c86b07e3069 ("net/mlx5: Added fw version query command")
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/devlink.c | 4 +-
+ drivers/net/ethernet/mellanox/mlx5/core/fw.c | 53 ++++++++++++-------
+ .../ethernet/mellanox/mlx5/core/mlx5_core.h | 4 +-
+ 3 files changed, 37 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+index b2532b1c9565a..8e8c15d825325 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+@@ -53,9 +53,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ if (err)
+ return err;
+
+- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+- if (err)
+- return err;
++ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+index 70898f0a9866c..d5de2df111ab4 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+@@ -802,48 +802,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ return 0;
+ }
+
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *pending_ver)
++void mlx5_fw_version_query(struct mlx5_core_dev *dev,
++ u32 *running_ver, u32 *pending_ver)
+ {
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
++ *running_ver = 0;
++ *pending_ver = 0;
++
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+- return -EOPNOTSUPP;
++ return;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+- if (component_index < 0)
+- return component_index;
++ if (component_index < 0) {
++ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
++ component_index);
++ return;
++ }
+
++ *running_ver = U32_MAX; /* indicate failure */
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
++ if (!err)
++ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query running version, err %d\n",
++ err);
++
++ *pending_ver = U32_MAX; /* indicate failure */
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+- if (err)
+- return err;
++ if (err) {
++ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
++ err);
++ return;
++ }
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+- return 0;
++ return;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+- if (err)
+- return err;
+-
+- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+-
+- return 0;
++ if (!err)
++ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
++ version);
++ else
++ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
++ err);
++
++ return;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+index 124352459c23d..562729cd95a87 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+@@ -269,8 +269,8 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev);
+
+ int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+- u32 *running_ver, u32 *stored_ver);
++void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
++ u32 *stored_ver);
+
+ #ifdef CONFIG_MLX5_CORE_EN
+ int mlx5e_init(void);
+--
+2.53.0
+
--- /dev/null
+From 3f44ed8eb8fe32a971965cb37f71f50414aebe9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:40:13 +0300
+Subject: net/mlx5: lag: Check for LAG device before creating debugfs
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit bf16bca6653679d8a514d6c1c5a2c67065033f14 ]
+
+__mlx5_lag_dev_add_mdev() may return 0 (success) even when an error
+occurs that is handled gracefully. Consequently, the initialization
+flow proceeds to call mlx5_ldev_add_debugfs() even when there is no
+valid LAG context.
+
+mlx5_ldev_add_debugfs() blindly created the debugfs directory and
+attributes. This exposed interfaces (like the members file) that rely on
+a valid ldev pointer, leading to potential NULL pointer dereferences if
+accessed when ldev is NULL.
+
+Add a check to verify that mlx5_lag_dev(dev) returns a valid pointer
+before attempting to create the debugfs entries.
+
+Fixes: 7f46a0b7327a ("net/mlx5: Lag, add debugfs to query hardware lag state")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reviewed-by: Mark Bloch <mbloch@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+index f4b777d4e1086..41ddca52e9547 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+@@ -163,8 +163,11 @@ DEFINE_SHOW_ATTRIBUTE(members);
+
+ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
+ {
++ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
+ struct dentry *dbg;
+
++ if (!ldev)
++ return;
+ dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
+ dev->priv.dbg.lag_debugfs = dbg;
+
+--
+2.53.0
+
--- /dev/null
+From 68f0927f551eb7ddb102c078065a6533bb5d1c1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Mar 2026 16:06:44 +0800
+Subject: net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory
+ leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jiayuan Chen <jiayuan.chen@shopee.com>
+
+[ Upstream commit 2428083101f6883f979cceffa76cd8440751ffe6 ]
+
+__radix_tree_create() allocates and links intermediate nodes into the
+tree one by one. If a subsequent allocation fails, the already-linked
+nodes remain in the tree with no corresponding leaf entry. These orphaned
+internal nodes are never reclaimed because radix_tree_for_each_slot()
+only visits slots containing leaf values.
+
+The radix_tree API is deprecated in favor of xarray. As suggested by
+Matthew Wilcox, migrate qrtr_tx_flow from radix_tree to xarray instead
+of fixing the radix_tree itself [1]. xarray properly handles cleanup of
+internal nodes — xa_destroy() frees all internal xarray nodes when the
+qrtr_node is released, preventing the leak.
+
+[1] https://lore.kernel.org/all/20260225071623.41275-1-jiayuan.chen@linux.dev/T/
+Reported-by: syzbot+006987d1be3586e13555@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/all/000000000000bfba3a060bf4ffcf@google.com/T/
+Fixes: 5fdeb0d372ab ("net: qrtr: Implement outgoing flow control")
+Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/qrtr/af_qrtr.c | 31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 00c51cf693f3d..b703e4c645853 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -118,7 +118,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
++ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
+ * @rx_queue: receive queue
+ * @item: list item for broadcast list
+@@ -129,7 +129,7 @@ struct qrtr_node {
+ struct kref ref;
+ unsigned int nid;
+
+- struct radix_tree_root qrtr_tx_flow;
++ struct xarray qrtr_tx_flow;
+ struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
+
+ struct sk_buff_head rx_queue;
+@@ -172,6 +172,7 @@ static void __qrtr_node_release(struct kref *kref)
+ struct qrtr_tx_flow *flow;
+ unsigned long flags;
+ void __rcu **slot;
++ unsigned long index;
+
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ /* If the node is a bridge for other nodes, there are possibly
+@@ -189,11 +190,9 @@ static void __qrtr_node_release(struct kref *kref)
+ skb_queue_purge(&node->rx_queue);
+
+ /* Free tx flow counters */
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
+- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ kfree(flow);
+- }
++ xa_destroy(&node->qrtr_tx_flow);
+ kfree(node);
+ }
+
+@@ -228,9 +227,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
+
+ key = remote_node << 32 | remote_port;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock(&flow->resume_tx.lock);
+ flow->pending = 0;
+@@ -269,12 +266,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
+ return 0;
+
+ mutex_lock(&node->qrtr_tx_lock);
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (!flow) {
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (flow) {
+ init_waitqueue_head(&flow->resume_tx);
+- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
++ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
++ GFP_KERNEL))) {
+ kfree(flow);
+ flow = NULL;
+ }
+@@ -326,9 +324,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
+ unsigned long key = (u64)dest_node << 32 | dest_port;
+ struct qrtr_tx_flow *flow;
+
+- rcu_read_lock();
+- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+- rcu_read_unlock();
++ flow = xa_load(&node->qrtr_tx_flow, key);
+ if (flow) {
+ spin_lock_irq(&flow->resume_tx.lock);
+ flow->tx_failed = 1;
+@@ -599,7 +595,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
++ xa_init(&node->qrtr_tx_flow);
+ mutex_init(&node->qrtr_tx_lock);
+
+ qrtr_node_assign(node, nid);
+@@ -627,6 +623,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+ struct qrtr_tx_flow *flow;
+ struct sk_buff *skb;
+ unsigned long flags;
++ unsigned long index;
+ void __rcu **slot;
+
+ mutex_lock(&node->ep_lock);
+@@ -649,10 +646,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+
+ /* Wake up any transmitters waiting for resume-tx from the node */
+ mutex_lock(&node->qrtr_tx_lock);
+- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
+- flow = *slot;
++ xa_for_each(&node->qrtr_tx_flow, index, flow)
+ wake_up_interruptible_all(&flow->resume_tx);
+- }
+ mutex_unlock(&node->qrtr_tx_lock);
+
+ qrtr_node_release(node);
+--
+2.53.0
+
--- /dev/null
+From 0d6bf8bde738c3024812f0aea399b62bbae4649f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Mar 2026 00:14:36 +0300
+Subject: net: sched: cls_api: fix tc_chain_fill_node to initialize tcm_info to
+ zero to prevent an info-leak
+
+From: Yochai Eisenrich <echelonh@gmail.com>
+
+[ Upstream commit e6e3eb5ee89ac4c163d46429391c889a1bb5e404 ]
+
+When building netlink messages, tc_chain_fill_node() never initializes
+the tcm_info field of struct tcmsg. Since the allocation is not zeroed,
+kernel heap memory is leaked to userspace through this 4-byte field.
+
+The fix simply zeroes tcm_info alongside the other fields that are
+already initialized.
+
+Fixes: 32a4f5ecd738 ("net: sched: introduce chain object to uapi")
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_api.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index a90a7b01f3f36..45124fd64d6b4 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -2886,6 +2886,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
+ tcm->tcm_handle = 0;
++ tcm->tcm_info = 0;
+ if (block->q) {
+ tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
+ tcm->tcm_parent = block->q->handle;
+--
+2.53.0
+
--- /dev/null
+From 98eba79176143eb3ed722b7b4e8c172d9608212f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:16 -0700
+Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 1a280dd4bd1d616a01d6ffe0de284c907b555504 ]
+
+flow_change() calls tcf_block_q() and dereferences q->handle to derive
+a default baseclass. Shared blocks leave block->q NULL, causing a NULL
+deref when a flow filter without a fully qualified baseclass is created
+on a shared block.
+
+Check tcf_block_shared() before accessing block->q and return -EINVAL
+for shared blocks. This avoids the null-deref shown below:
+
+=======================================================================
+KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+RIP: 0010:flow_change (net/sched/cls_flow.c:508)
+Call Trace:
+ tc_new_tfilter (net/sched/cls_api.c:2432)
+ rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
+ [...]
+=======================================================================
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flow.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+index 815216b564f32..d92ffdaf546c3 100644
+--- a/net/sched/cls_flow.c
++++ b/net/sched/cls_flow.c
+@@ -503,8 +503,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
+ }
+
+ if (TC_H_MAJ(baseclass) == 0) {
+- struct Qdisc *q = tcf_block_q(tp->chain->block);
++ struct tcf_block *block = tp->chain->block;
++ struct Qdisc *q;
+
++ if (tcf_block_shared(block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify baseclass when attaching flow filter to block");
++ goto err2;
++ }
++
++ q = tcf_block_q(block);
+ baseclass = TC_H_MAKE(q->handle, baseclass);
+ }
+ if (TC_H_MIN(baseclass) == 0)
+--
+2.53.0
+
--- /dev/null
+From 1e7566c846448d4598f806e2958169cfb2dd2005 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 22:02:15 -0700
+Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit faeea8bbf6e958bf3c00cb08263109661975987c ]
+
+The old-method path in fw_classify() calls tcf_block_q() and
+dereferences q->handle. Shared blocks leave block->q NULL, causing a
+NULL deref when an empty cls_fw filter is attached to a shared block
+and a packet with a nonzero major skb mark is classified.
+
+Reject the configuration in fw_change() when the old method (no
+TCA_OPTIONS) is used on a shared block, since fw_classify()'s
+old-method path needs block->q which is NULL for shared blocks.
+
+The fixed null-ptr-deref calling stack:
+ KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
+ RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
+ Call Trace:
+ tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
+ tc_run (net/core/dev.c:4401)
+ __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
+
+Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_fw.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index c49d6af0e0480..2e5e8df5ca55c 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -247,8 +247,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
+ struct nlattr *tb[TCA_FW_MAX + 1];
+ int err;
+
+- if (!opt)
+- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
++ if (!opt) {
++ if (handle)
++ return -EINVAL;
++
++ if (tcf_block_shared(tp->chain->block)) {
++ NL_SET_ERR_MSG(extack,
++ "Must specify mark when attaching fw filter to block");
++ return -EINVAL;
++ }
++
++ return 0; /* Succeed if it is old method. */
++ }
+
+ err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
+ NULL);
+--
+2.53.0
+
--- /dev/null
+From af78df3583ffe6d913687da1a0b9a739de8e5807 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 13:43:09 -0700
+Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min()
+
+From: Xiang Mei <xmei5@asu.edu>
+
+[ Upstream commit 4576100b8cd03118267513cafacde164b498b322 ]
+
+m2sm() converts a u32 slope to a u64 scaled value. For large inputs
+(e.g. m1=4000000000), the result can reach 2^32. rtsc_min() stores
+the difference of two such u64 values in a u32 variable `dsm` and
+uses it as a divisor. When the difference is exactly 2^32 the
+truncation yields zero, causing a divide-by-zero oops in the
+concave-curve intersection path:
+
+ Oops: divide error: 0000
+ RIP: 0010:rtsc_min (net/sched/sch_hfsc.c:601)
+ Call Trace:
+ init_ed (net/sched/sch_hfsc.c:629)
+ hfsc_enqueue (net/sched/sch_hfsc.c:1569)
+ [...]
+
+Widen `dsm` to u64 and replace do_div() with div64_u64() so the full
+difference is preserved.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Weiming Shi <bestswngs@gmail.com>
+Signed-off-by: Xiang Mei <xmei5@asu.edu>
+Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_hfsc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
+index 751b1e2c35b3f..1ac51d0249919 100644
+--- a/net/sched/sch_hfsc.c
++++ b/net/sched/sch_hfsc.c
+@@ -555,7 +555,7 @@ static void
+ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ {
+ u64 y1, y2, dx, dy;
+- u32 dsm;
++ u64 dsm;
+
+ if (isc->sm1 <= isc->sm2) {
+ /* service curve is convex */
+@@ -598,7 +598,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
+ */
+ dx = (y1 - y) << SM_SHIFT;
+ dsm = isc->sm1 - isc->sm2;
+- do_div(dx, dsm);
++ dx = div64_u64(dx, dsm);
+ /*
+ * check if (x, y1) belongs to the 1st segment of rtsc.
+ * if so, add the offset.
+--
+2.53.0
+
--- /dev/null
+From ae33b3a0ada541c59ae8c81152f1bd7bc265eb87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:00:21 +0800
+Subject: net/sched: sch_netem: fix out-of-bounds access in packet corruption
+
+From: Yucheng Lu <kanolyc@gmail.com>
+
+[ Upstream commit d64cb81dcbd54927515a7f65e5e24affdc73c14b ]
+
+In netem_enqueue(), the packet corruption logic uses
+get_random_u32_below(skb_headlen(skb)) to select an index for
+modifying skb->data. When an AF_PACKET TX_RING sends fully non-linear
+packets over an IPIP tunnel, skb_headlen(skb) evaluates to 0.
+
+Passing 0 to get_random_u32_below() takes the variable-ceil slow path
+which returns an unconstrained 32-bit random integer. Using this
+unconstrained value as an offset into skb->data results in an
+out-of-bounds memory access.
+
+Fix this by verifying skb_headlen(skb) is non-zero before attempting
+to corrupt the linear data area. Fully non-linear packets will silently
+bypass the corruption logic.
+
+Fixes: c865e5d99e25 ("[PKT_SCHED] netem: packet corruption option")
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Signed-off-by: Yuan Tan <tanyuan98@outlook.com>
+Signed-off-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Yuhang Zheng <z1652074432@gmail.com>
+Signed-off-by: Yucheng Lu <kanolyc@gmail.com>
+Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
+Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_netem.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
+index 0ad231e94e14d..7361f90c8c1a1 100644
+--- a/net/sched/sch_netem.c
++++ b/net/sched/sch_netem.c
+@@ -517,8 +517,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+ goto finish_segs;
+ }
+
+- skb->data[get_random_u32_below(skb_headlen(skb))] ^=
+- 1<<get_random_u32_below(8);
++ if (skb_headlen(skb))
++ skb->data[get_random_u32_below(skb_headlen(skb))] ^=
++ 1 << get_random_u32_below(8);
+ }
+
+ if (unlikely(q->t_len >= sch->limit)) {
+--
+2.53.0
+
--- /dev/null
+From 46c5ff0646cae2cf8428394030b476d7590efcb6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:18 +0200
+Subject: net/x25: Fix overflow when accumulating packets
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit a1822cb524e89b4cd2cf0b82e484a2335496a6d9 ]
+
+Add a check to ensure that `x25_sock.fraglen` does not overflow.
+
+The `fraglen` also needs to be resetted when purging `fragment_queue` in
+`x25_clear_queues()`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Suggested-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 4 ++++
+ net/x25/x25_subr.c | 1 +
+ 2 files changed, 5 insertions(+)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index 0dbc73efab1cb..e47ebd8acd21b 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ struct sk_buff *skbo, *skbn = skb;
+ struct x25_sock *x25 = x25_sk(sk);
+
++ /* make sure we don't overflow */
++ if (x25->fraglen + skb->len > USHRT_MAX)
++ return 1;
++
+ if (more) {
+ x25->fraglen += skb->len;
+ skb_queue_tail(&x25->fragment_queue, skb);
+diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
+index 0285aaa1e93c1..159708d9ad20c 100644
+--- a/net/x25/x25_subr.c
++++ b/net/x25/x25_subr.c
+@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
+ skb_queue_purge(&x25->interrupt_in_queue);
+ skb_queue_purge(&x25->interrupt_out_queue);
+ skb_queue_purge(&x25->fragment_queue);
++ x25->fraglen = 0;
+ }
+
+
+--
+2.53.0
+
--- /dev/null
+From 59befe0c6c5c8beb39c287398497b695574b9b75 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 09:43:17 +0200
+Subject: net/x25: Fix potential double free of skb
+
+From: Martin Schiller <ms@dev.tdt.de>
+
+[ Upstream commit d10a26aa4d072320530e6968ef945c8c575edf61 ]
+
+When alloc_skb fails in x25_queue_rx_frame it calls kfree_skb(skb) at
+line 48 and returns 1 (error).
+This error propagates back through the call chain:
+
+x25_queue_rx_frame returns 1
+ |
+ v
+x25_state3_machine receives the return value 1 and takes the else
+branch at line 278, setting queued=0 and returning 0
+ |
+ v
+x25_process_rx_frame returns queued=0
+ |
+ v
+x25_backlog_rcv at line 452 sees queued=0 and calls kfree_skb(skb)
+again
+
+This would free the same skb twice. Looking at x25_backlog_rcv:
+
+net/x25/x25_in.c:x25_backlog_rcv() {
+ ...
+ queued = x25_process_rx_frame(sk, skb);
+ ...
+ if (!queued)
+ kfree_skb(skb);
+}
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Martin Schiller <ms@dev.tdt.de>
+Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/x25/x25_in.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
+index b981a4828d08c..0dbc73efab1cb 100644
+--- a/net/x25/x25_in.c
++++ b/net/x25/x25_in.c
+@@ -44,10 +44,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+ if (x25->fraglen > 0) { /* End of fragment */
+ int len = x25->fraglen + skb->len;
+
+- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+- kfree_skb(skb);
++ skbn = alloc_skb(len, GFP_ATOMIC);
++ if (!skbn)
+ return 1;
+- }
+
+ skb_queue_tail(&x25->fragment_queue, skb);
+
+--
+2.53.0
+
--- /dev/null
+From e1ed3fe10cc5f667ff3d84e069a69cada63e0ff8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 27 Mar 2026 13:02:37 +0530
+Subject: net: xilinx: axienet: Correct BD length masks to match AXIDMA IP spec
+
+From: Suraj Gupta <suraj.gupta2@amd.com>
+
+[ Upstream commit 393e0b4f178ec7fce1141dacc3304e3607a92ee9 ]
+
+The XAXIDMA_BD_CTRL_LENGTH_MASK and XAXIDMA_BD_STS_ACTUAL_LEN_MASK
+macros were defined as 0x007FFFFF (23 bits), but the AXI DMA IP
+product guide (PG021) specifies the buffer length field as bits 25:0
+(26 bits). Update both masks to match the IP documentation.
+
+In practice this had no functional impact, since Ethernet frames are
+far smaller than 2^23 bytes and the extra bits were always zero, but
+the masks should still reflect the hardware specification.
+
+Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
+Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
+Reviewed-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/xilinx/xilinx_axienet.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+index 2facbdfbb319e..e6a1611b7aab2 100644
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
+@@ -103,7 +103,7 @@
+ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
+ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
+
+-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
++#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
+ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+@@ -129,7 +129,7 @@
+ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
+ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
+
+-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
++#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
+ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
+ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
+ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
+--
+2.53.0
+
--- /dev/null
+From 9bc3343eec332a35ec02d67e27b7a1c615dd03fd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 11:26:22 +0200
+Subject: netfilter: ctnetlink: ignore explicit helper on new expectations
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 917b61fa2042f11e2af4c428e43f08199586633a ]
+
+Use the existing master conntrack helper, anything else is not really
+supported and it just makes validation more complicated, so just ignore
+what helper userspace suggests for this expectation.
+
+This was uncovered when validating CTA_EXPECT_CLASS via different helper
+provided by userspace than the existing master conntrack helper:
+
+ BUG: KASAN: slab-out-of-bounds in nf_ct_expect_related_report+0x2479/0x27c0
+ Read of size 4 at addr ffff8880043fe408 by task poc/102
+ Call Trace:
+ nf_ct_expect_related_report+0x2479/0x27c0
+ ctnetlink_create_expect+0x22b/0x3b0
+ ctnetlink_new_expect+0x4bd/0x5c0
+ nfnetlink_rcv_msg+0x67a/0x950
+ netlink_rcv_skb+0x120/0x350
+
+Allowing to read kernel memory bytes off the expectation boundary.
+
+CTA_EXPECT_HELP_NAME is still used to offer the helper name to userspace
+via netlink dump.
+
+Fixes: bd0779370588 ("netfilter: nfnetlink_queue: allow to attach expectations to conntracks")
+Reported-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 54 +++++-----------------------
+ 1 file changed, 9 insertions(+), 45 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index d7acd3e967425..9b089cdfcd352 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2624,7 +2624,6 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask);
+
+@@ -2853,7 +2852,6 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ {
+ struct nlattr *cda[CTA_EXPECT_MAX+1];
+ struct nf_conntrack_tuple tuple, mask;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ int err;
+
+@@ -2867,17 +2865,8 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+ if (err < 0)
+ return err;
+
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+- nf_ct_protonum(ct));
+- if (helper == NULL)
+- return -EOPNOTSUPP;
+- }
+-
+ exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
+- helper, &tuple, &mask);
++ &tuple, &mask);
+ if (IS_ERR(exp))
+ return PTR_ERR(exp);
+
+@@ -3506,11 +3495,11 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
+
+ static struct nf_conntrack_expect *
+ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+- struct nf_conntrack_helper *helper,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+ struct net *net = read_pnet(&ct->ct_net);
++ struct nf_conntrack_helper *helper;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3520,7 +3509,11 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ if (!help)
+ return ERR_PTR(-EOPNOTSUPP);
+
+- if (cda[CTA_EXPECT_CLASS] && helper) {
++ helper = rcu_dereference(help->helper);
++ if (!helper)
++ return ERR_PTR(-EOPNOTSUPP);
++
++ if (cda[CTA_EXPECT_CLASS]) {
+ class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
+ if (class > helper->expect_class_max)
+ return ERR_PTR(-EINVAL);
+@@ -3554,8 +3547,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+ exp->zone = ct->zone;
+ #endif
+- if (!helper)
+- helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+@@ -3587,7 +3578,6 @@ ctnetlink_create_expect(struct net *net,
+ {
+ struct nf_conntrack_tuple tuple, mask, master_tuple;
+ struct nf_conntrack_tuple_hash *h = NULL;
+- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn *ct;
+ int err;
+@@ -3613,33 +3603,7 @@ ctnetlink_create_expect(struct net *net,
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ rcu_read_lock();
+- if (cda[CTA_EXPECT_HELP_NAME]) {
+- const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
+-
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper == NULL) {
+- rcu_read_unlock();
+-#ifdef CONFIG_MODULES
+- if (request_module("nfct-helper-%s", helpname) < 0) {
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- rcu_read_lock();
+- helper = __nf_conntrack_helper_find(helpname, u3,
+- nf_ct_protonum(ct));
+- if (helper) {
+- err = -EAGAIN;
+- goto err_rcu;
+- }
+- rcu_read_unlock();
+-#endif
+- err = -EOPNOTSUPP;
+- goto err_ct;
+- }
+- }
+-
+- exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
++ exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask);
+ if (IS_ERR(exp)) {
+ err = PTR_ERR(exp);
+ goto err_rcu;
+@@ -3649,8 +3613,8 @@ ctnetlink_create_expect(struct net *net,
+ nf_ct_expect_put(exp);
+ err_rcu:
+ rcu_read_unlock();
+-err_ct:
+ nf_ct_put(ct);
++
+ return err;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e4dc0c6d4c25cfd00dde3eecb1ea1add472c2f0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 14:17:12 +0800
+Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT
+ absent
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit 35177c6877134a21315f37d57a5577846225623e ]
+
+ctnetlink_alloc_expect() allocates expectations from a non-zeroing
+slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
+present in the netlink message, saved_addr and saved_proto are
+never initialized. Stale data from a previous slab occupant can
+then be dumped to userspace by ctnetlink_exp_dump_expect(), which
+checks these fields to decide whether to emit CTA_EXPECT_NAT.
+
+The safe sibling nf_ct_expect_init(), used by the packet path,
+explicitly zeroes these fields.
+
+Zero saved_addr, saved_proto and dir in the else branch, guarded
+by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
+NAT is enabled.
+
+Confirmed by priming the expect slab with NAT-bearing expectations,
+freeing them, creating a new expectation without CTA_EXPECT_NAT,
+and observing that the ctnetlink dump emits a spurious
+CTA_EXPECT_NAT containing stale data from the prior allocation.
+
+Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_netlink.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 718526867ffdc..d980f462714a9 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3565,6 +3565,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ exp, nf_ct_l3num(ct));
+ if (err < 0)
+ goto err_out;
++#if IS_ENABLED(CONFIG_NF_NAT)
++ } else {
++ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
++ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
++ exp->dir = 0;
++#endif
+ }
+ return exp;
+ err_out:
+--
+2.53.0
+
--- /dev/null
+From 06e835cc7f16e71c5b1c1f7bc5888121d5e7cabb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 00:17:09 +0100
+Subject: netfilter: flowtable: strictly check for maximum number of actions
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 76522fcdbc3a02b568f5d957f7e66fc194abb893 ]
+
+The maximum number of flowtable hardware offload actions in IPv6 is:
+
+* ethernet mangling (4 payload actions, 2 for each ethernet address)
+* SNAT (4 payload actions)
+* DNAT (4 payload actions)
+* Double VLAN (4 vlan actions, 2 for popping vlan, and 2 for pushing)
+ for QinQ.
+* Redirect (1 action)
+
+Which makes 17, while the maximum is 16. But act_ct supports for tunnels
+actions too. Note that payload action operates at 32-bit word level, so
+mangling an IPv6 address takes 4 payload actions.
+
+Update flow_action_entry_next() calls to check for the maximum number of
+supported actions.
+
+While at it, rise the maximum number of actions per flow from 16 to 24
+so this works fine with IPv6 setups.
+
+Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_flow_table_offload.c | 196 +++++++++++++++++---------
+ 1 file changed, 130 insertions(+), 66 deletions(-)
+
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index 3d46372b538e5..7136eed469862 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -13,6 +13,8 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
+
++#define NF_FLOW_RULE_ACTION_MAX 24
++
+ static struct workqueue_struct *nf_flow_offload_add_wq;
+ static struct workqueue_struct *nf_flow_offload_del_wq;
+ static struct workqueue_struct *nf_flow_offload_stats_wq;
+@@ -215,7 +217,12 @@ static void flow_offload_mangle(struct flow_action_entry *entry,
+ static inline struct flow_action_entry *
+ flow_action_entry_next(struct nf_flow_rule *flow_rule)
+ {
+- int i = flow_rule->rule->action.num_entries++;
++ int i;
++
++ if (unlikely(flow_rule->rule->action.num_entries >= NF_FLOW_RULE_ACTION_MAX))
++ return NULL;
++
++ i = flow_rule->rule->action.num_entries++;
+
+ return &flow_rule->rule->action.entries[i];
+ }
+@@ -233,6 +240,9 @@ static int flow_offload_eth_src(struct net *net,
+ u32 mask, val;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -283,6 +293,9 @@ static int flow_offload_eth_dst(struct net *net,
+ u8 nud_state;
+ u16 val16;
+
++ if (!entry0 || !entry1)
++ return -E2BIG;
++
+ this_tuple = &flow->tuplehash[dir].tuple;
+
+ switch (this_tuple->xmit_type) {
+@@ -324,16 +337,19 @@ static int flow_offload_eth_dst(struct net *net,
+ return 0;
+ }
+
+-static void flow_offload_ipv4_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4.s_addr;
+@@ -344,23 +360,27 @@ static void flow_offload_ipv4_snat(struct net *net,
+ offset = offsetof(struct iphdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask = ~htonl(0xffffffff);
+ __be32 addr;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4.s_addr;
+@@ -371,14 +391,15 @@ static void flow_offload_ipv4_dnat(struct net *net,
+ offset = offsetof(struct iphdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
+ &addr, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
++static int flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+ unsigned int offset,
+ const __be32 *addr, const __be32 *mask)
+ {
+@@ -387,15 +408,20 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
+
+ for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i++) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
++
+ flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
+ offset + i * sizeof(u32), &addr[i], mask);
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_ipv6_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -411,16 +437,16 @@ static void flow_offload_ipv6_snat(struct net *net,
+ offset = offsetof(struct ipv6hdr, daddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+-static void flow_offload_ipv6_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv6_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ u32 mask = ~htonl(0xffffffff);
+ const __be32 *addr;
+@@ -436,10 +462,10 @@ static void flow_offload_ipv6_dnat(struct net *net,
+ offset = offsetof(struct ipv6hdr, saddr);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+- flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
++ return flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
+ }
+
+ static int flow_offload_l4proto(const struct flow_offload *flow)
+@@ -461,15 +487,18 @@ static int flow_offload_l4proto(const struct flow_offload *flow)
+ return type;
+ }
+
+-static void flow_offload_port_snat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_snat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
+@@ -484,22 +513,26 @@ static void flow_offload_port_snat(struct net *net,
+ mask = ~htonl(0xffff);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_port_dnat(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_port_dnat(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+ u32 mask, port;
+ u32 offset;
+
++ if (!entry)
++ return -E2BIG;
++
+ switch (dir) {
+ case FLOW_OFFLOAD_DIR_ORIGINAL:
+ port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port);
+@@ -514,20 +547,24 @@ static void flow_offload_port_dnat(struct net *net,
+ mask = ~htonl(0xffff0000);
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
+ &port, &mask);
++ return 0;
+ }
+
+-static void flow_offload_ipv4_checksum(struct net *net,
+- const struct flow_offload *flow,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_ipv4_checksum(struct net *net,
++ const struct flow_offload *flow,
++ struct nf_flow_rule *flow_rule)
+ {
+ u8 protonum = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto;
+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+
++ if (!entry)
++ return -E2BIG;
++
+ entry->id = FLOW_ACTION_CSUM;
+ entry->csum_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR;
+
+@@ -539,12 +576,14 @@ static void flow_offload_ipv4_checksum(struct net *net,
+ entry->csum_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
+ break;
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_redirect(struct net *net,
+- const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_redirect(struct net *net,
++ const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple, *other_tuple;
+ struct flow_action_entry *entry;
+@@ -562,21 +601,28 @@ static void flow_offload_redirect(struct net *net,
+ ifindex = other_tuple->iifidx;
+ break;
+ default:
+- return;
++ return -EOPNOTSUPP;
+ }
+
+ dev = dev_get_by_index(net, ifindex);
+ if (!dev)
+- return;
++ return -ENODEV;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry) {
++ dev_put(dev);
++ return -E2BIG;
++ }
++
+ entry->id = FLOW_ACTION_REDIRECT;
+ entry->dev = dev;
++
++ return 0;
+ }
+
+-static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_encap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *this_tuple;
+ struct flow_action_entry *entry;
+@@ -584,7 +630,7 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+
+ this_tuple = &flow->tuplehash[dir].tuple;
+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = this_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -593,15 +639,19 @@ static void flow_offload_encap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_ENCAP;
+ entry->tunnel = tun_info;
+ }
+ }
++
++ return 0;
+ }
+
+-static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+- enum flow_offload_tuple_dir dir,
+- struct nf_flow_rule *flow_rule)
++static int flow_offload_decap_tunnel(const struct flow_offload *flow,
++ enum flow_offload_tuple_dir dir,
++ struct nf_flow_rule *flow_rule)
+ {
+ const struct flow_offload_tuple *other_tuple;
+ struct flow_action_entry *entry;
+@@ -609,7 +659,7 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+
+ other_tuple = &flow->tuplehash[!dir].tuple;
+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
+- return;
++ return 0;
+
+ dst = other_tuple->dst_cache;
+ if (dst && dst->lwtstate) {
+@@ -618,9 +668,13 @@ static void flow_offload_decap_tunnel(const struct flow_offload *flow,
+ tun_info = lwt_tun_info(dst->lwtstate);
+ if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -E2BIG;
+ entry->id = FLOW_ACTION_TUNNEL_DECAP;
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -632,8 +686,9 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ const struct flow_offload_tuple *tuple;
+ int i;
+
+- flow_offload_decap_tunnel(flow, dir, flow_rule);
+- flow_offload_encap_tunnel(flow, dir, flow_rule);
++ if (flow_offload_decap_tunnel(flow, dir, flow_rule) < 0 ||
++ flow_offload_encap_tunnel(flow, dir, flow_rule) < 0)
++ return -1;
+
+ if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
+ flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
+@@ -649,6 +704,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+
+ if (tuple->encap[i].proto == htons(ETH_P_8021Q)) {
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+ entry->id = FLOW_ACTION_VLAN_POP;
+ }
+ }
+@@ -662,6 +719,8 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
+ continue;
+
+ entry = flow_action_entry_next(flow_rule);
++ if (!entry)
++ return -1;
+
+ switch (other_tuple->encap[i].proto) {
+ case htons(ETH_P_PPP_SES):
+@@ -687,18 +746,22 @@ int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv4_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv4_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_SNAT, &flow->flags) ||
+ test_bit(NF_FLOW_DNAT, &flow->flags))
+- flow_offload_ipv4_checksum(net, flow, flow_rule);
++ if (flow_offload_ipv4_checksum(net, flow, flow_rule) < 0)
++ return -1;
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+@@ -712,22 +775,23 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow,
+ return -1;
+
+ if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
+- flow_offload_ipv6_snat(net, flow, dir, flow_rule);
+- flow_offload_port_snat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_snat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_snat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+ if (test_bit(NF_FLOW_DNAT, &flow->flags)) {
+- flow_offload_ipv6_dnat(net, flow, dir, flow_rule);
+- flow_offload_port_dnat(net, flow, dir, flow_rule);
++ if (flow_offload_ipv6_dnat(net, flow, dir, flow_rule) < 0 ||
++ flow_offload_port_dnat(net, flow, dir, flow_rule) < 0)
++ return -1;
+ }
+
+- flow_offload_redirect(net, flow, dir, flow_rule);
++ if (flow_offload_redirect(net, flow, dir, flow_rule) < 0)
++ return -1;
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_rule_route_ipv6);
+
+-#define NF_FLOW_RULE_ACTION_MAX 16
+-
+ static struct nf_flow_rule *
+ nf_flow_offload_rule_alloc(struct net *net,
+ const struct flow_offload_work *offload,
+--
+2.53.0
+
--- /dev/null
+From 7492a56ee779dfe0c08ed7857b224bfc27b08d96 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 14:16:34 +0200
+Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit b7e8590987aa94c9dc51518fad0e58cb887b1db5 ]
+
+IPSET_ATTR_NAME and IPSET_ATTR_NAMEREF are of NLA_STRING type, they
+cannot be treated like a c-string.
+
+They either have to be switched to NLA_NUL_STRING, or the compare
+operations need to use the nla functions.
+
+Fixes: f830837f0eed ("netfilter: ipset: list:set set type support")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/netfilter/ipset/ip_set.h | 2 +-
+ net/netfilter/ipset/ip_set_core.c | 4 ++--
+ net/netfilter/ipset/ip_set_list_set.c | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
+index e9f4f845d760a..b98331572ad29 100644
+--- a/include/linux/netfilter/ipset/ip_set.h
++++ b/include/linux/netfilter/ipset/ip_set.h
+@@ -309,7 +309,7 @@ enum {
+
+ /* register and unregister set references */
+ extern ip_set_id_t ip_set_get_byname(struct net *net,
+- const char *name, struct ip_set **set);
++ const struct nlattr *name, struct ip_set **set);
+ extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
+ extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
+ extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index cc20e6d56807c..a4e1d7951b2c6 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -821,7 +821,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
+ *
+ */
+ ip_set_id_t
+-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
++ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
+ {
+ ip_set_id_t i, index = IPSET_INVALID_ID;
+ struct ip_set *s;
+@@ -830,7 +830,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ rcu_read_lock();
+ for (i = 0; i < inst->ip_set_max; i++) {
+ s = rcu_dereference(inst->ip_set_list)[i];
+- if (s && STRNCMP(s->name, name)) {
++ if (s && nla_strcmp(name, s->name) == 0) {
+ __ip_set_get(s);
+ index = i;
+ *set = s;
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index db794fe1300e6..83e1fdcc752d6 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
++ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
+ if (e.id == IPSET_INVALID_ID)
+ return -IPSET_ERR_NAME;
+ /* "Loop detection" */
+@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
+
+ if (tb[IPSET_ATTR_NAMEREF]) {
+ e.refid = ip_set_get_byname(map->net,
+- nla_data(tb[IPSET_ATTR_NAMEREF]),
++ tb[IPSET_ATTR_NAMEREF],
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
+ ret = -IPSET_ERR_NAMEREF;
+--
+2.53.0
+
--- /dev/null
+From 8ec3612d9d1460105ca7bf14d442a8989fc82ace Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:02 +0100
+Subject: netfilter: nf_conntrack_expect: honor expectation helper field
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 9c42bc9db90a154bc61ae337a070465f3393485a ]
+
+The expectation helper field is mostly unused. As a result, the
+netfilter codebase relies on accessing the helper through exp->master.
+
+Always set on the expectation helper field so it can be used to reach
+the helper.
+
+nf_ct_expect_init() is called from packet path where the skb owns
+the ct object, therefore accessing exp->master for the newly created
+expectation is safe. This saves a lot of updates in all callsites
+to pass the ct object as parameter to nf_ct_expect_init().
+
+This is a preparation patches for follow up fixes.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 2 +-
+ net/netfilter/nf_conntrack_broadcast.c | 2 +-
+ net/netfilter/nf_conntrack_expect.c | 14 +++++++++++++-
+ net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------
+ net/netfilter/nf_conntrack_helper.c | 7 ++++++-
+ net/netfilter/nf_conntrack_netlink.c | 2 +-
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 7 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 165e7a03b8e9d..1b01400b10bdb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -40,7 +40,7 @@ struct nf_conntrack_expect {
+ struct nf_conntrack_expect *this);
+
+ /* Helper to assign to new connection */
+- struct nf_conntrack_helper *helper;
++ struct nf_conntrack_helper __rcu *helper;
+
+ /* The conntrack of the master connection */
+ struct nf_conn *master;
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 9fb9b80312989..721b3e87416be 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -70,7 +70,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->expectfn = NULL;
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+- exp->helper = NULL;
++ rcu_assign_pointer(exp->helper, helper);
+
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 7bc64eb89bac4..43c6fc0576177 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -309,12 +309,19 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
+
++/* This function can only be used from packet path, where accessing
++ * master's helper is safe, because the packet holds a reference on
++ * the conntrack object. Never use it from control plane.
++ */
+ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ u_int8_t family,
+ const union nf_inet_addr *saddr,
+ const union nf_inet_addr *daddr,
+ u_int8_t proto, const __be16 *src, const __be16 *dst)
+ {
++ struct nf_conntrack_helper *helper = NULL;
++ struct nf_conn *ct = exp->master;
++ struct nf_conn_help *help;
+ int len;
+
+ if (family == AF_INET)
+@@ -325,7 +332,12 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ exp->flags = 0;
+ exp->class = class;
+ exp->expectfn = NULL;
+- exp->helper = NULL;
++
++ help = nfct_help(ct);
++ if (help)
++ helper = rcu_dereference(help->helper);
++
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
+index ed983421e2eb2..791aafe9f3960 100644
+--- a/net/netfilter/nf_conntrack_h323_main.c
++++ b/net/netfilter/nf_conntrack_h323_main.c
+@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = &nf_conntrack_helper_h245;
++ rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+ if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
+@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3 : NULL,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+ exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
+
+ nathook = rcu_dereference(nfct_h323_nat_hook);
+@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_UDP, NULL, &port);
+- exp->helper = nf_conntrack_helper_ras;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect RAS ");
+@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+- exp->helper = nf_conntrack_helper_q931;
++ rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
+
+ if (nf_ct_expect_related(exp, 0) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 01d125fa2f76e..d7bf2fa414a87 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -404,7 +404,7 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (exp->helper == me)
++ if (rcu_access_pointer(exp->helper) == me)
+ return true;
+
+ this = rcu_dereference_protected(help->helper,
+@@ -426,6 +426,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
++
++ /* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
++ * last step, this ensures rcu readers of exp->helper are done.
++ * No need for another synchronize_rcu() here.
++ */
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index d980f462714a9..97d2f5eacbe1e 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3555,7 +3555,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+ exp->mask.src.u.all = mask->src.u.all;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 84334537c6067..6ae30a4cf3601 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -1303,7 +1303,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
+ nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
+ saddr, &daddr, proto, NULL, &port);
+ exp->timeout.expires = sip_timeout * HZ;
+- exp->helper = helper;
++ rcu_assign_pointer(exp->helper, helper);
+ exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
+
+ hooks = rcu_dereference(nf_nat_sip_hooks);
+--
+2.53.0
+
--- /dev/null
+From cc51dac6f9e9c259518d08962b8d319de415281a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 22:39:55 +0100
+Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 02a3231b6d82efe750da6554ebf280e4a6f78756 ]
+
+__nf_ct_expect_find() and nf_ct_expect_find_get() are called under
+rcu_read_lock() but they dereference the master conntrack via
+exp->master.
+
+Since the expectation does not hold a reference on the master conntrack,
+this could be dying conntrack or different recycled conntrack than the
+real master due to SLAB_TYPESAFE_RCU.
+
+Store the netns, the master_tuple and the zone in struct
+nf_conntrack_expect as a safety measure.
+
+This patch is required by the follow up fix not to dump expectations
+that do not belong to this netns.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++++++++++-
+ net/netfilter/nf_conntrack_broadcast.c | 6 +++++-
+ net/netfilter/nf_conntrack_expect.c | 9 +++++++--
+ net/netfilter/nf_conntrack_netlink.c | 5 +++++
+ 4 files changed, 34 insertions(+), 4 deletions(-)
+
+diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
+index 1b01400b10bdb..e9a8350e7ccfb 100644
+--- a/include/net/netfilter/nf_conntrack_expect.h
++++ b/include/net/netfilter/nf_conntrack_expect.h
+@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
+ /* Hash member */
+ struct hlist_node hnode;
+
++ /* Network namespace */
++ possible_net_t net;
++
+ /* We expect this tuple, with the following mask */
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
+
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ struct nf_conntrack_zone zone;
++#endif
+ /* Usage count. */
+ refcount_t use;
+
+@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
+
+ static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
+ {
+- return nf_ct_net(exp->master);
++ return read_pnet(&exp->net);
++}
++
++static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
++ const struct nf_conntrack_zone *b)
++{
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ return a->zone.id == b->id;
++#else
++ return true;
++#endif
+ }
+
+ #define NF_CT_EXP_POLICY_NAME_LEN 16
+diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
+index 721b3e87416be..d44d9379a8a08 100644
+--- a/net/netfilter/nf_conntrack_broadcast.c
++++ b/net/netfilter/nf_conntrack_broadcast.c
+@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ unsigned int timeout)
+ {
+ const struct nf_conntrack_helper *helper;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = skb_rtable(skb);
+@@ -71,7 +72,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
+ exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
+ rcu_assign_pointer(exp->helper, helper);
+-
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ nf_ct_expect_related(exp, 0);
+ nf_ct_expect_put(exp);
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index e0eb844c2cdcb..70bcddfc17ccc 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -112,8 +112,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
+ const struct net *net)
+ {
+ return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+- net_eq(net, nf_ct_net(i->master)) &&
+- nf_ct_zone_equal_any(i->master, zone);
++ net_eq(net, read_pnet(&i->net)) &&
++ nf_ct_exp_zone_equal_any(i, zone);
+ }
+
+ bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
+@@ -321,6 +321,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ {
+ struct nf_conntrack_helper *helper = NULL;
+ struct nf_conn *ct = exp->master;
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conn_help *help;
+ int len;
+
+@@ -338,6 +339,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ helper = rcu_dereference(help->helper);
+
+ rcu_assign_pointer(exp->helper, helper);
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ exp->tuple.src.l3num = family;
+ exp->tuple.dst.protonum = proto;
+
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 2a601dc58b856..d7acd3e967425 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -3510,6 +3510,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
++ struct net *net = read_pnet(&ct->ct_net);
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
+ u32 class = 0;
+@@ -3549,6 +3550,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ write_pnet(&exp->net, net);
++#ifdef CONFIG_NF_CONNTRACK_ZONES
++ exp->zone = ct->zone;
++#endif
+ if (!helper)
+ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+--
+2.53.0
+
--- /dev/null
+From 5fc3c0f73c078bdef55708b24f3d0ae65038a90c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 14:11:03 +0100
+Subject: netfilter: nf_conntrack_expect: use expect->helper
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit f01794106042ee27e54af6fdf5b319a2fe3df94d ]
+
+Use expect->helper in ctnetlink and /proc to dump the helper name.
+Using nfct_help() without holding a reference to the master conntrack
+is unsafe.
+
+Use exp->master->helper in ctnetlink path if userspace does not provide
+an explicit helper when creating an expectation to retain the existing
+behaviour. The ctnetlink expectation path holds the reference on the
+master conntrack and nf_conntrack_expect lock and the nfnetlink glue
+path refers to the master ct that is attached to the skb.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_expect.c | 2 +-
+ net/netfilter/nf_conntrack_helper.c | 6 +-----
+ net/netfilter/nf_conntrack_netlink.c | 24 ++++++++++--------------
+ net/netfilter/nf_conntrack_sip.c | 2 +-
+ 4 files changed, 13 insertions(+), 21 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
+index 43c6fc0576177..e0eb844c2cdcb 100644
+--- a/net/netfilter/nf_conntrack_expect.c
++++ b/net/netfilter/nf_conntrack_expect.c
+@@ -670,7 +670,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
+ if (expect->flags & NF_CT_EXPECT_USERSPACE)
+ seq_printf(s, "%sUSERSPACE", delim);
+
+- helper = rcu_dereference(nfct_help(expect->master)->helper);
++ helper = rcu_dereference(expect->helper);
+ if (helper) {
+ seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
+ if (helper->expect_policy[expect->class].name[0])
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index d7bf2fa414a87..7d5e4f67f268c 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -400,14 +400,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
+
+ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
+ {
+- struct nf_conn_help *help = nfct_help(exp->master);
+ const struct nf_conntrack_helper *me = data;
+ const struct nf_conntrack_helper *this;
+
+- if (rcu_access_pointer(exp->helper) == me)
+- return true;
+-
+- this = rcu_dereference_protected(help->helper,
++ this = rcu_dereference_protected(exp->helper,
+ lockdep_is_held(&nf_conntrack_expect_lock));
+ return this == me;
+ }
+diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
+index 97d2f5eacbe1e..2a601dc58b856 100644
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -2994,7 +2994,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ {
+ struct nf_conn *master = exp->master;
+ long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
+- struct nf_conn_help *help;
++ struct nf_conntrack_helper *helper;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+ struct nlattr *nest_parms;
+ struct nf_conntrack_tuple nat_tuple = {};
+@@ -3039,15 +3039,12 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
+ goto nla_put_failure;
+- help = nfct_help(master);
+- if (help) {
+- struct nf_conntrack_helper *helper;
+
+- helper = rcu_dereference(help->helper);
+- if (helper &&
+- nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
+- goto nla_put_failure;
+- }
++ helper = rcu_dereference(exp->helper);
++ if (helper &&
++ nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
++ goto nla_put_failure;
++
+ expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
+ if (expfn != NULL &&
+ nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
+@@ -3376,12 +3373,9 @@ static int ctnetlink_get_expect(struct sk_buff *skb,
+ static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
+ {
+ struct nf_conntrack_helper *helper;
+- const struct nf_conn_help *m_help;
+ const char *name = data;
+
+- m_help = nfct_help(exp->master);
+-
+- helper = rcu_dereference(m_help->helper);
++ helper = rcu_dereference(exp->helper);
+ if (!helper)
+ return false;
+
+@@ -3516,9 +3510,9 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+ struct nf_conntrack_tuple *tuple,
+ struct nf_conntrack_tuple *mask)
+ {
+- u_int32_t class = 0;
+ struct nf_conntrack_expect *exp;
+ struct nf_conn_help *help;
++ u32 class = 0;
+ int err;
+
+ help = nfct_help(ct);
+@@ -3555,6 +3549,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
+
+ exp->class = class;
+ exp->master = ct;
++ if (!helper)
++ helper = rcu_dereference(help->helper);
+ rcu_assign_pointer(exp->helper, helper);
+ exp->tuple = *tuple;
+ exp->mask.src.u3 = mask->src.u3;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index 6ae30a4cf3601..fda6fc1fc4c58 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -924,7 +924,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
+
+ if (!exp || exp->master == ct ||
+- nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
++ exp->helper != nfct_help(ct)->helper ||
+ exp->class != class)
+ break;
+ #if IS_ENABLED(CONFIG_NF_NAT)
+--
+2.53.0
+
--- /dev/null
+From 3502a335e7f4edb7820192cba352d174e80ea764 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Mar 2026 00:50:36 +0800
+Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup
+
+From: Qi Tang <tpluszz77@gmail.com>
+
+[ Upstream commit a242a9ae58aa46ff7dae51ce64150a93957abe65 ]
+
+nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
+to remove expectations belonging to the helper being unregistered.
+However, it passes NULL instead of the helper pointer as the data
+argument, so expect_iter_me() never matches any expectation and all
+of them survive the cleanup.
+
+After unregister returns, nfnl_cthelper_del() frees the helper
+object immediately. Subsequent expectation dumps or packet-driven
+init_conntrack() calls then dereference the freed exp->helper,
+causing a use-after-free.
+
+Pass the actual helper pointer so expectations referencing it are
+properly destroyed before the helper object is freed.
+
+ BUG: KASAN: slab-use-after-free in string+0x38f/0x430
+ Read of size 1 at addr ffff888003b14d20 by task poc/103
+ Call Trace:
+ string+0x38f/0x430
+ vsnprintf+0x3cc/0x1170
+ seq_printf+0x17a/0x240
+ exp_seq_show+0x2e5/0x560
+ seq_read_iter+0x419/0x1280
+ proc_reg_read+0x1ac/0x270
+ vfs_read+0x179/0x930
+ ksys_read+0xef/0x1c0
+ Freed by task 103:
+ The buggy address is located 32 bytes inside of
+ freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
+
+Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
+Signed-off-by: Qi Tang <tpluszz77@gmail.com>
+Reviewed-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_helper.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 10f72b5b4e1ad..01d125fa2f76e 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -424,7 +424,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ */
+ synchronize_rcu();
+
+- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
++ nf_ct_expect_iterate_destroy(expect_iter_me, me);
+ nf_ct_iterate_destroy(unhelp, me);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+--
+2.53.0
+
--- /dev/null
+From f28df0426a5596562a3550295a8da63f20862ad2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:08:02 +0200
+Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit da107398cbd4bbdb6bffecb2ce86d5c9384f4cec ]
+
+nft_queue is always used from userspace nftables to deliver the NF_QUEUE
+verdict. Immediately emitting an NF_QUEUE verdict is never used by the
+userspace nft tools, so reject immediate NF_QUEUE verdicts.
+
+The arp family does not provide queue support, but such an immediate
+verdict is still reachable. Globally reject NF_QUEUE immediate verdicts
+to address this issue.
+
+Fixes: f342de4e2f33 ("netfilter: nf_tables: reject QUEUE/DROP verdict parameters")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index b411abe9743b7..0aaddc1131c65 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -11105,8 +11105,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ case NF_DROP:
+- case NF_QUEUE:
+- break;
+ case NFT_CONTINUE:
+ case NFT_BREAK:
+ case NFT_RETURN:
+@@ -11141,6 +11139,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
+
+ data->verdict.chain = chain;
+ break;
++ case NF_QUEUE:
++ /* The nft_queue expression is used for this purpose, an
++ * immediate NF_QUEUE verdict should not ever be seen here.
++ */
++ fallthrough;
+ default:
+ return -EINVAL;
+ }
+--
+2.53.0
+
--- /dev/null
+From 85c67ac6dfbc702a840261d53cccdea2f5b8f1c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 16:17:24 +0100
+Subject: netfilter: nfnetlink_log: account for netlink header size
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6d52a4a0520a6696bdde51caa11f2d6821cd0c01 ]
+
+This is a followup to an old bug fix: NLMSG_DONE needs to account
+for the netlink header size, not just the attribute size.
+
+This can result in a WARN splat + drop of the netlink message,
+but other than this there are no ill effects.
+
+Fixes: 9dfa1dfe4d5e ("netfilter: nf_log: account for size of NLMSG_DONE attribute")
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nfnetlink_log.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
+index aa5fc9bffef0c..f96421ad14afb 100644
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -726,7 +726,7 @@ nfulnl_log_packet(struct net *net,
+ + nla_total_size(plen) /* prefix */
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
++ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+
+ if (in && skb_mac_header_was_set(skb)) {
+ size += nla_total_size(skb->dev->hard_header_len)
+--
+2.53.0
+
--- /dev/null
+From c9d261e8a5abc086414069f31544f41a7ab2e92e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 23:13:36 +0200
+Subject: netfilter: x_tables: ensure names are nul-terminated
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a958a4f90ddd7de0800b33ca9d7b886b7d40f74e ]
+
+Reject names that lack a \0 character before feeding them
+to functions that expect c-strings.
+
+Fixes tag is the most recent commit that needs this change.
+
+Fixes: c38c4597e4bf ("netfilter: implement xt_cgroup cgroup2 path match")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_cgroup.c | 6 ++++++
+ net/netfilter/xt_rateest.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
+index c0f5e9a4f3c65..bfc98719684e2 100644
+--- a/net/netfilter/xt_cgroup.c
++++ b/net/netfilter/xt_cgroup.c
+@@ -53,6 +53,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+@@ -85,6 +88,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
+
+ info->priv = NULL;
+ if (info->has_path) {
++ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
++ return -ENAMETOOLONG;
++
+ cgrp = cgroup_get_from_path(info->path);
+ if (IS_ERR(cgrp)) {
+ pr_info_ratelimited("invalid path, errno=%ld\n",
+diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
+index 72324bd976af8..b1d736c15fcbe 100644
+--- a/net/netfilter/xt_rateest.c
++++ b/net/netfilter/xt_rateest.c
+@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+ goto err1;
+ }
+
++ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
++ return -ENAMETOOLONG;
++ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
++ return -ENAMETOOLONG;
++
+ ret = -ENOENT;
+ est1 = xt_rateest_lookup(par->net, info->name1);
+ if (!est1)
+--
+2.53.0
+
--- /dev/null
+From 3a0fa73fb361fce735f7117430c8d52ae889b3df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 16:41:25 +0200
+Subject: netfilter: x_tables: restrict xt_check_match/xt_check_target
+ extensions for NFPROTO_ARP
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3d5d488f11776738deab9da336038add95d342d1 ]
+
+Weiming Shi says:
+
+xt_match and xt_target structs registered with NFPROTO_UNSPEC can be
+loaded by any protocol family through nft_compat. When such a
+match/target sets .hooks to restrict which hooks it may run on, the
+bitmask uses NF_INET_* constants. This is only correct for families
+whose hook layout matches NF_INET_*: IPv4, IPv6, INET, and bridge
+all share the same five hooks (PRE_ROUTING ... POST_ROUTING).
+
+ARP only has three hooks (IN=0, OUT=1, FORWARD=2) with different
+semantics. Because NF_ARP_OUT == 1 == NF_INET_LOCAL_IN, the .hooks
+validation silently passes for the wrong reasons, allowing matches to
+run on ARP chains where the hook assumptions (e.g. state->in being
+set on input hooks) do not hold. This leads to NULL pointer
+dereferences; xt_devgroup is one concrete example:
+
+ Oops: general protection fault, probably for non-canonical address 0xdffffc0000000044: 0000 [#1] SMP KASAN NOPTI
+ KASAN: null-ptr-deref in range [0x0000000000000220-0x0000000000000227]
+ RIP: 0010:devgroup_mt+0xff/0x350
+ Call Trace:
+ <TASK>
+ nft_match_eval (net/netfilter/nft_compat.c:407)
+ nft_do_chain (net/netfilter/nf_tables_core.c:285)
+ nft_do_chain_arp (net/netfilter/nft_chain_filter.c:61)
+ nf_hook_slow (net/netfilter/core.c:623)
+ arp_xmit (net/ipv4/arp.c:666)
+ </TASK>
+ Kernel panic - not syncing: Fatal exception in interrupt
+
+Fix it by restricting arptables to NFPROTO_ARP extensions only.
+Note that arptables-legacy only supports:
+
+- arpt_CLASSIFY
+- arpt_mangle
+- arpt_MARK
+
+that provide explicit NFPROTO_ARP match/target declarations.
+
+Fixes: 9291747f118d ("netfilter: xtables: add device group match")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
+index d892afc9a1acc..c1ab85fb8c46d 100644
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -501,6 +501,17 @@ int xt_check_match(struct xt_mtchk_param *par,
+ par->match->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->match->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
++ xt_prefix[par->family], par->match->name);
++ return -EINVAL;
++ }
+ if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+ char used[64], allow[64];
+
+@@ -1016,6 +1027,18 @@ int xt_check_target(struct xt_tgchk_param *par,
+ par->target->table, par->table);
+ return -EINVAL;
+ }
++
++ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
++ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
++ * support.
++ */
++ if (par->family == NFPROTO_ARP &&
++ par->target->family != NFPROTO_ARP) {
++ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
++ xt_prefix[par->family], par->target->name);
++ return -EINVAL;
++ }
++
+ if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+ char used[64], allow[64];
+
+--
+2.53.0
+
--- /dev/null
+From a850e0321247d1548eaf0a7d235aa549f6127431 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Mar 2026 22:20:33 +0800
+Subject: NFC: pn533: bound the UART receive buffer
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+[ Upstream commit 30fe3f5f6494f827d812ff179f295a8e532709d6 ]
+
+pn532_receive_buf() appends every incoming byte to dev->recv_skb and
+only resets the buffer after pn532_uart_rx_is_frame() recognizes a
+complete frame. A continuous stream of bytes without a valid PN532 frame
+header therefore keeps growing the skb until skb_put_u8() hits the tail
+limit.
+
+Drop the accumulated partial frame once the fixed receive buffer is full
+so malformed UART traffic cannot grow the skb past
+PN532_UART_SKB_BUFF_LEN.
+
+Fixes: c656aa4c27b1 ("nfc: pn533: add UART phy driver")
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nfc/pn533/uart.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
+index a556acdb947bb..f4afd1156e062 100644
+--- a/drivers/nfc/pn533/uart.c
++++ b/drivers/nfc/pn533/uart.c
+@@ -211,6 +211,9 @@ static int pn532_receive_buf(struct serdev_device *serdev,
+
+ del_timer(&dev->cmd_timeout);
+ for (i = 0; i < count; i++) {
++ if (unlikely(!skb_tailroom(dev->recv_skb)))
++ skb_trim(dev->recv_skb, 0);
++
+ skb_put_u8(dev->recv_skb, *data++);
+ if (!pn532_uart_rx_is_frame(dev->recv_skb))
+ continue;
+--
+2.53.0
+
--- /dev/null
+From 61ffca641c3547581d6908f47c3c85620f63dfb7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Mar 2026 09:03:05 -0700
+Subject: objtool: Fix Clang jump table detection
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 4e5019216402ad0b4a84cff457b662d26803f103 ]
+
+With Clang, there can be a conditional forward jump between the load of
+the jump table address and the indirect branch.
+
+Fixes the following warning:
+
+ vmlinux.o: warning: objtool: ___bpf_prog_run+0x1c5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Closes: https://lore.kernel.org/a426d669-58bb-4be1-9eaa-6f3d83109e2d@app.fastmail.com
+Link: https://patch.msgid.link/7d8600caed08901b6679767488acd639f6df9688.1773071992.git.jpoimboe@kernel.org
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/objtool/check.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 6497c80fd6f77..2c7b09c8415f0 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -2136,12 +2136,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
+ last = insn;
+
+ /*
+- * Store back-pointers for unconditional forward jumps such
++ * Store back-pointers for forward jumps such
+ * that find_jump_table() can back-track using those and
+ * avoid some potentially confusing code.
+ */
+- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
+- insn->offset > last->offset &&
++ if (insn->jump_dest &&
+ insn->jump_dest->offset > insn->offset &&
+ !insn->jump_dest->first_jump_src) {
+
+--
+2.53.0
+
--- /dev/null
+From 8344e6ab6a54f7b2a17d587e19f3c20f702a1354 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Mar 2026 00:32:38 +0800
+Subject: rds: ib: reject FRMR registration before IB connection is established
+
+From: Weiming Shi <bestswngs@gmail.com>
+
+[ Upstream commit a54ecccfae62c5c85259ae5ea5d9c20009519049 ]
+
+rds_ib_get_mr() extracts the rds_ib_connection from conn->c_transport_data
+and passes it to rds_ib_reg_frmr() for FRWR memory registration. On a
+fresh outgoing connection, ic is allocated in rds_ib_conn_alloc() with
+i_cm_id = NULL because the connection worker has not yet called
+rds_ib_conn_path_connect() to create the rdma_cm_id. When sendmsg() with
+RDS_CMSG_RDMA_MAP is called on such a connection, the sendmsg path parses
+the control message before any connection establishment, allowing
+rds_ib_post_reg_frmr() to dereference ic->i_cm_id->qp and crash the
+kernel.
+
+The existing guard in rds_ib_reg_frmr() only checks for !ic (added in
+commit 9e630bcb7701), which does not catch this case since ic is allocated
+early and is always non-NULL once the connection object exists.
+
+ KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
+ RIP: 0010:rds_ib_post_reg_frmr+0x50e/0x920
+ Call Trace:
+ rds_ib_post_reg_frmr (net/rds/ib_frmr.c:167)
+ rds_ib_map_frmr (net/rds/ib_frmr.c:252)
+ rds_ib_reg_frmr (net/rds/ib_frmr.c:430)
+ rds_ib_get_mr (net/rds/ib_rdma.c:615)
+ __rds_rdma_map (net/rds/rdma.c:295)
+ rds_cmsg_rdma_map (net/rds/rdma.c:860)
+ rds_sendmsg (net/rds/send.c:1363)
+ ____sys_sendmsg
+ do_syscall_64
+
+Add a check in rds_ib_get_mr() that verifies ic, i_cm_id, and qp are all
+non-NULL before proceeding with FRMR registration, mirroring the guard
+already present in rds_ib_post_inv(). Return -ENODEV when the connection
+is not ready, which the existing error handling in rds_cmsg_send() converts
+to -EAGAIN for userspace retry and triggers rds_conn_connect_if_down() to
+start the connection worker.
+
+Fixes: 1659185fb4d0 ("RDS: IB: Support Fastreg MR (FRMR) memory registration mode")
+Reported-by: Xiang Mei <xmei5@asu.edu>
+Signed-off-by: Weiming Shi <bestswngs@gmail.com>
+Reviewed-by: Allison Henderson <achender@kernel.org>
+Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/rds/ib_rdma.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
+index 8f070ee7e7426..30fca2169aa7a 100644
+--- a/net/rds/ib_rdma.c
++++ b/net/rds/ib_rdma.c
+@@ -608,8 +608,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+ return ibmr;
+ }
+
+- if (conn)
++ if (conn) {
+ ic = conn->c_transport_data;
++ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
++ ret = -ENODEV;
++ goto out;
++ }
++ }
+
+ if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
+ ret = -ENODEV;
+--
+2.53.0
+
--- /dev/null
+arm64-scs-fix-handling-of-advance_loc4.patch
+hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch
+atm-lec-fix-use-after-free-in-sock_def_readable.patch
+btrfs-don-t-take-device_list_mutex-when-querying-zon.patch
+tg3-replace-placeholder-mac-address-with-device-prop.patch
+objtool-fix-clang-jump-table-detection.patch
+hid-multitouch-check-to-ensure-report-responses-matc.patch
+i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch
+btrfs-reject-root-items-with-drop_progress-and-zero-.patch
+spi-geni-qcom-check-dma-interrupts-early-in-isr.patch
+dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch
+wifi-ath11k-skip-status-ring-entry-processing.patch
+wifi-ath11k-use-dma_alloc_noncoherent-for-rx_tid-buf.patch
+wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch
+crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch
+crypto-caam-fix-overflow-on-long-hmac-keys.patch
+crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch
+net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch
+net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch
+net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch
+net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch
+tg3-fix-race-for-querying-speed-duplex.patch
+ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch
+ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch
+bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch
+net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch
+asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch
+ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch
+net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch
+nfc-pn533-bound-the-uart-receive-buffer.patch
+net-xilinx-axienet-correct-bd-length-masks-to-match-.patch
+bpf-fix-regsafe-for-pointers-to-packet.patch
+net-ipv6-flowlabel-defer-exclusive-option-free-until.patch
+netfilter-flowtable-strictly-check-for-maximum-numbe.patch
+netfilter-nfnetlink_log-account-for-netlink-header-s.patch
+netfilter-x_tables-ensure-names-are-nul-terminated.patch
+netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch
+netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch
+netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch
+netfilter-nf_conntrack_expect-honor-expectation-help.patch
+netfilter-nf_conntrack_expect-use-expect-helper.patch
+netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch
+netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch
+netfilter-x_tables-restrict-xt_check_match-xt_check_.patch
+netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch
+bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch
+bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch
+bluetooth-mgmt-validate-ltk-enc_size-on-load.patch
+bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch
+bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch
+rds-ib-reject-frmr-registration-before-ib-connection.patch
+bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch
+net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch
+net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch
+net-macb-properly-unregister-fixed-rate-clocks.patch
+net-mlx5-lag-check-for-lag-device-before-creating-de.patch
+net-mlx5-avoid-no-data-available-when-fw-version-que.patch
+net-x25-fix-potential-double-free-of-skb.patch
+net-x25-fix-overflow-when-accumulating-packets.patch
+net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch
+net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch
+net-hsr-fix-vlan-add-unwind-on-slave-errors.patch
+ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch
+bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch
--- /dev/null
+From 75227d0609dfefbe714288d95fa077e682de9e21 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2026 21:49:01 +0530
+Subject: spi: geni-qcom: Check DMA interrupts early in ISR
+
+From: Praveen Talari <praveen.talari@oss.qualcomm.com>
+
+[ Upstream commit 8c89a077ca796a2fe248c584e9d7e66cff0388c8 ]
+
+The current interrupt handler only checks the GENI main IRQ status
+(m_irq) before deciding to return IRQ_NONE. This can lead to spurious
+IRQ_NONE returns when DMA interrupts are pending but m_irq is zero.
+
+Move the DMA TX/RX status register reads to the beginning of the ISR,
+right after reading m_irq. Update the early return condition to check
+all three status registers (m_irq, dma_tx_status, dma_rx_status) before
+returning IRQ_NONE.
+
+Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-geni-qcom.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
+index 37a20652fd2e7..ef1a05837cb97 100644
+--- a/drivers/spi/spi-geni-qcom.c
++++ b/drivers/spi/spi-geni-qcom.c
+@@ -948,10 +948,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ struct spi_master *spi = data;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+- u32 m_irq;
++ u32 m_irq, dma_tx_status, dma_rx_status;
+
+ m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
+- if (!m_irq)
++ dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
++ dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
++
++ if (!m_irq && !dma_tx_status && !dma_rx_status)
+ return IRQ_NONE;
+
+ if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
+@@ -999,8 +1002,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
+ }
+ } else if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ const struct spi_transfer *xfer = mas->cur_xfer;
+- u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+- u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (dma_tx_status)
+ writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
+--
+2.53.0
+
--- /dev/null
+From 6c4d36a5ad7c1fd1961b1ed31ca52caab6891037 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Mar 2026 12:20:53 +0100
+Subject: tg3: Fix race for querying speed/duplex
+
+From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+
+[ Upstream commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed ]
+
+When driver signals carrier up via netif_carrier_on() its internal
+link_up state isn't updated immediately. This leads to inconsistent
+speed/duplex in /proc/net/bonding/bondX where the speed and duplex
+is shown as unknown while ethtool shows correct values. Fix this by
+using netif_carrier_ok() for link checking in get_ksettings function.
+
+Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
+Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index 840231ebbef71..1ffd98a1c7417 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -12212,7 +12212,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
+- if (netif_running(dev) && tp->link_up) {
++ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ cmd->base.speed = tp->link_config.active_speed;
+ cmd->base.duplex = tp->link_config.active_duplex;
+ ethtool_convert_legacy_u32_to_link_mode(
+--
+2.53.0
+
--- /dev/null
+From e1fb9d8aed58f8a19fb9af8736fc67fcf650d44a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Mar 2026 03:24:30 +0530
+Subject: tg3: replace placeholder MAC address with device property
+
+From: Paul SAGE <paul.sage@42.fr>
+
+[ Upstream commit e4c00ba7274b613e3ab19e27eb009f0ec2e28379 ]
+
+On some systems (e.g. iMac 20,1 with BCM57766), the tg3 driver reads
+a default placeholder mac address (00:10:18:00:00:00) from the
+mailbox. The correct value on those systems are stored in the
+'local-mac-address' property.
+
+This patch, detect the default value and tries to retrieve
+the correct address from the device_get_mac_address
+function instead.
+
+The patch has been tested on two different systems:
+- iMac 20,1 (BCM57766) model which use the local-mac-address property
+- iMac 13,2 (BCM57766) model which can use the mailbox,
+ NVRAM or MAC control registers
+
+Tested-by: Rishon Jonathan R <mithicalaviator85@gmail.com>
+
+Co-developed-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Vincent MORVAN <vinc@42.fr>
+Signed-off-by: Paul SAGE <paul.sage@42.fr>
+Signed-off-by: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index ea4973096aa28..840231ebbef71 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -16945,6 +16945,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
+ return err;
+ }
+
++static int tg3_is_default_mac_address(u8 *addr)
++{
++ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
++
++ return ether_addr_equal(default_mac_address, addr);
++}
++
+ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+ {
+ u32 hi, lo, mac_offset;
+@@ -17016,6 +17023,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
+
+ if (!is_valid_ether_addr(addr))
+ return -EINVAL;
++
++ if (tg3_is_default_mac_address(addr))
++ return device_get_mac_address(&tp->pdev->dev, addr);
++
+ return 0;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From c0be9f661fc8a4a29077421dbc36f45807259e82 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Mar 2026 12:26:08 +0530
+Subject: wifi: ath11k: Pass the correct value of each TID during a stop AMPDU
+ session
+
+From: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+
+[ Upstream commit e225b36f83d7926c1f2035923bb0359d851fdb73 ]
+
+During ongoing traffic, a request to stop an AMPDU session
+for one TID could incorrectly affect other active sessions.
+This can happen because an incorrect TID reference would be
+passed when updating the BA session state, causing the wrong
+session to be stopped. As a result, the affected session would
+be reduced to a minimal BA size, leading to a noticeable
+throughput degradation.
+
+Fix this issue by passing the correct argument from
+ath11k_dp_rx_ampdu_stop() to ath11k_peer_rx_tid_reo_update()
+during a stop AMPDU session. Instead of passing peer->tx_tid, which
+is the base address of the array, corresponding to TID 0; pass
+the value of &peer->rx_tid[params->tid], where the different TID numbers
+are accounted for.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1
+
+Fixes: d5c65159f2895 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
+Signed-off-by: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
+Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index 411749e8e209e..d2d994e094809 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_peer *peer;
+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
++ struct dp_rx_tid *rx_tid;
+ int vdev_id = arsta->arvif->vdev_id;
+- dma_addr_t paddr;
+- bool active;
+ int ret;
+
+ spin_lock_bh(&ab->base_lock);
+@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ return -ENOENT;
+ }
+
+- paddr = peer->rx_tid[params->tid].paddr;
+- active = peer->rx_tid[params->tid].active;
++ rx_tid = &peer->rx_tid[params->tid];
+
+- if (!active) {
++ if (!rx_tid->active) {
+ spin_unlock_bh(&ab->base_lock);
+ return 0;
+ }
+
+- ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
++ ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
+ spin_unlock_bh(&ab->base_lock);
+ if (ret) {
+ ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
+@@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+ }
+
+ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
+- params->sta->addr, paddr,
++ params->sta->addr,
++ rx_tid->paddr,
+ params->tid, 1, 1);
+ if (ret)
+ ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
+--
+2.53.0
+
--- /dev/null
+From 939642a71e6125cdeb92ad6626310a8f1394ed57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 May 2024 16:24:16 +0300
+Subject: wifi: ath11k: skip status ring entry processing
+
+From: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
+
+[ Upstream commit 4c2b796be3a12a11ab611917fafdabc9d3862a1d ]
+
+If STATUS_BUFFER_DONE is not set for a monitor status ring entry,
+we don't process the status ring until STATUS_BUFFER_DONE set
+for that status ring entry.
+
+During LMAC reset it may happen that hardware will not write
+STATUS_BUFFER_DONE tlv in status buffer, in that case we end up
+waiting for STATUS_BUFFER_DONE leading to backpressure on monitor
+status ring.
+
+To fix the issue, when HP (Head Pointer) + 1 entry is peeked and if DMA is not
+done and if HP + 2 entry's DMA done is set, replenish HP + 1 entry and start
+processing in next interrupt. If HP + 2 entry's DMA done is not set, poll onto
+HP + 1 entry DMA done to be set.
+
+Also, during monitor attach HP points to the end of the ring and TP (Tail
+Pointer) points to the start of the ring. Using ath11k_hal_srng_src_peek() may
+result in processing invalid buffer for the very first interrupt. Since, HW
+starts writing buffer from TP.
+
+To avoid this issue call ath11k_hal_srng_src_next_peek() instead of
+calling ath11k_hal_srng_src_peek().
+
+Tested-on: IPQ5018 hw1.0 AHB WLAN.HK.2.6.0.1-00861-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
+Co-developed-by: Tamizh Chelvam Raja <quic_tamizhr@quicinc.com>
+Signed-off-by: Tamizh Chelvam Raja <quic_tamizhr@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://msgid.link/20240429073624.736147-1-quic_tamizhr@quicinc.com
+Stable-dep-of: e225b36f83d7 ("wifi: ath11k: Pass the correct value of each TID during a stop AMPDU session")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 82 ++++++++++++++++++++++---
+ drivers/net/wireless/ath/ath11k/hal.c | 16 ++++-
+ drivers/net/wireless/ath/ath11k/hal.h | 2 +
+ 3 files changed, 90 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index ed1ea61c81420..c37722a727309 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -2996,11 +2996,52 @@ ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon,
+ }
+ }
+
++static enum dp_mon_status_buf_state
++ath11k_dp_rx_mon_buf_done(struct ath11k_base *ab, struct hal_srng *srng,
++ struct dp_rxdma_ring *rx_ring)
++{
++ struct ath11k_skb_rxcb *rxcb;
++ struct hal_tlv_hdr *tlv;
++ struct sk_buff *skb;
++ void *status_desc;
++ dma_addr_t paddr;
++ u32 cookie;
++ int buf_id;
++ u8 rbm;
++
++ status_desc = ath11k_hal_srng_src_next_peek(ab, srng);
++ if (!status_desc)
++ return DP_MON_STATUS_NO_DMA;
++
++ ath11k_hal_rx_buf_addr_info_get(status_desc, &paddr, &cookie, &rbm);
++
++ buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie);
++
++ spin_lock_bh(&rx_ring->idr_lock);
++ skb = idr_find(&rx_ring->bufs_idr, buf_id);
++ spin_unlock_bh(&rx_ring->idr_lock);
++
++ if (!skb)
++ return DP_MON_STATUS_NO_DMA;
++
++ rxcb = ATH11K_SKB_RXCB(skb);
++ dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
++ skb->len + skb_tailroom(skb),
++ DMA_FROM_DEVICE);
++
++ tlv = (struct hal_tlv_hdr *)skb->data;
++ if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_STATUS_BUFFER_DONE)
++ return DP_MON_STATUS_NO_DMA;
++
++ return DP_MON_STATUS_REPLINISH;
++}
++
+ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
+ int *budget, struct sk_buff_head *skb_list)
+ {
+ struct ath11k *ar;
+ const struct ath11k_hw_hal_params *hal_params;
++ enum dp_mon_status_buf_state reap_status;
+ struct ath11k_pdev_dp *dp;
+ struct dp_rxdma_ring *rx_ring;
+ struct ath11k_mon_data *pmon;
+@@ -3063,15 +3104,38 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
+ ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n",
+ FIELD_GET(HAL_TLV_HDR_TAG,
+ tlv->tl), buf_id);
+- /* If done status is missing, hold onto status
+- * ring until status is done for this status
+- * ring buffer.
+- * Keep HP in mon_status_ring unchanged,
+- * and break from here.
+- * Check status for same buffer for next time
++ /* RxDMA status done bit might not be set even
++ * though tp is moved by HW.
+ */
+- pmon->buf_state = DP_MON_STATUS_NO_DMA;
+- break;
++
++ /* If done status is missing:
++ * 1. As per MAC team's suggestion,
++ * when HP + 1 entry is peeked and if DMA
++ * is not done and if HP + 2 entry's DMA done
++ * is set. skip HP + 1 entry and
++ * start processing in next interrupt.
++ * 2. If HP + 2 entry's DMA done is not set,
++ * poll onto HP + 1 entry DMA done to be set.
++ * Check status for same buffer for next time
++ * dp_rx_mon_status_srng_process
++ */
++
++ reap_status = ath11k_dp_rx_mon_buf_done(ab, srng,
++ rx_ring);
++ if (reap_status == DP_MON_STATUS_NO_DMA)
++ continue;
++
++ spin_lock_bh(&rx_ring->idr_lock);
++ idr_remove(&rx_ring->bufs_idr, buf_id);
++ spin_unlock_bh(&rx_ring->idr_lock);
++
++ dma_unmap_single(ab->dev, rxcb->paddr,
++ skb->len + skb_tailroom(skb),
++ DMA_FROM_DEVICE);
++
++ dev_kfree_skb_any(skb);
++ pmon->buf_state = DP_MON_STATUS_REPLINISH;
++ goto move_next;
+ }
+
+ spin_lock_bh(&rx_ring->idr_lock);
+diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c
+index 79cf65bc2e172..b42925f84200c 100644
+--- a/drivers/net/wireless/ath/ath11k/hal.c
++++ b/drivers/net/wireless/ath/ath11k/hal.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+ #include <linux/dma-mapping.h>
+ #include "hal_tx.h"
+@@ -783,6 +783,20 @@ u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab,
+ return desc;
+ }
+
++u32 *ath11k_hal_srng_src_next_peek(struct ath11k_base *ab, struct hal_srng *srng)
++{
++ u32 next_hp;
++
++ lockdep_assert_held(&srng->lock);
++
++ next_hp = (srng->u.src_ring.hp + srng->entry_size) % srng->ring_size;
++
++ if (next_hp != srng->u.src_ring.cached_tp)
++ return srng->ring_base_vaddr + next_hp;
++
++ return NULL;
++}
++
+ u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng)
+ {
+ lockdep_assert_held(&srng->lock);
+diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h
+index aa21eb1fdce15..494c2b8a12816 100644
+--- a/drivers/net/wireless/ath/ath11k/hal.h
++++ b/drivers/net/wireless/ath/ath11k/hal.h
+@@ -946,6 +946,8 @@ u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng);
+ int ath11k_hal_srng_dst_num_free(struct ath11k_base *ab, struct hal_srng *srng,
+ bool sync_hw_ptr);
+ u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng);
++u32 *ath11k_hal_srng_src_next_peek(struct ath11k_base *ab,
++ struct hal_srng *srng);
+ u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab,
+ struct hal_srng *srng);
+ u32 *ath11k_hal_srng_src_reap_next(struct ath11k_base *ab,
+--
+2.53.0
+
--- /dev/null
+From 697499bc5c8357db99d3840be3e1246340cfbf44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jan 2025 22:12:19 +0530
+Subject: wifi: ath11k: Use dma_alloc_noncoherent for rx_tid buffer allocation
+
+From: P Praneesh <quic_ppranees@quicinc.com>
+
+[ Upstream commit eeadc6baf8b3dcd32787cc84f0473dc2a2850370 ]
+
+Currently, the driver allocates cacheable DMA buffers for the rx_tid
+structure using kzalloc() and dma_map_single(). These buffers are
+long-lived and can persist for the lifetime of the peer, which is not
+advisable. Instead of using kzalloc() and dma_map_single() for allocating
+cacheable DMA buffers, utilize the dma_alloc_noncoherent() helper for the
+allocation of long-lived cacheable DMA buffers, such as the peer's rx_tid.
+Since dma_alloc_noncoherent() returns unaligned physical and virtual
+addresses, align them internally before use within the driver. This
+ensures proper allocation of non-coherent memory through the kernel
+helper.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3
+
+Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
+Tested-by: Tim Harvey <tharvey@gateworks.com>
+Link: https://patch.msgid.link/20250119164219.647059-3-quic_ppranees@quicinc.com
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Stable-dep-of: e225b36f83d7 ("wifi: ath11k: Pass the correct value of each TID during a stop AMPDU session")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp.h | 6 +-
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 117 +++++++++++-------------
+ 2 files changed, 58 insertions(+), 65 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
+index 2f6dd69d3be27..0ce26f76bb815 100644
+--- a/drivers/net/wireless/ath/ath11k/dp.h
++++ b/drivers/net/wireless/ath/ath11k/dp.h
+@@ -1,7 +1,7 @@
+ /* SPDX-License-Identifier: BSD-3-Clause-Clear */
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #ifndef ATH11K_DP_H
+@@ -20,7 +20,6 @@ struct ath11k_ext_irq_grp;
+
+ struct dp_rx_tid {
+ u8 tid;
+- u32 *vaddr;
+ dma_addr_t paddr;
+ u32 size;
+ u32 ba_win_sz;
+@@ -37,6 +36,9 @@ struct dp_rx_tid {
+ /* Timer info related to fragments */
+ struct timer_list frag_timer;
+ struct ath11k_base *ab;
++ u32 *vaddr_unaligned;
++ dma_addr_t paddr_unaligned;
++ u32 unaligned_size;
+ };
+
+ #define DP_REO_DESC_FREE_THRESHOLD 64
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index c37722a727309..411749e8e209e 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
+ /*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
++ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+ #include <linux/ieee80211.h>
+@@ -675,11 +675,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
+ list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
+ list_del(&cmd->list);
+ rx_tid = &cmd->data;
+- if (rx_tid->vaddr) {
+- dma_unmap_single(ab->dev, rx_tid->paddr,
+- rx_tid->size, DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ if (rx_tid->vaddr_unaligned) {
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ kfree(cmd);
+ }
+@@ -689,11 +689,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
+ list_del(&cmd_cache->list);
+ dp->reo_cmd_cache_flush_count--;
+ rx_tid = &cmd_cache->data;
+- if (rx_tid->vaddr) {
+- dma_unmap_single(ab->dev, rx_tid->paddr,
+- rx_tid->size, DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ if (rx_tid->vaddr_unaligned) {
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ kfree(cmd_cache);
+ }
+@@ -708,11 +708,11 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
+ if (status != HAL_REO_CMD_SUCCESS)
+ ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
+ rx_tid->tid, status);
+- if (rx_tid->vaddr) {
+- dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ if (rx_tid->vaddr_unaligned) {
++ dma_free_noncoherent(dp->ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ }
+
+@@ -749,10 +749,10 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
+ if (ret) {
+ ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
+ rx_tid->tid, ret);
+- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+ }
+
+@@ -802,10 +802,10 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
+
+ return;
+ free_desc:
+- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+
+ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
+@@ -831,14 +831,16 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
+ if (ret != -ESHUTDOWN)
+ ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
+ tid, ret);
+- dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ar->ab->dev, rx_tid->unaligned_size,
++ rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+ }
+
+ rx_tid->paddr = 0;
++ rx_tid->paddr_unaligned = 0;
+ rx_tid->size = 0;
++ rx_tid->unaligned_size = 0;
+ }
+
+ static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
+@@ -982,10 +984,9 @@ static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
+ if (!rx_tid->active)
+ goto unlock_exit;
+
+- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+- DMA_BIDIRECTIONAL);
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
++ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size, rx_tid->vaddr_unaligned,
++ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
++ rx_tid->vaddr_unaligned = NULL;
+
+ rx_tid->active = false;
+
+@@ -1000,9 +1001,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_peer *peer;
+ struct dp_rx_tid *rx_tid;
+- u32 hw_desc_sz;
+- u32 *addr_aligned;
+- void *vaddr;
++ u32 hw_desc_sz, *vaddr;
++ void *vaddr_unaligned;
+ dma_addr_t paddr;
+ int ret;
+
+@@ -1050,49 +1050,40 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
+ else
+ hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
+
+- vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
+- if (!vaddr) {
++ rx_tid->unaligned_size = hw_desc_sz + HAL_LINK_DESC_ALIGN - 1;
++ vaddr_unaligned = dma_alloc_noncoherent(ab->dev, rx_tid->unaligned_size, &paddr,
++ DMA_BIDIRECTIONAL, GFP_ATOMIC);
++ if (!vaddr_unaligned) {
+ spin_unlock_bh(&ab->base_lock);
+ return -ENOMEM;
+ }
+
+- addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
+-
+- ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz,
+- ssn, pn_type);
+-
+- paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
+- DMA_BIDIRECTIONAL);
+-
+- ret = dma_mapping_error(ab->dev, paddr);
+- if (ret) {
+- spin_unlock_bh(&ab->base_lock);
+- ath11k_warn(ab, "failed to setup dma map for peer %pM rx tid %d: %d\n",
+- peer_mac, tid, ret);
+- goto err_mem_free;
+- }
+-
+- rx_tid->vaddr = vaddr;
+- rx_tid->paddr = paddr;
++ rx_tid->vaddr_unaligned = vaddr_unaligned;
++ vaddr = PTR_ALIGN(vaddr_unaligned, HAL_LINK_DESC_ALIGN);
++ rx_tid->paddr_unaligned = paddr;
++ rx_tid->paddr = rx_tid->paddr_unaligned + ((unsigned long)vaddr -
++ (unsigned long)rx_tid->vaddr_unaligned);
++ ath11k_hal_reo_qdesc_setup(vaddr, tid, ba_win_sz, ssn, pn_type);
+ rx_tid->size = hw_desc_sz;
+ rx_tid->active = true;
+
++ /* After dma_alloc_noncoherent, vaddr is being modified for reo qdesc setup.
++ * Since these changes are not reflected in the device, driver now needs to
++ * explicitly call dma_sync_single_for_device.
++ */
++ dma_sync_single_for_device(ab->dev, rx_tid->paddr,
++ rx_tid->size,
++ DMA_TO_DEVICE);
+ spin_unlock_bh(&ab->base_lock);
+
+- ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
+- paddr, tid, 1, ba_win_sz);
++ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, rx_tid->paddr,
++ tid, 1, ba_win_sz);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n",
+ peer_mac, tid, ret);
+ ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
+ }
+
+- return ret;
+-
+-err_mem_free:
+- kfree(rx_tid->vaddr);
+- rx_tid->vaddr = NULL;
+-
+ return ret;
+ }
+
+--
+2.53.0
+