From: Sasha Levin Date: Sun, 5 Apr 2026 14:36:17 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v6.6.133~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea65dff534553038c9ebbd9252b45a124ce0ca9e;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-5.10/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..f1f2660748 --- /dev/null +++ b/queue-5.10/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 209d6773af061614cbb6db7dfad59537fb76b96e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-5.10/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..8edf843535 --- /dev/null +++ b/queue-5.10/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From da816bf00f2c5306ad63cb36a6b0a080537e17ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-5.10/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..3b415a298a --- /dev/null +++ b/queue-5.10/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From fdeabe225a6f7c2818836b700f8b126818a3d320 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-5.10/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..6458166dab --- /dev/null +++ b/queue-5.10/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From 568425250eed5841a954c5d34b35930b1aeaa0f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-5.10/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..22567ea18f --- /dev/null +++ b/queue-5.10/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From 18b72e664ddcdd25191d2e5175a9a8d5302c9a07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-5.10/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..e6b4311e6e --- /dev/null +++ b/queue-5.10/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From da7c780b555d1d936d3770eb670640ebdf7394d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-5.10/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..45731bbefd --- /dev/null +++ b/queue-5.10/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From 31d59b97739b0e8b6206b9fb12a3d82beb8ffa6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-5.10/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..a8905eb0dd --- /dev/null +++ b/queue-5.10/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From 94a58b72ba4f9ad28fe9e564131f0e07d45c4685 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-5.10/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..135aac0b5a --- /dev/null +++ b/queue-5.10/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From 0daf0dd2ae4fa22268ab0555793b755d26939b50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-5.10/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..286ac2407d --- /dev/null +++ b/queue-5.10/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From 162a777ed64c0e51babe6048fe83da7b89d890df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-5.10/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..87d9a58fe7 --- /dev/null +++ b/queue-5.10/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From 4e5d6d83ce88929d6cba9f74abf1935b95f560f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-5.10/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..f1c05076b0 --- /dev/null +++ b/queue-5.10/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From 3ffc6b7a0e3bfff237e3e4b519b031b225c95a56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-5.10/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..df11c38e04 --- /dev/null +++ b/queue-5.10/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From 29176ae7a3668dc89dbdd4190ad20fdb584bc7bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-5.10/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..c0b1cca52b --- /dev/null +++ b/queue-5.10/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From 4a37da5626f59556aeb06ce5aab722f7fdb1ae6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-5.10/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..105260c13d --- /dev/null +++ b/queue-5.10/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From 1956761739cc84c79017e9573694740d1408d984 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-5.10/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..1ea0d598a1 --- /dev/null +++ b/queue-5.10/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From d4317049df589e4dfa85f10b128ff4ad0b592869 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-5.10/net-qrtr-add-gfp-flags-parameter-to-qrtr_alloc_ctrl_.patch b/queue-5.10/net-qrtr-add-gfp-flags-parameter-to-qrtr_alloc_ctrl_.patch new file mode 100644 index 0000000000..e8c1bc9678 --- /dev/null +++ b/queue-5.10/net-qrtr-add-gfp-flags-parameter-to-qrtr_alloc_ctrl_.patch @@ -0,0 +1,76 @@ +From 3b3b0162fb2c118af3ef6f9c76b91745f8d7e074 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Nov 2020 18:33:29 +0100 +Subject: net: qrtr: Add GFP flags parameter to qrtr_alloc_ctrl_packet + +From: Loic Poulain + +[ Upstream commit f7dec6cb914c8923808eefc034bba8227a5dfe3a ] + +This will be requested for allocating control packet in atomic context. + +Signed-off-by: Loic Poulain +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2428083101f6 ("net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory leak") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-qrtr-release-distant-nodes-along-the-bridge-node.patch b/queue-5.10/net-qrtr-release-distant-nodes-along-the-bridge-node.patch new file mode 100644 index 0000000000..8bfd62b971 --- /dev/null +++ b/queue-5.10/net-qrtr-release-distant-nodes-along-the-bridge-node.patch @@ -0,0 +1,81 @@ +From 4f40afd8bd45d690421e467296bc7f30e6a19cec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Nov 2020 18:33:30 +0100 +Subject: net: qrtr: Release distant nodes along the bridge node + +From: Loic Poulain + +[ 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 +Signed-off-by: Jakub Kicinski +Stable-dep-of: 2428083101f6 ("net: qrtr: replace qrtr_tx_flow radix_tree with xarray to fix memory leak") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-5.10/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..3b53e5dfdd --- /dev/null +++ b/queue-5.10/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From 5156604c09f0687a285fdce7b9280bb0aebf1100 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-5.10/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..31a3819ea5 --- /dev/null +++ b/queue-5.10/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From ebf7ce3b795025352db25a26358b79fdc3dcf155 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-5.10/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..6eba42d320 --- /dev/null +++ b/queue-5.10/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From e6c2f2b0a138f4b3f4fd585a2bd54c1641e4bf30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-5.10/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..b07479b44b --- /dev/null +++ b/queue-5.10/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From a72d859eca8609cbad9bfd449e6ed0c41ec213fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-5.10/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..4669146366 --- /dev/null +++ b/queue-5.10/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From 900fb13ffc2f014ced61a72ab6eb0d9cfd2302a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-5.10/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..c11193c373 --- /dev/null +++ b/queue-5.10/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 169bf69c5a79b027405c6f62d468c01922d2fcaf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-x25-fix-potential-double-free-of-skb.patch b/queue-5.10/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..162a9a8aa1 --- /dev/null +++ b/queue-5.10/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 1d11677f92f320f10157bf8d85295ac5e60fced4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-5.10/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..a10e67de81 --- /dev/null +++ b/queue-5.10/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From b9152c6df62b06acc6ccfc0fbddf4cdf75d2f42d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-5.10/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..cdb58556c2 --- /dev/null +++ b/queue-5.10/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From 2dbc9afb1b5eb0845d6c4a3a18287fb6512a5537 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-5.10/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..311cfd9448 --- /dev/null +++ b/queue-5.10/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 63ca94754c3d0f9426afce54a52210c79dcb86f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-5.10/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..4179f5c819 --- /dev/null +++ b/queue-5.10/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From e930e2067a8235b76e39a1b80a91317d275ceb27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-5.10/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..1a8310e33c --- /dev/null +++ b/queue-5.10/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From 06a7b19830f6c1330da2303419d4af0706164489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-5.10/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..9037f49d87 --- /dev/null +++ b/queue-5.10/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From 8c849ec772340d039446ca6799a2295fe8431458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-5.10/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..c2790d7855 --- /dev/null +++ b/queue-5.10/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From cbbc2d680cb536fd3b2aebba9974de702e018594 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-5.10/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..243274f33c --- /dev/null +++ b/queue-5.10/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 158d9436d2e55d39bc6b8f816c9dfd3604cd3894 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-5.10/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..efb2927897 --- /dev/null +++ b/queue-5.10/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From c872bc54ebbd8ca141bd8bc107c978d2767f0241 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/objtool-fix-clang-jump-table-detection.patch b/queue-5.10/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..cb99369574 --- /dev/null +++ b/queue-5.10/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From 6f1c973008e7bd4e054012ae5c127f4df3bc3ea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-5.10/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..71c9d4e224 --- /dev/null +++ b/queue-5.10/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From 5b07972c657651efd796f477a2da9cfda99af0de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/series b/queue-5.10/series index ab36fa711e..aef9bdc4f4 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -316,3 +316,40 @@ btrfs-fix-lost-error-when-running-device-stats-on-mu.patch 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 diff --git a/queue-5.10/tg3-fix-race-for-querying-speed-duplex.patch b/queue-5.10/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..73db56548c --- /dev/null +++ b/queue-5.10/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From dd89bb9db624a0cd4c7e56aac6e466e7784c9d5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-5.15/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..0defcba9f2 --- /dev/null +++ b/queue-5.15/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 3ad4e46b4acc6891cfdaf3dc748d603f49b525ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-5.15/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..8e1da4eae0 --- /dev/null +++ b/queue-5.15/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From fd1aa338dcaff471ab3e6cbf79e13edcb63cc708 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-5.15/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..d7094b24d8 --- /dev/null +++ b/queue-5.15/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From e078f7ef5f90db06c38ddaad062db337772d666d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch b/queue-5.15/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch new file mode 100644 index 0000000000..2cd36b0154 --- /dev/null +++ b/queue-5.15/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch @@ -0,0 +1,45 @@ +From ad7cfcbff32f0915894b2b411f201d21588f7b64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:29:22 +0800 +Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers + +From: Qi Tang + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-5.15/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..3a8eda1e61 --- /dev/null +++ b/queue-5.15/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From dfbb411134eb80dd3fce19c81f102359a5c13f16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch b/queue-5.15/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch new file mode 100644 index 0000000000..923da92411 --- /dev/null +++ b/queue-5.15/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch @@ -0,0 +1,196 @@ +From 25b412feb294ed2c4202a883c6e191c62e085869 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:53:46 +0100 +Subject: btrfs: don't take device_list_mutex when querying zone info + +From: Johannes Thumshirn + +[ 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: + + 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 + + +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 +Reviewed-by: Damien Le Moal +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/btrfs-reject-root-items-with-drop_progress-and-zero-.patch b/queue-5.15/btrfs-reject-root-items-with-drop_progress-and-zero-.patch new file mode 100644 index 0000000000..74fdca48fe --- /dev/null +++ b/queue-5.15/btrfs-reject-root-items-with-drop_progress-and-zero-.patch @@ -0,0 +1,114 @@ +From 687de106fe9e0cfb92a3a4d0c895f2be2519ddfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:14:43 +0800 +Subject: btrfs: reject root items with drop_progress and zero drop_level + +From: ZhengYuan Huang + +[ 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 +Signed-off-by: ZhengYuan Huang +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-5.15/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..c0183d4489 --- /dev/null +++ b/queue-5.15/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From e2a15e19d90861bd8e56492526e8e5acc4d56bb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch b/queue-5.15/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch new file mode 100644 index 0000000000..8936b02caa --- /dev/null +++ b/queue-5.15/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch @@ -0,0 +1,42 @@ +From 4672e3353be96d33df6248af28dd3ad0f7a2eeee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:59:55 -0500 +Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix + common property warning + +From: Frank Li + +[ 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) +Signed-off-by: Frank Li +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-5.15/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-5.15/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..c58e746c63 --- /dev/null +++ b/queue-5.15/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From 5dc7bf5682b93f0c1df181959d740b0948c7d34c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-5.15/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..7e03a9b8f2 --- /dev/null +++ b/queue-5.15/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From 0452aeac749403b783438aee1ce088142e9a7868 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-5.15/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..2d3531ee98 --- /dev/null +++ b/queue-5.15/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From 5a2f189c0cc64e4a42f6d291c61f5478783880b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-5.15/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..bdb3cb2370 --- /dev/null +++ b/queue-5.15/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From 843d6604aa7d7551e68a23ad7487fa08d56233f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-5.15/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..6c2ed7556f --- /dev/null +++ b/queue-5.15/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From 050488467d4eda4b4ba2dcc4dac9a9fb136f327c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-5.15/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..1e44e11ca9 --- /dev/null +++ b/queue-5.15/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From d69e520ae1edea69cfdd2c8cd3b8b8742fe916c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch b/queue-5.15/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch new file mode 100644 index 0000000000..c3cc24cd92 --- /dev/null +++ b/queue-5.15/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch @@ -0,0 +1,93 @@ +From c7ae95b865d06dd5c5fd89a423445c1f2d08f4f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 11:22:43 +0200 +Subject: net: hsr: fix VLAN add unwind on slave errors + +From: Luka Gejak + +[ 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 +Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-5.15/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..dcacf298b3 --- /dev/null +++ b/queue-5.15/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From a47b5eb6afc1a29197435feda48f7d3a11c3d300 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-5.15/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..5ed4e751e1 --- /dev/null +++ b/queue-5.15/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From 4dda93635ce6193bf6318ba899dad4a56c54ad6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-5.15/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..d2b38af4ac --- /dev/null +++ b/queue-5.15/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From 3c63912b45574fb232b7166509bfe883e9a602b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-5.15/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..6ac2ce6327 --- /dev/null +++ b/queue-5.15/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From 0092bc9309d7fb72c0323ef6bb756aef09b4cfce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-5.15/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..46f298a61c --- /dev/null +++ b/queue-5.15/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From 3e1f38aef0cde2026a84be00401a1a4204c61aba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-5.15/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-5.15/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..78e1d3ac2d --- /dev/null +++ b/queue-5.15/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From a4b281cbfde451db3c4c4412f59248c01d8bd802 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-5.15/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..9059bf42e1 --- /dev/null +++ b/queue-5.15/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From f0c67743a88f8a0528531ee2573405ed248dfefd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-5.15/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..32dcb4d363 --- /dev/null +++ b/queue-5.15/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From f6a08c5320cd52524b7bf8399b09aa5aa0496c74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-5.15/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..6266774309 --- /dev/null +++ b/queue-5.15/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From bb6c57ed40cdbe5a174253793dd20cd8d42638d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-5.15/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..30762e6685 --- /dev/null +++ b/queue-5.15/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From bcc3e7f5e4fa67565facdecda10d695e919053bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-5.15/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..fa04451104 --- /dev/null +++ b/queue-5.15/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 642543e865ef198c4e77af165c1cef2acf8216b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-x25-fix-potential-double-free-of-skb.patch b/queue-5.15/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..57fdb1d65c --- /dev/null +++ b/queue-5.15/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 4ba757cf45a53a28736facbe732a06e94d72b06f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-5.15/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..5502392254 --- /dev/null +++ b/queue-5.15/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From a2aeb822cfbf8270d270998adc18c319551fc0f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-5.15/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..59b60cea2e --- /dev/null +++ b/queue-5.15/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From 0994b094b7d07614de98402b78c78fc816d56345 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-flowtable-strictly-check-for-maximum-numbe.patch b/queue-5.15/netfilter-flowtable-strictly-check-for-maximum-numbe.patch new file mode 100644 index 0000000000..5d1c3350d2 --- /dev/null +++ b/queue-5.15/netfilter-flowtable-strictly-check-for-maximum-numbe.patch @@ -0,0 +1,504 @@ +From f7e91cef15079a8d6f7ff1c811efcd95fd860fc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:17:09 +0100 +Subject: netfilter: flowtable: strictly check for maximum number of actions + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + #include + ++#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 + diff --git a/queue-5.15/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-5.15/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..0c66f9f87b --- /dev/null +++ b/queue-5.15/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 42dd568a0b9075b44ed7a987e8081f679c056907 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-5.15/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..07297e04e7 --- /dev/null +++ b/queue-5.15/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From 387adf2bfef33a3a32d321c901e754e0f841efd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-5.15/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..a77ca8ce8e --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From fac33d670cf46d4e1cc4a6dcb8049344ca63c9f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-5.15/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..8714d6e927 --- /dev/null +++ b/queue-5.15/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From eb426d853767417edd5c694c8cd992a3ef5cd1d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-5.15/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..9184ffe040 --- /dev/null +++ b/queue-5.15/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From eb977a03ca700909db8f666cd3f4e639efe6f026 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-5.15/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..15bbc4a018 --- /dev/null +++ b/queue-5.15/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 50af1caa7ade2f3336d494d0e6818a7944948250 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-5.15/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..b00053b908 --- /dev/null +++ b/queue-5.15/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From d72c2fb688a5c67f4827b943c3d48ac309a7a7ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/objtool-fix-clang-jump-table-detection.patch b/queue-5.15/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..42d4e59f8b --- /dev/null +++ b/queue-5.15/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From 7e7b43fa4229e1be92f71949b46f3a313cd77eb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-5.15/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..84608e909d --- /dev/null +++ b/queue-5.15/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From f9b5c7238ec1c3c6fc4ef57c2247d0644ecfde18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/series b/queue-5.15/series index 6eb31142df..029c14334b 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -395,3 +395,44 @@ dmaengine-idxd-fix-freeing-the-allocated-ida-too-lat.patch 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 diff --git a/queue-5.15/tg3-fix-race-for-querying-speed-duplex.patch b/queue-5.15/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..bfc3dbbcc2 --- /dev/null +++ b/queue-5.15/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From dd4e7f2d9819b10f99e114d9ee965f5d3db76638 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch b/queue-6.1/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch new file mode 100644 index 0000000000..594c439a7d --- /dev/null +++ b/queue-6.1/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch @@ -0,0 +1,113 @@ +From 03a6ef544d77dc0bee5c19f3a63a2edcba6f8857 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/asoc-ep93xx-i2s-move-enable-call-to-startup-callback.patch b/queue-6.1/asoc-ep93xx-i2s-move-enable-call-to-startup-callback.patch new file mode 100644 index 0000000000..d114ed92f5 --- /dev/null +++ b/queue-6.1/asoc-ep93xx-i2s-move-enable-call-to-startup-callback.patch @@ -0,0 +1,93 @@ +From 90bd0d291f54fc040680b5cd5accd7ee87fa92a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Apr 2023 00:39:00 +0200 +Subject: ASoC: ep93xx: i2s: move enable call to startup callback + +From: Alexander Sverdlin + +[ 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 +Link: https://lore.kernel.org/r/20230410223902.2321834-2-alexander.sverdlin@gmail.com +Signed-off-by: Mark Brown +Stable-dep-of: 622363757b22 ("ASoC: ep93xx: Fix unchecked clk_prepare_enable() and add rollback on failure") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-6.1/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..681cc0e2d6 --- /dev/null +++ b/queue-6.1/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 72318dd696338010186f713e64b250d60da05e9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch b/queue-6.1/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch new file mode 100644 index 0000000000..752d65c883 --- /dev/null +++ b/queue-6.1/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch @@ -0,0 +1,93 @@ +From c3906212aa6ce12a00686db1eaf57d27ba4f616a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-6.1/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..c80664e616 --- /dev/null +++ b/queue-6.1/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From 6928569040cf96ade491c554da105e4596b9090a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch b/queue-6.1/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch new file mode 100644 index 0000000000..61cf219992 --- /dev/null +++ b/queue-6.1/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch @@ -0,0 +1,68 @@ +From f11d56f397bb380a4ebb14fad0f6935983b2349c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 22:25:26 +0800 +Subject: Bluetooth: MGMT: validate mesh send advertising payload length + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch b/queue-6.1/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch new file mode 100644 index 0000000000..83013083f9 --- /dev/null +++ b/queue-6.1/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch @@ -0,0 +1,144 @@ +From 454c8b807f97ea86e701dc2b0c15df1fea68aa57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 23:16:45 +0800 +Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect() + +From: Cen Zhang + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-6.1/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..6b225c4771 --- /dev/null +++ b/queue-6.1/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From 27a7ebc26f9cf2ac337b63ad6e521eb8ffdde08f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch b/queue-6.1/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch new file mode 100644 index 0000000000..5eb86c7ee4 --- /dev/null +++ b/queue-6.1/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch @@ -0,0 +1,45 @@ +From 5decedb24d276d397b09e4e0ae4fe295b18981d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:29:22 +0800 +Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers + +From: Qi Tang + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-6.1/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..d015ab884b --- /dev/null +++ b/queue-6.1/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From ff9576b115d71c5563463a11efdf87a779797927 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch b/queue-6.1/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch new file mode 100644 index 0000000000..dfccdfdbe2 --- /dev/null +++ b/queue-6.1/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch @@ -0,0 +1,196 @@ +From 8cdee1a2fe6cedda04c4298efcda174b0e960f9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:53:46 +0100 +Subject: btrfs: don't take device_list_mutex when querying zone info + +From: Johannes Thumshirn + +[ 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: + + 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 + + +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 +Reviewed-by: Damien Le Moal +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/btrfs-reject-root-items-with-drop_progress-and-zero-.patch b/queue-6.1/btrfs-reject-root-items-with-drop_progress-and-zero-.patch new file mode 100644 index 0000000000..e93c58ba30 --- /dev/null +++ b/queue-6.1/btrfs-reject-root-items-with-drop_progress-and-zero-.patch @@ -0,0 +1,114 @@ +From 3cd9bede1e55fde8a6ec4273e2b6662c776b36c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:14:43 +0800 +Subject: btrfs: reject root items with drop_progress and zero drop_level + +From: ZhengYuan Huang + +[ 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 +Signed-off-by: ZhengYuan Huang +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-6.1/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..9d8caeee7c --- /dev/null +++ b/queue-6.1/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From ed78013f42f94885fd2cb2412a4cce612d6d5464 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch b/queue-6.1/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch new file mode 100644 index 0000000000..52a162c23f --- /dev/null +++ b/queue-6.1/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch @@ -0,0 +1,42 @@ +From 437c6f4e7e6db38559341da3b7ec2e1bafb3514a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:59:55 -0500 +Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix + common property warning + +From: Frank Li + +[ 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) +Signed-off-by: Frank Li +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.1/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-6.1/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..f3aa526f78 --- /dev/null +++ b/queue-6.1/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From 374ed0982e5b8926217a46bf44ee5dafaf0733b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-6.1/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..4ec674f991 --- /dev/null +++ b/queue-6.1/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From bc8c571e94fea86cfc231b411c204503818e8ee3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch b/queue-6.1/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch new file mode 100644 index 0000000000..7facfd90f7 --- /dev/null +++ b/queue-6.1/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch @@ -0,0 +1,58 @@ +From 5b387b1eeabdbdc6c6db3d4a0bc43266690255a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 13:32:11 +0900 +Subject: i2c: tegra: Don't mark devices with pins as IRQ safe + +From: Mikko Perttunen + +[ 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 +Reported-by: Russell King +Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/ +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-6.1/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..8f3a533099 --- /dev/null +++ b/queue-6.1/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From 4a85cc38b0e31d3286e6cb6057de04ef4115f614 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-6.1/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..0461a3893c --- /dev/null +++ b/queue-6.1/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From ead7f65444831fb88b26e3a07514db91f29d8bb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-6.1/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..db9e669f64 --- /dev/null +++ b/queue-6.1/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From 85a93dc3b906b6800d2046b9b2560561bd4c97a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-6.1/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..8359bbd186 --- /dev/null +++ b/queue-6.1/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From 928a302093f51fdd57c59fb8836d73165c728b5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch b/queue-6.1/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch new file mode 100644 index 0000000000..a11a403f79 --- /dev/null +++ b/queue-6.1/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch @@ -0,0 +1,93 @@ +From d900e9e5ed8fdf2b90faa41936b9f8bf2de5c84f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 11:22:43 +0200 +Subject: net: hsr: fix VLAN add unwind on slave errors + +From: Luka Gejak + +[ 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 +Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-6.1/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..6244799163 --- /dev/null +++ b/queue-6.1/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From b70c88d45d932382c1ce5d07dab68825583c30a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch b/queue-6.1/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch new file mode 100644 index 0000000000..4666c142a2 --- /dev/null +++ b/queue-6.1/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch @@ -0,0 +1,54 @@ +From e8b1d08e3a81101fd20dd3ff9f16b200daae6fde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 15:41:52 +0800 +Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Justin Iurman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-6.1/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..52187a164f --- /dev/null +++ b/queue-6.1/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From c3637b46ce6736b8c86495fbdb2c4e376d6d0a11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-6.1/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..6205088eef --- /dev/null +++ b/queue-6.1/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From 851bfcf116d0a726a9f1be90186c4b5ec3b13351 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-6.1/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..c285ef6dc4 --- /dev/null +++ b/queue-6.1/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From d61a14cfd2ba39ef3432618e21deeb68309a7efc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-6.1/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..f3814774be --- /dev/null +++ b/queue-6.1/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From 28425c78523dbeb2c52a6c68d29c98ee88968ff1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.1/net-mlx5-lag-check-for-lag-device-before-creating-de.patch b/queue-6.1/net-mlx5-lag-check-for-lag-device-before-creating-de.patch new file mode 100644 index 0000000000..ba2e31ef40 --- /dev/null +++ b/queue-6.1/net-mlx5-lag-check-for-lag-device-before-creating-de.patch @@ -0,0 +1,52 @@ +From eefc990784ed96e56e7f9646994a251e38e84c5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:13 +0300 +Subject: net/mlx5: lag: Check for LAG device before creating debugfs + +From: Shay Drory + +[ 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 +Reviewed-by: Mark Bloch +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-6.1/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..85033f7494 --- /dev/null +++ b/queue-6.1/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From 5bf959682b490d77f677b105039c4ac3e5ee6476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-6.1/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..0b4fafbc8a --- /dev/null +++ b/queue-6.1/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From cb2883be8751f8ee3961c6041606a1e5f288ecf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-6.1/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..8592a8978e --- /dev/null +++ b/queue-6.1/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From f5d234bda3aac8c6482daca47e4a6c8cacca1a2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-6.1/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..e56988b0f8 --- /dev/null +++ b/queue-6.1/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From f712d8cae8b469ebbafd34606eee5aa39d66bd1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-6.1/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..598ed9e389 --- /dev/null +++ b/queue-6.1/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From 35d7c95c014db5e3cf6004c63ba8e871d472719b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-6.1/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..3db8a1c53c --- /dev/null +++ b/queue-6.1/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 275f6add54d0eecdfa24d15b3f88f1681b4dcded Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-x25-fix-potential-double-free-of-skb.patch b/queue-6.1/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..02a5e8cb5f --- /dev/null +++ b/queue-6.1/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 475be12b055baa65d797bb8b2f89bd845741c297 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-6.1/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..ba767821e3 --- /dev/null +++ b/queue-6.1/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From 9e4ececca809a76ac6127676a38e2716ca15a373 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch b/queue-6.1/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch new file mode 100644 index 0000000000..d199455267 --- /dev/null +++ b/queue-6.1/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch @@ -0,0 +1,168 @@ +From 63c1b8bf9c8b8172a70416cfd547dc69e8cee479 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 11:26:22 +0200 +Subject: netfilter: ctnetlink: ignore explicit helper on new expectations + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-6.1/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..74fb658020 --- /dev/null +++ b/queue-6.1/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From df6600d14225ccd6e4cf001adef9b2ab1f7886cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-flowtable-strictly-check-for-maximum-numbe.patch b/queue-6.1/netfilter-flowtable-strictly-check-for-maximum-numbe.patch new file mode 100644 index 0000000000..b50ea7a481 --- /dev/null +++ b/queue-6.1/netfilter-flowtable-strictly-check-for-maximum-numbe.patch @@ -0,0 +1,504 @@ +From 833eb354987976f55e85145d3a1a3b38cea8ad46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:17:09 +0100 +Subject: netfilter: flowtable: strictly check for maximum number of actions + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + #include + ++#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 + diff --git a/queue-6.1/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-6.1/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..8818d14884 --- /dev/null +++ b/queue-6.1/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 3cce5bf4404cdcf36a1e4ef6f68fe70b5d30c822 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-nf_conntrack_expect-honor-expectation-help.patch b/queue-6.1/netfilter-nf_conntrack_expect-honor-expectation-help.patch new file mode 100644 index 0000000000..ad877c9526 --- /dev/null +++ b/queue-6.1/netfilter-nf_conntrack_expect-honor-expectation-help.patch @@ -0,0 +1,212 @@ +From ddd2b5d7e1fd378cb2ac0f7c92cc894e467e29b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:02 +0100 +Subject: netfilter: nf_conntrack_expect: honor expectation helper field + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch b/queue-6.1/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch new file mode 100644 index 0000000000..5415a7fcb9 --- /dev/null +++ b/queue-6.1/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch @@ -0,0 +1,158 @@ +From 044f6016db39f6807593ef4d8302d5e40ee914db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 22:39:55 +0100 +Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-nf_conntrack_expect-use-expect-helper.patch b/queue-6.1/netfilter-nf_conntrack_expect-use-expect-helper.patch new file mode 100644 index 0000000000..00f9564b81 --- /dev/null +++ b/queue-6.1/netfilter-nf_conntrack_expect-use-expect-helper.patch @@ -0,0 +1,148 @@ +From 430196a72ec1653eaddcec74b741abe155d3bcd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:03 +0100 +Subject: netfilter: nf_conntrack_expect: use expect->helper + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-6.1/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..689a18159f --- /dev/null +++ b/queue-6.1/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From ec10e49b61f926112db2f5191bde3f10d62fcd5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-6.1/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..58904c78a3 --- /dev/null +++ b/queue-6.1/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From d6e8713a804b32d94d3f3e53ee0ba9bf70b539df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-6.1/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..71dda53786 --- /dev/null +++ b/queue-6.1/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From 2056d1e746f1adc8537c4ea0b0d1b80d0be352d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-reorder-fields-in-struct-nf_conntrack_expe.patch b/queue-6.1/netfilter-reorder-fields-in-struct-nf_conntrack_expe.patch new file mode 100644 index 0000000000..fc6bd86f71 --- /dev/null +++ b/queue-6.1/netfilter-reorder-fields-in-struct-nf_conntrack_expe.patch @@ -0,0 +1,63 @@ +From 5120a59cf7e50fdb11738c032a5e084bf39f13c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 May 2023 18:53:14 +0200 +Subject: netfilter: Reorder fields in 'struct nf_conntrack_expect' + +From: Christophe JAILLET + +[ 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 +Reviewed-by: Simon Horman +Signed-off-by: Florian Westphal +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-6.1/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..2917f50d2c --- /dev/null +++ b/queue-6.1/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From 7bc6ae672a42c3b6b0a4d931edd579fca0231f01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-6.1/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..c139bbbd0d --- /dev/null +++ b/queue-6.1/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 6474737229ed7cc3cab085b13b026473e75658bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-6.1/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..7cb764a02d --- /dev/null +++ b/queue-6.1/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From d34eb93db1437b75bc033c7dd40c7f2d44ab5c26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/objtool-fix-clang-jump-table-detection.patch b/queue-6.1/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..c7b235f730 --- /dev/null +++ b/queue-6.1/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From 18b715effb94aef65e89e0242837524c14ebd00f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-6.1/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..b25fa2de4c --- /dev/null +++ b/queue-6.1/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From d26d3dbaf8007ab769d6efea8372701eb664860b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/series b/queue-6.1/series index 5ec83ce28c..c467381eaa 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -134,3 +134,58 @@ 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 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 diff --git a/queue-6.1/tg3-fix-race-for-querying-speed-duplex.patch b/queue-6.1/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..73d78b62ff --- /dev/null +++ b/queue-6.1/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From 6b6e24f99f95b3a93248acef9c3ca14df25b8e23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/tg3-replace-placeholder-mac-address-with-device-prop.patch b/queue-6.1/tg3-replace-placeholder-mac-address-with-device-prop.patch new file mode 100644 index 0000000000..c1a6a5312b --- /dev/null +++ b/queue-6.1/tg3-replace-placeholder-mac-address-with-device-prop.patch @@ -0,0 +1,69 @@ +From a0114f9c65462ebb298fc89d1f4b148a03b0dea9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 03:24:30 +0530 +Subject: tg3: replace placeholder MAC address with device property + +From: Paul SAGE + +[ 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 + +Co-developed-by: Vincent MORVAN +Signed-off-by: Vincent MORVAN +Signed-off-by: Paul SAGE +Signed-off-by: Atharva Tiwari +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/arm64-scs-fix-handling-of-advance_loc4.patch b/queue-6.12/arm64-scs-fix-handling-of-advance_loc4.patch new file mode 100644 index 0000000000..d1a3be882e --- /dev/null +++ b/queue-6.12/arm64-scs-fix-handling-of-advance_loc4.patch @@ -0,0 +1,43 @@ +From 702437757a174ee29820e753770c63cffd39f2f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 14:44:28 +0100 +Subject: arm64/scs: Fix handling of advance_loc4 + +From: Pepper Gray + +[ 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 +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch b/queue-6.12/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch new file mode 100644 index 0000000000..792b825e80 --- /dev/null +++ b/queue-6.12/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch @@ -0,0 +1,113 @@ +From b9fbe56c91fa2b60ca6362b6c065a8268e9685b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch b/queue-6.12/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch new file mode 100644 index 0000000000..e0167c5c64 --- /dev/null +++ b/queue-6.12/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch @@ -0,0 +1,57 @@ +From 278a42bbcd2d49d7e11f4ef07415046f6322cc02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:15:21 +0000 +Subject: ASoC: Intel: boards: fix unmet dependency on PINCTRL + +From: Julian Braha + +[ 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 +Acked-by: Arnd Bergmann +Link: https://patch.msgid.link/20260325001522.1727678-1-julianbraha@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-6.12/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..652d3e13d9 --- /dev/null +++ b/queue-6.12/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 770c971a830757fd1a6d7c98882ce2551609c314 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch b/queue-6.12/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch new file mode 100644 index 0000000000..747c907099 --- /dev/null +++ b/queue-6.12/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch @@ -0,0 +1,55 @@ +From b43ebd0f1c52b6ff4cef815334da6336c752c425 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:43:01 +0300 +Subject: Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync + +From: Pauli Virtanen + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch b/queue-6.12/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch new file mode 100644 index 0000000000..b0022e6c41 --- /dev/null +++ b/queue-6.12/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch @@ -0,0 +1,93 @@ +From 94b73c852ddf773b3806ec9a2c1754dbdec39ba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch b/queue-6.12/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch new file mode 100644 index 0000000000..9f046a028f --- /dev/null +++ b/queue-6.12/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch @@ -0,0 +1,55 @@ +From 63f1d1c753a7e0ca3b29a42048ee8a515acfc1dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-6.12/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..6706c27715 --- /dev/null +++ b/queue-6.12/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From a8fcd4792c93db61e8e1366e41371c897702fdb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch b/queue-6.12/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch new file mode 100644 index 0000000000..18b005a384 --- /dev/null +++ b/queue-6.12/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch @@ -0,0 +1,68 @@ +From ed5a278c34e586796aa179f743dde44c5c7849f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 22:25:26 +0800 +Subject: Bluetooth: MGMT: validate mesh send advertising payload length + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch b/queue-6.12/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch new file mode 100644 index 0000000000..0676820d3b --- /dev/null +++ b/queue-6.12/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch @@ -0,0 +1,144 @@ +From 93ea7cf32176f005ddac7d3ec65c28d9ca5690b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 23:16:45 +0800 +Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect() + +From: Cen Zhang + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-allocate-backing-store-memory-for-fw-trace-l.patch b/queue-6.12/bnxt_en-allocate-backing-store-memory-for-fw-trace-l.patch new file mode 100644 index 0000000000..0aed72c58f --- /dev/null +++ b/queue-6.12/bnxt_en-allocate-backing-store-memory-for-fw-trace-l.patch @@ -0,0 +1,163 @@ +From 2749c932f0b429ee0a1746832aa8b82817f2129d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Nov 2024 07:14:31 -0800 +Subject: bnxt_en: Allocate backing store memory for FW trace logs + +From: Shruti Parab + +[ 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 +Signed-off-by: Shruti Parab +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20241115151438.550106-6-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-do-not-free-fw-log-context-memory.patch b/queue-6.12/bnxt_en-do-not-free-fw-log-context-memory.patch new file mode 100644 index 0000000000..9f7e30316d --- /dev/null +++ b/queue-6.12/bnxt_en-do-not-free-fw-log-context-memory.patch @@ -0,0 +1,157 @@ +From 6718d9e19aece13ba758b7029fe3f9f8c8643e7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Nov 2024 07:14:33 -0800 +Subject: bnxt_en: Do not free FW log context memory + +From: Hongguang Gao + +[ 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 +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20241115151438.550106-8-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-manage-the-fw-trace-context-memory.patch b/queue-6.12/bnxt_en-manage-the-fw-trace-context-memory.patch new file mode 100644 index 0000000000..a7925e4ccc --- /dev/null +++ b/queue-6.12/bnxt_en-manage-the-fw-trace-context-memory.patch @@ -0,0 +1,178 @@ +From 25947381eec5795cce4283b58dcca204d3eaf98d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Nov 2024 07:14:32 -0800 +Subject: bnxt_en: Manage the FW trace context memory + +From: Shruti Parab + +[ 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 +Signed-off-by: Shruti Parab +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20241115151438.550106-7-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch b/queue-6.12/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch new file mode 100644 index 0000000000..878d7ec5b1 --- /dev/null +++ b/queue-6.12/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch @@ -0,0 +1,48 @@ +From f033e66fc0b303a45ceb664208b4724f455fc08c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Pavan Chebbi +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260331065138.948205-4-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-set-backing-store-type-from-query-type.patch b/queue-6.12/bnxt_en-set-backing-store-type-from-query-type.patch new file mode 100644 index 0000000000..ca8ddd9fe9 --- /dev/null +++ b/queue-6.12/bnxt_en-set-backing-store-type-from-query-type.patch @@ -0,0 +1,76 @@ +From fc13ea785682358c9537f610e344b10cb3c056a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 07:43:56 +0800 +Subject: bnxt_en: set backing store type from query type + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Michael Chan +Tested-by: Michael Chan +Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bnxt_en-update-firmware-interface-spec-to-1.10.3.85.patch b/queue-6.12/bnxt_en-update-firmware-interface-spec-to-1.10.3.85.patch new file mode 100644 index 0000000000..1ff00901d9 --- /dev/null +++ b/queue-6.12/bnxt_en-update-firmware-interface-spec-to-1.10.3.85.patch @@ -0,0 +1,350 @@ +From 390ba44d3b6f35bddb17e6e0a7ccf30fec634256 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Nov 2024 07:14:27 -0800 +Subject: bnxt_en: Update firmware interface spec to 1.10.3.85 + +From: Michael Chan + +[ 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 +Reviewed-by: Kalesh AP +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20241115151438.550106-2-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-6.12/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..f8a9abbae8 --- /dev/null +++ b/queue-6.12/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From f3e41d8bfc1b096b919c4b301a996347d819f23f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch b/queue-6.12/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch new file mode 100644 index 0000000000..53bf830c64 --- /dev/null +++ b/queue-6.12/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch @@ -0,0 +1,45 @@ +From edd3edc6f7e961c35c7555dde401154264eaf398 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:29:22 +0800 +Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers + +From: Qi Tang + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch b/queue-6.12/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch new file mode 100644 index 0000000000..325f6f5339 --- /dev/null +++ b/queue-6.12/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch @@ -0,0 +1,145 @@ +From b2714984a4e532f2e6d33dac149a8a6c93054a57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-6.12/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..f10258628e --- /dev/null +++ b/queue-6.12/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From d38740294b73d082bbcbc6244b4f4f59351d6e7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch b/queue-6.12/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch new file mode 100644 index 0000000000..667a6a6723 --- /dev/null +++ b/queue-6.12/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch @@ -0,0 +1,196 @@ +From c3ebc1a3f8e1df1b053dca4f72ae4af18a42166f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:53:46 +0100 +Subject: btrfs: don't take device_list_mutex when querying zone info + +From: Johannes Thumshirn + +[ 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: + + 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 + + +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 +Reviewed-by: Damien Le Moal +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/btrfs-reject-root-items-with-drop_progress-and-zero-.patch b/queue-6.12/btrfs-reject-root-items-with-drop_progress-and-zero-.patch new file mode 100644 index 0000000000..e962e91d27 --- /dev/null +++ b/queue-6.12/btrfs-reject-root-items-with-drop_progress-and-zero-.patch @@ -0,0 +1,114 @@ +From 036d74c03e59ac8db079e9d6f6b9c8900a9756cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:14:43 +0800 +Subject: btrfs: reject root items with drop_progress and zero drop_level + +From: ZhengYuan Huang + +[ 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 +Signed-off-by: ZhengYuan Huang +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch b/queue-6.12/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch new file mode 100644 index 0000000000..fc5148c7a5 --- /dev/null +++ b/queue-6.12/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch @@ -0,0 +1,147 @@ +From 16aec98240998e5e50b56ddb8b772da2fbadb0de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 16:08:53 +0000 +Subject: btrfs: reserve enough transaction items for qgroup ioctls + +From: Filipe Manana + +[ 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] + [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] + [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 +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-6.12/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..7fe47a5be9 --- /dev/null +++ b/queue-6.12/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From 09894ce72fbbfcac92727ebc35b0ff4827064003 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch b/queue-6.12/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch new file mode 100644 index 0000000000..5436806c31 --- /dev/null +++ b/queue-6.12/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch @@ -0,0 +1,49 @@ +From 6510646894f03afac4e828a28aacababdede4a7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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 +Signed-off-by: Horia Geantă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/crypto-caam-fix-overflow-on-long-hmac-keys.patch b/queue-6.12/crypto-caam-fix-overflow-on-long-hmac-keys.patch new file mode 100644 index 0000000000..5ef3be86e1 --- /dev/null +++ b/queue-6.12/crypto-caam-fix-overflow-on-long-hmac-keys.patch @@ -0,0 +1,48 @@ +From f5f523a227b76d5438677c8b144ff9747752f2f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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ă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch b/queue-6.12/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch new file mode 100644 index 0000000000..6b35295685 --- /dev/null +++ b/queue-6.12/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch @@ -0,0 +1,42 @@ +From 48fd9ee11b6b778864b811a18e14f8d9cc07d651 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:59:55 -0500 +Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix + common property warning + +From: Frank Li + +[ 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) +Signed-off-by: Frank Li +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.12/eth-fbnic-account-for-page-fragments-when-updating-b.patch b/queue-6.12/eth-fbnic-account-for-page-fragments-when-updating-b.patch new file mode 100644 index 0000000000..6f82281e73 --- /dev/null +++ b/queue-6.12/eth-fbnic-account-for-page-fragments-when-updating-b.patch @@ -0,0 +1,62 @@ +From f6c23ec1550fa3f9a10760a84e15501aa694d25d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:51:22 -0700 +Subject: eth: fbnic: Account for page fragments when updating BDQ tail + +From: Dimitri Daskalakis + +[ 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 +Link: https://patch.msgid.link/20260324195123.3486219-2-dimitri.daskalakis1@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch b/queue-6.12/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch new file mode 100644 index 0000000000..f0b1ed6ce4 --- /dev/null +++ b/queue-6.12/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch @@ -0,0 +1,39 @@ +From 6b0d8919c38c9c0793681fc2f113f4aefbda1726 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 20:19:33 +0100 +Subject: HID: logitech-hidpp: Enable MX Master 4 over bluetooth + +From: Adrian Freund + +[ 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 +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch b/queue-6.12/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch new file mode 100644 index 0000000000..2651ef6883 --- /dev/null +++ b/queue-6.12/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch @@ -0,0 +1,56 @@ +From 8d2118cf4d85428cbe9fab70896eb25a1d76cf89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Günther Noack +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-6.12/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..fee6778bd7 --- /dev/null +++ b/queue-6.12/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From 7b467e2ac1b850e2fd47e8f28164b1bb18e4bba7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-6.12/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..049d275aca --- /dev/null +++ b/queue-6.12/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From b3f22fa417be9611dec5cd22de757c775628711e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch b/queue-6.12/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch new file mode 100644 index 0000000000..0a1dfe406a --- /dev/null +++ b/queue-6.12/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch @@ -0,0 +1,58 @@ +From e448303a5a42e279acb249dced824e2129349883 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 13:32:11 +0900 +Subject: i2c: tegra: Don't mark devices with pins as IRQ safe + +From: Mikko Perttunen + +[ 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 +Reported-by: Russell King +Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/ +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-6.12/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..92c83b6ddf --- /dev/null +++ b/queue-6.12/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From 1b49143271fba772b111f1daef3f0cc5dfb3847c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-6.12/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..4c3ba45416 --- /dev/null +++ b/queue-6.12/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From 6dc20d7258ba7506b70af613471fe097ebd5e2b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-6.12/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..6b3da45041 --- /dev/null +++ b/queue-6.12/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From 36bcc65a567db2b6a7fdf894493a0dec5bf80bfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-6.12/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..45a018e001 --- /dev/null +++ b/queue-6.12/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From c8027a5ccc36965ede8e4e95efaab75394277ff6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch b/queue-6.12/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch new file mode 100644 index 0000000000..dfd1349253 --- /dev/null +++ b/queue-6.12/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch @@ -0,0 +1,67 @@ +From 85dbe88a74fc5aa0c3d10b5e45aa525be6b72a50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260327-airoha_qdma_cleanup_rx_queue-fix-v1-1-369d6ab1511a@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch b/queue-6.12/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch new file mode 100644 index 0000000000..82decec90f --- /dev/null +++ b/queue-6.12/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch @@ -0,0 +1,42 @@ +From b135fa59e132a4101a90668c05580c12afb28dbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:52:32 +0800 +Subject: net: enetc: check whether the RSS algorithm is Toeplitz + +From: Wei Fang + +[ 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 +Reviewed-by: Clark Wang +Reviewed-by: Claudiu Manoil +Link: https://patch.msgid.link/20260326075233.3628047-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch b/queue-6.12/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch new file mode 100644 index 0000000000..5044093fba --- /dev/null +++ b/queue-6.12/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch @@ -0,0 +1,50 @@ +From 095b9576e0755474f0e64224978ea01eaa074f58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:32:30 +0100 +Subject: net: fec: fix the PTP periodic output sysfs interface + +From: Buday Csaba + +[ 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 +Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch b/queue-6.12/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch new file mode 100644 index 0000000000..f258ffb4b9 --- /dev/null +++ b/queue-6.12/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch @@ -0,0 +1,93 @@ +From dc1f19d0157b4913d509f8b361de3f709b748bbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 11:22:43 +0200 +Subject: net: hsr: fix VLAN add unwind on slave errors + +From: Luka Gejak + +[ 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 +Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-introduce-mangleid_features.patch b/queue-6.12/net-introduce-mangleid_features.patch new file mode 100644 index 0000000000..e00b3c0297 --- /dev/null +++ b/queue-6.12/net-introduce-mangleid_features.patch @@ -0,0 +1,92 @@ +From 87993bc3daa75d1d4036a78542b2cca63df52576 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:11:27 +0100 +Subject: net: introduce mangleid_features + +From: Paolo Abeni + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/5a7cdaeea40b0a29b88e525b6c942d73ed3b8ce7.1769011015.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: ddc748a391dd ("net: use skb_header_pointer() for TCPv4 GSO frag_off check") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-6.12/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..3f1fbec3f3 --- /dev/null +++ b/queue-6.12/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From 49bf4797b12c23dfd46aa6db9e5d74aa5803663c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch b/queue-6.12/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch new file mode 100644 index 0000000000..db37b442a1 --- /dev/null +++ b/queue-6.12/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch @@ -0,0 +1,54 @@ +From bfc7052b2d560dacabc76d23852a38ebeb5b3a61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 15:41:52 +0800 +Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Justin Iurman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-6.12/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..6d9cf4c0cb --- /dev/null +++ b/queue-6.12/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From 73a70322e149bea35391b9454c62896ec8423ab3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-6.12/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..111572b09c --- /dev/null +++ b/queue-6.12/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From 6429cf407f17f222949ff5c18558d4497c96b842 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-6.12/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..1571ab4a5e --- /dev/null +++ b/queue-6.12/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From 790701f7bcdb892d6cb704ca9c04a278b134b219 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-6.12/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..2fe6f5599b --- /dev/null +++ b/queue-6.12/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From d2b72d3891542c31d8f77a40be7ae3bf0db0b69d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.12/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch b/queue-6.12/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch new file mode 100644 index 0000000000..9b493831ef --- /dev/null +++ b/queue-6.12/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch @@ -0,0 +1,86 @@ +From 545d6842b908bfb4c2636c16ebf170fba64b1e00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:15 +0300 +Subject: net/mlx5: Fix switchdev mode rollback in case of failure + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-4-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-mlx5-lag-check-for-lag-device-before-creating-de.patch b/queue-6.12/net-mlx5-lag-check-for-lag-device-before-creating-de.patch new file mode 100644 index 0000000000..b1866d550b --- /dev/null +++ b/queue-6.12/net-mlx5-lag-check-for-lag-device-before-creating-de.patch @@ -0,0 +1,52 @@ +From 457522e235e1bd1389e5f5fb1eb9726db98d9b60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:13 +0300 +Subject: net/mlx5: lag: Check for LAG device before creating debugfs + +From: Shay Drory + +[ 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 +Reviewed-by: Mark Bloch +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-6.12/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..a3bbd28ce5 --- /dev/null +++ b/queue-6.12/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From 16e38c5814b9232075f1162bdf87d342a2fbd4e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-6.12/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..8b071d22f9 --- /dev/null +++ b/queue-6.12/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From 7cf9b415600e47ab9eab394ddc2f658597ca303c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-6.12/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..7cc36f73d4 --- /dev/null +++ b/queue-6.12/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From 719faf09e927550d7b5660b480d9a06f33110a4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-6.12/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..b4efc46304 --- /dev/null +++ b/queue-6.12/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From 23d33246dab73a83b185367d832600c722c3581f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-6.12/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..34f0abbc80 --- /dev/null +++ b/queue-6.12/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From d0b820648b369765b7b5eb9b16806d2b97d07cfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch b/queue-6.12/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch new file mode 100644 index 0000000000..5f13f88fa8 --- /dev/null +++ b/queue-6.12/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch @@ -0,0 +1,57 @@ +From 1e8ccd1a1f28be7c39d54208692b1ec39274a235 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Juefei Pu +Signed-off-by: Yuan Tan +Signed-off-by: Xin Liu +Signed-off-by: Yuhang Zheng +Signed-off-by: Yucheng Lu +Reviewed-by: Stephen Hemminger +Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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<data[get_random_u32_below(skb_headlen(skb))] ^= ++ 1 << get_random_u32_below(8); + } + + if (unlikely(q->t_len >= sch->limit)) { +-- +2.53.0 + diff --git a/queue-6.12/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch b/queue-6.12/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch new file mode 100644 index 0000000000..80cc657c47 --- /dev/null +++ b/queue-6.12/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch @@ -0,0 +1,65 @@ +From 53f215d2bbebbaa9e8015f905c276b33bf6c03fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260326122038.2489589-1-kabel@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch b/queue-6.12/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch new file mode 100644 index 0000000000..8dd707ff02 --- /dev/null +++ b/queue-6.12/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch @@ -0,0 +1,62 @@ +From 78512bd234f0698948500d32cb06473ce4b8f61a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 23:35:07 +0800 +Subject: net: use skb_header_pointer() for TCPv4 GSO frag_off check + +From: Guoyu Su + +[ 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 +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260327153507.39742-1-yss2813483011xxl@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-6.12/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..69c811465e --- /dev/null +++ b/queue-6.12/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 3019c41bdbc350ca81e500500db00f620d2e2aeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-x25-fix-potential-double-free-of-skb.patch b/queue-6.12/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..8b7bb891ba --- /dev/null +++ b/queue-6.12/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 9e19a5b40dad849c55a412e088ddf5e83f310ede Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-6.12/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..5d515c0dc2 --- /dev/null +++ b/queue-6.12/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From 2e816a6314cb3feef543e038d82ad575cc5d8609 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch b/queue-6.12/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch new file mode 100644 index 0000000000..ed8e6b6406 --- /dev/null +++ b/queue-6.12/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch @@ -0,0 +1,168 @@ +From 397a7fa2536b5c21f0c33207030177b572db6b8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 11:26:22 +0200 +Subject: netfilter: ctnetlink: ignore explicit helper on new expectations + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-6.12/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..94c9f4f8f4 --- /dev/null +++ b/queue-6.12/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From 78e838fd0862ff628d1fc98101f4d4ea67f75479 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-flowtable-strictly-check-for-maximum-numbe.patch b/queue-6.12/netfilter-flowtable-strictly-check-for-maximum-numbe.patch new file mode 100644 index 0000000000..907d70d4fb --- /dev/null +++ b/queue-6.12/netfilter-flowtable-strictly-check-for-maximum-numbe.patch @@ -0,0 +1,504 @@ +From 149a8451eb2b1ec0d7d2e234ba246def05c06b88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:17:09 +0100 +Subject: netfilter: flowtable: strictly check for maximum number of actions + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + #include + ++#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 + diff --git a/queue-6.12/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-6.12/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..bae18d75cf --- /dev/null +++ b/queue-6.12/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 0f7c201d13f38724cd92756fd15ddf8373281ef9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-nf_conntrack_expect-honor-expectation-help.patch b/queue-6.12/netfilter-nf_conntrack_expect-honor-expectation-help.patch new file mode 100644 index 0000000000..54d458d094 --- /dev/null +++ b/queue-6.12/netfilter-nf_conntrack_expect-honor-expectation-help.patch @@ -0,0 +1,212 @@ +From 6374af5414d861a014f9fc36e7e9b8dd1847da44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:02 +0100 +Subject: netfilter: nf_conntrack_expect: honor expectation helper field + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch b/queue-6.12/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch new file mode 100644 index 0000000000..324f41732f --- /dev/null +++ b/queue-6.12/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch @@ -0,0 +1,158 @@ +From 805a02cc26d24f93047e8a1bc007d2c21eab5775 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 22:39:55 +0100 +Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-nf_conntrack_expect-use-expect-helper.patch b/queue-6.12/netfilter-nf_conntrack_expect-use-expect-helper.patch new file mode 100644 index 0000000000..415bc5268a --- /dev/null +++ b/queue-6.12/netfilter-nf_conntrack_expect-use-expect-helper.patch @@ -0,0 +1,148 @@ +From dc707da2cc7716f4df5210cb378a275e99064d84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:03 +0100 +Subject: netfilter: nf_conntrack_expect: use expect->helper + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-6.12/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..f4b3882539 --- /dev/null +++ b/queue-6.12/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From 0d094bc1bbe9b975ff0e3a0f2107200cb0d0b24d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-6.12/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..62cb8aa91e --- /dev/null +++ b/queue-6.12/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From 828501180ffdb366ce93bc2becfe799666c15f82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-6.12/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..385396a39e --- /dev/null +++ b/queue-6.12/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From 182c72cb7ac7c8deab579a1785ac23b1252b9f39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-6.12/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..a498af735d --- /dev/null +++ b/queue-6.12/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From b3f3a7a26daf7c02410c4bac6b538bfdc766d92c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-6.12/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..9f6550304f --- /dev/null +++ b/queue-6.12/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 0ce8aac5bbb6c0283e7c979b8c6e79579a5627a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-6.12/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..16316ae4ae --- /dev/null +++ b/queue-6.12/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From dbdea64d37758c06fd953d751f70a9fc09bab6a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/objtool-fix-clang-jump-table-detection.patch b/queue-6.12/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..35327b6266 --- /dev/null +++ b/queue-6.12/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From f4591454e1403adef6fa3fe14356bad3e8eaa5a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-6.12/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..e7a418158f --- /dev/null +++ b/queue-6.12/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From 8cee9d3afc962dcd1312a83720d6a83589e33012 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/series b/queue-6.12/series index 3bf76134e8..c94b9f78fb 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -23,3 +23,84 @@ io_uring-kbuf-use-read_once-for-userspace-mapped-memory.patch 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 diff --git a/queue-6.12/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch b/queue-6.12/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch new file mode 100644 index 0000000000..b9aa59ee19 --- /dev/null +++ b/queue-6.12/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch @@ -0,0 +1,59 @@ +From 886f480b444cbba6bb53ab2131112cde9c89c478 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 21:49:01 +0530 +Subject: spi: geni-qcom: Check DMA interrupts early in ISR + +From: Praveen Talari + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/tg3-fix-race-for-querying-speed-duplex.patch b/queue-6.12/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..c17211a938 --- /dev/null +++ b/queue-6.12/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From f5006e311ec9ea4353ea38979d298bebaff90ca3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/tg3-replace-placeholder-mac-address-with-device-prop.patch b/queue-6.12/tg3-replace-placeholder-mac-address-with-device-prop.patch new file mode 100644 index 0000000000..5c80edb5c7 --- /dev/null +++ b/queue-6.12/tg3-replace-placeholder-mac-address-with-device-prop.patch @@ -0,0 +1,69 @@ +From 1a5bcb2ff5446680bba6d25c47210491d4d33618 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 03:24:30 +0530 +Subject: tg3: replace placeholder MAC address with device property + +From: Paul SAGE + +[ 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 + +Co-developed-by: Vincent MORVAN +Signed-off-by: Vincent MORVAN +Signed-off-by: Paul SAGE +Signed-off-by: Atharva Tiwari +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch b/queue-6.12/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch new file mode 100644 index 0000000000..cb5a0b2f6d --- /dev/null +++ b/queue-6.12/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch @@ -0,0 +1,94 @@ +From f391974165147e826d7bb09c156c3a5dcb4e64e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + 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 +@@ -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 + diff --git a/queue-6.12/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch b/queue-6.12/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch new file mode 100644 index 0000000000..4a4ae3b698 --- /dev/null +++ b/queue-6.12/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch @@ -0,0 +1,47 @@ +From 824f27658b20966544ef8f1b9ba13cf5a8d0cddd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:54:17 +0530 +Subject: wifi: mac80211: check tdls flag in ieee80211_tdls_oper + +From: Deepanshu Kartikey + +[ 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 +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260313092417.520807-1-kartikey406@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch b/queue-6.18/alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch new file mode 100644 index 0000000000..b272bfe50b --- /dev/null +++ b/queue-6.18/alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch @@ -0,0 +1,39 @@ +From 19abdef03a0d15c73ff210cd549224601e89ca5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/acytr8aEUba4VXmZ@m.b4.vu +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch b/queue-6.18/alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch new file mode 100644 index 0000000000..5f973fe0d1 --- /dev/null +++ b/queue-6.18/alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch @@ -0,0 +1,39 @@ +From 6911b316834ec1ee530622d945e9f65a2f445342 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Dag Smedberg +Signed-off-by: Dag Smedberg +Link: https://patch.msgid.link/20260329170420.4122-1-dag@dsmedberg.se +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/arm64-scs-fix-handling-of-advance_loc4.patch b/queue-6.18/arm64-scs-fix-handling-of-advance_loc4.patch new file mode 100644 index 0000000000..e7ebeadc50 --- /dev/null +++ b/queue-6.18/arm64-scs-fix-handling-of-advance_loc4.patch @@ -0,0 +1,43 @@ +From db24f3f4466d97218b3447d1955a1406d472a63a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 14:44:28 +0100 +Subject: arm64/scs: Fix handling of advance_loc4 + +From: Pepper Gray + +[ 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 +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch b/queue-6.18/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch new file mode 100644 index 0000000000..b9e317f797 --- /dev/null +++ b/queue-6.18/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch @@ -0,0 +1,113 @@ +From 1c9f830dca7b9cc3098811ba0723bdb0dd180de8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch b/queue-6.18/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch new file mode 100644 index 0000000000..211b2d8e1e --- /dev/null +++ b/queue-6.18/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch @@ -0,0 +1,57 @@ +From c193c40d8c83d9bade72e6783184bec9883d63ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:15:21 +0000 +Subject: ASoC: Intel: boards: fix unmet dependency on PINCTRL + +From: Julian Braha + +[ 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 +Acked-by: Arnd Bergmann +Link: https://patch.msgid.link/20260325001522.1727678-1-julianbraha@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-6.18/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..a09c2810f8 --- /dev/null +++ b/queue-6.18/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 994e50f21381dc3868bfe9196fcca2123bf9db1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch b/queue-6.18/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch new file mode 100644 index 0000000000..d8928e36a7 --- /dev/null +++ b/queue-6.18/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch @@ -0,0 +1,55 @@ +From 4e35347fd52fc18a96ea8bcd23c4bb26c33b8225 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:43:01 +0300 +Subject: Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync + +From: Pauli Virtanen + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch b/queue-6.18/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch new file mode 100644 index 0000000000..f73a9e6d10 --- /dev/null +++ b/queue-6.18/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch @@ -0,0 +1,93 @@ +From c7b9d439e8e2d585c7e210f8facd55c453c863c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-hci_h4-fix-race-during-initialization.patch b/queue-6.18/bluetooth-hci_h4-fix-race-during-initialization.patch new file mode 100644 index 0000000000..91de7b865f --- /dev/null +++ b/queue-6.18/bluetooth-hci_h4-fix-race-during-initialization.patch @@ -0,0 +1,59 @@ +From ad11d4d0f29479751243970f84e613cb946f7902 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:21 +0100 +Subject: Bluetooth: hci_h4: Fix race during initialization + +From: Jonathan Rissanen + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch b/queue-6.18/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch new file mode 100644 index 0000000000..3b15f3d9ea --- /dev/null +++ b/queue-6.18/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch @@ -0,0 +1,55 @@ +From 00d3bcc6d0fb77728a8a79aca1fd6fb9b3c2df4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-6.18/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..d03ca62633 --- /dev/null +++ b/queue-6.18/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From 757f103d90ded71c079fbf0f4077a078c47d67b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch b/queue-6.18/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch new file mode 100644 index 0000000000..ecd048f3f5 --- /dev/null +++ b/queue-6.18/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch @@ -0,0 +1,68 @@ +From 4de508b4ea74d3be6cda32e13cb5e000c1130876 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 22:25:26 +0800 +Subject: Bluetooth: MGMT: validate mesh send advertising payload length + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch b/queue-6.18/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch new file mode 100644 index 0000000000..6c53084bf9 --- /dev/null +++ b/queue-6.18/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch @@ -0,0 +1,144 @@ +From 81a3060046da8440b0072d8047bd9fa00ffc668e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 23:16:45 +0800 +Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect() + +From: Cen Zhang + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch b/queue-6.18/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch new file mode 100644 index 0000000000..df3de19840 --- /dev/null +++ b/queue-6.18/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch @@ -0,0 +1,48 @@ +From a9e643ec94493b04355107ebecfdba42a8e0a033 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Pavan Chebbi +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260331065138.948205-4-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bnxt_en-set-backing-store-type-from-query-type.patch b/queue-6.18/bnxt_en-set-backing-store-type-from-query-type.patch new file mode 100644 index 0000000000..7fabbd4be8 --- /dev/null +++ b/queue-6.18/bnxt_en-set-backing-store-type-from-query-type.patch @@ -0,0 +1,76 @@ +From f2c16128a6974e1922888ccec8650d22fa945346 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 07:43:56 +0800 +Subject: bnxt_en: set backing store type from query type + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Michael Chan +Tested-by: Michael Chan +Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-6.18/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..008a5e5891 --- /dev/null +++ b/queue-6.18/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From d2da1b74dc5d49d11ff51bc6fc90ba50210e3069 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch b/queue-6.18/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch new file mode 100644 index 0000000000..d17d034b2e --- /dev/null +++ b/queue-6.18/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch @@ -0,0 +1,45 @@ +From ace3534e5c022501abbad468bfeeb022923d9a88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:29:22 +0800 +Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers + +From: Qi Tang + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch b/queue-6.18/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch new file mode 100644 index 0000000000..8d39f704f3 --- /dev/null +++ b/queue-6.18/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch @@ -0,0 +1,55 @@ +From 2c354c907b06d8f7c53a6b22d7621676c6e6f22f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 00:41:25 +0530 +Subject: bpf: Reject sleepable kprobe_multi programs at attach time + +From: Varun R Mallya + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Acked-by: Leon Hwang +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260401191126.440683-1-varunrmallya@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch b/queue-6.18/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch new file mode 100644 index 0000000000..6dc3cbb9a4 --- /dev/null +++ b/queue-6.18/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch @@ -0,0 +1,145 @@ +From 0acbd185f03cec6b55e0a21026e9c3a61f165872 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-6.18/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..d9d2413d63 --- /dev/null +++ b/queue-6.18/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From b10716ffc5af9f686c48a3cf208d8d516b39b79d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch b/queue-6.18/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch new file mode 100644 index 0000000000..b47108110e --- /dev/null +++ b/queue-6.18/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch @@ -0,0 +1,196 @@ +From fdb471276c8b64186f01b39d72134b0722fbb443 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:53:46 +0100 +Subject: btrfs: don't take device_list_mutex when querying zone info + +From: Johannes Thumshirn + +[ 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: + + 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 + + +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 +Reviewed-by: Damien Le Moal +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-reject-root-items-with-drop_progress-and-zero-.patch b/queue-6.18/btrfs-reject-root-items-with-drop_progress-and-zero-.patch new file mode 100644 index 0000000000..d85feee16e --- /dev/null +++ b/queue-6.18/btrfs-reject-root-items-with-drop_progress-and-zero-.patch @@ -0,0 +1,114 @@ +From 44b7488ac4b53b1be93c791a7689c60c3cf6b34f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:14:43 +0800 +Subject: btrfs: reject root items with drop_progress and zero drop_level + +From: ZhengYuan Huang + +[ 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 +Signed-off-by: ZhengYuan Huang +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch b/queue-6.18/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch new file mode 100644 index 0000000000..9cf0ffad81 --- /dev/null +++ b/queue-6.18/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch @@ -0,0 +1,147 @@ +From 59dcad1f1c1f46ea36cacf2bbf2829368e89a14d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 16:08:53 +0000 +Subject: btrfs: reserve enough transaction items for qgroup ioctls + +From: Filipe Manana + +[ 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] + [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] + [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 +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-6.18/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..c1e3745090 --- /dev/null +++ b/queue-6.18/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From 73a76d6438fe0ef9d3f8402769f44cff95088f6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/crypto-algif_aead-revert-to-operating-out-of-place.patch b/queue-6.18/crypto-algif_aead-revert-to-operating-out-of-place.patch new file mode 100644 index 0000000000..c37be91109 --- /dev/null +++ b/queue-6.18/crypto-algif_aead-revert-to-operating-out-of-place.patch @@ -0,0 +1,323 @@ +From cb9db7522aed39078b0c06780961de150fbc7f8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:30:20 +0900 +Subject: crypto: algif_aead - Revert to operating out-of-place + +From: Herbert Xu + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.18/crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch b/queue-6.18/crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch new file mode 100644 index 0000000000..e3e68f77e5 --- /dev/null +++ b/queue-6.18/crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch @@ -0,0 +1,127 @@ +From b59966ca212361fdeb1d422673b2288108f96771 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 + +Thanks, + +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch b/queue-6.18/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch new file mode 100644 index 0000000000..911d65d4c3 --- /dev/null +++ b/queue-6.18/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch @@ -0,0 +1,49 @@ +From 4dd9338deb60919509bcc4bc79faf01a2a1d4303 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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 +Signed-off-by: Horia Geantă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/crypto-caam-fix-overflow-on-long-hmac-keys.patch b/queue-6.18/crypto-caam-fix-overflow-on-long-hmac-keys.patch new file mode 100644 index 0000000000..8f7960da2c --- /dev/null +++ b/queue-6.18/crypto-caam-fix-overflow-on-long-hmac-keys.patch @@ -0,0 +1,48 @@ +From 05db72961167e14f83b9f2ca474ab0d60a74efe2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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ă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/crypto-deflate-fix-spurious-enospc.patch b/queue-6.18/crypto-deflate-fix-spurious-enospc.patch new file mode 100644 index 0000000000..30521b501e --- /dev/null +++ b/queue-6.18/crypto-deflate-fix-spurious-enospc.patch @@ -0,0 +1,75 @@ +From ea92eeabe1efef51640000c14550f8c8a6bf3ff4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 16:31:38 +0100 +Subject: crypto: deflate - fix spurious -ENOSPC + +From: Mikulas Patocka + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch b/queue-6.18/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch new file mode 100644 index 0000000000..d5529bad41 --- /dev/null +++ b/queue-6.18/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch @@ -0,0 +1,42 @@ +From e62662dc2057a8b11f2e1db8908105036d19e305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:59:55 -0500 +Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix + common property warning + +From: Frank Li + +[ 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) +Signed-off-by: Frank Li +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.18/eth-fbnic-account-for-page-fragments-when-updating-b.patch b/queue-6.18/eth-fbnic-account-for-page-fragments-when-updating-b.patch new file mode 100644 index 0000000000..5ffe0e7763 --- /dev/null +++ b/queue-6.18/eth-fbnic-account-for-page-fragments-when-updating-b.patch @@ -0,0 +1,62 @@ +From dae616f72972b4f817967eb9916e165d6423d97e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:51:22 -0700 +Subject: eth: fbnic: Account for page fragments when updating BDQ tail + +From: Dimitri Daskalakis + +[ 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 +Link: https://patch.msgid.link/20260324195123.3486219-2-dimitri.daskalakis1@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/eth-fbnic-increase-fbnic_queue_size_min-to-64.patch b/queue-6.18/eth-fbnic-increase-fbnic_queue_size_min-to-64.patch new file mode 100644 index 0000000000..af6521b1f5 --- /dev/null +++ b/queue-6.18/eth-fbnic-increase-fbnic_queue_size_min-to-64.patch @@ -0,0 +1,47 @@ +From ad1c0537a536e6ec5476241656295736ea06c044 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 09:28:48 -0700 +Subject: eth: fbnic: Increase FBNIC_QUEUE_SIZE_MIN to 64 + +From: Dimitri Daskalakis + +[ 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 +Link: https://patch.msgid.link/20260401162848.2335350-1-dimitri.daskalakis1@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hid-core-mitigate-potential-oob-by-removing-bogus-me.patch b/queue-6.18/hid-core-mitigate-potential-oob-by-removing-bogus-me.patch new file mode 100644 index 0000000000..acd8dc31ba --- /dev/null +++ b/queue-6.18/hid-core-mitigate-potential-oob-by-removing-bogus-me.patch @@ -0,0 +1,50 @@ +From 4606655b8439d0f1d8ccb76cb4320262b08d734b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:59:29 +0000 +Subject: HID: core: Mitigate potential OOB by removing bogus memset() + +From: Lee Jones + +[ 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 + +Signed-off-by: Lee Jones +[bentiss: changed the return value] +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch b/queue-6.18/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch new file mode 100644 index 0000000000..c1a109723d --- /dev/null +++ b/queue-6.18/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch @@ -0,0 +1,39 @@ +From d35b5f799b4731e8e2958829d341b112b22ceeac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 20:19:33 +0100 +Subject: HID: logitech-hidpp: Enable MX Master 4 over bluetooth + +From: Adrian Freund + +[ 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 +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch b/queue-6.18/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch new file mode 100644 index 0000000000..ee60c14f61 --- /dev/null +++ b/queue-6.18/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch @@ -0,0 +1,56 @@ +From 8e54a1f5daac9c0c4c0c1dee7d519ae398454633 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Günther Noack +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-6.18/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..33d875c11b --- /dev/null +++ b/queue-6.18/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From 685f40fed775ee368a172d7d7103b4f2f7b93ccd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-6.18/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..55d6210ed0 --- /dev/null +++ b/queue-6.18/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From 89607f1704a5d4d24879112d54e731c38f7041c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch b/queue-6.18/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch new file mode 100644 index 0000000000..aa610053c3 --- /dev/null +++ b/queue-6.18/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch @@ -0,0 +1,58 @@ +From f0311fd57b5b808752b77add63168190798f6f53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 13:32:11 +0900 +Subject: i2c: tegra: Don't mark devices with pins as IRQ safe + +From: Mikko Perttunen + +[ 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 +Reported-by: Russell King +Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/ +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-6.18/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..3d50b3544a --- /dev/null +++ b/queue-6.18/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From 0ee4fa9489353a3c00d65ca59fc2e2939393cf4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-6.18/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..9e7ca563f5 --- /dev/null +++ b/queue-6.18/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From 69eccb5422cef5d6dd2747567e3874a3930485ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-6.18/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..20e5d432b3 --- /dev/null +++ b/queue-6.18/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From e0845ae1d79e493f5cd1fcb88b6ece1344237f46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-6.18/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..60b7a26c35 --- /dev/null +++ b/queue-6.18/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From 0979558e3e9c11b564e8417cd7ccbacfb86dadb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/mptcp-add-eat_recv_skb-helper.patch b/queue-6.18/mptcp-add-eat_recv_skb-helper.patch new file mode 100644 index 0000000000..333016350b --- /dev/null +++ b/queue-6.18/mptcp-add-eat_recv_skb-helper.patch @@ -0,0 +1,66 @@ +From 3b6abe5493645bcba11ca1d1045c724446a3639b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 20:24:24 +0100 +Subject: mptcp: add eat_recv_skb helper + +From: Geliang Tang + +[ 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 +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260130-net-next-mptcp-splice-v2-1-31332ba70d7f@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch b/queue-6.18/mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch new file mode 100644 index 0000000000..4582b564b8 --- /dev/null +++ b/queue-6.18/mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch @@ -0,0 +1,121 @@ +From d42d2ff8921af350608ed1ee4a4008770ad7d223 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 20:03:35 +0800 +Subject: mptcp: fix soft lockup in mptcp_recvmsg() + +From: Li Xiasong + +[ 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: + + 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 + + +Fixes: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption") +Signed-off-by: Li Xiasong +Reviewed-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260330120335.659027-1-lixiasong1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch b/queue-6.18/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch new file mode 100644 index 0000000000..00ff53238d --- /dev/null +++ b/queue-6.18/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch @@ -0,0 +1,67 @@ +From 638fabf79b557c52d8e38dd68f27089758d445e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260327-airoha_qdma_cleanup_rx_queue-fix-v1-1-369d6ab1511a@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch b/queue-6.18/net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch new file mode 100644 index 0000000000..332c6b578d --- /dev/null +++ b/queue-6.18/net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch @@ -0,0 +1,94 @@ +From 5303719b1bdbbffd5b11b6646105a543a2506cfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:55:53 -0700 +Subject: net: bonding: fix use-after-free in bond_xmit_broadcast() + +From: Xiang Mei + +[ 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: + + 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) + + +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 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch b/queue-6.18/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch new file mode 100644 index 0000000000..ea7681d7c4 --- /dev/null +++ b/queue-6.18/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch @@ -0,0 +1,42 @@ +From 04410039349298b8b10b294465809aefc0ec660e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:52:32 +0800 +Subject: net: enetc: check whether the RSS algorithm is Toeplitz + +From: Wei Fang + +[ 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 +Reviewed-by: Clark Wang +Reviewed-by: Claudiu Manoil +Link: https://patch.msgid.link/20260326075233.3628047-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch b/queue-6.18/net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch new file mode 100644 index 0000000000..7e1ee270e7 --- /dev/null +++ b/queue-6.18/net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch @@ -0,0 +1,48 @@ +From 81318b8c362b08ec8e7fa763dcbe70a5ea1470f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:52:33 +0800 +Subject: net: enetc: do not allow VF to configure the RSS key + +From: Wei Fang + +[ 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 +Reviewed-by: Clark Wang +Reviewed-by: Claudiu Manoil +Link: https://patch.msgid.link/20260326075233.3628047-3-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch b/queue-6.18/net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch new file mode 100644 index 0000000000..215d32a0aa --- /dev/null +++ b/queue-6.18/net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch @@ -0,0 +1,72 @@ +From 65e4c4c237affaa5638235ed2de676fa3682382d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Claudiu Manoil +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324062121.2745033-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch b/queue-6.18/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch new file mode 100644 index 0000000000..44d4de98e9 --- /dev/null +++ b/queue-6.18/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch @@ -0,0 +1,50 @@ +From 92055f4506f3ae782b58ce8b46d6f1a0c28ec8fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:32:30 +0100 +Subject: net: fec: fix the PTP periodic output sysfs interface + +From: Buday Csaba + +[ 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 +Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch b/queue-6.18/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch new file mode 100644 index 0000000000..e04a08a005 --- /dev/null +++ b/queue-6.18/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch @@ -0,0 +1,93 @@ +From a3142164d0e89ef02f777600ebd178edffb76c8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 11:22:43 +0200 +Subject: net: hsr: fix VLAN add unwind on slave errors + +From: Luka Gejak + +[ 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 +Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-introduce-mangleid_features.patch b/queue-6.18/net-introduce-mangleid_features.patch new file mode 100644 index 0000000000..74402c5dd2 --- /dev/null +++ b/queue-6.18/net-introduce-mangleid_features.patch @@ -0,0 +1,92 @@ +From d3443dcf37847ace14832d7e237ee5fd75e22436 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:11:27 +0100 +Subject: net: introduce mangleid_features + +From: Paolo Abeni + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/5a7cdaeea40b0a29b88e525b6c942d73ed3b8ce7.1769011015.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: ddc748a391dd ("net: use skb_header_pointer() for TCPv4 GSO frag_off check") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-6.18/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..c698102be0 --- /dev/null +++ b/queue-6.18/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From fe180e3bbe83f9da8c06b2bcd05b74bcbcbb9abc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch b/queue-6.18/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch new file mode 100644 index 0000000000..017561fa69 --- /dev/null +++ b/queue-6.18/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch @@ -0,0 +1,54 @@ +From dd656a1ec1b48c55912c80c39f98fab441b1eb92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 15:41:52 +0800 +Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Justin Iurman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-6.18/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..6d85be8661 --- /dev/null +++ b/queue-6.18/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From c1eb919aedc991e296aed1e4d9b83d9667aad951 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-6.18/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..d0dbbaaea2 --- /dev/null +++ b/queue-6.18/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From fd67a7a525580d04500de9534312389af204f45e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-6.18/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..646506b13b --- /dev/null +++ b/queue-6.18/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From bbb259514ca8884e79a1fda42325365f3f932750 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-mana-fix-rx-skb-truesize-accounting.patch b/queue-6.18/net-mana-fix-rx-skb-truesize-accounting.patch new file mode 100644 index 0000000000..07dfb73fbf --- /dev/null +++ b/queue-6.18/net-mana-fix-rx-skb-truesize-accounting.patch @@ -0,0 +1,54 @@ +From 6a5bf5651353b07eda56b229bbd7e87a09af0354 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:14:28 -0700 +Subject: net: mana: Fix RX skb truesize accounting + +From: Dipayaan Roy + +[ 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 +Reviewed-by: Haiyang Zhang +Link: https://patch.msgid.link/acLUhLpLum6qrD/N@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-6.18/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..98b1475656 --- /dev/null +++ b/queue-6.18/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From 8ad5166861ab77632fbf935c023ba992c759b8cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.18/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch b/queue-6.18/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch new file mode 100644 index 0000000000..d06056038c --- /dev/null +++ b/queue-6.18/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch @@ -0,0 +1,86 @@ +From 311e29c0c1d7b7cce8ea76ff71842087e1941c49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:15 +0300 +Subject: net/mlx5: Fix switchdev mode rollback in case of failure + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-4-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-mlx5-lag-check-for-lag-device-before-creating-de.patch b/queue-6.18/net-mlx5-lag-check-for-lag-device-before-creating-de.patch new file mode 100644 index 0000000000..8accff7147 --- /dev/null +++ b/queue-6.18/net-mlx5-lag-check-for-lag-device-before-creating-de.patch @@ -0,0 +1,52 @@ +From 27f47ae3817826582feac09917f3e76c85406286 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:13 +0300 +Subject: net/mlx5: lag: Check for LAG device before creating debugfs + +From: Shay Drory + +[ 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 +Reviewed-by: Mark Bloch +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-6.18/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..3335ae8f0a --- /dev/null +++ b/queue-6.18/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From f3ba3386ecd6c6f3029bfb9d0aae300760b5ff66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-6.18/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..0897002d18 --- /dev/null +++ b/queue-6.18/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From efc0ad09c6fbaec78571e45e7aaef409f0a5c207 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-6.18/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..a5c2a65fbe --- /dev/null +++ b/queue-6.18/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From 2424fdba385f56f7f95869014f192b9398e0243f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-6.18/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..ace1147fe5 --- /dev/null +++ b/queue-6.18/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From b073a0ba9063e366850470fc987982c5dfeaed12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-6.18/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..1d2a0ddab9 --- /dev/null +++ b/queue-6.18/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From 446687164741b051b2b819e2b33ee1b040244d5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch b/queue-6.18/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch new file mode 100644 index 0000000000..6c7795f331 --- /dev/null +++ b/queue-6.18/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch @@ -0,0 +1,57 @@ +From 94d3eab37e78910917a2172eeea1d0661ad0088a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Juefei Pu +Signed-off-by: Yuan Tan +Signed-off-by: Xin Liu +Signed-off-by: Yuhang Zheng +Signed-off-by: Yucheng Lu +Reviewed-by: Stephen Hemminger +Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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<data[get_random_u32_below(skb_headlen(skb))] ^= ++ 1 << get_random_u32_below(8); + } + + if (unlikely(q->t_len >= sch->limit)) { +-- +2.53.0 + diff --git a/queue-6.18/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch b/queue-6.18/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch new file mode 100644 index 0000000000..287730f3a1 --- /dev/null +++ b/queue-6.18/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch @@ -0,0 +1,65 @@ +From 5a72331222a3d1a71abaa375c44734457523c594 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260326122038.2489589-1-kabel@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch b/queue-6.18/net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch new file mode 100644 index 0000000000..fac1e7f205 --- /dev/null +++ b/queue-6.18/net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch @@ -0,0 +1,70 @@ +From 522ca63ab79c9566e1cfad4e82f9189494084b8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 09:55:51 +0100 +Subject: net: stmmac: skip VLAN restore when VLAN hash ops are missing + +From: Michal Piekos + +[ 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 +Link: https://patch.msgid.link/20260328-vlan-restore-error-v4-1-f88624c530dc@mmpsystems.pl +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch b/queue-6.18/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch new file mode 100644 index 0000000000..c641dcc800 --- /dev/null +++ b/queue-6.18/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch @@ -0,0 +1,62 @@ +From 1ad7ddb9bc4bbd475efb5b9f28f5b88735996620 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 23:35:07 +0800 +Subject: net: use skb_header_pointer() for TCPv4 GSO frag_off check + +From: Guoyu Su + +[ 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 +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260327153507.39742-1-yss2813483011xxl@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-6.18/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..bbdc4f64bc --- /dev/null +++ b/queue-6.18/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 6c2cf4cb9ff2698ce63da42abbe34f7e3deb43c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-x25-fix-potential-double-free-of-skb.patch b/queue-6.18/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..824df47ed6 --- /dev/null +++ b/queue-6.18/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 3c29576cbb5728005fb91a932bfb21f790b76af9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-6.18/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..7df8330168 --- /dev/null +++ b/queue-6.18/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From 75c967ddf0f8146cf35bf68cc0e76b5fa307fc67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch b/queue-6.18/net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch new file mode 100644 index 0000000000..3b89f3e7a2 --- /dev/null +++ b/queue-6.18/net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch @@ -0,0 +1,70 @@ +From 87508d132e469ffd7f10842436133bb58853652f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 13:02:38 +0530 +Subject: net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets + +From: Suraj Gupta + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-3-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netdevsim-fix-build-if-skb_extensions-n.patch b/queue-6.18/netdevsim-fix-build-if-skb_extensions-n.patch new file mode 100644 index 0000000000..5b330d0ca7 --- /dev/null +++ b/queue-6.18/netdevsim-fix-build-if-skb_extensions-n.patch @@ -0,0 +1,45 @@ +From 84dac6fea62590abb15f37ed6a00abf49f81ff96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 22:08:56 +0800 +Subject: netdevsim: fix build if SKB_EXTENSIONS=n + +From: Qingfang Deng + +[ 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 +Link: https://patch.msgid.link/20260324140857.783-1-dqfext@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch b/queue-6.18/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch new file mode 100644 index 0000000000..99dfe5f2e8 --- /dev/null +++ b/queue-6.18/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch @@ -0,0 +1,168 @@ +From 34cbc0a4586c70cf4f204c16408678decc49283e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 11:26:22 +0200 +Subject: netfilter: ctnetlink: ignore explicit helper on new expectations + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-6.18/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..bd28c57652 --- /dev/null +++ b/queue-6.18/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From 0ac061756967f5e17a3387341096d18ce919a301 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-flowtable-strictly-check-for-maximum-numbe.patch b/queue-6.18/netfilter-flowtable-strictly-check-for-maximum-numbe.patch new file mode 100644 index 0000000000..8c621a7bac --- /dev/null +++ b/queue-6.18/netfilter-flowtable-strictly-check-for-maximum-numbe.patch @@ -0,0 +1,504 @@ +From 4fe622a18cd20ffff03b03c2d80a7a4105678169 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:17:09 +0100 +Subject: netfilter: flowtable: strictly check for maximum number of actions + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + #include + ++#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 + diff --git a/queue-6.18/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-6.18/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..563b34b0c6 --- /dev/null +++ b/queue-6.18/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 5cc71e152c34ed623f18832884aef68ac033321d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-nf_conntrack_expect-honor-expectation-help.patch b/queue-6.18/netfilter-nf_conntrack_expect-honor-expectation-help.patch new file mode 100644 index 0000000000..91e3e15000 --- /dev/null +++ b/queue-6.18/netfilter-nf_conntrack_expect-honor-expectation-help.patch @@ -0,0 +1,212 @@ +From a3abb613d5af13c59fcdcde284ccaa10add615e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:02 +0100 +Subject: netfilter: nf_conntrack_expect: honor expectation helper field + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch b/queue-6.18/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch new file mode 100644 index 0000000000..1647ac3cd3 --- /dev/null +++ b/queue-6.18/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch @@ -0,0 +1,158 @@ +From 8e98eb54fd93e0a51fd7fffd074cfd403c1cb0d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 22:39:55 +0100 +Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-nf_conntrack_expect-use-expect-helper.patch b/queue-6.18/netfilter-nf_conntrack_expect-use-expect-helper.patch new file mode 100644 index 0000000000..686414706c --- /dev/null +++ b/queue-6.18/netfilter-nf_conntrack_expect-use-expect-helper.patch @@ -0,0 +1,148 @@ +From f3ddbeff3b961ba95f49437a5970ac7f6509d8cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:03 +0100 +Subject: netfilter: nf_conntrack_expect: use expect->helper + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-6.18/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..1224a0911f --- /dev/null +++ b/queue-6.18/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From 25d81aa19bd445bd3bd1483676aa75b3027e9697 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-6.18/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..a72bd22777 --- /dev/null +++ b/queue-6.18/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From 95cb661fe8487e8330b20e9fb1dc9c227d4cbe68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-6.18/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..ce5f9f8740 --- /dev/null +++ b/queue-6.18/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From ad2ee5dd21b2eb5a8bbcaa611c868ecbae974147 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-6.18/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..91290505e1 --- /dev/null +++ b/queue-6.18/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From 24171b76a78392068d91c6158d30d3776eab27b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-6.18/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..6537083d0d --- /dev/null +++ b/queue-6.18/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 0b372a126447fd1b44b20e35941c6e9583dde59c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-6.18/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..9a23482771 --- /dev/null +++ b/queue-6.18/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From 46c44d1225da66f0d93124d057fd90ad51c469a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/objtool-fix-clang-jump-table-detection.patch b/queue-6.18/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..bcb0965a06 --- /dev/null +++ b/queue-6.18/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From 35ebc66162390286beb5c6dcee173b5d88512c73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-6.18/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..2bd1a5c286 --- /dev/null +++ b/queue-6.18/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From 34f840864f07fe288d9657434c362e6a4bd0c0ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/series b/queue-6.18/series new file mode 100644 index 0000000000..1d6e49bd63 --- /dev/null +++ b/queue-6.18/series @@ -0,0 +1,102 @@ +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 diff --git a/queue-6.18/smb-client-fix-generic-694-due-to-wrong-i_blocks.patch b/queue-6.18/smb-client-fix-generic-694-due-to-wrong-i_blocks.patch new file mode 100644 index 0000000000..73504689f0 --- /dev/null +++ b/queue-6.18/smb-client-fix-generic-694-due-to-wrong-i_blocks.patch @@ -0,0 +1,152 @@ +From 327c657f19c10437ef972a452347513d20820444 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 21:43:51 -0300 +Subject: smb: client: fix generic/694 due to wrong ->i_blocks + +From: Paulo Alcantara + +[ 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 +Closes: https://lore.kernel.org/r/CANT5p=rqgRwaADB=b_PhJkqXjtfq3SFv41SSTXSVEHnuh871pA@mail.gmail.com +Signed-off-by: Paulo Alcantara (Red Hat) +Cc: David Howells +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch b/queue-6.18/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch new file mode 100644 index 0000000000..7785c73d2e --- /dev/null +++ b/queue-6.18/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch @@ -0,0 +1,59 @@ +From 240c05155643299fc312c9e3c8cf7539de7b1c8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 21:49:01 +0530 +Subject: spi: geni-qcom: Check DMA interrupts early in ISR + +From: Praveen Talari + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/tg3-fix-race-for-querying-speed-duplex.patch b/queue-6.18/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..7aae7943db --- /dev/null +++ b/queue-6.18/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From 933fff370316c4f43c731cf20d4d4ef141a8e806 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/tg3-replace-placeholder-mac-address-with-device-prop.patch b/queue-6.18/tg3-replace-placeholder-mac-address-with-device-prop.patch new file mode 100644 index 0000000000..685d5b9838 --- /dev/null +++ b/queue-6.18/tg3-replace-placeholder-mac-address-with-device-prop.patch @@ -0,0 +1,69 @@ +From fedf1db33e22e0a03b02e7f4e04bc8b435d9f3da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 03:24:30 +0530 +Subject: tg3: replace placeholder MAC address with device property + +From: Paul SAGE + +[ 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 + +Co-developed-by: Vincent MORVAN +Signed-off-by: Vincent MORVAN +Signed-off-by: Paul SAGE +Signed-off-by: Atharva Tiwari +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch b/queue-6.18/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch new file mode 100644 index 0000000000..f447ebb976 --- /dev/null +++ b/queue-6.18/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch @@ -0,0 +1,94 @@ +From e6aa8af861dab0f3fd594e0294aecd174f278b18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + 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 +@@ -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 + diff --git a/queue-6.18/wifi-iwlwifi-cfg-add-new-device-names.patch b/queue-6.18/wifi-iwlwifi-cfg-add-new-device-names.patch new file mode 100644 index 0000000000..bc6634929f --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-cfg-add-new-device-names.patch @@ -0,0 +1,66 @@ +From 1317e6d773125c27e5ea4d7d9faad0683e18193b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Sep 2025 11:34:27 +0300 +Subject: wifi: iwlwifi: cfg: add new device names + +From: Johannes Berg + +[ Upstream commit 30d47d8fe781469ebd4e38240999767f139effb2 ] + +Add a couple of device names so that these new devices will +be shown correctly. + +Signed-off-by: Johannes Berg +Signed-off-by: Miri Korenblit +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 +--- + 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 + diff --git a/queue-6.18/wifi-iwlwifi-disable-eht-if-the-device-doesn-t-allow.patch b/queue-6.18/wifi-iwlwifi-disable-eht-if-the-device-doesn-t-allow.patch new file mode 100644 index 0000000000..3fd9bccaaf --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-disable-eht-if-the-device-doesn-t-allow.patch @@ -0,0 +1,136 @@ +From c1a7a296724bccbc8b920f1499a36abfe2f486fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Oct 2025 11:45:13 +0300 +Subject: wifi: iwlwifi: disable EHT if the device doesn't allow it + +From: Emmanuel Grumbach + +[ 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 +Signed-off-by: Miri Korenblit +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 +--- + .../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 + diff --git a/queue-6.18/wifi-iwlwifi-fix-remaining-kernel-doc-warnings.patch b/queue-6.18/wifi-iwlwifi-fix-remaining-kernel-doc-warnings.patch new file mode 100644 index 0000000000..5189173432 --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-fix-remaining-kernel-doc-warnings.patch @@ -0,0 +1,1177 @@ +From 89eec42a23f0af7e78d0827f1e55949b30d5cf5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Sep 2025 11:34:29 +0300 +Subject: wifi: iwlwifi: fix remaining kernel-doc warnings + +From: Johannes Berg + +[ Upstream commit 58a4ebe3168813a04bef08f7858a63b199e866e1 ] + +Fix the remaining kernel-doc warnings across the driver. + +Signed-off-by: Johannes Berg +Signed-off-by: Miri Korenblit +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 +--- + 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 . The driver will issue a ++ * @time_events: a list of tuples . 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 -.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 + diff --git a/queue-6.18/wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch b/queue-6.18/wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch new file mode 100644 index 0000000000..a2c7c209cd --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch @@ -0,0 +1,209 @@ +From b759c54760072eccf2dfe6a462c2080e1dd63885 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:33:26 +0200 +Subject: wifi: iwlwifi: mld: correctly set wifi generation data + +From: Johannes Berg + +[ 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 +Signed-off-by: Miri Korenblit +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 +--- + .../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 + diff --git a/queue-6.18/wifi-iwlwifi-mld-fix-mlo-scan-timing.patch b/queue-6.18/wifi-iwlwifi-mld-fix-mlo-scan-timing.patch new file mode 100644 index 0000000000..55c54643ae --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-mld-fix-mlo-scan-timing.patch @@ -0,0 +1,233 @@ +From d3c2401ad580a8821cb9628c662cb2e860303b5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:33:24 +0200 +Subject: wifi: iwlwifi: mld: Fix MLO scan timing + +From: Pagadala Yesu Anjaneyulu + +[ 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 +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260324113316.4c56b8bac533.I6e656d8cc30bb82c96aabadedd62bd67f4c46bf9@changeid +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.18/wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch b/queue-6.18/wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch new file mode 100644 index 0000000000..6627f88bd5 --- /dev/null +++ b/queue-6.18/wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch @@ -0,0 +1,44 @@ +From e4e817851f6c1adb6a97e3da2bbaa6846a6ad716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260324113316.e171f0163f2a.I0c444d1f82d1773054e7ffc391ad49697d58f44e@changeid +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch b/queue-6.18/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch new file mode 100644 index 0000000000..265d84e9a1 --- /dev/null +++ b/queue-6.18/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch @@ -0,0 +1,47 @@ +From 14d46c9ac199ac7068f7fc8ce842ca040a63e4bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:54:17 +0530 +Subject: wifi: mac80211: check tdls flag in ieee80211_tdls_oper + +From: Deepanshu Kartikey + +[ 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 +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260313092417.520807-1-kartikey406@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch b/queue-6.19/alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch new file mode 100644 index 0000000000..c600c3c6a3 --- /dev/null +++ b/queue-6.19/alsa-usb-audio-exclude-scarlett-2i2-1st-gen-8016-fro.patch @@ -0,0 +1,39 @@ +From 919f770334f52053663716a5298cab950f8f69ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/acytr8aEUba4VXmZ@m.b4.vu +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch b/queue-6.19/alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch new file mode 100644 index 0000000000..59d3e33f7b --- /dev/null +++ b/queue-6.19/alsa-usb-audio-exclude-scarlett-solo-1st-gen-from-sk.patch @@ -0,0 +1,39 @@ +From d21f301bc4002ddeb5e1f50510bd276f20c015fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Dag Smedberg +Signed-off-by: Dag Smedberg +Link: https://patch.msgid.link/20260329170420.4122-1-dag@dsmedberg.se +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/arm64-scs-fix-handling-of-advance_loc4.patch b/queue-6.19/arm64-scs-fix-handling-of-advance_loc4.patch new file mode 100644 index 0000000000..f4de23bdf9 --- /dev/null +++ b/queue-6.19/arm64-scs-fix-handling-of-advance_loc4.patch @@ -0,0 +1,43 @@ +From 83aeb5b79e350a8ae43af1511212b532729e7ef3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 14:44:28 +0100 +Subject: arm64/scs: Fix handling of advance_loc4 + +From: Pepper Gray + +[ 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 +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch b/queue-6.19/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch new file mode 100644 index 0000000000..d66c199631 --- /dev/null +++ b/queue-6.19/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch @@ -0,0 +1,113 @@ +From b2128d3e80174fa319ebcd57e3fbd4000895e28d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch b/queue-6.19/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch new file mode 100644 index 0000000000..bafb038dd0 --- /dev/null +++ b/queue-6.19/asoc-intel-boards-fix-unmet-dependency-on-pinctrl.patch @@ -0,0 +1,57 @@ +From 5e000583da64b1e5774f34392bc1db3f026bad6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:15:21 +0000 +Subject: ASoC: Intel: boards: fix unmet dependency on PINCTRL + +From: Julian Braha + +[ 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 +Acked-by: Arnd Bergmann +Link: https://patch.msgid.link/20260325001522.1727678-1-julianbraha@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-6.19/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..52ae1da8db --- /dev/null +++ b/queue-6.19/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 86441742dcd9d8b35a1c3d8c484f39ab69794c67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch b/queue-6.19/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch new file mode 100644 index 0000000000..7537bfb288 --- /dev/null +++ b/queue-6.19/bluetooth-hci_conn-fix-potential-uaf-in-set_cig_para.patch @@ -0,0 +1,55 @@ +From 04326786268467a9e8a61b97a0f233696c80966c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:43:01 +0300 +Subject: Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync + +From: Pauli Virtanen + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch b/queue-6.19/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch new file mode 100644 index 0000000000..347397f729 --- /dev/null +++ b/queue-6.19/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch @@ -0,0 +1,93 @@ +From ae5f76c635037053215b88b0d95c2aa3af4f96da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_h4-fix-race-during-initialization.patch b/queue-6.19/bluetooth-hci_h4-fix-race-during-initialization.patch new file mode 100644 index 0000000000..ac77d40e5e --- /dev/null +++ b/queue-6.19/bluetooth-hci_h4-fix-race-during-initialization.patch @@ -0,0 +1,59 @@ +From 67197c54197b2f1a495333ba60f6b79b8fd6bd17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:21 +0100 +Subject: Bluetooth: hci_h4: Fix race during initialization + +From: Jonathan Rissanen + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch b/queue-6.19/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch new file mode 100644 index 0000000000..6cff77e979 --- /dev/null +++ b/queue-6.19/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch @@ -0,0 +1,55 @@ +From 775e2e0ce2fe4c0361991b5fc6e24183a276f6ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_sync-fix-leaks-when-hci_cmd_sync_queue.patch b/queue-6.19/bluetooth-hci_sync-fix-leaks-when-hci_cmd_sync_queue.patch new file mode 100644 index 0000000000..7dd944d0f5 --- /dev/null +++ b/queue-6.19/bluetooth-hci_sync-fix-leaks-when-hci_cmd_sync_queue.patch @@ -0,0 +1,67 @@ +From d5091f5f9f898930ceefb6317ff5fbd56454823b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 035c25007c9e ("Bluetooth: hci_sync: Fix UAF in le_read_features_complete") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_sync-fix-uaf-in-le_read_features_compl.patch b/queue-6.19/bluetooth-hci_sync-fix-uaf-in-le_read_features_compl.patch new file mode 100644 index 0000000000..10d1ccbf89 --- /dev/null +++ b/queue-6.19/bluetooth-hci_sync-fix-uaf-in-le_read_features_compl.patch @@ -0,0 +1,241 @@ +From 56b32254651a8110e864fd09098079d6ca06841b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + __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 + + +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 +Signed-off-by: Pauli Virtanen +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-hci_sync-hci_cmd_sync_queue_once-return-ee.patch b/queue-6.19/bluetooth-hci_sync-hci_cmd_sync_queue_once-return-ee.patch new file mode 100644 index 0000000000..874b8ea7a3 --- /dev/null +++ b/queue-6.19/bluetooth-hci_sync-hci_cmd_sync_queue_once-return-ee.patch @@ -0,0 +1,175 @@ +From 878ef2da9ac705157c7b86abd366e952946962b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 035c25007c9e ("Bluetooth: hci_sync: Fix UAF in le_read_features_complete") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-l2cap-add-support-for-setting-bt_phy.patch b/queue-6.19/bluetooth-l2cap-add-support-for-setting-bt_phy.patch new file mode 100644 index 0000000000..c83369c7c5 --- /dev/null +++ b/queue-6.19/bluetooth-l2cap-add-support-for-setting-bt_phy.patch @@ -0,0 +1,448 @@ +From a894b49a3d50dcb45e6e01684fa51504e215bf18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Dec 2025 10:50:51 -0500 +Subject: Bluetooth: L2CAP: Add support for setting BT_PHY + +From: Luiz Augusto von Dentz + +[ 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 +Stable-dep-of: 035c25007c9e ("Bluetooth: hci_sync: Fix UAF in le_read_features_complete") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-6.19/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..7954fcce41 --- /dev/null +++ b/queue-6.19/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From bd36a8a6680ee8bc7acd824cadbbf8916b918ffb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch b/queue-6.19/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch new file mode 100644 index 0000000000..a923afc02b --- /dev/null +++ b/queue-6.19/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch @@ -0,0 +1,68 @@ +From c939d5b69b2519421ca62cce3f9279c1c9faa6c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 22:25:26 +0800 +Subject: Bluetooth: MGMT: validate mesh send advertising payload length + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch b/queue-6.19/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch new file mode 100644 index 0000000000..7fd7be2006 --- /dev/null +++ b/queue-6.19/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch @@ -0,0 +1,144 @@ +From 6e9f35aa4a53672a4d7ac4c8917b23ad4dd859c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 23:16:45 +0800 +Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect() + +From: Cen Zhang + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bnxt_en-don-t-assume-xdp-is-never-enabled-in-bnxt_in.patch b/queue-6.19/bnxt_en-don-t-assume-xdp-is-never-enabled-in-bnxt_in.patch new file mode 100644 index 0000000000..1118ac74f2 --- /dev/null +++ b/queue-6.19/bnxt_en-don-t-assume-xdp-is-never-enabled-in-bnxt_in.patch @@ -0,0 +1,87 @@ +From 5472d3ac318b140d77bc756eecac952ed97851fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Pavan Chebbi +Reviewed-by: Kalesh AP +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 +Link: https://patch.msgid.link/20260331065138.948205-3-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bnxt_en-refactor-some-basic-ring-setup-and-adjustmen.patch b/queue-6.19/bnxt_en-refactor-some-basic-ring-setup-and-adjustmen.patch new file mode 100644 index 0000000000..c1393baa72 --- /dev/null +++ b/queue-6.19/bnxt_en-refactor-some-basic-ring-setup-and-adjustmen.patch @@ -0,0 +1,192 @@ +From 8927ad8fe9bb538d5b2a1aa960ce561d26adb9d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 23:51:36 -0700 +Subject: bnxt_en: Refactor some basic ring setup and adjustment logic + +From: Michael Chan + +[ 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 +Reviewed-by: Pavan Chebbi +Reviewed-by: Andy Gospodarek +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260331065138.948205-2-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: e4bf81dcad0a ("bnxt_en: Don't assume XDP is never enabled in bnxt_init_dflt_ring_mode()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch b/queue-6.19/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch new file mode 100644 index 0000000000..1b42444146 --- /dev/null +++ b/queue-6.19/bnxt_en-restore-default-stat-ctxs-for-ulp-when-resou.patch @@ -0,0 +1,48 @@ +From 0ae3037ab8608aed10166d96e65ffcfd6b373abc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Pavan Chebbi +Signed-off-by: Michael Chan +Link: https://patch.msgid.link/20260331065138.948205-4-michael.chan@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bnxt_en-set-backing-store-type-from-query-type.patch b/queue-6.19/bnxt_en-set-backing-store-type-from-query-type.patch new file mode 100644 index 0000000000..2ce81983c2 --- /dev/null +++ b/queue-6.19/bnxt_en-set-backing-store-type-from-query-type.patch @@ -0,0 +1,76 @@ +From 6cb8d3bc5ef2546209dfa3c960f8f492b93d80b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 07:43:56 +0800 +Subject: bnxt_en: set backing store type from query type + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Michael Chan +Tested-by: Michael Chan +Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bpf-fix-incorrect-pruning-due-to-atomic-fetch-precis.patch b/queue-6.19/bpf-fix-incorrect-pruning-due-to-atomic-fetch-precis.patch new file mode 100644 index 0000000000..1977e63b3f --- /dev/null +++ b/queue-6.19/bpf-fix-incorrect-pruning-due-to-atomic-fetch-precis.patch @@ -0,0 +1,125 @@ +From 25d9f7d112a884d112a0a13b24e7dd605ebccb2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 00:20:19 +0200 +Subject: bpf: Fix incorrect pruning due to atomic fetch precision tracking + +From: Daniel Borkmann + +[ 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 +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260331222020.401848-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-6.19/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..f24dcc045a --- /dev/null +++ b/queue-6.19/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From cbe7166e28f37b9b7225d532727b0d23bc4846d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch b/queue-6.19/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch new file mode 100644 index 0000000000..0a2bc98396 --- /dev/null +++ b/queue-6.19/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch @@ -0,0 +1,45 @@ +From b1481b721e9a4f0f77389cae9f168a8b394bdc1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:29:22 +0800 +Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers + +From: Qi Tang + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch b/queue-6.19/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch new file mode 100644 index 0000000000..7975eed177 --- /dev/null +++ b/queue-6.19/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch @@ -0,0 +1,55 @@ +From 80bebbb45adf12c8b7a260ccec4f1c12281b03ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 00:41:25 +0530 +Subject: bpf: Reject sleepable kprobe_multi programs at attach time + +From: Varun R Mallya + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Acked-by: Leon Hwang +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260401191126.440683-1-varunrmallya@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch b/queue-6.19/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch new file mode 100644 index 0000000000..a9247e83b6 --- /dev/null +++ b/queue-6.19/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch @@ -0,0 +1,145 @@ +From 7d33bb28b9a088fc7ec083f66bd91098ca4a78f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-6.19/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..e77264b472 --- /dev/null +++ b/queue-6.19/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From 4dd397cba2471c5c4b6b12159bb3905acdac34a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/bridge-mrp-reject-zero-test-interval-to-avoid-oom-pa.patch b/queue-6.19/bridge-mrp-reject-zero-test-interval-to-avoid-oom-pa.patch new file mode 100644 index 0000000000..828715655a --- /dev/null +++ b/queue-6.19/bridge-mrp-reject-zero-test-interval-to-avoid-oom-pa.patch @@ -0,0 +1,66 @@ +From 9590e2f5a09d753eec62fefe1706130ae667ff2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 23:30:00 -0700 +Subject: bridge: mrp: reject zero test interval to avoid OOM panic + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Nikolay Aleksandrov +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260328063000.1845376-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch b/queue-6.19/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch new file mode 100644 index 0000000000..fa33230199 --- /dev/null +++ b/queue-6.19/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch @@ -0,0 +1,196 @@ +From 225f673d588566a243721c7d0a176f619e1c6c0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:53:46 +0100 +Subject: btrfs: don't take device_list_mutex when querying zone info + +From: Johannes Thumshirn + +[ 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: + + 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 + + +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 +Reviewed-by: Damien Le Moal +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/btrfs-reject-root-items-with-drop_progress-and-zero-.patch b/queue-6.19/btrfs-reject-root-items-with-drop_progress-and-zero-.patch new file mode 100644 index 0000000000..1343864b2f --- /dev/null +++ b/queue-6.19/btrfs-reject-root-items-with-drop_progress-and-zero-.patch @@ -0,0 +1,114 @@ +From 44b43649a8717f0ac78d6dd2ff95f8b1a46cf15e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:14:43 +0800 +Subject: btrfs: reject root items with drop_progress and zero drop_level + +From: ZhengYuan Huang + +[ 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 +Signed-off-by: ZhengYuan Huang +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch b/queue-6.19/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch new file mode 100644 index 0000000000..ec7e393d04 --- /dev/null +++ b/queue-6.19/btrfs-reserve-enough-transaction-items-for-qgroup-io.patch @@ -0,0 +1,147 @@ +From 14376f1c7ba834dc0c2767b281bc80022b9fcce8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 16:08:53 +0000 +Subject: btrfs: reserve enough transaction items for qgroup ioctls + +From: Filipe Manana + +[ 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] + [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] + [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 +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/cgroup-fix-cgroup_drain_dying-testing-the-wrong-cond.patch b/queue-6.19/cgroup-fix-cgroup_drain_dying-testing-the-wrong-cond.patch new file mode 100644 index 0000000000..f3d977f08f --- /dev/null +++ b/queue-6.19/cgroup-fix-cgroup_drain_dying-testing-the-wrong-cond.patch @@ -0,0 +1,111 @@ +From a2d199376b86beb5bceaf0a873ea4183b8007a43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 07:23:48 -1000 +Subject: cgroup: Fix cgroup_drain_dying() testing the wrong condition + +From: Tejun Heo + +[ 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 +Fixes: 1b164b876c36 ("cgroup: Wait for dying tasks to leave on rmdir") +Signed-off-by: Tejun Heo +Tested-by: Sebastian Andrzej Siewior +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/cgroup-wait-for-dying-tasks-to-leave-on-rmdir.patch b/queue-6.19/cgroup-wait-for-dying-tasks-to-leave-on-rmdir.patch new file mode 100644 index 0000000000..c9c1295f35 --- /dev/null +++ b/queue-6.19/cgroup-wait-for-dying-tasks-to-leave-on-rmdir.patch @@ -0,0 +1,184 @@ +From ca1e97763a2046abc85e068fd62033172a70b346 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:21:25 -1000 +Subject: cgroup: Wait for dying tasks to leave on rmdir + +From: Tejun Heo + +[ 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 +Closes: https://lore.kernel.org/oe-lkp/202603222104.2c81684e-lkp@intel.com +Reported-by: Sebastian Andrzej Siewior +Signed-off-by: Tejun Heo +Reviewed-by: Sebastian Andrzej Siewior +Cc: Bert Karwatzki +Cc: Michal Koutny +Cc: cgroups@vger.kernel.org +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-6.19/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..a13d5b4f17 --- /dev/null +++ b/queue-6.19/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From d9f386e5932437f8afc7ce730e7debed24b1b502 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/crypto-algif_aead-revert-to-operating-out-of-place.patch b/queue-6.19/crypto-algif_aead-revert-to-operating-out-of-place.patch new file mode 100644 index 0000000000..d010af1daa --- /dev/null +++ b/queue-6.19/crypto-algif_aead-revert-to-operating-out-of-place.patch @@ -0,0 +1,323 @@ +From cc561b4dbe8abd568e4432790cfb37c93bbe9209 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:30:20 +0900 +Subject: crypto: algif_aead - Revert to operating out-of-place + +From: Herbert Xu + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.19/crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch b/queue-6.19/crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch new file mode 100644 index 0000000000..2e143cfad9 --- /dev/null +++ b/queue-6.19/crypto-authencesn-do-not-place-hiseq-at-end-of-dst-f.patch @@ -0,0 +1,127 @@ +From 7c725251959f8ade1ff4bb31087b2381d03ca84c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 + +Thanks, + +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch b/queue-6.19/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch new file mode 100644 index 0000000000..2a37289d33 --- /dev/null +++ b/queue-6.19/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch @@ -0,0 +1,49 @@ +From 2822bd8a349bc93a3db4bc825ac3efb1f4a06d51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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 +Signed-off-by: Horia Geantă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/crypto-caam-fix-overflow-on-long-hmac-keys.patch b/queue-6.19/crypto-caam-fix-overflow-on-long-hmac-keys.patch new file mode 100644 index 0000000000..73c1ec740a --- /dev/null +++ b/queue-6.19/crypto-caam-fix-overflow-on-long-hmac-keys.patch @@ -0,0 +1,48 @@ +From a1c590e3e5cb8abfa41f0fc221a834fc0b2269cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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ă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/crypto-deflate-fix-spurious-enospc.patch b/queue-6.19/crypto-deflate-fix-spurious-enospc.patch new file mode 100644 index 0000000000..296532117b --- /dev/null +++ b/queue-6.19/crypto-deflate-fix-spurious-enospc.patch @@ -0,0 +1,75 @@ +From d8372a209f835b90d0c56a0f7752d47c27a0bd1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 16:31:38 +0100 +Subject: crypto: deflate - fix spurious -ENOSPC + +From: Mikulas Patocka + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/drm-amd-display-fix-gamma-2.2-colorop-tfs.patch b/queue-6.19/drm-amd-display-fix-gamma-2.2-colorop-tfs.patch new file mode 100644 index 0000000000..5b49c8be83 --- /dev/null +++ b/queue-6.19/drm-amd-display-fix-gamma-2.2-colorop-tfs.patch @@ -0,0 +1,54 @@ +From 6b787e360f7c95601ad09f54cc476b920dc5b70b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 15:18:37 -0600 +Subject: drm/amd/display: Fix gamma 2.2 colorop TFs + +From: Alex Hung + +[ 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 +Reviewed-by: Melissa Wen +Reviewed-by: Harry Wentland +Signed-off-by: Alex Hung +Signed-off-by: Alex Deucher +(cherry picked from commit d8f9f42effd767ffa7bbcd7e05fbd6b20737e468) +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch b/queue-6.19/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch new file mode 100644 index 0000000000..e5f926fbbc --- /dev/null +++ b/queue-6.19/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch @@ -0,0 +1,42 @@ +From c1f5824cfc8c3e5ebf434923acc3d793ecc2f6a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:59:55 -0500 +Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix + common property warning + +From: Frank Li + +[ 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) +Signed-off-by: Frank Li +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.19/eth-fbnic-account-for-page-fragments-when-updating-b.patch b/queue-6.19/eth-fbnic-account-for-page-fragments-when-updating-b.patch new file mode 100644 index 0000000000..6e7d05664c --- /dev/null +++ b/queue-6.19/eth-fbnic-account-for-page-fragments-when-updating-b.patch @@ -0,0 +1,62 @@ +From ea78969febacceda8b1aca6c4d04054d14542abd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:51:22 -0700 +Subject: eth: fbnic: Account for page fragments when updating BDQ tail + +From: Dimitri Daskalakis + +[ 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 +Link: https://patch.msgid.link/20260324195123.3486219-2-dimitri.daskalakis1@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/eth-fbnic-increase-fbnic_queue_size_min-to-64.patch b/queue-6.19/eth-fbnic-increase-fbnic_queue_size_min-to-64.patch new file mode 100644 index 0000000000..d0007335c8 --- /dev/null +++ b/queue-6.19/eth-fbnic-increase-fbnic_queue_size_min-to-64.patch @@ -0,0 +1,47 @@ +From 1ead5dc269c5fb52b91ff8f3c70c660852171bb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 09:28:48 -0700 +Subject: eth: fbnic: Increase FBNIC_QUEUE_SIZE_MIN to 64 + +From: Dimitri Daskalakis + +[ 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 +Link: https://patch.msgid.link/20260401162848.2335350-1-dimitri.daskalakis1@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/hid-core-mitigate-potential-oob-by-removing-bogus-me.patch b/queue-6.19/hid-core-mitigate-potential-oob-by-removing-bogus-me.patch new file mode 100644 index 0000000000..eefbefe04d --- /dev/null +++ b/queue-6.19/hid-core-mitigate-potential-oob-by-removing-bogus-me.patch @@ -0,0 +1,50 @@ +From 210260a33eec4ea5f22df208263c453a4e03baf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:59:29 +0000 +Subject: HID: core: Mitigate potential OOB by removing bogus memset() + +From: Lee Jones + +[ 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 + +Signed-off-by: Lee Jones +[bentiss: changed the return value] +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch b/queue-6.19/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch new file mode 100644 index 0000000000..f61b9df210 --- /dev/null +++ b/queue-6.19/hid-logitech-hidpp-enable-mx-master-4-over-bluetooth.patch @@ -0,0 +1,39 @@ +From 94d242731653cb0dde4b43c48dc4e762f103adb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 20:19:33 +0100 +Subject: HID: logitech-hidpp: Enable MX Master 4 over bluetooth + +From: Adrian Freund + +[ 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 +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch b/queue-6.19/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch new file mode 100644 index 0000000000..8c1a37a2ad --- /dev/null +++ b/queue-6.19/hid-logitech-hidpp-prevent-use-after-free-on-force-f.patch @@ -0,0 +1,56 @@ +From 7ab56fdef4f286bc61113d05b95551837b6d6517 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Günther Noack +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-6.19/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..c5b047a0e8 --- /dev/null +++ b/queue-6.19/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From a287dc5f2793b1e7d27aa81c711a4f7f8ae3a1f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-6.19/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..6f2cb0a112 --- /dev/null +++ b/queue-6.19/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From e8e6381cbb94b244ec547f9cfe7670cd7661cb83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch b/queue-6.19/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch new file mode 100644 index 0000000000..d13fc2294b --- /dev/null +++ b/queue-6.19/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch @@ -0,0 +1,58 @@ +From 9c1434f39305436595babf24cdfe0bffa9049e6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 13:32:11 +0900 +Subject: i2c: tegra: Don't mark devices with pins as IRQ safe + +From: Mikko Perttunen + +[ 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 +Reported-by: Russell King +Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/ +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/iommupt-amdv1-mark-amdv1pt_install_leaf_entry-as-__a.patch b/queue-6.19/iommupt-amdv1-mark-amdv1pt_install_leaf_entry-as-__a.patch new file mode 100644 index 0000000000..113d6fc3a3 --- /dev/null +++ b/queue-6.19/iommupt-amdv1-mark-amdv1pt_install_leaf_entry-as-__a.patch @@ -0,0 +1,72 @@ +From 0bf736eb0be37f12934da976809f566706583f56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sherry Yang +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-6.19/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..efcfa9d5c0 --- /dev/null +++ b/queue-6.19/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From 60fa8ad71a5b3db3d3c9ebd2bad8418786f0d55a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-6.19/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..470d3e6ab7 --- /dev/null +++ b/queue-6.19/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From 754bfbe798fae88c2eb37bc8f4bbf1d1454c4cdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-6.19/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..9714003c0c --- /dev/null +++ b/queue-6.19/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From 1d914e3e30dae71e9347c7d5802dc4a11eb35b62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-6.19/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..6049ea30bf --- /dev/null +++ b/queue-6.19/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From 4d9057acaf13b7a6c7443ea254a904958ec4bf3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/mpls-add-seqcount-to-protect-the-platform_label-s-pa.patch b/queue-6.19/mpls-add-seqcount-to-protect-the-platform_label-s-pa.patch new file mode 100644 index 0000000000..0b906f6a19 --- /dev/null +++ b/queue-6.19/mpls-add-seqcount-to-protect-the-platform_label-s-pa.patch @@ -0,0 +1,121 @@ +From 93c3733b966af16f61f7e1d9633e760f0c8318b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 00:25:57 +0100 +Subject: mpls: add seqcount to protect the platform_label{,s} pair + +From: Sabrina Dubroca + +[ 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 +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +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 +Link: https://patch.msgid.link/cd8fca15e3eb7e212b094064cd83652e20fd9d31.1774284088.git.sd@queasysnail.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/mptcp-add-eat_recv_skb-helper.patch b/queue-6.19/mptcp-add-eat_recv_skb-helper.patch new file mode 100644 index 0000000000..f4b094bbaa --- /dev/null +++ b/queue-6.19/mptcp-add-eat_recv_skb-helper.patch @@ -0,0 +1,66 @@ +From e8de53113901733a13e9d50ba9235d7423ff709c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 20:24:24 +0100 +Subject: mptcp: add eat_recv_skb helper + +From: Geliang Tang + +[ 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 +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260130-net-next-mptcp-splice-v2-1-31332ba70d7f@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch b/queue-6.19/mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch new file mode 100644 index 0000000000..649f66bd65 --- /dev/null +++ b/queue-6.19/mptcp-fix-soft-lockup-in-mptcp_recvmsg.patch @@ -0,0 +1,121 @@ +From b7109a8b73bfd2b44e470bde0e166647a2e81199 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 20:03:35 +0800 +Subject: mptcp: fix soft lockup in mptcp_recvmsg() + +From: Li Xiasong + +[ 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: + + 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 + + +Fixes: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption") +Signed-off-by: Li Xiasong +Reviewed-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260330120335.659027-1-lixiasong1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/mshv-fix-error-handling-in-mshv_region_pin.patch b/queue-6.19/mshv-fix-error-handling-in-mshv_region_pin.patch new file mode 100644 index 0000000000..f19400defc --- /dev/null +++ b/queue-6.19/mshv-fix-error-handling-in-mshv_region_pin.patch @@ -0,0 +1,58 @@ +From 6c085c4e0a7b39ad6c4cf7e8702c039abe2f6360 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:04:55 +0000 +Subject: mshv: Fix error handling in mshv_region_pin + +From: Stanislav Kinsburskii + +[ 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 +Reviewed-by: Michael Kelley +Signed-off-by: Wei Liu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch b/queue-6.19/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch new file mode 100644 index 0000000000..9996819c4f --- /dev/null +++ b/queue-6.19/net-airoha-add-missing-cleanup-bits-in-airoha_qdma_c.patch @@ -0,0 +1,67 @@ +From c54bcb55b35632d52f18f6d43e5c3d02d4bd9dfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260327-airoha_qdma_cleanup_rx_queue-fix-v1-1-369d6ab1511a@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch b/queue-6.19/net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch new file mode 100644 index 0000000000..2a56539f62 --- /dev/null +++ b/queue-6.19/net-bonding-fix-use-after-free-in-bond_xmit_broadcas.patch @@ -0,0 +1,94 @@ +From 470b2d4fdb198e51187115e4486944512dcd26f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:55:53 -0700 +Subject: net: bonding: fix use-after-free in bond_xmit_broadcast() + +From: Xiang Mei + +[ 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: + + 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) + + +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 +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-enetc-add-graceful-stop-to-safely-reinitialize-t.patch b/queue-6.19/net-enetc-add-graceful-stop-to-safely-reinitialize-t.patch new file mode 100644 index 0000000000..e1e8f458d3 --- /dev/null +++ b/queue-6.19/net-enetc-add-graceful-stop-to-safely-reinitialize-t.patch @@ -0,0 +1,227 @@ +From acf09541fa3d50e21627fff4d60d450750ecc56d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:21:20 +0800 +Subject: net: enetc: add graceful stop to safely reinitialize the TX Ring + +From: Wei Fang + +[ 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 +Reviewed-by: Claudiu Manoil +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324062121.2745033-3-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.19/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch b/queue-6.19/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch new file mode 100644 index 0000000000..f3cd760c40 --- /dev/null +++ b/queue-6.19/net-enetc-check-whether-the-rss-algorithm-is-toeplit.patch @@ -0,0 +1,42 @@ +From 3bc93b860ed92c074bdbc91ea4545ec7c4660468 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:52:32 +0800 +Subject: net: enetc: check whether the RSS algorithm is Toeplitz + +From: Wei Fang + +[ 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 +Reviewed-by: Clark Wang +Reviewed-by: Claudiu Manoil +Link: https://patch.msgid.link/20260326075233.3628047-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-enetc-do-not-access-non-existent-registers-on-ps.patch b/queue-6.19/net-enetc-do-not-access-non-existent-registers-on-ps.patch new file mode 100644 index 0000000000..0c0820295d --- /dev/null +++ b/queue-6.19/net-enetc-do-not-access-non-existent-registers-on-ps.patch @@ -0,0 +1,59 @@ +From 16b6b8fd6642fd47f46478284da82cf74000d69b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:21:21 +0800 +Subject: net: enetc: do not access non-existent registers on pseudo MAC + +From: Wei Fang + +[ 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 +Tested-by: Claudiu Manoil +Reviewed-by: Claudiu Manoil +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324062121.2745033-4-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch b/queue-6.19/net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch new file mode 100644 index 0000000000..9ff2a92b28 --- /dev/null +++ b/queue-6.19/net-enetc-do-not-allow-vf-to-configure-the-rss-key.patch @@ -0,0 +1,48 @@ +From 9af4dfcd4656e90d0a33d2670690da77ccb4c711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:52:33 +0800 +Subject: net: enetc: do not allow VF to configure the RSS key + +From: Wei Fang + +[ 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 +Reviewed-by: Clark Wang +Reviewed-by: Claudiu Manoil +Link: https://patch.msgid.link/20260326075233.3628047-3-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch b/queue-6.19/net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch new file mode 100644 index 0000000000..c52fd52a24 --- /dev/null +++ b/queue-6.19/net-enetc-reset-pir-and-cir-if-they-are-not-equal-wh.patch @@ -0,0 +1,72 @@ +From 199e2ae1cc0fa124d853231ddb690c1781fdaa4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Claudiu Manoil +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324062121.2745033-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch b/queue-6.19/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch new file mode 100644 index 0000000000..9852cac858 --- /dev/null +++ b/queue-6.19/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch @@ -0,0 +1,50 @@ +From bfda6df93a394b9ebf988da44c642bbd8ec3c189 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:32:30 +0100 +Subject: net: fec: fix the PTP periodic output sysfs interface + +From: Buday Csaba + +[ 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 +Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch b/queue-6.19/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch new file mode 100644 index 0000000000..c83c2b3ec2 --- /dev/null +++ b/queue-6.19/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch @@ -0,0 +1,93 @@ +From 188ee5de04343f2e059b063cf33cb1153358e74c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 11:22:43 +0200 +Subject: net: hsr: fix VLAN add unwind on slave errors + +From: Luka Gejak + +[ 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 +Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-introduce-mangleid_features.patch b/queue-6.19/net-introduce-mangleid_features.patch new file mode 100644 index 0000000000..79ac5e0ff0 --- /dev/null +++ b/queue-6.19/net-introduce-mangleid_features.patch @@ -0,0 +1,92 @@ +From dc7f820a49b671493cb743d81d995ccd5eecf2f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 17:11:27 +0100 +Subject: net: introduce mangleid_features + +From: Paolo Abeni + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/5a7cdaeea40b0a29b88e525b6c942d73ed3b8ce7.1769011015.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: ddc748a391dd ("net: use skb_header_pointer() for TCPv4 GSO frag_off check") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-6.19/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..340c66e329 --- /dev/null +++ b/queue-6.19/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From e5282baa914c29440a006d2a6d3f8e0403574192 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch b/queue-6.19/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch new file mode 100644 index 0000000000..a4ecdaabd8 --- /dev/null +++ b/queue-6.19/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch @@ -0,0 +1,54 @@ +From b5c13036206c02cc966fff53f498ab5fd9e3e24c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 15:41:52 +0800 +Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Justin Iurman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-6.19/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..8701994b04 --- /dev/null +++ b/queue-6.19/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From f073c0613a75037cee1374c2b31c4ed9fce28b27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-6.19/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..f30e41ebb4 --- /dev/null +++ b/queue-6.19/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From d953c6d7f8ef8cf0ffcf9eabfd8aed4f2d118a48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-6.19/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..bd4f8500e6 --- /dev/null +++ b/queue-6.19/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From c30bcd5c64971799437f651e12f9197f760c0776 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-mana-fix-rx-skb-truesize-accounting.patch b/queue-6.19/net-mana-fix-rx-skb-truesize-accounting.patch new file mode 100644 index 0000000000..7aa691fac3 --- /dev/null +++ b/queue-6.19/net-mana-fix-rx-skb-truesize-accounting.patch @@ -0,0 +1,54 @@ +From 85bfb080480e631b88759d74eedcaff7755dea2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:14:28 -0700 +Subject: net: mana: Fix RX skb truesize accounting + +From: Dipayaan Roy + +[ 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 +Reviewed-by: Haiyang Zhang +Link: https://patch.msgid.link/acLUhLpLum6qrD/N@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-6.19/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..3af9e46fb7 --- /dev/null +++ b/queue-6.19/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From f61f3dc4a4daf1e41b7f2350cd52b7f0b98851dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.19/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch b/queue-6.19/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch new file mode 100644 index 0000000000..7dfd282c1c --- /dev/null +++ b/queue-6.19/net-mlx5-fix-switchdev-mode-rollback-in-case-of-fail.patch @@ -0,0 +1,86 @@ +From 171ca0174affcd6c7264cdf15a403885698026c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:15 +0300 +Subject: net/mlx5: Fix switchdev mode rollback in case of failure + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-4-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-mlx5-lag-check-for-lag-device-before-creating-de.patch b/queue-6.19/net-mlx5-lag-check-for-lag-device-before-creating-de.patch new file mode 100644 index 0000000000..8ef673f3b0 --- /dev/null +++ b/queue-6.19/net-mlx5-lag-check-for-lag-device-before-creating-de.patch @@ -0,0 +1,52 @@ +From 00921ac14e6ec324c2894657d77b37ae0f67136c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:13 +0300 +Subject: net/mlx5: lag: Check for LAG device before creating debugfs + +From: Shay Drory + +[ 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 +Reviewed-by: Mark Bloch +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-6.19/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..154fc59f28 --- /dev/null +++ b/queue-6.19/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From 79cc77e315c4c56ebffebcb740d5b54ee781f957 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-6.19/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..90fdd5e865 --- /dev/null +++ b/queue-6.19/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From 0209052ee1ee2a7f48bd23d065a029c2b906f206 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-6.19/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..f491a7963c --- /dev/null +++ b/queue-6.19/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From f2994b70cfe095e57e4dfdae18bfe89ac4fbf257 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-6.19/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..22cc64f0e7 --- /dev/null +++ b/queue-6.19/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From 8e0b548a8d5e761298adb89c103f1e2e1e91e9e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-6.19/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..d6570c788f --- /dev/null +++ b/queue-6.19/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From f51e36323691e5b32a2c307daceb5079b74d693c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch b/queue-6.19/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch new file mode 100644 index 0000000000..a3e57724bb --- /dev/null +++ b/queue-6.19/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch @@ -0,0 +1,57 @@ +From e23b1347ff48fd750180e3d098bd84cd91876176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Juefei Pu +Signed-off-by: Yuan Tan +Signed-off-by: Xin Liu +Signed-off-by: Yuhang Zheng +Signed-off-by: Yucheng Lu +Reviewed-by: Stephen Hemminger +Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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<data[get_random_u32_below(skb_headlen(skb))] ^= ++ 1 << get_random_u32_below(8); + } + + if (unlikely(q->t_len >= sch->limit)) { +-- +2.53.0 + diff --git a/queue-6.19/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch b/queue-6.19/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch new file mode 100644 index 0000000000..58d03d9835 --- /dev/null +++ b/queue-6.19/net-sfp-fix-ubiquiti-u-fiber-instant-sfp-module-on-m.patch @@ -0,0 +1,65 @@ +From 6e99346c2eb8955d6d19965f3ad054b4dd1dcf98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260326122038.2489589-1-kabel@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch b/queue-6.19/net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch new file mode 100644 index 0000000000..7c18e3fd7a --- /dev/null +++ b/queue-6.19/net-stmmac-skip-vlan-restore-when-vlan-hash-ops-are-.patch @@ -0,0 +1,70 @@ +From f51b994cc3f1b5ae5ac2dfc7db89b7ee08a9b090 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 09:55:51 +0100 +Subject: net: stmmac: skip VLAN restore when VLAN hash ops are missing + +From: Michal Piekos + +[ 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 +Link: https://patch.msgid.link/20260328-vlan-restore-error-v4-1-f88624c530dc@mmpsystems.pl +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-ti-icssg-prueth-fix-missing-data-copy-and-wrong-.patch b/queue-6.19/net-ti-icssg-prueth-fix-missing-data-copy-and-wrong-.patch new file mode 100644 index 0000000000..45f0e1d6fd --- /dev/null +++ b/queue-6.19/net-ti-icssg-prueth-fix-missing-data-copy-and-wrong-.patch @@ -0,0 +1,60 @@ +From add287e5df9d306fc357522b85e1627ba4a478b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch b/queue-6.19/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch new file mode 100644 index 0000000000..9d7cfb2103 --- /dev/null +++ b/queue-6.19/net-use-skb_header_pointer-for-tcpv4-gso-frag_off-ch.patch @@ -0,0 +1,62 @@ +From b8435bc097b09f5905cf4f27df6b2548c28d89d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 23:35:07 +0800 +Subject: net: use skb_header_pointer() for TCPv4 GSO frag_off check + +From: Guoyu Su + +[ 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 +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260327153507.39742-1-yss2813483011xxl@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-6.19/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..2d5987f545 --- /dev/null +++ b/queue-6.19/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 84ec2a0c40350fa9361b5ad3c3de3d5cd3d3c43f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-x25-fix-potential-double-free-of-skb.patch b/queue-6.19/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..84624fdfab --- /dev/null +++ b/queue-6.19/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 6bda358f99f7e0ae83d42aaae23d220c5a367ba3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-6.19/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..2dc2ce1320 --- /dev/null +++ b/queue-6.19/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From c93d61675895246e8d58185bb9bde6f7d27a42b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch b/queue-6.19/net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch new file mode 100644 index 0000000000..4de8e619ed --- /dev/null +++ b/queue-6.19/net-xilinx-axienet-fix-bql-accounting-for-multi-bd-t.patch @@ -0,0 +1,70 @@ +From be80886c3aa2e3f68effb34a7530b24d5effd46a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 13:02:38 +0530 +Subject: net: xilinx: axienet: Fix BQL accounting for multi-BD TX packets + +From: Suraj Gupta + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-3-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netdevsim-fix-build-if-skb_extensions-n.patch b/queue-6.19/netdevsim-fix-build-if-skb_extensions-n.patch new file mode 100644 index 0000000000..3f76301137 --- /dev/null +++ b/queue-6.19/netdevsim-fix-build-if-skb_extensions-n.patch @@ -0,0 +1,45 @@ +From 21be7cf00fb388a24b2b0a2205f8a2e03f0be3e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 22:08:56 +0800 +Subject: netdevsim: fix build if SKB_EXTENSIONS=n + +From: Qingfang Deng + +[ 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 +Link: https://patch.msgid.link/20260324140857.783-1-dqfext@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch b/queue-6.19/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch new file mode 100644 index 0000000000..c6bd4b8416 --- /dev/null +++ b/queue-6.19/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch @@ -0,0 +1,168 @@ +From 030c73c1963f97037de10042dae0d63bac5c8f0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 11:26:22 +0200 +Subject: netfilter: ctnetlink: ignore explicit helper on new expectations + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-6.19/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..7e5d0519c0 --- /dev/null +++ b/queue-6.19/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From 9f9f9b8d6e9249bbf774187379c6292492f0a19c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-flowtable-strictly-check-for-maximum-numbe.patch b/queue-6.19/netfilter-flowtable-strictly-check-for-maximum-numbe.patch new file mode 100644 index 0000000000..11ccaf1bef --- /dev/null +++ b/queue-6.19/netfilter-flowtable-strictly-check-for-maximum-numbe.patch @@ -0,0 +1,504 @@ +From 9ac5645986ecaa033b63c3e8aec743bed5c23f40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:17:09 +0100 +Subject: netfilter: flowtable: strictly check for maximum number of actions + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + #include + ++#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 + diff --git a/queue-6.19/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-6.19/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..fd14ef5ae4 --- /dev/null +++ b/queue-6.19/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 6dc15e0d5e7d0da8c278c407803eb1697167d457 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-nf_conntrack_expect-honor-expectation-help.patch b/queue-6.19/netfilter-nf_conntrack_expect-honor-expectation-help.patch new file mode 100644 index 0000000000..0cd4827aaa --- /dev/null +++ b/queue-6.19/netfilter-nf_conntrack_expect-honor-expectation-help.patch @@ -0,0 +1,212 @@ +From a7f464726fa548135140ab6c13f72535ac0f10db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:02 +0100 +Subject: netfilter: nf_conntrack_expect: honor expectation helper field + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch b/queue-6.19/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch new file mode 100644 index 0000000000..efccb623c6 --- /dev/null +++ b/queue-6.19/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch @@ -0,0 +1,158 @@ +From 82b9b3fa17d3f5a78ab8990a31b1f75d850ef76d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 22:39:55 +0100 +Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-nf_conntrack_expect-use-expect-helper.patch b/queue-6.19/netfilter-nf_conntrack_expect-use-expect-helper.patch new file mode 100644 index 0000000000..bf461e4da1 --- /dev/null +++ b/queue-6.19/netfilter-nf_conntrack_expect-use-expect-helper.patch @@ -0,0 +1,148 @@ +From 95fca6bbc526a868d45bee52dee24990ddae8132 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:03 +0100 +Subject: netfilter: nf_conntrack_expect: use expect->helper + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-6.19/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..e147f118cb --- /dev/null +++ b/queue-6.19/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From 9e09c207378402ee54fdc50f2e2d48f31c0f08e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-6.19/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..279a7ab6b8 --- /dev/null +++ b/queue-6.19/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From 2888a637513ba66658545c08788c394c73be595b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-6.19/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..dfe1bece22 --- /dev/null +++ b/queue-6.19/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From 0fb502798d297582784bde1094bb7ba1f1fe1029 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-6.19/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..db87db3c92 --- /dev/null +++ b/queue-6.19/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From 0614b2c1600315323be5a276fc8b94afb4388706 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-6.19/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..63a6f8dc28 --- /dev/null +++ b/queue-6.19/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 95c69190eb63387d12a81e0f892c3f719d6c8a5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-6.19/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..f96a2655a8 --- /dev/null +++ b/queue-6.19/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From f0c393d8a05809a2675f6249dc913c9e8f4b9ede Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/objtool-fix-clang-jump-table-detection.patch b/queue-6.19/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..85052fa2a2 --- /dev/null +++ b/queue-6.19/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From 044dbaa81ce9213e7c6f19e94a7a255b56d33a5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/objtool-klp-fix-mkstemp-failure-with-long-paths.patch b/queue-6.19/objtool-klp-fix-mkstemp-failure-with-long-paths.patch new file mode 100644 index 0000000000..f6b84e6828 --- /dev/null +++ b/queue-6.19/objtool-klp-fix-mkstemp-failure-with-long-paths.patch @@ -0,0 +1,82 @@ +From aca4a5152909020e287ce4750a80df9f2578772b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 16:37:41 -0400 +Subject: objtool/klp: fix mkstemp() failure with long paths + +From: Joe Lawrence + +[ 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 +Signed-off-by: Joe Lawrence +Link: https://patch.msgid.link/20260310203751.1479229-3-joe.lawrence@redhat.com +Signed-off-by: Josh Poimboeuf +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.19/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-6.19/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..c389c2d86a --- /dev/null +++ b/queue-6.19/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From ada5dad3ed6a8ff4ccd46a7c8b9f0f70ec209b15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/selftests-cgroup-don-t-require-synchronous-populated.patch b/queue-6.19/selftests-cgroup-don-t-require-synchronous-populated.patch new file mode 100644 index 0000000000..68b85cf249 --- /dev/null +++ b/queue-6.19/selftests-cgroup-don-t-require-synchronous-populated.patch @@ -0,0 +1,131 @@ +From 36b3d83078ee2247969c454c7dc82ab1bbbc10c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:21:47 -1000 +Subject: selftests/cgroup: Don't require synchronous populated update on task + exit + +From: Tejun Heo + +[ 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 +Signed-off-by: Tejun Heo +Tested-by: Sebastian Andrzej Siewior +Cc: Christian Brauner +Cc: cgroups@vger.kernel.org +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/series b/queue-6.19/series index 229e3ddc28..7cdc88bcbe 100644 --- a/queue-6.19/series +++ b/queue-6.19/series @@ -6,3 +6,121 @@ scsi-target-tcm_loop-drain-commands-in-target_reset-handler.patch 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 diff --git a/queue-6.19/smb-client-fix-generic-694-due-to-wrong-i_blocks.patch b/queue-6.19/smb-client-fix-generic-694-due-to-wrong-i_blocks.patch new file mode 100644 index 0000000000..5b80908a8f --- /dev/null +++ b/queue-6.19/smb-client-fix-generic-694-due-to-wrong-i_blocks.patch @@ -0,0 +1,152 @@ +From d01b97ed1977923b7ca008b94df01fee15a63a4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 21:43:51 -0300 +Subject: smb: client: fix generic/694 due to wrong ->i_blocks + +From: Paulo Alcantara + +[ 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 +Closes: https://lore.kernel.org/r/CANT5p=rqgRwaADB=b_PhJkqXjtfq3SFv41SSTXSVEHnuh871pA@mail.gmail.com +Signed-off-by: Paulo Alcantara (Red Hat) +Cc: David Howells +Cc: linux-cifs@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch b/queue-6.19/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch new file mode 100644 index 0000000000..154d0d4f36 --- /dev/null +++ b/queue-6.19/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch @@ -0,0 +1,59 @@ +From f32cec81b2dfa2a25a93ae0dea04bf7b06fae9d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 21:49:01 +0530 +Subject: spi: geni-qcom: Check DMA interrupts early in ISR + +From: Praveen Talari + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/tg3-fix-race-for-querying-speed-duplex.patch b/queue-6.19/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..9134b164cf --- /dev/null +++ b/queue-6.19/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From c5c2e6c3be61f35288e3b1526d0b3c8d3f7650e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/tg3-replace-placeholder-mac-address-with-device-prop.patch b/queue-6.19/tg3-replace-placeholder-mac-address-with-device-prop.patch new file mode 100644 index 0000000000..bc0b9efbf5 --- /dev/null +++ b/queue-6.19/tg3-replace-placeholder-mac-address-with-device-prop.patch @@ -0,0 +1,69 @@ +From 4a9611568624aa78c8cfce17732618288eedabbf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 03:24:30 +0530 +Subject: tg3: replace placeholder MAC address with device property + +From: Paul SAGE + +[ 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 + +Co-developed-by: Vincent MORVAN +Signed-off-by: Vincent MORVAN +Signed-off-by: Paul SAGE +Signed-off-by: Atharva Tiwari +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch b/queue-6.19/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch new file mode 100644 index 0000000000..115d5cf2eb --- /dev/null +++ b/queue-6.19/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch @@ -0,0 +1,94 @@ +From b4df7e86c286f2a710d62b63180f17c83d00e692 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + 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 +@@ -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 + diff --git a/queue-6.19/wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch b/queue-6.19/wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch new file mode 100644 index 0000000000..8f636812aa --- /dev/null +++ b/queue-6.19/wifi-iwlwifi-mld-correctly-set-wifi-generation-data.patch @@ -0,0 +1,209 @@ +From 6e5ac9ee8f6b003c304c1fd420bc263ae460991d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:33:26 +0200 +Subject: wifi: iwlwifi: mld: correctly set wifi generation data + +From: Johannes Berg + +[ 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 +Signed-off-by: Miri Korenblit +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 +--- + .../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 + diff --git a/queue-6.19/wifi-iwlwifi-mld-fix-mlo-scan-timing.patch b/queue-6.19/wifi-iwlwifi-mld-fix-mlo-scan-timing.patch new file mode 100644 index 0000000000..49982c395c --- /dev/null +++ b/queue-6.19/wifi-iwlwifi-mld-fix-mlo-scan-timing.patch @@ -0,0 +1,233 @@ +From 399ba6c08e364814c0385e523f702eb914466253 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:33:24 +0200 +Subject: wifi: iwlwifi: mld: Fix MLO scan timing + +From: Pagadala Yesu Anjaneyulu + +[ 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 +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260324113316.4c56b8bac533.I6e656d8cc30bb82c96aabadedd62bd67f4c46bf9@changeid +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.19/wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch b/queue-6.19/wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch new file mode 100644 index 0000000000..caafc63ccc --- /dev/null +++ b/queue-6.19/wifi-iwlwifi-mvm-don-t-send-a-6e-related-command-whe.patch @@ -0,0 +1,44 @@ +From 51f723acb0b89de4b2d1bdfa8bda859ebe5051fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://patch.msgid.link/20260324113316.e171f0163f2a.I0c444d1f82d1773054e7ffc391ad49697d58f44e@changeid +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.19/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch b/queue-6.19/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch new file mode 100644 index 0000000000..80591c3162 --- /dev/null +++ b/queue-6.19/wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch @@ -0,0 +1,47 @@ +From ab6c8c0ad696b3510db923867be712ac6fc55dc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:54:17 +0530 +Subject: wifi: mac80211: check tdls flag in ieee80211_tdls_oper + +From: Deepanshu Kartikey + +[ 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 +Signed-off-by: Deepanshu Kartikey +Link: https://patch.msgid.link/20260313092417.520807-1-kartikey406@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/arm64-scs-fix-handling-of-advance_loc4.patch b/queue-6.6/arm64-scs-fix-handling-of-advance_loc4.patch new file mode 100644 index 0000000000..234eb0b527 --- /dev/null +++ b/queue-6.6/arm64-scs-fix-handling-of-advance_loc4.patch @@ -0,0 +1,43 @@ +From 0636bb6d097f824e07bbea60a930186ca5daa73b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 14:44:28 +0100 +Subject: arm64/scs: Fix handling of advance_loc4 + +From: Pepper Gray + +[ 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 +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch b/queue-6.6/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch new file mode 100644 index 0000000000..c7905b47f9 --- /dev/null +++ b/queue-6.6/asoc-ep93xx-fix-unchecked-clk_prepare_enable-and-add.patch @@ -0,0 +1,113 @@ +From 379cefa0aca002daaf89b0cc65f06c430038150f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/atm-lec-fix-use-after-free-in-sock_def_readable.patch b/queue-6.6/atm-lec-fix-use-after-free-in-sock_def_readable.patch new file mode 100644 index 0000000000..855ba5aa34 --- /dev/null +++ b/queue-6.6/atm-lec-fix-use-after-free-in-sock_def_readable.patch @@ -0,0 +1,237 @@ +From 79b95c78493197e842873bfa1cf6344461fe3351 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 21:29:08 +0530 +Subject: atm: lec: fix use-after-free in sock_def_readable() + +From: Deepanshu Kartikey + +[ 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 +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260309155908.508768-1-kartikey406@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch b/queue-6.6/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch new file mode 100644 index 0000000000..e246d03c13 --- /dev/null +++ b/queue-6.6/bluetooth-hci_event-fix-potential-uaf-in-hci_le_remo.patch @@ -0,0 +1,93 @@ +From 83bf0c05a76d75faf050dc2257f6b9f53b812d9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch b/queue-6.6/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch new file mode 100644 index 0000000000..1e24880c6c --- /dev/null +++ b/queue-6.6/bluetooth-hci_sync-call-destroy-in-hci_cmd_sync_run-.patch @@ -0,0 +1,55 @@ +From 0128ada87dc3ef55222776cc4d2340a712740b9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch b/queue-6.6/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch new file mode 100644 index 0000000000..c861862aca --- /dev/null +++ b/queue-6.6/bluetooth-mgmt-validate-ltk-enc_size-on-load.patch @@ -0,0 +1,43 @@ +From 2874133aee909d8c5a6a1c58f8e5e5e761c9d41e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 16:46:47 +0800 +Subject: Bluetooth: MGMT: validate LTK enc_size on load + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch b/queue-6.6/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch new file mode 100644 index 0000000000..1d93b5a1dd --- /dev/null +++ b/queue-6.6/bluetooth-mgmt-validate-mesh-send-advertising-payloa.patch @@ -0,0 +1,68 @@ +From 682c7654bcbc20450599aab073923b921fee7414 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 22:25:26 +0800 +Subject: Bluetooth: MGMT: validate mesh send advertising payload length + +From: Keenan Dong + +[ 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 +Signed-off-by: Keenan Dong +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch b/queue-6.6/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch new file mode 100644 index 0000000000..2fde051a8a --- /dev/null +++ b/queue-6.6/bluetooth-sco-fix-race-conditions-in-sco_sock_connec.patch @@ -0,0 +1,144 @@ +From 63c9ece260e4223abe518933bedbbb3266be5dea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 23:16:45 +0800 +Subject: Bluetooth: SCO: fix race conditions in sco_sock_connect() + +From: Cen Zhang + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-fix-regsafe-for-pointers-to-packet.patch b/queue-6.6/bpf-fix-regsafe-for-pointers-to-packet.patch new file mode 100644 index 0000000000..31bd85a833 --- /dev/null +++ b/queue-6.6/bpf-fix-regsafe-for-pointers-to-packet.patch @@ -0,0 +1,47 @@ +From f07e1ea232d32f17776a991e7cf2fbea77f1eeca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 13:42:28 -0700 +Subject: bpf: Fix regsafe() for pointers to packet + +From: Alexei Starovoitov + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Daniel Borkmann +Reviewed-by: Amery Hung +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/bpf/20260331204228.26726-1-alexei.starovoitov@gmail.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch b/queue-6.6/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch new file mode 100644 index 0000000000..560608c005 --- /dev/null +++ b/queue-6.6/bpf-reject-direct-access-to-nullable-ptr_to_buf-poin.patch @@ -0,0 +1,45 @@ +From 51b5480360cd3abbf5fc51b728d5aed4337d4a77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:29:22 +0800 +Subject: bpf: reject direct access to nullable PTR_TO_BUF pointers + +From: Qi Tang + +[ 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 +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260402092923.38357-2-tpluszz77@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch b/queue-6.6/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch new file mode 100644 index 0000000000..b1c8a28344 --- /dev/null +++ b/queue-6.6/bpf-sockmap-fix-use-after-free-of-sk-sk_socket-in-sk.patch @@ -0,0 +1,145 @@ +From 4d9702713c9e3f8a9824cb67fe2565cefdfe32b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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 + + +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 +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260401005418.2452999-1-kuniyu@google.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch b/queue-6.6/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch new file mode 100644 index 0000000000..84522a4e6c --- /dev/null +++ b/queue-6.6/bridge-br_nd_send-linearize-skb-before-parsing-nd-op.patch @@ -0,0 +1,88 @@ +From a296d6211de05736e4e54a939bc8dc3ea538dddc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 03:44:39 +0000 +Subject: bridge: br_nd_send: linearize skb before parsing ND options + +From: Yang Yang + +[ 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 +Reported-by: Juefei Pu +Tested-by: Ao Zhou +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Yang Yang +Reviewed-by: Ido Schimmel +Acked-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260326034441.2037420-2-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch b/queue-6.6/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch new file mode 100644 index 0000000000..1ca68f618e --- /dev/null +++ b/queue-6.6/btrfs-don-t-take-device_list_mutex-when-querying-zon.patch @@ -0,0 +1,196 @@ +From e95a9aa0207f6e8e59a1de2853e94232b4b9347a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:53:46 +0100 +Subject: btrfs: don't take device_list_mutex when querying zone info + +From: Johannes Thumshirn + +[ 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: + + 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 + + +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 +Reviewed-by: Damien Le Moal +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/btrfs-reject-root-items-with-drop_progress-and-zero-.patch b/queue-6.6/btrfs-reject-root-items-with-drop_progress-and-zero-.patch new file mode 100644 index 0000000000..28f8a15a41 --- /dev/null +++ b/queue-6.6/btrfs-reject-root-items-with-drop_progress-and-zero-.patch @@ -0,0 +1,114 @@ +From b003682f3172977a3d1cfe3ab87f265de4072098 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:14:43 +0800 +Subject: btrfs: reject root items with drop_progress and zero drop_level + +From: ZhengYuan Huang + +[ 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 +Signed-off-by: ZhengYuan Huang +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch b/queue-6.6/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch new file mode 100644 index 0000000000..9d3eda7c8d --- /dev/null +++ b/queue-6.6/crypto-af-alg-fix-null-pointer-dereference-in-scatte.patch @@ -0,0 +1,48 @@ +From dadab559ee0f0ea028c133faf6e82375da920001 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 18:26:13 +0100 +Subject: crypto: af-alg - fix NULL pointer dereference in scatterwalk + +From: Norbert Szetei + +[ 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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch b/queue-6.6/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch new file mode 100644 index 0000000000..c8070f0207 --- /dev/null +++ b/queue-6.6/crypto-caam-fix-dma-corruption-on-long-hmac-keys.patch @@ -0,0 +1,49 @@ +From 8f78e4185a524594bdb514f464e8a307d075e43a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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 +Signed-off-by: Horia Geantă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/crypto-caam-fix-overflow-on-long-hmac-keys.patch b/queue-6.6/crypto-caam-fix-overflow-on-long-hmac-keys.patch new file mode 100644 index 0000000000..a4ac1a007c --- /dev/null +++ b/queue-6.6/crypto-caam-fix-overflow-on-long-hmac-keys.patch @@ -0,0 +1,48 @@ +From 6d694604fbe75496d91d77843a88c4f908c0cffa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ă + +[ 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ă +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch b/queue-6.6/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch new file mode 100644 index 0000000000..26e0c8d32c --- /dev/null +++ b/queue-6.6/dt-bindings-auxdisplay-ht16k33-use-unevaluatedproper.patch @@ -0,0 +1,42 @@ +From b77cc2893443740726665f9fafb0328a0e9f591f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 16:59:55 -0500 +Subject: dt-bindings: auxdisplay: ht16k33: Use unevaluatedProperties to fix + common property warning + +From: Frank Li + +[ 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) +Signed-off-by: Frank Li +Signed-off-by: Andy Shevchenko +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.6/hid-multitouch-check-to-ensure-report-responses-matc.patch b/queue-6.6/hid-multitouch-check-to-ensure-report-responses-matc.patch new file mode 100644 index 0000000000..b227f3487c --- /dev/null +++ b/queue-6.6/hid-multitouch-check-to-ensure-report-responses-matc.patch @@ -0,0 +1,52 @@ +From e8ce74b4d0cab7cd9edde4d08c9f0182262cba3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 16:30:25 +0000 +Subject: HID: multitouch: Check to ensure report responses match the request + +From: Lee Jones + +[ 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 +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch b/queue-6.6/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch new file mode 100644 index 0000000000..a0c083890a --- /dev/null +++ b/queue-6.6/hid-wacom-fix-out-of-bounds-read-in-wacom_intuos_bt_.patch @@ -0,0 +1,60 @@ +From 7ec01d1280368b9a7c0b34cfc30f018ed67c0e68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Jason Gerecke +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch b/queue-6.6/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch new file mode 100644 index 0000000000..55a4404c19 --- /dev/null +++ b/queue-6.6/i2c-tegra-don-t-mark-devices-with-pins-as-irq-safe.patch @@ -0,0 +1,58 @@ +From dac15ab7d1cc60478656f6577d8092f91fa0a717 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 13:32:11 +0900 +Subject: i2c: tegra: Don't mark devices with pins as IRQ safe + +From: Mikko Perttunen + +[ 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 +Reported-by: Russell King +Link: https://lore.kernel.org/all/E1vsNBv-00000009nfA-27ZK@rmk-PC.armlinux.org.uk/ +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch b/queue-6.6/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch new file mode 100644 index 0000000000..d69e4e7870 --- /dev/null +++ b/queue-6.6/ip6_tunnel-clear-skb2-cb-in-ip4ip6_err.patch @@ -0,0 +1,59 @@ +From fc2dbaf3f42812ff1c5d7a6fd13f4ba4ea37c818 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +From: Eric Dumazet + +[ 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 +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch b/queue-6.6/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch new file mode 100644 index 0000000000..0a7f01f63e --- /dev/null +++ b/queue-6.6/ipv6-avoid-overflows-in-ip6_datagram_send_ctl.patch @@ -0,0 +1,189 @@ +From 1b7178c02b4aef8ddd29ef736929499a75bb9f01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 15:47:21 +0000 +Subject: ipv6: avoid overflows in ip6_datagram_send_ctl() + +From: Eric Dumazet + +[ Upstream commit 4e453375561fc60820e6b9d8ebeb6b3ee177d42e ] + +Yiming Qian reported : + + 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. + + +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 +Closes: https://lore.kernel.org/netdev/CAL_bE8JNzawgr5OX5m+3jnQDHry2XxhQT5=jThW1zDPtUikRYA@mail.gmail.com/ +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401154721.3740056-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch b/queue-6.6/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch new file mode 100644 index 0000000000..da30f95ed3 --- /dev/null +++ b/queue-6.6/ipv6-icmp-clear-skb2-cb-in-ip6_err_gen_icmpv6_unreac.patch @@ -0,0 +1,68 @@ +From f8396d0c62320e07deedf6dbef7eb7976139f565 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:26:08 +0000 +Subject: ipv6: icmp: clear skb2->cb[] in ip6_err_gen_icmpv6_unreach() + +From: Eric Dumazet + +[ 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 +Closes: https://sashiko.dev/#/patchset/20260326155138.2429480-1-edumazet%40google.com +Signed-off-by: Eric Dumazet +Cc: Oskar Kjos +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326202608.2976021-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch b/queue-6.6/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch new file mode 100644 index 0000000000..a51bb47376 --- /dev/null +++ b/queue-6.6/ipv6-prevent-possible-uaf-in-addrconf_permanent_addr.patch @@ -0,0 +1,50 @@ +From 32325032c33431d4a80a39ebe856134c0cd4a5ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 10:52:57 +0100 +Subject: ipv6: prevent possible UaF in addrconf_permanent_addr() + +From: Paolo Abeni + +[ 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 +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 +Link: https://patch.msgid.link/ef973c3a8cb4f8f1787ed469f3e5391b9fe95aa0.1774601542.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch b/queue-6.6/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch new file mode 100644 index 0000000000..79f45ebc4b --- /dev/null +++ b/queue-6.6/net-fec-fix-the-ptp-periodic-output-sysfs-interface.patch @@ -0,0 +1,50 @@ +From 12765c79b4c5281001e977d602b50184ae86c848 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:32:30 +0100 +Subject: net: fec: fix the PTP periodic output sysfs interface + +From: Buday Csaba + +[ 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 +Link: https://patch.msgid.link/8ec2afe88423c2231f9cf8044d212ce57846670e.1774359059.git.buday.csaba@prolan.hu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch b/queue-6.6/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch new file mode 100644 index 0000000000..4b92e6bd8d --- /dev/null +++ b/queue-6.6/net-hsr-fix-vlan-add-unwind-on-slave-errors.patch @@ -0,0 +1,93 @@ +From 23ab5fa68fc602f5b5a9e84671e2a6d98973f04b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 11:22:43 +0200 +Subject: net: hsr: fix VLAN add unwind on slave errors + +From: Luka Gejak + +[ 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 +Link: https://patch.msgid.link/20260401092243.52121-3-luka.gejak@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch b/queue-6.6/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch new file mode 100644 index 0000000000..60ab19a737 --- /dev/null +++ b/queue-6.6/net-ipv6-flowlabel-defer-exclusive-option-free-until.patch @@ -0,0 +1,63 @@ +From 0ae4b7665722b3195040935b1e2578fdde376483 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 16:46:24 +0800 +Subject: net: ipv6: flowlabel: defer exclusive option free until RCU teardown + +From: Zhengchuan Liang + +[ 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 +Reported-by: Juefei Pu +Co-developed-by: Yuan Tan +Signed-off-by: Yuan Tan +Suggested-by: Xin Liu +Tested-by: Ren Wei +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/07351f0ec47bcee289576f39f9354f4a64add6e4.1774855883.git.zcliangcn@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch b/queue-6.6/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch new file mode 100644 index 0000000000..813d18f49e --- /dev/null +++ b/queue-6.6/net-ipv6-ioam6-prevent-schema-length-wraparound-in-t.patch @@ -0,0 +1,54 @@ +From 84e8275b4793bdb0fdcb9d5fa3da22b0f7cbfbd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 15:41:52 +0800 +Subject: net/ipv6: ioam6: prevent schema length wraparound in trace fill + +From: Pengpeng Hou + +[ 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 +Reviewed-by: Justin Iurman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch b/queue-6.6/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch new file mode 100644 index 0000000000..bef014ac94 --- /dev/null +++ b/queue-6.6/net-ipv6-ndisc-fix-ndisc_ra_useropt-to-initialize-nd.patch @@ -0,0 +1,43 @@ +From 762e31e3ede1487e1e74a939273e7eb43ca1fdc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324224925.2437775-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch b/queue-6.6/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch new file mode 100644 index 0000000000..c825cd34c9 --- /dev/null +++ b/queue-6.6/net-macb-fix-clk-handling-on-pci-glue-driver-removal.patch @@ -0,0 +1,127 @@ +From 05bdf7cab0aeb359b881c3b0e5112a7a84a6e4ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:40 +0300 +Subject: net: macb: fix clk handling on PCI glue driver removal + +From: Fedor Pchelkin + +[ 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: + + 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 + + +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 +Link: https://patch.msgid.link/20260330184542.626619-1-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-macb-properly-unregister-fixed-rate-clocks.patch b/queue-6.6/net-macb-properly-unregister-fixed-rate-clocks.patch new file mode 100644 index 0000000000..e04ac41e09 --- /dev/null +++ b/queue-6.6/net-macb-properly-unregister-fixed-rate-clocks.patch @@ -0,0 +1,52 @@ +From 44772290607ee1c7db98f6bb7e38c4f26ccf23f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:45:41 +0300 +Subject: net: macb: properly unregister fixed rate clocks + +From: Fedor Pchelkin + +[ 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 +Link: https://patch.msgid.link/20260330184542.626619-2-pchelkin@ispras.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-mlx5-avoid-no-data-available-when-fw-version-que.patch b/queue-6.6/net-mlx5-avoid-no-data-available-when-fw-version-que.patch new file mode 100644 index 0000000000..0ce6b25ea7 --- /dev/null +++ b/queue-6.6/net-mlx5-avoid-no-data-available-when-fw-version-que.patch @@ -0,0 +1,175 @@ +From 3a4a3cf6b346eee3b5ba22d3e474a2a833121e9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:14 +0300 +Subject: net/mlx5: Avoid "No data available" when FW version queries fail + +From: Saeed Mahameed + +[ 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 +Reviewed-by: Moshe Shemesh +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.6/net-mlx5-lag-check-for-lag-device-before-creating-de.patch b/queue-6.6/net-mlx5-lag-check-for-lag-device-before-creating-de.patch new file mode 100644 index 0000000000..747103d027 --- /dev/null +++ b/queue-6.6/net-mlx5-lag-check-for-lag-device-before-creating-de.patch @@ -0,0 +1,52 @@ +From 3f44ed8eb8fe32a971965cb37f71f50414aebe9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:40:13 +0300 +Subject: net/mlx5: lag: Check for LAG device before creating debugfs + +From: Shay Drory + +[ 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 +Reviewed-by: Mark Bloch +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260330194015.53585-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch b/queue-6.6/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch new file mode 100644 index 0000000000..f8c31f168e --- /dev/null +++ b/queue-6.6/net-qrtr-replace-qrtr_tx_flow-radix_tree-with-xarray.patch @@ -0,0 +1,152 @@ +From 68f0927f551eb7ddb102c078065a6533bb5d1c1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260324080645.290197-1-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch b/queue-6.6/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch new file mode 100644 index 0000000000..1b56d95346 --- /dev/null +++ b/queue-6.6/net-sched-cls_api-fix-tc_chain_fill_node-to-initiali.patch @@ -0,0 +1,42 @@ +From 0d6bf8bde738c3024812f0aea399b62bbae4649f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260328211436.1010152-1-echelonh@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch b/queue-6.6/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch new file mode 100644 index 0000000000..d91e3467ca --- /dev/null +++ b/queue-6.6/net-sched-cls_flow-fix-null-pointer-dereference-on-s.patch @@ -0,0 +1,62 @@ +From 98eba79176143eb3ed722b7b4e8c172d9608212f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:16 -0700 +Subject: net/sched: cls_flow: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-2-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch b/queue-6.6/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch new file mode 100644 index 0000000000..c1ea9060b0 --- /dev/null +++ b/queue-6.6/net-sched-cls_fw-fix-null-pointer-dereference-on-sha.patch @@ -0,0 +1,65 @@ +From 1e7566c846448d4598f806e2958169cfb2dd2005 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:02:15 -0700 +Subject: net/sched: cls_fw: fix NULL pointer dereference on shared blocks + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260331050217.504278-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch b/queue-6.6/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch new file mode 100644 index 0000000000..d36badda35 --- /dev/null +++ b/queue-6.6/net-sched-sch_hfsc-fix-divide-by-zero-in-rtsc_min.patch @@ -0,0 +1,62 @@ +From af78df3583ffe6d913687da1a0b9a739de8e5807 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 13:43:09 -0700 +Subject: net/sched: sch_hfsc: fix divide-by-zero in rtsc_min() + +From: Xiang Mei + +[ 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 +Signed-off-by: Xiang Mei +Acked-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260326204310.1549327-1-xmei5@asu.edu +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch b/queue-6.6/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch new file mode 100644 index 0000000000..87056e7a2c --- /dev/null +++ b/queue-6.6/net-sched-sch_netem-fix-out-of-bounds-access-in-pack.patch @@ -0,0 +1,57 @@ +From ae33b3a0ada541c59ae8c81152f1bd7bc265eb87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reported-by: Juefei Pu +Signed-off-by: Yuan Tan +Signed-off-by: Xin Liu +Signed-off-by: Yuhang Zheng +Signed-off-by: Yucheng Lu +Reviewed-by: Stephen Hemminger +Link: https://patch.msgid.link/45435c0935df877853a81e6d06205ac738ec65fa.1774941614.git.kanolyc@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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<data[get_random_u32_below(skb_headlen(skb))] ^= ++ 1 << get_random_u32_below(8); + } + + if (unlikely(q->t_len >= sch->limit)) { +-- +2.53.0 + diff --git a/queue-6.6/net-x25-fix-overflow-when-accumulating-packets.patch b/queue-6.6/net-x25-fix-overflow-when-accumulating-packets.patch new file mode 100644 index 0000000000..e2997b9d31 --- /dev/null +++ b/queue-6.6/net-x25-fix-overflow-when-accumulating-packets.patch @@ -0,0 +1,55 @@ +From 46c5ff0646cae2cf8428394030b476d7590efcb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:18 +0200 +Subject: net/x25: Fix overflow when accumulating packets + +From: Martin Schiller + +[ 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 +Signed-off-by: Martin Schiller +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-2-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-x25-fix-potential-double-free-of-skb.patch b/queue-6.6/net-x25-fix-potential-double-free-of-skb.patch new file mode 100644 index 0000000000..8f069a3f61 --- /dev/null +++ b/queue-6.6/net-x25-fix-potential-double-free-of-skb.patch @@ -0,0 +1,65 @@ +From 59befe0c6c5c8beb39c287398497b695574b9b75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 09:43:17 +0200 +Subject: net/x25: Fix potential double free of skb + +From: Martin Schiller + +[ 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 +Link: https://patch.msgid.link/20260331-x25_fraglen-v4-1-3e69f18464b4@dev.tdt.de +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch b/queue-6.6/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch new file mode 100644 index 0000000000..355daf2e4a --- /dev/null +++ b/queue-6.6/net-xilinx-axienet-correct-bd-length-masks-to-match-.patch @@ -0,0 +1,53 @@ +From e1ed3fe10cc5f667ff3d84e069a69cada63e0ff8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Sean Anderson +Link: https://patch.msgid.link/20260327073238.134948-2-suraj.gupta2@amd.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch b/queue-6.6/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch new file mode 100644 index 0000000000..ae013c713f --- /dev/null +++ b/queue-6.6/netfilter-ctnetlink-ignore-explicit-helper-on-new-ex.patch @@ -0,0 +1,168 @@ +From 9bc3343eec332a35ec02d67e27b7a1c615dd03fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 11:26:22 +0200 +Subject: netfilter: ctnetlink: ignore explicit helper on new expectations + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch b/queue-6.6/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch new file mode 100644 index 0000000000..1c162007ef --- /dev/null +++ b/queue-6.6/netfilter-ctnetlink-zero-expect-nat-fields-when-cta_.patch @@ -0,0 +1,58 @@ +From e4dc0c6d4c25cfd00dde3eecb1ea1add472c2f0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 14:17:12 +0800 +Subject: netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT + absent + +From: Qi Tang + +[ 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 +Signed-off-by: Qi Tang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-flowtable-strictly-check-for-maximum-numbe.patch b/queue-6.6/netfilter-flowtable-strictly-check-for-maximum-numbe.patch new file mode 100644 index 0000000000..7ba0312ba3 --- /dev/null +++ b/queue-6.6/netfilter-flowtable-strictly-check-for-maximum-numbe.patch @@ -0,0 +1,504 @@ +From 06e835cc7f16e71c5b1c1f7bc5888121d5e7cabb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 00:17:09 +0100 +Subject: netfilter: flowtable: strictly check for maximum number of actions + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + #include + ++#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 + diff --git a/queue-6.6/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch b/queue-6.6/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch new file mode 100644 index 0000000000..4a8536c37d --- /dev/null +++ b/queue-6.6/netfilter-ipset-use-nla_strcmp-for-ipset_attr_name-a.patch @@ -0,0 +1,85 @@ +From 7492a56ee779dfe0c08ed7857b224bfc27b08d96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:16:34 +0200 +Subject: netfilter: ipset: use nla_strcmp for IPSET_ATTR_NAME attr + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-nf_conntrack_expect-honor-expectation-help.patch b/queue-6.6/netfilter-nf_conntrack_expect-honor-expectation-help.patch new file mode 100644 index 0000000000..ceb25b0a83 --- /dev/null +++ b/queue-6.6/netfilter-nf_conntrack_expect-honor-expectation-help.patch @@ -0,0 +1,212 @@ +From 8ec3612d9d1460105ca7bf14d442a8989fc82ace Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:02 +0100 +Subject: netfilter: nf_conntrack_expect: honor expectation helper field + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch b/queue-6.6/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch new file mode 100644 index 0000000000..2e1dc570e5 --- /dev/null +++ b/queue-6.6/netfilter-nf_conntrack_expect-store-netns-and-zone-i.patch @@ -0,0 +1,158 @@ +From cc51dac6f9e9c259518d08962b8d319de415281a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 22:39:55 +0100 +Subject: netfilter: nf_conntrack_expect: store netns and zone in expectation + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-nf_conntrack_expect-use-expect-helper.patch b/queue-6.6/netfilter-nf_conntrack_expect-use-expect-helper.patch new file mode 100644 index 0000000000..90566a95d7 --- /dev/null +++ b/queue-6.6/netfilter-nf_conntrack_expect-use-expect-helper.patch @@ -0,0 +1,148 @@ +From 5fc3c0f73c078bdef55708b24f3d0ae65038a90c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 14:11:03 +0100 +Subject: netfilter: nf_conntrack_expect: use expect->helper + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch b/queue-6.6/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch new file mode 100644 index 0000000000..b9241d7059 --- /dev/null +++ b/queue-6.6/netfilter-nf_conntrack_helper-pass-helper-to-expect-.patch @@ -0,0 +1,63 @@ +From 3502a335e7f4edb7820192cba352d174e80ea764 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 00:50:36 +0800 +Subject: netfilter: nf_conntrack_helper: pass helper to expect cleanup + +From: Qi Tang + +[ 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 +Reviewed-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch b/queue-6.6/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch new file mode 100644 index 0000000000..da62e41199 --- /dev/null +++ b/queue-6.6/netfilter-nf_tables-reject-immediate-nf_queue-verdic.patch @@ -0,0 +1,52 @@ +From f28df0426a5596562a3550295a8da63f20862ad2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:08:02 +0200 +Subject: netfilter: nf_tables: reject immediate NF_QUEUE verdict + +From: Pablo Neira Ayuso + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-nfnetlink_log-account-for-netlink-header-s.patch b/queue-6.6/netfilter-nfnetlink_log-account-for-netlink-header-s.patch new file mode 100644 index 0000000000..8280ed2b51 --- /dev/null +++ b/queue-6.6/netfilter-nfnetlink_log-account-for-netlink-header-s.patch @@ -0,0 +1,40 @@ +From 85c67ac6dfbc702a840261d53cccdea2f5b8f1c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:17:24 +0100 +Subject: netfilter: nfnetlink_log: account for netlink header size + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-x_tables-ensure-names-are-nul-terminated.patch b/queue-6.6/netfilter-x_tables-ensure-names-are-nul-terminated.patch new file mode 100644 index 0000000000..66cf23ee5b --- /dev/null +++ b/queue-6.6/netfilter-x_tables-ensure-names-are-nul-terminated.patch @@ -0,0 +1,66 @@ +From c9d261e8a5abc086414069f31544f41a7ab2e92e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 23:13:36 +0200 +Subject: netfilter: x_tables: ensure names are nul-terminated + +From: Florian Westphal + +[ 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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch b/queue-6.6/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch new file mode 100644 index 0000000000..2fe8fa5a91 --- /dev/null +++ b/queue-6.6/netfilter-x_tables-restrict-xt_check_match-xt_check_.patch @@ -0,0 +1,101 @@ +From 3a0fa73fb361fce735f7117430c8d52ae889b3df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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: + + 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) + + 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/nfc-pn533-bound-the-uart-receive-buffer.patch b/queue-6.6/nfc-pn533-bound-the-uart-receive-buffer.patch new file mode 100644 index 0000000000..ca2fe864f4 --- /dev/null +++ b/queue-6.6/nfc-pn533-bound-the-uart-receive-buffer.patch @@ -0,0 +1,45 @@ +From a850e0321247d1548eaf0a7d235aa549f6127431 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:20:33 +0800 +Subject: NFC: pn533: bound the UART receive buffer + +From: Pengpeng Hou + +[ 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 +Link: https://patch.msgid.link/20260326142033.82297-1-pengpeng@iscas.ac.cn +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/objtool-fix-clang-jump-table-detection.patch b/queue-6.6/objtool-fix-clang-jump-table-detection.patch new file mode 100644 index 0000000000..80038b5d66 --- /dev/null +++ b/queue-6.6/objtool-fix-clang-jump-table-detection.patch @@ -0,0 +1,47 @@ +From 61ffca641c3547581d6908f47c3c85620f63dfb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:03:05 -0700 +Subject: objtool: Fix Clang jump table detection + +From: Josh Poimboeuf + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/rds-ib-reject-frmr-registration-before-ib-connection.patch b/queue-6.6/rds-ib-reject-frmr-registration-before-ib-connection.patch new file mode 100644 index 0000000000..d27120e169 --- /dev/null +++ b/queue-6.6/rds-ib-reject-frmr-registration-before-ib-connection.patch @@ -0,0 +1,76 @@ +From 8344e6ab6a54f7b2a17d587e19f3c20f702a1354 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 00:32:38 +0800 +Subject: rds: ib: reject FRMR registration before IB connection is established + +From: Weiming Shi + +[ 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 +Signed-off-by: Weiming Shi +Reviewed-by: Allison Henderson +Link: https://patch.msgid.link/20260330163237.2752440-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/series b/queue-6.6/series new file mode 100644 index 0000000000..f54cbf96a6 --- /dev/null +++ b/queue-6.6/series @@ -0,0 +1,64 @@ +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 diff --git a/queue-6.6/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch b/queue-6.6/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch new file mode 100644 index 0000000000..69a31b091b --- /dev/null +++ b/queue-6.6/spi-geni-qcom-check-dma-interrupts-early-in-isr.patch @@ -0,0 +1,59 @@ +From 75227d0609dfefbe714288d95fa077e682de9e21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 21:49:01 +0530 +Subject: spi: geni-qcom: Check DMA interrupts early in ISR + +From: Praveen Talari + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260313-spi-geni-qcom-fix-dma-irq-handling-v1-1-0bd122589e02@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/tg3-fix-race-for-querying-speed-duplex.patch b/queue-6.6/tg3-fix-race-for-querying-speed-duplex.patch new file mode 100644 index 0000000000..b2c8a93d7a --- /dev/null +++ b/queue-6.6/tg3-fix-race-for-querying-speed-duplex.patch @@ -0,0 +1,40 @@ +From 6c4d36a5ad7c1fd1961b1ed31ca52caab6891037 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 12:20:53 +0100 +Subject: tg3: Fix race for querying speed/duplex + +From: Thomas Bogendoerfer + +[ 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 +Reviewed-by: Pavan Chebbi +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/tg3-replace-placeholder-mac-address-with-device-prop.patch b/queue-6.6/tg3-replace-placeholder-mac-address-with-device-prop.patch new file mode 100644 index 0000000000..784fcb234e --- /dev/null +++ b/queue-6.6/tg3-replace-placeholder-mac-address-with-device-prop.patch @@ -0,0 +1,69 @@ +From e1fb9d8aed58f8a19fb9af8736fc67fcf650d44a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 03:24:30 +0530 +Subject: tg3: replace placeholder MAC address with device property + +From: Paul SAGE + +[ 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 + +Co-developed-by: Vincent MORVAN +Signed-off-by: Vincent MORVAN +Signed-off-by: Paul SAGE +Signed-off-by: Atharva Tiwari +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20260314215432.3589-1-atharvatiwarilinuxdev@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.6/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch b/queue-6.6/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch new file mode 100644 index 0000000000..5fb743f675 --- /dev/null +++ b/queue-6.6/wifi-ath11k-pass-the-correct-value-of-each-tid-durin.patch @@ -0,0 +1,94 @@ +From c0be9f661fc8a4a29077421dbc36f45807259e82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260319065608.2408179-1-reshma.rajkumar@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + 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 +@@ -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 + diff --git a/queue-6.6/wifi-ath11k-skip-status-ring-entry-processing.patch b/queue-6.6/wifi-ath11k-skip-status-ring-entry-processing.patch new file mode 100644 index 0000000000..db603a0ce1 --- /dev/null +++ b/queue-6.6/wifi-ath11k-skip-status-ring-entry-processing.patch @@ -0,0 +1,209 @@ +From 939642a71e6125cdeb92ad6626310a8f1394ed57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 May 2024 16:24:16 +0300 +Subject: wifi: ath11k: skip status ring entry processing + +From: Venkateswara Naralasetty + +[ 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 +Co-developed-by: Tamizh Chelvam Raja +Signed-off-by: Tamizh Chelvam Raja +Signed-off-by: Kalle Valo +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 +--- + 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 +@@ -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 + #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 + diff --git a/queue-6.6/wifi-ath11k-use-dma_alloc_noncoherent-for-rx_tid-buf.patch b/queue-6.6/wifi-ath11k-use-dma_alloc_noncoherent-for-rx_tid-buf.patch new file mode 100644 index 0000000000..5709e9c847 --- /dev/null +++ b/queue-6.6/wifi-ath11k-use-dma_alloc_noncoherent-for-rx_tid-buf.patch @@ -0,0 +1,278 @@ +From 697499bc5c8357db99d3840be3e1246340cfbf44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jan 2025 22:12:19 +0530 +Subject: wifi: ath11k: Use dma_alloc_noncoherent for rx_tid buffer allocation + +From: P Praneesh + +[ 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 +Tested-by: Tim Harvey +Link: https://patch.msgid.link/20250119164219.647059-3-quic_ppranees@quicinc.com +Signed-off-by: Jeff Johnson +Stable-dep-of: e225b36f83d7 ("wifi: ath11k: Pass the correct value of each TID during a stop AMPDU session") +Signed-off-by: Sasha Levin +--- + 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 +@@ -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 +